]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - image.c
Add a Quake Live-style mouse acceleration mode.
[xonotic/darkplaces.git] / image.c
1
2 #include "quakedef.h"
3 #include "image.h"
4 #include "jpeg.h"
5 #include "image_png.h"
6 #include "r_shadow.h"
7 #include "wad.h"
8
9 int             image_width;
10 int             image_height;
11
12 static unsigned char *Image_GetEmbeddedPicBGRA(const char *name);
13
14 static void Image_CopyAlphaFromBlueBGRA(unsigned char *outpixels, const unsigned char *inpixels, int w, int h)
15 {
16         int i, n;
17         n = w * h;
18         for(i = 0; i < n; ++i)
19                 outpixels[4*i+3] = inpixels[4*i]; // blue channel
20 }
21
22 #if 1
23 // written by LadyHavoc in a readable way, optimized by Vic, further optimized by LadyHavoc (the non-special index case), readable version preserved below this
24 void Image_CopyMux(unsigned char *outpixels, const unsigned char *inpixels, int inputwidth, int inputheight, qboolean inputflipx, qboolean inputflipy, qboolean inputflipdiagonal, int numoutputcomponents, int numinputcomponents, int *outputinputcomponentindices)
25 {
26         int index, c, x, y;
27         const unsigned char *in, *line;
28         int row_inc = (inputflipy ? -inputwidth : inputwidth) * numinputcomponents, col_inc = (inputflipx ? -1 : 1) * numinputcomponents;
29         int row_ofs = (inputflipy ? (inputheight - 1) * inputwidth * numinputcomponents : 0), col_ofs = (inputflipx ? (inputwidth - 1) * numinputcomponents : 0);
30
31         for (c = 0; c < numoutputcomponents; c++)
32                 if (outputinputcomponentindices[c] & 0x80000000)
33                         break;
34         if (c < numoutputcomponents)
35         {
36                 // special indices used
37                 if (inputflipdiagonal)
38                 {
39                         for (x = 0, line = inpixels + col_ofs; x < inputwidth; x++, line += col_inc)
40                                 for (y = 0, in = line + row_ofs; y < inputheight; y++, in += row_inc, outpixels += numoutputcomponents)
41                                         for (c = 0; c < numoutputcomponents; c++)
42                                                 outpixels[c] = ((index = outputinputcomponentindices[c]) & 0x80000000) ? index : in[index];
43                 }
44                 else
45                 {
46                         for (y = 0, line = inpixels + row_ofs; y < inputheight; y++, line += row_inc)
47                                 for (x = 0, in = line + col_ofs; x < inputwidth; x++, in += col_inc, outpixels += numoutputcomponents)
48                                         for (c = 0; c < numoutputcomponents; c++)
49                                                 outpixels[c] = ((index = outputinputcomponentindices[c]) & 0x80000000) ? index : in[index];
50                 }
51         }
52         else
53         {
54                 // special indices not used
55                 if (inputflipdiagonal)
56                 {
57                         for (x = 0, line = inpixels + col_ofs; x < inputwidth; x++, line += col_inc)
58                                 for (y = 0, in = line + row_ofs; y < inputheight; y++, in += row_inc, outpixels += numoutputcomponents)
59                                         for (c = 0; c < numoutputcomponents; c++)
60                                                 outpixels[c] = in[outputinputcomponentindices[c]];
61                 }
62                 else
63                 {
64                         for (y = 0, line = inpixels + row_ofs; y < inputheight; y++, line += row_inc)
65                                 for (x = 0, in = line + col_ofs; x < inputwidth; x++, in += col_inc, outpixels += numoutputcomponents)
66                                         for (c = 0; c < numoutputcomponents; c++)
67                                                 outpixels[c] = in[outputinputcomponentindices[c]];
68                 }
69         }
70 }
71 #else
72 // intentionally readable version
73 void Image_CopyMux(unsigned char *outpixels, const unsigned char *inpixels, int inputwidth, int inputheight, qboolean inputflipx, qboolean inputflipy, qboolean inputflipdiagonal, int numoutputcomponents, int numinputcomponents, int *outputinputcomponentindices)
74 {
75         int index, c, x, y;
76         const unsigned char *in, *inrow, *incolumn;
77         if (inputflipdiagonal)
78         {
79                 for (x = 0;x < inputwidth;x++)
80                 {
81                         for (y = 0;y < inputheight;y++)
82                         {
83                                 in = inpixels + ((inputflipy ? inputheight - 1 - y : y) * inputwidth + (inputflipx ? inputwidth - 1 - x : x)) * numinputcomponents;
84                                 for (c = 0;c < numoutputcomponents;c++)
85                                 {
86                                         index = outputinputcomponentindices[c];
87                                         if (index & 0x80000000)
88                                                 *outpixels++ = index;
89                                         else
90                                                 *outpixels++ = in[index];
91                                 }
92                         }
93                 }
94         }
95         else
96         {
97                 for (y = 0;y < inputheight;y++)
98                 {
99                         for (x = 0;x < inputwidth;x++)
100                         {
101                                 in = inpixels + ((inputflipy ? inputheight - 1 - y : y) * inputwidth + (inputflipx ? inputwidth - 1 - x : x)) * numinputcomponents;
102                                 for (c = 0;c < numoutputcomponents;c++)
103                                 {
104                                         index = outputinputcomponentindices[c];
105                                         if (index & 0x80000000)
106                                                 *outpixels++ = index;
107                                         else
108                                                 *outpixels++ = in[index];
109                                 }
110                         }
111                 }
112         }
113 }
114 #endif
115
116 void Image_GammaRemapRGB(const unsigned char *in, unsigned char *out, int pixels, const unsigned char *gammar, const unsigned char *gammag, const unsigned char *gammab)
117 {
118         while (pixels--)
119         {
120                 out[0] = gammar[in[0]];
121                 out[1] = gammag[in[1]];
122                 out[2] = gammab[in[2]];
123                 in += 3;
124                 out += 3;
125         }
126 }
127
128 // note: pal must be 32bit color
129 void Image_Copy8bitBGRA(const unsigned char *in, unsigned char *out, int pixels, const unsigned int *pal)
130 {
131         int *iout = (int *)out;
132         while (pixels >= 8)
133         {
134                 iout[0] = pal[in[0]];
135                 iout[1] = pal[in[1]];
136                 iout[2] = pal[in[2]];
137                 iout[3] = pal[in[3]];
138                 iout[4] = pal[in[4]];
139                 iout[5] = pal[in[5]];
140                 iout[6] = pal[in[6]];
141                 iout[7] = pal[in[7]];
142                 in += 8;
143                 iout += 8;
144                 pixels -= 8;
145         }
146         if (pixels & 4)
147         {
148                 iout[0] = pal[in[0]];
149                 iout[1] = pal[in[1]];
150                 iout[2] = pal[in[2]];
151                 iout[3] = pal[in[3]];
152                 in += 4;
153                 iout += 4;
154         }
155         if (pixels & 2)
156         {
157                 iout[0] = pal[in[0]];
158                 iout[1] = pal[in[1]];
159                 in += 2;
160                 iout += 2;
161         }
162         if (pixels & 1)
163                 iout[0] = pal[in[0]];
164 }
165
166 /*
167 =================================================================
168
169   PCX Loading
170
171 =================================================================
172 */
173
174 typedef struct pcx_s
175 {
176     char        manufacturer;
177     char        version;
178     char        encoding;
179     char        bits_per_pixel;
180     unsigned short      xmin,ymin,xmax,ymax;
181     unsigned short      hres,vres;
182     unsigned char       palette[48];
183     char        reserved;
184     char        color_planes;
185     unsigned short      bytes_per_line;
186     unsigned short      palette_type;
187     char        filler[58];
188 } pcx_t;
189
190 /*
191 ============
192 LoadPCX
193 ============
194 */
195 static unsigned char* LoadPCX_BGRA (const unsigned char *f, int filesize, int *miplevel)
196 {
197         pcx_t pcx;
198         unsigned char *a, *b, *image_buffer, *pbuf;
199         const unsigned char *palette, *fin, *enddata;
200         int x, y, x2, dataByte;
201
202         if (filesize < (int)sizeof(pcx) + 768)
203         {
204                 Con_Print("Bad pcx file\n");
205                 return NULL;
206         }
207
208         fin = f;
209
210         memcpy(&pcx, fin, sizeof(pcx));
211         fin += sizeof(pcx);
212
213         // LadyHavoc: big-endian support ported from QF newtree
214         pcx.xmax = LittleShort (pcx.xmax);
215         pcx.xmin = LittleShort (pcx.xmin);
216         pcx.ymax = LittleShort (pcx.ymax);
217         pcx.ymin = LittleShort (pcx.ymin);
218         pcx.hres = LittleShort (pcx.hres);
219         pcx.vres = LittleShort (pcx.vres);
220         pcx.bytes_per_line = LittleShort (pcx.bytes_per_line);
221         pcx.palette_type = LittleShort (pcx.palette_type);
222
223         image_width = pcx.xmax + 1 - pcx.xmin;
224         image_height = pcx.ymax + 1 - pcx.ymin;
225         if (pcx.manufacturer != 0x0a || pcx.version != 5 || pcx.encoding != 1 || pcx.bits_per_pixel != 8 || image_width > 32768 || image_height > 32768 || image_width <= 0 || image_height <= 0)
226         {
227                 Con_Print("Bad pcx file\n");
228                 return NULL;
229         }
230
231         palette = f + filesize - 768;
232
233         image_buffer = (unsigned char *)Mem_Alloc(tempmempool, image_width*image_height*4);
234         if (!image_buffer)
235         {
236                 Con_Printf("LoadPCX: not enough memory for %i by %i image\n", image_width, image_height);
237                 return NULL;
238         }
239         pbuf = image_buffer + image_width*image_height*3;
240         enddata = palette;
241
242         for (y = 0;y < image_height && fin < enddata;y++)
243         {
244                 a = pbuf + y * image_width;
245                 for (x = 0;x < image_width && fin < enddata;)
246                 {
247                         dataByte = *fin++;
248                         if(dataByte >= 0xC0)
249                         {
250                                 if (fin >= enddata)
251                                         break;
252                                 x2 = x + (dataByte & 0x3F);
253                                 dataByte = *fin++;
254                                 if (x2 > image_width)
255                                         x2 = image_width; // technically an error
256                                 while(x < x2)
257                                         a[x++] = dataByte;
258                         }
259                         else
260                                 a[x++] = dataByte;
261                 }
262                 while(x < image_width)
263                         a[x++] = 0;
264         }
265
266         a = image_buffer;
267         b = pbuf;
268
269         for(x = 0;x < image_width*image_height;x++)
270         {
271                 y = *b++ * 3;
272                 *a++ = palette[y+2];
273                 *a++ = palette[y+1];
274                 *a++ = palette[y];
275                 *a++ = 255;
276         }
277
278         return image_buffer;
279 }
280
281 /*
282 ============
283 LoadPCX
284 ============
285 */
286 qboolean LoadPCX_QWSkin(const unsigned char *f, int filesize, unsigned char *pixels, int outwidth, int outheight)
287 {
288         pcx_t pcx;
289         unsigned char *a;
290         const unsigned char *fin, *enddata;
291         int x, y, x2, dataByte, pcxwidth, pcxheight;
292
293         if (filesize < (int)sizeof(pcx) + 768)
294                 return false;
295
296         image_width = outwidth;
297         image_height = outheight;
298         fin = f;
299
300         memcpy(&pcx, fin, sizeof(pcx));
301         fin += sizeof(pcx);
302
303         // LadyHavoc: big-endian support ported from QF newtree
304         pcx.xmax = LittleShort (pcx.xmax);
305         pcx.xmin = LittleShort (pcx.xmin);
306         pcx.ymax = LittleShort (pcx.ymax);
307         pcx.ymin = LittleShort (pcx.ymin);
308         pcx.hres = LittleShort (pcx.hres);
309         pcx.vres = LittleShort (pcx.vres);
310         pcx.bytes_per_line = LittleShort (pcx.bytes_per_line);
311         pcx.palette_type = LittleShort (pcx.palette_type);
312
313         pcxwidth = pcx.xmax + 1 - pcx.xmin;
314         pcxheight = pcx.ymax + 1 - pcx.ymin;
315         if (pcx.manufacturer != 0x0a || pcx.version != 5 || pcx.encoding != 1 || pcx.bits_per_pixel != 8 || pcxwidth > 4096 || pcxheight > 4096 || pcxwidth <= 0 || pcxheight <= 0)
316                 return false;
317
318         enddata = f + filesize - 768;
319
320         for (y = 0;y < outheight && fin < enddata;y++)
321         {
322                 a = pixels + y * outwidth;
323                 // pad the output with blank lines if needed
324                 if (y >= pcxheight)
325                 {
326                         memset(a, 0, outwidth);
327                         continue;
328                 }
329                 for (x = 0;x < pcxwidth;)
330                 {
331                         if (fin >= enddata)
332                                 return false;
333                         dataByte = *fin++;
334                         if(dataByte >= 0xC0)
335                         {
336                                 x2 = x + (dataByte & 0x3F);
337                                 if (fin >= enddata)
338                                         return false;
339                                 if (x2 > pcxwidth)
340                                         return false;
341                                 dataByte = *fin++;
342                                 for (;x < x2;x++)
343                                         if (x < outwidth)
344                                                 a[x] = dataByte;
345                         }
346                         else
347                         {
348                                 if (x < outwidth) // truncate to destination width
349                                         a[x] = dataByte;
350                                 x++;
351                         }
352                 }
353                 while(x < outwidth)
354                         a[x++] = 0;
355         }
356
357         return true;
358 }
359
360 /*
361 ============
362 LoadPCX
363 ============
364 */
365 qboolean LoadPCX_PaletteOnly(const unsigned char *f, int filesize, unsigned char *palette768b)
366 {
367         if (filesize < 768)
368                 return false;
369         memcpy(palette768b, f + filesize - 768, 768);
370         return true;
371 }
372
373 /*
374 =========================================================
375
376 TARGA LOADING
377
378 =========================================================
379 */
380
381 typedef struct _TargaHeader
382 {
383         unsigned char   id_length, colormap_type, image_type;
384         unsigned short  colormap_index, colormap_length;
385         unsigned char   colormap_size;
386         unsigned short  x_origin, y_origin, width, height;
387         unsigned char   pixel_size, attributes;
388 }
389 TargaHeader;
390
391 static void PrintTargaHeader(TargaHeader *t)
392 {
393         Con_Printf("TargaHeader:\nuint8 id_length = %i;\nuint8 colormap_type = %i;\nuint8 image_type = %i;\nuint16 colormap_index = %i;\nuint16 colormap_length = %i;\nuint8 colormap_size = %i;\nuint16 x_origin = %i;\nuint16 y_origin = %i;\nuint16 width = %i;\nuint16 height = %i;\nuint8 pixel_size = %i;\nuint8 attributes = %i;\n", t->id_length, t->colormap_type, t->image_type, t->colormap_index, t->colormap_length, t->colormap_size, t->x_origin, t->y_origin, t->width, t->height, t->pixel_size, t->attributes);
394 }
395
396 /*
397 =============
398 LoadTGA
399 =============
400 */
401 unsigned char *LoadTGA_BGRA (const unsigned char *f, int filesize, int *miplevel)
402 {
403         int x, y, pix_inc, row_inci, runlen, alphabits;
404         unsigned char *image_buffer;
405         unsigned int *pixbufi;
406         const unsigned char *fin, *enddata;
407         TargaHeader targa_header;
408         unsigned int palettei[256];
409         union
410         {
411                 unsigned int i;
412                 unsigned char b[4];
413         }
414         bgra;
415
416         if (filesize < 19)
417                 return NULL;
418
419         enddata = f + filesize;
420
421         targa_header.id_length = f[0];
422         targa_header.colormap_type = f[1];
423         targa_header.image_type = f[2];
424
425         targa_header.colormap_index = f[3] + f[4] * 256;
426         targa_header.colormap_length = f[5] + f[6] * 256;
427         targa_header.colormap_size = f[7];
428         targa_header.x_origin = f[8] + f[9] * 256;
429         targa_header.y_origin = f[10] + f[11] * 256;
430         targa_header.width = image_width = f[12] + f[13] * 256;
431         targa_header.height = image_height = f[14] + f[15] * 256;
432         targa_header.pixel_size = f[16];
433         targa_header.attributes = f[17];
434
435         if (image_width > 32768 || image_height > 32768 || image_width <= 0 || image_height <= 0)
436         {
437                 Con_Print("LoadTGA: invalid size\n");
438                 PrintTargaHeader(&targa_header);
439                 return NULL;
440         }
441
442         memset(palettei, 0, sizeof(palettei));
443
444         // advance to end of header
445         fin = f + 18;
446
447         // skip TARGA image comment (usually 0 bytes)
448         fin += targa_header.id_length;
449
450         // read/skip the colormap if present (note: according to the TARGA spec it
451         // can be present even on truecolor or greyscale images, just not used by
452         // the image data)
453         if (targa_header.colormap_type)
454         {
455                 if (targa_header.colormap_length > 256)
456                 {
457                         Con_Print("LoadTGA: only up to 256 colormap_length supported\n");
458                         PrintTargaHeader(&targa_header);
459                         return NULL;
460                 }
461                 if (targa_header.colormap_index)
462                 {
463                         Con_Print("LoadTGA: colormap_index not supported\n");
464                         PrintTargaHeader(&targa_header);
465                         return NULL;
466                 }
467                 if (targa_header.colormap_size == 24)
468                 {
469                         for (x = 0;x < targa_header.colormap_length;x++)
470                         {
471                                 bgra.b[0] = *fin++;
472                                 bgra.b[1] = *fin++;
473                                 bgra.b[2] = *fin++;
474                                 bgra.b[3] = 255;
475                                 palettei[x] = bgra.i;
476                         }
477                 }
478                 else if (targa_header.colormap_size == 32)
479                 {
480                         memcpy(palettei, fin, targa_header.colormap_length*4);
481                         fin += targa_header.colormap_length * 4;
482                 }
483                 else
484                 {
485                         Con_Print("LoadTGA: Only 32 and 24 bit colormap_size supported\n");
486                         PrintTargaHeader(&targa_header);
487                         return NULL;
488                 }
489         }
490
491         // check our pixel_size restrictions according to image_type
492         switch (targa_header.image_type & ~8)
493         {
494         case 2:
495                 if (targa_header.pixel_size != 24 && targa_header.pixel_size != 32)
496                 {
497                         Con_Print("LoadTGA: only 24bit and 32bit pixel sizes supported for type 2 and type 10 images\n");
498                         PrintTargaHeader(&targa_header);
499                         return NULL;
500                 }
501                 break;
502         case 3:
503                 // set up a palette to make the loader easier
504                 for (x = 0;x < 256;x++)
505                 {
506                         bgra.b[0] = bgra.b[1] = bgra.b[2] = x;
507                         bgra.b[3] = 255;
508                         palettei[x] = bgra.i;
509                 }
510                 // fall through to colormap case
511         case 1:
512                 if (targa_header.pixel_size != 8)
513                 {
514                         Con_Print("LoadTGA: only 8bit pixel size for type 1, 3, 9, and 11 images supported\n");
515                         PrintTargaHeader(&targa_header);
516                         return NULL;
517                 }
518                 break;
519         default:
520                 Con_Printf("LoadTGA: Only type 1, 2, 3, 9, 10, and 11 targa RGB images supported, image_type = %i\n", targa_header.image_type);
521                 PrintTargaHeader(&targa_header);
522                 return NULL;
523         }
524
525         if (targa_header.attributes & 0x10)
526         {
527                 Con_Print("LoadTGA: origin must be in top left or bottom left, top right and bottom right are not supported\n");
528                 return NULL;
529         }
530
531         // number of attribute bits per pixel, we only support 0 or 8
532         alphabits = targa_header.attributes & 0x0F;
533         if (alphabits != 8 && alphabits != 0)
534         {
535                 Con_Print("LoadTGA: only 0 or 8 attribute (alpha) bits supported\n");
536                 return NULL;
537         }
538
539         image_buffer = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
540         if (!image_buffer)
541         {
542                 Con_Printf("LoadTGA: not enough memory for %i by %i image\n", image_width, image_height);
543                 return NULL;
544         }
545
546         // If bit 5 of attributes isn't set, the image has been stored from bottom to top
547         if ((targa_header.attributes & 0x20) == 0)
548         {
549                 pixbufi = (unsigned int*)image_buffer + (image_height - 1)*image_width;
550                 row_inci = -image_width*2;
551         }
552         else
553         {
554                 pixbufi = (unsigned int*)image_buffer;
555                 row_inci = 0;
556         }
557
558         pix_inc = 1;
559         if ((targa_header.image_type & ~8) == 2)
560                 pix_inc = (targa_header.pixel_size + 7) / 8;
561         switch (targa_header.image_type)
562         {
563         case 1: // colormapped, uncompressed
564         case 3: // greyscale, uncompressed
565                 if (fin + image_width * image_height * pix_inc > enddata)
566                         break;
567                 for (y = 0;y < image_height;y++, pixbufi += row_inci)
568                         for (x = 0;x < image_width;x++)
569                                 *pixbufi++ = palettei[*fin++];
570                 break;
571         case 2:
572                 // BGR or BGRA, uncompressed
573                 if (fin + image_width * image_height * pix_inc > enddata)
574                         break;
575                 if (targa_header.pixel_size == 32 && alphabits)
576                 {
577                         for (y = 0;y < image_height;y++)
578                                 memcpy(pixbufi + y * (image_width + row_inci), fin + y * image_width * pix_inc, image_width*4);
579                 }
580                 else
581                 {
582                         for (y = 0;y < image_height;y++, pixbufi += row_inci)
583                         {
584                                 for (x = 0;x < image_width;x++, fin += pix_inc)
585                                 {
586                                         bgra.b[0] = fin[0];
587                                         bgra.b[1] = fin[1];
588                                         bgra.b[2] = fin[2];
589                                         bgra.b[3] = 255;
590                                         *pixbufi++ = bgra.i;
591                                 }
592                         }
593                 }
594                 break;
595         case 9: // colormapped, RLE
596         case 11: // greyscale, RLE
597                 for (y = 0;y < image_height;y++, pixbufi += row_inci)
598                 {
599                         for (x = 0;x < image_width;)
600                         {
601                                 if (fin >= enddata)
602                                         break; // error - truncated file
603                                 runlen = *fin++;
604                                 if (runlen & 0x80)
605                                 {
606                                         // RLE - all pixels the same color
607                                         runlen += 1 - 0x80;
608                                         if (fin + pix_inc > enddata)
609                                                 break; // error - truncated file
610                                         if (x + runlen > image_width)
611                                                 break; // error - line exceeds width
612                                         bgra.i = palettei[*fin++];
613                                         for (;runlen--;x++)
614                                                 *pixbufi++ = bgra.i;
615                                 }
616                                 else
617                                 {
618                                         // uncompressed - all pixels different color
619                                         runlen++;
620                                         if (fin + pix_inc * runlen > enddata)
621                                                 break; // error - truncated file
622                                         if (x + runlen > image_width)
623                                                 break; // error - line exceeds width
624                                         for (;runlen--;x++)
625                                                 *pixbufi++ = palettei[*fin++];
626                                 }
627                         }
628
629                         if (x != image_width)
630                         {
631                                 // pixbufi is useless now
632                                 Con_Printf("LoadTGA: corrupt file\n");
633                                 break;
634                         }
635                 }
636                 break;
637         case 10:
638                 // BGR or BGRA, RLE
639                 if (targa_header.pixel_size == 32 && alphabits)
640                 {
641                         for (y = 0;y < image_height;y++, pixbufi += row_inci)
642                         {
643                                 for (x = 0;x < image_width;)
644                                 {
645                                         if (fin >= enddata)
646                                                 break; // error - truncated file
647                                         runlen = *fin++;
648                                         if (runlen & 0x80)
649                                         {
650                                                 // RLE - all pixels the same color
651                                                 runlen += 1 - 0x80;
652                                                 if (fin + pix_inc > enddata)
653                                                         break; // error - truncated file
654                                                 if (x + runlen > image_width)
655                                                         break; // error - line exceeds width
656                                                 bgra.b[0] = fin[0];
657                                                 bgra.b[1] = fin[1];
658                                                 bgra.b[2] = fin[2];
659                                                 bgra.b[3] = fin[3];
660                                                 fin += pix_inc;
661                                                 for (;runlen--;x++)
662                                                         *pixbufi++ = bgra.i;
663                                         }
664                                         else
665                                         {
666                                                 // uncompressed - all pixels different color
667                                                 runlen++;
668                                                 if (fin + pix_inc * runlen > enddata)
669                                                         break; // error - truncated file
670                                                 if (x + runlen > image_width)
671                                                         break; // error - line exceeds width
672                                                 for (;runlen--;x++)
673                                                 {
674                                                         bgra.b[0] = fin[0];
675                                                         bgra.b[1] = fin[1];
676                                                         bgra.b[2] = fin[2];
677                                                         bgra.b[3] = fin[3];
678                                                         fin += pix_inc;
679                                                         *pixbufi++ = bgra.i;
680                                                 }
681                                         }
682                                 }
683
684                                 if (x != image_width)
685                                 {
686                                         // pixbufi is useless now
687                                         Con_Printf("LoadTGA: corrupt file\n");
688                                         break;
689                                 }
690                         }
691                 }
692                 else
693                 {
694                         for (y = 0;y < image_height;y++, pixbufi += row_inci)
695                         {
696                                 for (x = 0;x < image_width;)
697                                 {
698                                         if (fin >= enddata)
699                                                 break; // error - truncated file
700                                         runlen = *fin++;
701                                         if (runlen & 0x80)
702                                         {
703                                                 // RLE - all pixels the same color
704                                                 runlen += 1 - 0x80;
705                                                 if (fin + pix_inc > enddata)
706                                                         break; // error - truncated file
707                                                 if (x + runlen > image_width)
708                                                         break; // error - line exceeds width
709                                                 bgra.b[0] = fin[0];
710                                                 bgra.b[1] = fin[1];
711                                                 bgra.b[2] = fin[2];
712                                                 bgra.b[3] = 255;
713                                                 fin += pix_inc;
714                                                 for (;runlen--;x++)
715                                                         *pixbufi++ = bgra.i;
716                                         }
717                                         else
718                                         {
719                                                 // uncompressed - all pixels different color
720                                                 runlen++;
721                                                 if (fin + pix_inc * runlen > enddata)
722                                                         break; // error - truncated file
723                                                 if (x + runlen > image_width)
724                                                         break; // error - line exceeds width
725                                                 for (;runlen--;x++)
726                                                 {
727                                                         bgra.b[0] = fin[0];
728                                                         bgra.b[1] = fin[1];
729                                                         bgra.b[2] = fin[2];
730                                                         bgra.b[3] = 255;
731                                                         fin += pix_inc;
732                                                         *pixbufi++ = bgra.i;
733                                                 }
734                                         }
735                                 }
736
737                                 if (x != image_width)
738                                 {
739                                         // pixbufi is useless now
740                                         Con_Printf("LoadTGA: corrupt file\n");
741                                         break;
742                                 }
743                         }
744                 }
745                 break;
746         default:
747                 // unknown image_type
748                 break;
749         }
750
751         return image_buffer;
752 }
753
754 typedef struct q2wal_s
755 {
756         char            name[32];
757         unsigned        width, height;
758         unsigned        offsets[MIPLEVELS];             // four mip maps stored
759         char            animname[32];                   // next frame in animation chain
760         int                     flags;
761         int                     contents;
762         int                     value;
763 } q2wal_t;
764
765 static unsigned char *LoadWAL_BGRA (const unsigned char *f, int filesize, int *miplevel)
766 {
767         unsigned char *image_buffer;
768         const q2wal_t *inwal = (const q2wal_t *)f;
769
770         if (filesize < (int) sizeof(q2wal_t))
771         {
772                 Con_Print("LoadWAL: invalid WAL file\n");
773                 return NULL;
774         }
775
776         image_width = LittleLong(inwal->width);
777         image_height = LittleLong(inwal->height);
778         if (image_width > 32768 || image_height > 32768 || image_width <= 0 || image_height <= 0)
779         {
780                 Con_Printf("LoadWAL: invalid size %ix%i\n", image_width, image_height);
781                 return NULL;
782         }
783
784         if (filesize < (int) LittleLong(inwal->offsets[0]) + image_width * image_height)
785         {
786                 Con_Print("LoadWAL: invalid WAL file\n");
787                 return NULL;
788         }
789
790         image_buffer = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
791         if (!image_buffer)
792         {
793                 Con_Printf("LoadWAL: not enough memory for %i by %i image\n", image_width, image_height);
794                 return NULL;
795         }
796         Image_Copy8bitBGRA(f + LittleLong(inwal->offsets[0]), image_buffer, image_width * image_height, q2palette_bgra_complete);
797         return image_buffer;
798 }
799
800 qboolean LoadWAL_GetMetadata(const unsigned char *f, int filesize, int *retwidth, int *retheight, int *retflags, int *retvalue, int *retcontents, char *retanimname32c)
801 {
802         const q2wal_t *inwal = (const q2wal_t *)f;
803
804         if (filesize < (int) sizeof(q2wal_t))
805         {
806                 Con_Print("LoadWAL: invalid WAL file\n");
807                 if (retwidth)
808                         *retwidth = 16;
809                 if (retheight)
810                         *retheight = 16;
811                 if (retflags)
812                         *retflags = 0;
813                 if (retvalue)
814                         *retvalue = 0;
815                 if (retcontents)
816                         *retcontents = 0;
817                 if (retanimname32c)
818                         memset(retanimname32c, 0, 32);
819                 return false;
820         }
821
822         if (retwidth)
823                 *retwidth = LittleLong(inwal->width);
824         if (retheight)
825                 *retheight = LittleLong(inwal->height);
826         if (retflags)
827                 *retflags = LittleLong(inwal->flags);
828         if (retvalue)
829                 *retvalue = LittleLong(inwal->value);
830         if (retcontents)
831                 *retcontents = LittleLong(inwal->contents);
832         if (retanimname32c)
833         {
834                 memcpy(retanimname32c, inwal->animname, 32);
835                 retanimname32c[31] = 0;
836         }
837         return true;
838 }
839
840 // gfx/* wad lumps and gfx/*.lmp files are simply width and height and paletted pixels, with color 255 as transparent
841 static unsigned char* LoadLMP_BGRA(const unsigned char *f, int filesize, int *miplevel)
842 {
843         unsigned char *image_buffer;
844         int i;
845
846         if (filesize < 9)
847         {
848                 Con_Print("Bad lmp file\n");
849                 return NULL;
850         }
851
852         image_width = f[0] + f[1] * 0x100 + f[2] * 0x10000 + f[3] * 0x1000000;
853         image_height = f[4] + f[5] * 0x100 + f[6] * 0x10000 + f[7] * 0x1000000;
854
855         if (image_width > 32768 || image_height > 32768 || image_width <= 0 || image_height <= 0 || image_width * image_height > filesize - 8)
856         {
857                 Con_Print("Bad lmp file\n");
858                 return NULL;
859         }
860
861         image_buffer = (unsigned char *)Mem_Alloc(tempmempool, image_width*image_height * 4);
862         if (!image_buffer)
863         {
864                 Con_Printf("LoadLMP: not enough memory for %i by %i image\n", image_width, image_height);
865                 return NULL;
866         }
867
868         for (i = 0; i < image_width * image_height; i++)
869         {
870                 const unsigned char *p = (const unsigned char *)palette_bgra_transparent + 4 * f[8 + i];
871                 image_buffer[i * 4 + 0] = p[0];
872                 image_buffer[i * 4 + 1] = p[1];
873                 image_buffer[i * 4 + 2] = p[2];
874                 image_buffer[i * 4 + 3] = p[3];
875         }
876
877         return image_buffer;
878 }
879
880 // gfx/conchars is a raw 128x128 image with 0 as transparent color rather than 255
881 unsigned char *LoadConChars_BGRA(const unsigned char *f, int filesize, int *miplevel)
882 {
883         unsigned char *image_buffer;
884         int i;
885
886         image_width = 128;
887         image_height = 128;
888         if (image_width * image_height > filesize)
889         {
890                 Con_Print("Bad lmp file\n");
891                 return NULL;
892         }
893
894         image_buffer = (unsigned char *)Mem_Alloc(tempmempool, image_width*image_height * 4);
895         if (!image_buffer)
896         {
897                 Con_Printf("LoadConChars: not enough memory for %i by %i image\n", image_width, image_height);
898                 return NULL;
899         }
900
901         for (i = 0; i < image_width * image_height; i++)
902         {
903                 const unsigned char *p = (const unsigned char *)palette_bgra_font + 4 * f[i];
904                 image_buffer[i * 4 + 0] = p[0];
905                 image_buffer[i * 4 + 1] = p[1];
906                 image_buffer[i * 4 + 2] = p[2];
907                 image_buffer[i * 4 + 3] = p[3];
908         }
909
910         return image_buffer;
911 }
912
913 void Image_StripImageExtension (const char *in, char *out, size_t size_out)
914 {
915         const char *ext;
916
917         if (size_out == 0)
918                 return;
919
920         ext = FS_FileExtension(in);
921         if (ext && (!strcmp(ext, "tga") || !strcmp(ext, "pcx") || !strcmp(ext, "lmp") || !strcmp(ext, "png") || !strcmp(ext, "jpg") || !strcmp(ext, "wal")))
922                 FS_StripExtension(in, out, size_out);
923         else
924                 strlcpy(out, in, size_out);
925 }
926
927 static unsigned char image_linearfromsrgb[256];
928 static unsigned char image_srgbfromlinear_lightmap[256];
929
930 void Image_MakeLinearColorsFromsRGB(unsigned char *pout, const unsigned char *pin, int numpixels)
931 {
932         int i;
933         // this math from http://www.opengl.org/registry/specs/EXT/texture_sRGB.txt
934         if (!image_linearfromsrgb[255])
935                 for (i = 0;i < 256;i++)
936                         image_linearfromsrgb[i] = (unsigned char)floor(Image_LinearFloatFromsRGB(i) * 255.0f + 0.5f);
937         for (i = 0;i < numpixels;i++)
938         {
939                 pout[i*4+0] = image_linearfromsrgb[pin[i*4+0]];
940                 pout[i*4+1] = image_linearfromsrgb[pin[i*4+1]];
941                 pout[i*4+2] = image_linearfromsrgb[pin[i*4+2]];
942                 pout[i*4+3] = pin[i*4+3];
943         }
944 }
945
946 void Image_MakesRGBColorsFromLinear_Lightmap(unsigned char *pout, const unsigned char *pin, int numpixels)
947 {
948         int i;
949         // this math from http://www.opengl.org/registry/specs/EXT/texture_sRGB.txt
950         if (!image_srgbfromlinear_lightmap[255])
951                 for (i = 0;i < 256;i++)
952                         image_srgbfromlinear_lightmap[i] = (unsigned char)floor(bound(0.0f, Image_sRGBFloatFromLinear_Lightmap(i), 1.0f) * 255.0f + 0.5f);
953         for (i = 0;i < numpixels;i++)
954         {
955                 pout[i*4+0] = image_srgbfromlinear_lightmap[pin[i*4+0]];
956                 pout[i*4+1] = image_srgbfromlinear_lightmap[pin[i*4+1]];
957                 pout[i*4+2] = image_srgbfromlinear_lightmap[pin[i*4+2]];
958                 pout[i*4+3] = pin[i*4+3];
959         }
960 }
961
962 typedef struct imageformat_s
963 {
964         const char *formatstring;
965         unsigned char *(*loadfunc)(const unsigned char *f, int filesize, int *miplevel);
966 }
967 imageformat_t;
968
969 // GAME_TENEBRAE only
970 imageformat_t imageformats_tenebrae[] =
971 {
972         {"override/%s.tga", LoadTGA_BGRA},
973         {"override/%s.png", PNG_LoadImage_BGRA},
974         {"override/%s.jpg", JPEG_LoadImage_BGRA},
975         {"override/%s.pcx", LoadPCX_BGRA},
976         {"%s.tga", LoadTGA_BGRA},
977         {"%s.png", PNG_LoadImage_BGRA},
978         {"%s.jpg", JPEG_LoadImage_BGRA},
979         {"%s.pcx", LoadPCX_BGRA},
980         {NULL, NULL}
981 };
982
983 imageformat_t imageformats_nopath[] =
984 {
985         {"override/%s.tga", LoadTGA_BGRA},
986         {"override/%s.png", PNG_LoadImage_BGRA},
987         {"override/%s.jpg", JPEG_LoadImage_BGRA},
988         {"textures/%s.tga", LoadTGA_BGRA},
989         {"textures/%s.png", PNG_LoadImage_BGRA},
990         {"textures/%s.jpg", JPEG_LoadImage_BGRA},
991         {"%s.tga", LoadTGA_BGRA},
992         {"%s.png", PNG_LoadImage_BGRA},
993         {"%s.jpg", JPEG_LoadImage_BGRA},
994         {"%s.pcx", LoadPCX_BGRA},
995         {NULL, NULL}
996 };
997
998 // GAME_DELUXEQUAKE only
999 // VorteX: the point why i use such messy texture paths is
1000 // that GtkRadiant can't detect normal/gloss textures
1001 // and exclude them from texture browser
1002 // so i just use additional folder to store this textures
1003 imageformat_t imageformats_dq[] =
1004 {
1005         {"%s.tga", LoadTGA_BGRA},
1006         {"%s.jpg", JPEG_LoadImage_BGRA},
1007         {"texturemaps/%s.tga", LoadTGA_BGRA},
1008         {"texturemaps/%s.jpg", JPEG_LoadImage_BGRA},
1009         {NULL, NULL}
1010 };
1011
1012 imageformat_t imageformats_textures[] =
1013 {
1014         {"%s.tga", LoadTGA_BGRA},
1015         {"%s.png", PNG_LoadImage_BGRA},
1016         {"%s.jpg", JPEG_LoadImage_BGRA},
1017         {"%s.pcx", LoadPCX_BGRA},
1018         {"%s.wal", LoadWAL_BGRA},
1019         {NULL, NULL}
1020 };
1021
1022 imageformat_t imageformats_gfx[] =
1023 {
1024         {"%s.tga", LoadTGA_BGRA},
1025         {"%s.png", PNG_LoadImage_BGRA},
1026         {"%s.jpg", JPEG_LoadImage_BGRA},
1027         {"%s.pcx", LoadPCX_BGRA},
1028         {"%s.lmp", LoadLMP_BGRA},
1029         {NULL, NULL}
1030 };
1031
1032 imageformat_t imageformats_other[] =
1033 {
1034         {"%s.tga", LoadTGA_BGRA},
1035         {"%s.png", PNG_LoadImage_BGRA},
1036         {"%s.jpg", JPEG_LoadImage_BGRA},
1037         {"%s.pcx", LoadPCX_BGRA},
1038         {"%s.lmp", LoadLMP_BGRA},
1039         {NULL, NULL}
1040 };
1041
1042 int fixtransparentpixels(unsigned char *data, int w, int h);
1043 unsigned char *loadimagepixelsbgra (const char *filename, qboolean complain, qboolean allowFixtrans, qboolean convertsRGB, int *miplevel)
1044 {
1045         fs_offset_t filesize;
1046         imageformat_t *firstformat, *format;
1047         unsigned char *f, *data = NULL, *data2 = NULL;
1048         char basename[MAX_QPATH], name[MAX_QPATH], name2[MAX_QPATH], path[MAX_QPATH], afterpath[MAX_QPATH], *c;
1049         char vabuf[1024];
1050         //if (developer_memorydebug.integer)
1051         //      Mem_CheckSentinelsGlobal();
1052         if (developer_texturelogging.integer)
1053                 Log_Printf("textures.log", "%s\n", filename);
1054         Image_StripImageExtension(filename, basename, sizeof(basename)); // strip filename extensions to allow replacement by other types
1055         // replace *'s with #, so commandline utils don't get confused when dealing with the external files
1056         for (c = basename;*c;c++)
1057                 if (*c == '*')
1058                         *c = '#';
1059         path[0] = 0;
1060         name[0] = 0;
1061         strlcpy(afterpath, basename, sizeof(afterpath));
1062         if (strchr(basename, '/'))
1063         {
1064                 int i;
1065                 for (i = 0;i < (int)sizeof(path)-1 && basename[i] != '/' && basename[i];i++)
1066                         path[i] = basename[i];
1067                 path[i] = 0;
1068                 strlcpy(afterpath, basename + i + 1, sizeof(afterpath));
1069         }
1070         if (gamemode == GAME_TENEBRAE)
1071                 firstformat = imageformats_tenebrae;
1072         else if (gamemode == GAME_DELUXEQUAKE)
1073                 firstformat = imageformats_dq;
1074         else if (!strcasecmp(path, "textures"))
1075                 firstformat = imageformats_textures;
1076         else if (!strcasecmp(path, "gfx") || !strcasecmp(path, "locale")) // locale/ is used in GAME_BLOODOMNICIDE
1077                 firstformat = imageformats_gfx;
1078         else if (!path[0])
1079                 firstformat = imageformats_nopath;
1080         else
1081                 firstformat = imageformats_other;
1082         // now try all the formats in the selected list
1083         for (format = firstformat;format->formatstring;format++)
1084         {
1085                 dpsnprintf (name, sizeof(name), format->formatstring, basename);
1086                 f = FS_LoadFile(name, tempmempool, true, &filesize);
1087                 if (f)
1088                 {
1089                         int mymiplevel = miplevel ? *miplevel : 0;
1090                         image_width = 0;
1091                         image_height = 0;
1092                         data = format->loadfunc(f, (int)filesize, &mymiplevel);
1093                         Mem_Free(f);
1094                         if (data)
1095                         {
1096                                 if(format->loadfunc == JPEG_LoadImage_BGRA) // jpeg can't do alpha, so let's simulate it by loading another jpeg
1097                                 {
1098                                         dpsnprintf (name2, sizeof(name2), format->formatstring, va(vabuf, sizeof(vabuf), "%s_alpha", basename));
1099                                         f = FS_LoadFile(name2, tempmempool, true, &filesize);
1100                                         if(f)
1101                                         {
1102                                                 int mymiplevel2 = miplevel ? *miplevel : 0;
1103                                                 int image_width_save = image_width;
1104                                                 int image_height_save = image_height;
1105                                                 data2 = format->loadfunc(f, (int)filesize, &mymiplevel2);
1106                                                 if(data2 && mymiplevel == mymiplevel2 && image_width == image_width_save && image_height == image_height_save)
1107                                                         Image_CopyAlphaFromBlueBGRA(data, data2, image_width, image_height);
1108                                                 else
1109                                                         Con_Printf("loadimagepixelsrgba: corrupt or invalid alpha image %s_alpha\n", basename);
1110                                                 image_width = image_width_save;
1111                                                 image_height = image_height_save;
1112                                                 if(data2)
1113                                                         Mem_Free(data2);
1114                                                 Mem_Free(f);
1115                                         }
1116                                 }
1117                                 if (developer_loading.integer)
1118                                         Con_DPrintf("loaded image %s (%dx%d)\n", name, image_width, image_height);
1119                                 if(miplevel)
1120                                         *miplevel = mymiplevel;
1121                                 //if (developer_memorydebug.integer)
1122                                 //      Mem_CheckSentinelsGlobal();
1123                                 if(allowFixtrans && r_fixtrans_auto.integer)
1124                                 {
1125                                         int n = fixtransparentpixels(data, image_width, image_height);
1126                                         if(n)
1127                                         {
1128                                                 Con_Printf("- had to fix %s (%d pixels changed)\n", name, n);
1129                                                 if(r_fixtrans_auto.integer >= 2)
1130                                                 {
1131                                                         char outfilename[MAX_QPATH], buf[MAX_QPATH];
1132                                                         Image_StripImageExtension(name, buf, sizeof(buf));
1133                                                         dpsnprintf(outfilename, sizeof(outfilename), "fixtrans/%s.tga", buf);
1134                                                         Image_WriteTGABGRA(outfilename, image_width, image_height, data);
1135                                                         Con_Printf("- %s written.\n", outfilename);
1136                                                 }
1137                                         }
1138                                 }
1139                                 if (convertsRGB)
1140                                         Image_MakeLinearColorsFromsRGB(data, data, image_width * image_height);
1141                                 return data;
1142                         }
1143                         else
1144                                 Con_DPrintf("Error loading image %s (file loaded but decode failed)\n", name);
1145                 }
1146         }
1147         if (!strcasecmp(path, "gfx"))
1148         {
1149                 unsigned char *lmpdata;
1150                 if ((lmpdata = W_GetLumpName(afterpath, &filesize)))
1151                 {
1152                         if (developer_loading.integer)
1153                                 Con_Printf("loading gfx.wad lump \"%s\"\n", afterpath);
1154
1155                         int mymiplevel = miplevel ? *miplevel : 0;
1156                         if (!strcmp(afterpath, "conchars"))
1157                         {
1158                                 // conchars is a raw image and with color 0 as transparent instead of 255
1159                                 data = LoadConChars_BGRA(lmpdata, filesize, &mymiplevel);
1160                         }
1161                         else
1162                                 data = LoadLMP_BGRA(lmpdata, filesize, &mymiplevel);
1163                         // no cleanup after looking up a wad lump - the whole gfx.wad is loaded at once
1164                         if (data)
1165                                 return data;
1166                         Con_DPrintf("Error loading image %s (file loaded but decode failed)\n", name);
1167                 }
1168         }
1169
1170         // check if the image name exists as an embedded pic
1171         if ((data = Image_GetEmbeddedPicBGRA(basename)))
1172                 return data;
1173
1174         if (complain)
1175         {
1176                 Con_Printf("Couldn't load %s using ", filename);
1177                 for (format = firstformat;format->formatstring;format++)
1178                 {
1179                         dpsnprintf (name, sizeof(name), format->formatstring, basename);
1180                         Con_Printf(format == firstformat ? "\"%s\"" : (format[1].formatstring ? ", \"%s\"" : " or \"%s\".\n"), format->formatstring);
1181                 }
1182         }
1183
1184         // texture loading can take a while, so make sure we're sending keepalives
1185         CL_KeepaliveMessage(false);
1186
1187         //if (developer_memorydebug.integer)
1188         //      Mem_CheckSentinelsGlobal();
1189
1190         return NULL;
1191 }
1192
1193 qboolean Image_GetStockPicSize(const char *filename, int *returnwidth, int *returnheight)
1194 {
1195         unsigned char *data;
1196         fs_offset_t filesize;
1197         char lmppath[MAX_QPATH];
1198         if (!strcasecmp(filename, "gfx/conchars"))
1199         {
1200                 *returnwidth = 128;
1201                 *returnheight = 128;
1202                 return true;
1203         }
1204
1205         dpsnprintf(lmppath, sizeof(lmppath), "%s.lmp", filename);
1206         data = FS_LoadFile(lmppath, tempmempool, true, &filesize);
1207         if (data)
1208         {
1209                 if (filesize > 8)
1210                 {
1211                         int w = data[0] + data[1] * 0x100 + data[2] * 0x10000 + data[3] * 0x1000000;
1212                         int h = data[4] + data[5] * 0x100 + data[6] * 0x10000 + data[7] * 0x1000000;
1213                         if (w >= 1 && w <= 32768 && h >= 1 && h <= 32768)
1214                         {
1215                                 *returnwidth = w;
1216                                 *returnheight = h;
1217                                 Mem_Free(data);
1218                                 return true;
1219                         }
1220                 }
1221                 Mem_Free(data);
1222         }
1223         if (!strncasecmp(filename, "gfx/", 4))
1224         {
1225                 data = W_GetLumpName(filename + 4, &filesize);
1226                 if (data && filesize > 8)
1227                 {
1228                         int w = data[0] + data[1] * 0x100 + data[2] * 0x10000 + data[3] * 0x1000000;
1229                         int h = data[4] + data[5] * 0x100 + data[6] * 0x10000 + data[7] * 0x1000000;
1230                         if (w >= 1 && w <= 32768 && h >= 1 && h <= 32768)
1231                         {
1232                                 *returnwidth = w;
1233                                 *returnheight = h;
1234                                 return true;
1235                         }
1236                 }
1237         }
1238         return false;
1239 }
1240
1241 extern cvar_t gl_picmip;
1242 rtexture_t *loadtextureimage (rtexturepool_t *pool, const char *filename, qboolean complain, int flags, qboolean allowFixtrans, qboolean sRGB)
1243 {
1244         unsigned char *data;
1245         rtexture_t *rt;
1246         int miplevel = R_PicmipForFlags(flags);
1247         if (!(data = loadimagepixelsbgra (filename, complain, allowFixtrans, false, &miplevel)))
1248                 return 0;
1249         rt = R_LoadTexture2D(pool, filename, image_width, image_height, data, sRGB ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, flags, miplevel, NULL);
1250         Mem_Free(data);
1251         return rt;
1252 }
1253
1254 int fixtransparentpixels(unsigned char *data, int w, int h)
1255 {
1256         int const FIXTRANS_NEEDED = 1;
1257         int const FIXTRANS_HAS_L = 2;
1258         int const FIXTRANS_HAS_R = 4;
1259         int const FIXTRANS_HAS_U = 8;
1260         int const FIXTRANS_HAS_D = 16;
1261         int const FIXTRANS_FIXED = 32;
1262         unsigned char *fixMask = (unsigned char *) Mem_Alloc(tempmempool, w * h);
1263         int fixPixels = 0;
1264         int changedPixels = 0;
1265         int x, y;
1266
1267 #define FIXTRANS_PIXEL (y*w+x)
1268 #define FIXTRANS_PIXEL_U (((y+h-1)%h)*w+x)
1269 #define FIXTRANS_PIXEL_D (((y+1)%h)*w+x)
1270 #define FIXTRANS_PIXEL_L (y*w+((x+w-1)%w))
1271 #define FIXTRANS_PIXEL_R (y*w+((x+1)%w))
1272
1273         memset(fixMask, 0, w * h);
1274         for(y = 0; y < h; ++y)
1275                 for(x = 0; x < w; ++x)
1276                 {
1277                         if(data[FIXTRANS_PIXEL * 4 + 3] == 0)
1278                         {
1279                                 fixMask[FIXTRANS_PIXEL] |= FIXTRANS_NEEDED;
1280                                 ++fixPixels;
1281                         }
1282                         else
1283                         {
1284                                 fixMask[FIXTRANS_PIXEL_D] |= FIXTRANS_HAS_U;
1285                                 fixMask[FIXTRANS_PIXEL_U] |= FIXTRANS_HAS_D;
1286                                 fixMask[FIXTRANS_PIXEL_R] |= FIXTRANS_HAS_L;
1287                                 fixMask[FIXTRANS_PIXEL_L] |= FIXTRANS_HAS_R;
1288                         }
1289                 }
1290         if(fixPixels == w * h)
1291                 return 0; // sorry, can't do anything about this
1292         while(fixPixels)
1293         {
1294                 for(y = 0; y < h; ++y)
1295                         for(x = 0; x < w; ++x)
1296                                 if(fixMask[FIXTRANS_PIXEL] & FIXTRANS_NEEDED)
1297                                 {
1298                                         unsigned int sumR = 0, sumG = 0, sumB = 0, sumA = 0, sumRA = 0, sumGA = 0, sumBA = 0, cnt = 0;
1299                                         unsigned char r, g, b, a, r0, g0, b0;
1300                                         if(fixMask[FIXTRANS_PIXEL] & FIXTRANS_HAS_U)
1301                                         {
1302                                                 r = data[FIXTRANS_PIXEL_U * 4 + 2];
1303                                                 g = data[FIXTRANS_PIXEL_U * 4 + 1];
1304                                                 b = data[FIXTRANS_PIXEL_U * 4 + 0];
1305                                                 a = data[FIXTRANS_PIXEL_U * 4 + 3];
1306                                                 sumR += r; sumG += g; sumB += b; sumA += a; sumRA += r*a; sumGA += g*a; sumBA += b*a; ++cnt;
1307                                         }
1308                                         if(fixMask[FIXTRANS_PIXEL] & FIXTRANS_HAS_D)
1309                                         {
1310                                                 r = data[FIXTRANS_PIXEL_D * 4 + 2];
1311                                                 g = data[FIXTRANS_PIXEL_D * 4 + 1];
1312                                                 b = data[FIXTRANS_PIXEL_D * 4 + 0];
1313                                                 a = data[FIXTRANS_PIXEL_D * 4 + 3];
1314                                                 sumR += r; sumG += g; sumB += b; sumA += a; sumRA += r*a; sumGA += g*a; sumBA += b*a; ++cnt;
1315                                         }
1316                                         if(fixMask[FIXTRANS_PIXEL] & FIXTRANS_HAS_L)
1317                                         {
1318                                                 r = data[FIXTRANS_PIXEL_L * 4 + 2];
1319                                                 g = data[FIXTRANS_PIXEL_L * 4 + 1];
1320                                                 b = data[FIXTRANS_PIXEL_L * 4 + 0];
1321                                                 a = data[FIXTRANS_PIXEL_L * 4 + 3];
1322                                                 sumR += r; sumG += g; sumB += b; sumA += a; sumRA += r*a; sumGA += g*a; sumBA += b*a; ++cnt;
1323                                         }
1324                                         if(fixMask[FIXTRANS_PIXEL] & FIXTRANS_HAS_R)
1325                                         {
1326                                                 r = data[FIXTRANS_PIXEL_R * 4 + 2];
1327                                                 g = data[FIXTRANS_PIXEL_R * 4 + 1];
1328                                                 b = data[FIXTRANS_PIXEL_R * 4 + 0];
1329                                                 a = data[FIXTRANS_PIXEL_R * 4 + 3];
1330                                                 sumR += r; sumG += g; sumB += b; sumA += a; sumRA += r*a; sumGA += g*a; sumBA += b*a; ++cnt;
1331                                         }
1332                                         if(!cnt)
1333                                                 continue;
1334                                         r0 = data[FIXTRANS_PIXEL * 4 + 2];
1335                                         g0 = data[FIXTRANS_PIXEL * 4 + 1];
1336                                         b0 = data[FIXTRANS_PIXEL * 4 + 0];
1337                                         if(sumA)
1338                                         {
1339                                                 // there is a surrounding non-alpha pixel
1340                                                 r = (sumRA + sumA / 2) / sumA;
1341                                                 g = (sumGA + sumA / 2) / sumA;
1342                                                 b = (sumBA + sumA / 2) / sumA;
1343                                         }
1344                                         else
1345                                         {
1346                                                 // need to use a "regular" average
1347                                                 r = (sumR + cnt / 2) / cnt;
1348                                                 g = (sumG + cnt / 2) / cnt;
1349                                                 b = (sumB + cnt / 2) / cnt;
1350                                         }
1351                                         if(r != r0 || g != g0 || b != b0)
1352                                                 ++changedPixels;
1353                                         data[FIXTRANS_PIXEL * 4 + 2] = r;
1354                                         data[FIXTRANS_PIXEL * 4 + 1] = g;
1355                                         data[FIXTRANS_PIXEL * 4 + 0] = b;
1356                                         fixMask[FIXTRANS_PIXEL] |= FIXTRANS_FIXED;
1357                                 }
1358                 for(y = 0; y < h; ++y)
1359                         for(x = 0; x < w; ++x)
1360                                 if(fixMask[FIXTRANS_PIXEL] & FIXTRANS_FIXED)
1361                                 {
1362                                         fixMask[FIXTRANS_PIXEL] &= ~(FIXTRANS_NEEDED | FIXTRANS_FIXED);
1363                                         fixMask[FIXTRANS_PIXEL_D] |= FIXTRANS_HAS_U;
1364                                         fixMask[FIXTRANS_PIXEL_U] |= FIXTRANS_HAS_D;
1365                                         fixMask[FIXTRANS_PIXEL_R] |= FIXTRANS_HAS_L;
1366                                         fixMask[FIXTRANS_PIXEL_L] |= FIXTRANS_HAS_R;
1367                                         --fixPixels;
1368                                 }
1369         }
1370         return changedPixels;
1371 }
1372
1373 void Image_FixTransparentPixels_f(cmd_state_t *cmd)
1374 {
1375         const char *filename, *filename_pattern;
1376         fssearch_t *search;
1377         int i, n;
1378         char outfilename[MAX_QPATH], buf[MAX_QPATH];
1379         unsigned char *data;
1380         if(Cmd_Argc(cmd) != 2)
1381         {
1382                 Con_Printf("Usage: %s imagefile\n", Cmd_Argv(cmd, 0));
1383                 return;
1384         }
1385         filename_pattern = Cmd_Argv(cmd, 1);
1386         search = FS_Search(filename_pattern, true, true);
1387         if(!search)
1388                 return;
1389         for(i = 0; i < search->numfilenames; ++i)
1390         {
1391                 filename = search->filenames[i];
1392                 Con_Printf("Processing %s... ", filename);
1393                 Image_StripImageExtension(filename, buf, sizeof(buf));
1394                 dpsnprintf(outfilename, sizeof(outfilename), "fixtrans/%s.tga", buf);
1395                 if(!(data = loadimagepixelsbgra(filename, true, false, false, NULL)))
1396                         return;
1397                 if((n = fixtransparentpixels(data, image_width, image_height)))
1398                 {
1399                         Image_WriteTGABGRA(outfilename, image_width, image_height, data);
1400                         Con_Printf("%s written (%d pixels changed).\n", outfilename, n);
1401                 }
1402                 else
1403                         Con_Printf("unchanged.\n");
1404                 Mem_Free(data);
1405         }
1406         FS_FreeSearch(search);
1407 }
1408
1409 qboolean Image_WriteTGABGR_preflipped (const char *filename, int width, int height, const unsigned char *data)
1410 {
1411         qboolean ret;
1412         unsigned char buffer[18];
1413         const void *buffers[2];
1414         fs_offset_t sizes[2];
1415
1416         memset (buffer, 0, 18);
1417         buffer[2] = 2;          // uncompressed type
1418         buffer[12] = (width >> 0) & 0xFF;
1419         buffer[13] = (width >> 8) & 0xFF;
1420         buffer[14] = (height >> 0) & 0xFF;
1421         buffer[15] = (height >> 8) & 0xFF;
1422         buffer[16] = 24;        // pixel size
1423
1424         buffers[0] = buffer;
1425         sizes[0] = 18;
1426         buffers[1] = data;
1427         sizes[1] = width*height*3;
1428         ret = FS_WriteFileInBlocks(filename, buffers, sizes, 2);
1429
1430         return ret;
1431 }
1432
1433 qboolean Image_WriteTGABGRA (const char *filename, int width, int height, const unsigned char *data)
1434 {
1435         int y;
1436         unsigned char *buffer, *out;
1437         const unsigned char *in, *end;
1438         qboolean ret;
1439
1440         buffer = (unsigned char *)Mem_Alloc(tempmempool, width*height*4 + 18);
1441
1442         memset (buffer, 0, 18);
1443         buffer[2] = 2;          // uncompressed type
1444         buffer[12] = (width >> 0) & 0xFF;
1445         buffer[13] = (width >> 8) & 0xFF;
1446         buffer[14] = (height >> 0) & 0xFF;
1447         buffer[15] = (height >> 8) & 0xFF;
1448
1449         for (y = 3;y < width*height*4;y += 4)
1450                 if (data[y] < 255)
1451                         break;
1452
1453         if (y < width*height*4)
1454         {
1455                 // save the alpha channel
1456                 buffer[16] = 32;        // pixel size
1457                 buffer[17] = 8; // 8 bits of alpha
1458
1459                 // flip upside down
1460                 out = buffer + 18;
1461                 for (y = height - 1;y >= 0;y--)
1462                 {
1463                         memcpy(out, data + y * width * 4, width * 4);
1464                         out += width*4;
1465                 }
1466         }
1467         else
1468         {
1469                 // save only the color channels
1470                 buffer[16] = 24;        // pixel size
1471                 buffer[17] = 0; // 8 bits of alpha
1472
1473                 // truncate bgra to bgr and flip upside down
1474                 out = buffer + 18;
1475                 for (y = height - 1;y >= 0;y--)
1476                 {
1477                         in = data + y * width * 4;
1478                         end = in + width * 4;
1479                         for (;in < end;in += 4)
1480                         {
1481                                 *out++ = in[0];
1482                                 *out++ = in[1];
1483                                 *out++ = in[2];
1484                         }
1485                 }
1486         }
1487         ret = FS_WriteFile (filename, buffer, out - buffer);
1488
1489         Mem_Free(buffer);
1490
1491         return ret;
1492 }
1493
1494 static void Image_Resample32LerpLine (const unsigned char *in, unsigned char *out, int inwidth, int outwidth)
1495 {
1496         int             j, xi, oldx = 0, f, fstep, endx, lerp;
1497         fstep = (int) (inwidth*65536.0f/outwidth);
1498         endx = (inwidth-1);
1499         for (j = 0,f = 0;j < outwidth;j++, f += fstep)
1500         {
1501                 xi = f >> 16;
1502                 if (xi != oldx)
1503                 {
1504                         in += (xi - oldx) * 4;
1505                         oldx = xi;
1506                 }
1507                 if (xi < endx)
1508                 {
1509                         lerp = f & 0xFFFF;
1510                         *out++ = (unsigned char) ((((in[4] - in[0]) * lerp) >> 16) + in[0]);
1511                         *out++ = (unsigned char) ((((in[5] - in[1]) * lerp) >> 16) + in[1]);
1512                         *out++ = (unsigned char) ((((in[6] - in[2]) * lerp) >> 16) + in[2]);
1513                         *out++ = (unsigned char) ((((in[7] - in[3]) * lerp) >> 16) + in[3]);
1514                 }
1515                 else // last pixel of the line has no pixel to lerp to
1516                 {
1517                         *out++ = in[0];
1518                         *out++ = in[1];
1519                         *out++ = in[2];
1520                         *out++ = in[3];
1521                 }
1522         }
1523 }
1524
1525 #define LERPBYTE(i) r = resamplerow1[i];out[i] = (unsigned char) ((((resamplerow2[i] - r) * lerp) >> 16) + r)
1526 static void Image_Resample32Lerp(const void *indata, int inwidth, int inheight, void *outdata, int outwidth, int outheight)
1527 {
1528         int i, j, r, yi, oldy, f, fstep, lerp, endy = (inheight-1), inwidth4 = inwidth*4, outwidth4 = outwidth*4;
1529         unsigned char *out;
1530         const unsigned char *inrow;
1531         unsigned char *resamplerow1;
1532         unsigned char *resamplerow2;
1533         out = (unsigned char *)outdata;
1534         fstep = (int) (inheight*65536.0f/outheight);
1535
1536         resamplerow1 = (unsigned char *)Mem_Alloc(tempmempool, outwidth*4*2);
1537         resamplerow2 = resamplerow1 + outwidth*4;
1538
1539         inrow = (const unsigned char *)indata;
1540         oldy = 0;
1541         Image_Resample32LerpLine (inrow, resamplerow1, inwidth, outwidth);
1542         Image_Resample32LerpLine (inrow + inwidth4, resamplerow2, inwidth, outwidth);
1543         for (i = 0, f = 0;i < outheight;i++,f += fstep)
1544         {
1545                 yi = f >> 16;
1546                 if (yi < endy)
1547                 {
1548                         lerp = f & 0xFFFF;
1549                         if (yi != oldy)
1550                         {
1551                                 inrow = (unsigned char *)indata + inwidth4*yi;
1552                                 if (yi == oldy+1)
1553                                         memcpy(resamplerow1, resamplerow2, outwidth4);
1554                                 else
1555                                         Image_Resample32LerpLine (inrow, resamplerow1, inwidth, outwidth);
1556                                 Image_Resample32LerpLine (inrow + inwidth4, resamplerow2, inwidth, outwidth);
1557                                 oldy = yi;
1558                         }
1559                         j = outwidth - 4;
1560                         while(j >= 0)
1561                         {
1562                                 LERPBYTE( 0);
1563                                 LERPBYTE( 1);
1564                                 LERPBYTE( 2);
1565                                 LERPBYTE( 3);
1566                                 LERPBYTE( 4);
1567                                 LERPBYTE( 5);
1568                                 LERPBYTE( 6);
1569                                 LERPBYTE( 7);
1570                                 LERPBYTE( 8);
1571                                 LERPBYTE( 9);
1572                                 LERPBYTE(10);
1573                                 LERPBYTE(11);
1574                                 LERPBYTE(12);
1575                                 LERPBYTE(13);
1576                                 LERPBYTE(14);
1577                                 LERPBYTE(15);
1578                                 out += 16;
1579                                 resamplerow1 += 16;
1580                                 resamplerow2 += 16;
1581                                 j -= 4;
1582                         }
1583                         if (j & 2)
1584                         {
1585                                 LERPBYTE( 0);
1586                                 LERPBYTE( 1);
1587                                 LERPBYTE( 2);
1588                                 LERPBYTE( 3);
1589                                 LERPBYTE( 4);
1590                                 LERPBYTE( 5);
1591                                 LERPBYTE( 6);
1592                                 LERPBYTE( 7);
1593                                 out += 8;
1594                                 resamplerow1 += 8;
1595                                 resamplerow2 += 8;
1596                         }
1597                         if (j & 1)
1598                         {
1599                                 LERPBYTE( 0);
1600                                 LERPBYTE( 1);
1601                                 LERPBYTE( 2);
1602                                 LERPBYTE( 3);
1603                                 out += 4;
1604                                 resamplerow1 += 4;
1605                                 resamplerow2 += 4;
1606                         }
1607                         resamplerow1 -= outwidth4;
1608                         resamplerow2 -= outwidth4;
1609                 }
1610                 else
1611                 {
1612                         if (yi != oldy)
1613                         {
1614                                 inrow = (unsigned char *)indata + inwidth4*yi;
1615                                 if (yi == oldy+1)
1616                                         memcpy(resamplerow1, resamplerow2, outwidth4);
1617                                 else
1618                                         Image_Resample32LerpLine (inrow, resamplerow1, inwidth, outwidth);
1619                                 oldy = yi;
1620                         }
1621                         memcpy(out, resamplerow1, outwidth4);
1622                 }
1623         }
1624
1625         Mem_Free(resamplerow1);
1626         resamplerow1 = NULL;
1627         resamplerow2 = NULL;
1628 }
1629
1630 static void Image_Resample32Nolerp(const void *indata, int inwidth, int inheight, void *outdata, int outwidth, int outheight)
1631 {
1632         int i, j;
1633         unsigned frac, fracstep;
1634         // relies on int being 4 bytes
1635         int *inrow, *out;
1636         out = (int *)outdata;
1637
1638         fracstep = inwidth*0x10000/outwidth;
1639         for (i = 0;i < outheight;i++)
1640         {
1641                 inrow = (int *)indata + inwidth*(i*inheight/outheight);
1642                 frac = fracstep >> 1;
1643                 j = outwidth - 4;
1644                 while (j >= 0)
1645                 {
1646                         out[0] = inrow[frac >> 16];frac += fracstep;
1647                         out[1] = inrow[frac >> 16];frac += fracstep;
1648                         out[2] = inrow[frac >> 16];frac += fracstep;
1649                         out[3] = inrow[frac >> 16];frac += fracstep;
1650                         out += 4;
1651                         j -= 4;
1652                 }
1653                 if (j & 2)
1654                 {
1655                         out[0] = inrow[frac >> 16];frac += fracstep;
1656                         out[1] = inrow[frac >> 16];frac += fracstep;
1657                         out += 2;
1658                 }
1659                 if (j & 1)
1660                 {
1661                         out[0] = inrow[frac >> 16];frac += fracstep;
1662                         out += 1;
1663                 }
1664         }
1665 }
1666
1667 /*
1668 ================
1669 Image_Resample
1670 ================
1671 */
1672 void Image_Resample32(const void *indata, int inwidth, int inheight, int indepth, void *outdata, int outwidth, int outheight, int outdepth, int quality)
1673 {
1674         if (indepth != 1 || outdepth != 1)
1675         {
1676                 Con_Printf ("Image_Resample: 3D resampling not supported\n");
1677                 return;
1678         }
1679         if (quality)
1680                 Image_Resample32Lerp(indata, inwidth, inheight, outdata, outwidth, outheight);
1681         else
1682                 Image_Resample32Nolerp(indata, inwidth, inheight, outdata, outwidth, outheight);
1683 }
1684
1685 // in can be the same as out
1686 void Image_MipReduce32(const unsigned char *in, unsigned char *out, int *width, int *height, int *depth, int destwidth, int destheight, int destdepth)
1687 {
1688         const unsigned char *inrow;
1689         int x, y, nextrow;
1690         if (*depth != 1 || destdepth != 1)
1691         {
1692                 Con_Printf ("Image_Resample: 3D resampling not supported\n");
1693                 if (*width > destwidth)
1694                         *width >>= 1;
1695                 if (*height > destheight)
1696                         *height >>= 1;
1697                 if (*depth > destdepth)
1698                         *depth >>= 1;
1699                 return;
1700         }
1701         // note: if given odd width/height this discards the last row/column of
1702         // pixels, rather than doing a proper box-filter scale down
1703         inrow = in;
1704         nextrow = *width * 4;
1705         if (*width > destwidth)
1706         {
1707                 *width >>= 1;
1708                 if (*height > destheight)
1709                 {
1710                         // reduce both
1711                         *height >>= 1;
1712                         for (y = 0;y < *height;y++, inrow += nextrow * 2)
1713                         {
1714                                 for (in = inrow, x = 0;x < *width;x++)
1715                                 {
1716                                         out[0] = (unsigned char) ((in[0] + in[4] + in[nextrow  ] + in[nextrow+4]) >> 2);
1717                                         out[1] = (unsigned char) ((in[1] + in[5] + in[nextrow+1] + in[nextrow+5]) >> 2);
1718                                         out[2] = (unsigned char) ((in[2] + in[6] + in[nextrow+2] + in[nextrow+6]) >> 2);
1719                                         out[3] = (unsigned char) ((in[3] + in[7] + in[nextrow+3] + in[nextrow+7]) >> 2);
1720                                         out += 4;
1721                                         in += 8;
1722                                 }
1723                         }
1724                 }
1725                 else
1726                 {
1727                         // reduce width
1728                         for (y = 0;y < *height;y++, inrow += nextrow)
1729                         {
1730                                 for (in = inrow, x = 0;x < *width;x++)
1731                                 {
1732                                         out[0] = (unsigned char) ((in[0] + in[4]) >> 1);
1733                                         out[1] = (unsigned char) ((in[1] + in[5]) >> 1);
1734                                         out[2] = (unsigned char) ((in[2] + in[6]) >> 1);
1735                                         out[3] = (unsigned char) ((in[3] + in[7]) >> 1);
1736                                         out += 4;
1737                                         in += 8;
1738                                 }
1739                         }
1740                 }
1741         }
1742         else
1743         {
1744                 if (*height > destheight)
1745                 {
1746                         // reduce height
1747                         *height >>= 1;
1748                         for (y = 0;y < *height;y++, inrow += nextrow * 2)
1749                         {
1750                                 for (in = inrow, x = 0;x < *width;x++)
1751                                 {
1752                                         out[0] = (unsigned char) ((in[0] + in[nextrow  ]) >> 1);
1753                                         out[1] = (unsigned char) ((in[1] + in[nextrow+1]) >> 1);
1754                                         out[2] = (unsigned char) ((in[2] + in[nextrow+2]) >> 1);
1755                                         out[3] = (unsigned char) ((in[3] + in[nextrow+3]) >> 1);
1756                                         out += 4;
1757                                         in += 4;
1758                                 }
1759                         }
1760                 }
1761                 else
1762                         Con_Printf ("Image_MipReduce: desired size already achieved\n");
1763         }
1764 }
1765
1766 void Image_HeightmapToNormalmap_BGRA(const unsigned char *inpixels, unsigned char *outpixels, int width, int height, int clamp, float bumpscale)
1767 {
1768         int x, y, x1, x2, y1, y2;
1769         const unsigned char *b, *row[3];
1770         int p[5];
1771         unsigned char *out;
1772         float ibumpscale, n[3];
1773         ibumpscale = (255.0f * 6.0f) / bumpscale;
1774         out = outpixels;
1775         for (y = 0, y1 = height-1;y < height;y1 = y, y++)
1776         {
1777                 y2 = y + 1;if (y2 >= height) y2 = 0;
1778                 row[0] = inpixels + (y1 * width) * 4;
1779                 row[1] = inpixels + (y  * width) * 4;
1780                 row[2] = inpixels + (y2 * width) * 4;
1781                 for (x = 0, x1 = width-1;x < width;x1 = x, x++)
1782                 {
1783                         x2 = x + 1;if (x2 >= width) x2 = 0;
1784                         // left, right
1785                         b = row[1] + x1 * 4;p[0] = (b[0] + b[1] + b[2]);
1786                         b = row[1] + x2 * 4;p[1] = (b[0] + b[1] + b[2]);
1787                         // above, below
1788                         b = row[0] + x  * 4;p[2] = (b[0] + b[1] + b[2]);
1789                         b = row[2] + x  * 4;p[3] = (b[0] + b[1] + b[2]);
1790                         // center
1791                         b = row[1] + x  * 4;p[4] = (b[0] + b[1] + b[2]);
1792                         // calculate a normal from the slopes
1793                         n[0] = p[0] - p[1];
1794                         n[1] = p[3] - p[2];
1795                         n[2] = ibumpscale;
1796                         VectorNormalize(n);
1797                         // turn it into a dot3 rgb vector texture
1798                         out[2] = (int)(128.0f + n[0] * 127.0f);
1799                         out[1] = (int)(128.0f + n[1] * 127.0f);
1800                         out[0] = (int)(128.0f + n[2] * 127.0f);
1801                         out[3] = (p[4]) / 3;
1802                         out += 4;
1803                 }
1804         }
1805 }
1806
1807 static const unsigned char concharimage[] =
1808 {
1809 #include "lhfont.h"
1810 };
1811
1812 static unsigned char *Image_GenerateConChars(void)
1813 {
1814         int i;
1815         unsigned char *data;
1816         double random;
1817
1818         image_width = 256;
1819         image_height = 256;
1820
1821         data = LoadTGA_BGRA(concharimage, sizeof(concharimage), NULL);
1822         // Gold numbers
1823         for (i = 0; i < 8192; i++)
1824         {
1825                 random = lhrandom(0.0, 1.0);
1826                 data[i * 4 + 3] = data[i * 4 + 0];
1827                 data[i * 4 + 2] = 83 + (unsigned char)(random * 64);
1828                 data[i * 4 + 1] = 71 + (unsigned char)(random * 32);
1829                 data[i * 4 + 0] = 23 + (unsigned char)(random * 16);
1830         }
1831         // White chars
1832         for (i = 8192; i < 32768; i++)
1833         {
1834                 random = lhrandom(0.0, 1.0);
1835                 data[i * 4 + 3] = data[i * 4 + 0];
1836                 data[i * 4 + 2] = 95 + (unsigned char)(random * 64);
1837                 data[i * 4 + 1] = 95 + (unsigned char)(random * 64);
1838                 data[i * 4 + 0] = 95 + (unsigned char)(random * 64);
1839         }
1840         // Gold numbers
1841         for (i = 32768; i < 40960; i++)
1842         {
1843                 random = lhrandom(0.0, 1.0);
1844                 data[i * 4 + 3] = data[i * 4 + 0];
1845                 data[i * 4 + 2] = 83 + (unsigned char)(random * 64);
1846                 data[i * 4 + 1] = 71 + (unsigned char)(random * 32);
1847                 data[i * 4 + 0] = 23 + (unsigned char)(random * 16);
1848         }
1849         // Red chars
1850         for (i = 40960; i < 65536; i++)
1851         {
1852                 random = lhrandom(0.0, 1.0);
1853                 data[i * 4 + 3] = data[i * 4 + 0];
1854                 data[i * 4 + 2] = 96 + (unsigned char)(random * 64);
1855                 data[i * 4 + 1] = 43 + (unsigned char)(random * 32);
1856                 data[i * 4 + 0] = 27 + (unsigned char)(random * 32);
1857         }
1858
1859 #if 0
1860         Image_WriteTGABGRA("gfx/generated_conchars.tga", 256, 256, data);
1861 #endif
1862
1863         return data;
1864 }
1865
1866 static unsigned char *Image_GenerateDitherPattern(void)
1867 {
1868         int x, y;
1869         unsigned char *data = (unsigned char *)Mem_Alloc(tempmempool, 8 * 8 * 4);
1870         image_width = 8;
1871         image_height = 8;
1872         for (y = 0; y < 8; y++)
1873         {
1874                 for (x = 0; x < 8; x++)
1875                 {
1876                         data[(y * 8 + x) * 4 + 0] = ((x^y) & 4) ? 255 : 0;
1877                         data[(y * 8 + x) * 4 + 1] = ((x^y) & 4) ? 255 : 0;
1878                         data[(y * 8 + x) * 4 + 2] = ((x^y) & 4) ? 255 : 0;
1879                         data[(y * 8 + x) * 4 + 3] = 255;
1880                 }
1881         }
1882         return data;
1883 }
1884
1885 // also used in R_SkinFrame code
1886 unsigned char *Image_GenerateNoTexture(void)
1887 {
1888         int x, y;
1889         unsigned char *data = (unsigned char *)Mem_Alloc(tempmempool, 16 * 16 * 4);
1890         image_width = 16;
1891         image_height = 16;
1892         // this makes a light grey/dark grey checkerboard texture
1893         for (y = 0; y < 16; y++)
1894         {
1895                 for (x = 0; x < 16; x++)
1896                 {
1897                         data[(y * 16 + x) * 4 + 0] =
1898                         data[(y * 16 + x) * 4 + 1] =
1899                         data[(y * 16 + x) * 4 + 2] = (y < 8) ^ (x < 8) ? 128 : 64;
1900                         data[(y * 16 + x) * 4 + 3] = 255;
1901                 }
1902         }
1903         return data;
1904 }
1905
1906 static unsigned char *Image_GenerateWhite(void)
1907 {
1908         unsigned char *data = (unsigned char *)Mem_Alloc(tempmempool, 1 * 1 * 4);
1909         image_width = 1;
1910         image_height = 1;
1911         data[0] = data[1] = data[2] = data[3] = 255;
1912         return data;
1913 }
1914
1915 typedef struct embeddedpic_s
1916 {
1917 const char *name;
1918 int width;
1919 int height;
1920 const char *pixels;
1921 }
1922 embeddedpic_t;
1923
1924 static const embeddedpic_t embeddedpics[] =
1925 {
1926         {
1927                 "gfx/prydoncursor001", 16, 16,
1928                 "477777774......."
1929                 "77.....6........"
1930                 "7.....6........."
1931                 "7....6.........."
1932                 "7.....6........."
1933                 "7..6...6........"
1934                 "7.6.6...6......."
1935                 "76...6...6......"
1936                 "4.....6.6......."
1937                 ".......6........"
1938                 "................"
1939                 "................"
1940                 "................"
1941                 "................"
1942                 "................"
1943                 "................"
1944         },
1945         {
1946                 "ui/mousepointer", 16, 16,
1947                 "477777774......."
1948                 "77.....6........"
1949                 "7.....6........."
1950                 "7....6.........."
1951                 "7.....6........."
1952                 "7..6...6........"
1953                 "7.6.6...6......."
1954                 "76...6...6......"
1955                 "4.....6.6......."
1956                 ".......6........"
1957                 "................"
1958                 "................"
1959                 "................"
1960                 "................"
1961                 "................"
1962                 "................"
1963         },
1964         {
1965                 "gfx/crosshair1", 16, 16,
1966                 "................"
1967                 "................"
1968                 "................"
1969                 "...33......33..."
1970                 "...355....553..."
1971                 "....577..775...."
1972                 ".....77..77....."
1973                 "................"
1974                 "................"
1975                 ".....77..77....."
1976                 "....577..775...."
1977                 "...355....553..."
1978                 "...33......33..."
1979                 "................"
1980                 "................"
1981                 "................"
1982         },
1983         {
1984                 "gfx/crosshair2", 16, 16,
1985                 "................"
1986                 "................"
1987                 "................"
1988                 "...3........3..."
1989                 "....5......5...."
1990                 ".....7....7....."
1991                 "......7..7......"
1992                 "................"
1993                 "................"
1994                 "......7..7......"
1995                 ".....7....7....."
1996                 "....5......5...."
1997                 "...3........3..."
1998                 "................"
1999                 "................"
2000                 "................"
2001         },
2002         {
2003                 "gfx/crosshair3", 16, 16,
2004                 "................"
2005                 ".......77......."
2006                 ".......77......."
2007                 "................"
2008                 "................"
2009                 ".......44......."
2010                 ".......44......."
2011                 ".77..44..44..77."
2012                 ".77..44..44..77."
2013                 ".......44......."
2014                 ".......44......."
2015                 "................"
2016                 "................"
2017                 ".......77......."
2018                 ".......77......."
2019                 "................"
2020         },
2021         {
2022                 "gfx/crosshair4", 16, 16,
2023                 "................"
2024                 "................"
2025                 "................"
2026                 "................"
2027                 "................"
2028                 "................"
2029                 "................"
2030                 "................"
2031                 "........7777777."
2032                 "........752....."
2033                 "........72......"
2034                 "........7......."
2035                 "........7......."
2036                 "........7......."
2037                 "........7......."
2038                 "................"
2039         },
2040         {
2041                 "gfx/crosshair5", 8, 8,
2042                 "........"
2043                 "........"
2044                 "....7..."
2045                 "........"
2046                 "..7.7.7."
2047                 "........"
2048                 "....7..."
2049                 "........"
2050         },
2051         {
2052                 "gfx/crosshair6", 2, 2,
2053                 "77"
2054                 "77"
2055         },
2056         {
2057                 "gfx/crosshair7", 16, 16,
2058                 "................"
2059                 ".3............3."
2060                 "..5...2332...5.."
2061                 "...7.3....3.7..."
2062                 "....7......7...."
2063                 "...3.7....7.3..."
2064                 "..2...7..7...2.."
2065                 "..3..........3.."
2066                 "..3..........3.."
2067                 "..2...7..7...2.."
2068                 "...3.7....7.3..."
2069                 "....7......7...."
2070                 "...7.3....3.7..."
2071                 "..5...2332...5.."
2072                 ".3............3."
2073                 "................"
2074         },
2075         { NULL, 0, 0, NULL }
2076 };
2077
2078 unsigned char *Image_GetEmbeddedPicBGRA(const char *name)
2079 {
2080         const embeddedpic_t *p;
2081         for (p = embeddedpics; p->name; p++)
2082         {
2083                 if (!strcmp(name, p->name))
2084                 {
2085                         int i;
2086                         unsigned char *data = (unsigned char *)Mem_Alloc(tempmempool, p->width * p->height * 4);
2087                         image_width = p->width;
2088                         image_height = p->height;
2089                         for (i = 0; i < p->width * p->height; i++)
2090                         {
2091                                 const unsigned char *c = (const unsigned char *)palette_bgra_embeddedpic + 4 * p->pixels[i];
2092                                 Vector4Copy(c, data + 4 * i);
2093                         }
2094                         return data;
2095                 }
2096         }
2097         if (!strcmp(name, "white"))
2098                 return Image_GenerateWhite();
2099         if (!strcmp(name, "gfx/conchars"))
2100                 return Image_GenerateConChars();
2101         if (!strcmp(name, "gfx/colorcontrol/ditherpattern"))
2102                 return Image_GenerateDitherPattern();
2103         return NULL;
2104 }