]> git.xonotic.org Git - xonotic/darkplaces.git/blob - image.c
common: Move infostring functions to new com_infostring.c
[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, qbool inputflipx, qbool inputflipy, qbool 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, qbool inputflipx, qbool inputflipy, qbool 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 qbool 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 qbool 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 qbool 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 static 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, qbool complain, qbool allowFixtrans, qbool convertsRGB, int *miplevel)
1044 {
1045         fs_offset_t filesize;
1046         imageformat_t *firstformat, *format;
1047         int mymiplevel;
1048         unsigned char *f, *data = NULL, *data2 = NULL;
1049         char basename[MAX_QPATH], name[MAX_QPATH], name2[MAX_QPATH], path[MAX_QPATH], afterpath[MAX_QPATH], *c;
1050         char vabuf[1024];
1051         //if (developer_memorydebug.integer)
1052         //      Mem_CheckSentinelsGlobal();
1053         if (developer_texturelogging.integer)
1054                 Log_Printf("textures.log", "%s\n", filename);
1055         Image_StripImageExtension(filename, basename, sizeof(basename)); // strip filename extensions to allow replacement by other types
1056         // replace *'s with #, so commandline utils don't get confused when dealing with the external files
1057         for (c = basename;*c;c++)
1058                 if (*c == '*')
1059                         *c = '#';
1060         path[0] = 0;
1061         name[0] = 0;
1062         strlcpy(afterpath, basename, sizeof(afterpath));
1063         if (strchr(basename, '/'))
1064         {
1065                 int i;
1066                 for (i = 0;i < (int)sizeof(path)-1 && basename[i] != '/' && basename[i];i++)
1067                         path[i] = basename[i];
1068                 path[i] = 0;
1069                 strlcpy(afterpath, basename + i + 1, sizeof(afterpath));
1070         }
1071         if (gamemode == GAME_TENEBRAE)
1072                 firstformat = imageformats_tenebrae;
1073         else if (gamemode == GAME_DELUXEQUAKE)
1074                 firstformat = imageformats_dq;
1075         else if (!strcasecmp(path, "textures"))
1076                 firstformat = imageformats_textures;
1077         else if (!strcasecmp(path, "gfx") || !strcasecmp(path, "locale")) // locale/ is used in GAME_BLOODOMNICIDE
1078                 firstformat = imageformats_gfx;
1079         else if (!path[0])
1080                 firstformat = imageformats_nopath;
1081         else
1082                 firstformat = imageformats_other;
1083         // now try all the formats in the selected list
1084         for (format = firstformat;format->formatstring;format++)
1085         {
1086                 dpsnprintf (name, sizeof(name), format->formatstring, basename);
1087
1088                 FS_SanitizePath(name);
1089
1090                 if(FS_FileExists(name) && (f = FS_LoadFile(name, tempmempool, true, &filesize)) != NULL)
1091                 {
1092                         mymiplevel = miplevel ? *miplevel : 0;
1093                         image_width = 0;
1094                         image_height = 0;
1095                         data = format->loadfunc(f, (int)filesize, &mymiplevel);
1096                         Mem_Free(f);
1097                         if (data)
1098                         {
1099                                 if(format->loadfunc == JPEG_LoadImage_BGRA) // jpeg can't do alpha, so let's simulate it by loading another jpeg
1100                                 {
1101                                         dpsnprintf (name2, sizeof(name2), format->formatstring, va(vabuf, sizeof(vabuf), "%s_alpha", basename));
1102                                         f = FS_LoadFile(name2, tempmempool, true, &filesize);
1103                                         if(f)
1104                                         {
1105                                                 int mymiplevel2 = miplevel ? *miplevel : 0;
1106                                                 int image_width_save = image_width;
1107                                                 int image_height_save = image_height;
1108                                                 data2 = format->loadfunc(f, (int)filesize, &mymiplevel2);
1109                                                 if(data2 && mymiplevel == mymiplevel2 && image_width == image_width_save && image_height == image_height_save)
1110                                                         Image_CopyAlphaFromBlueBGRA(data, data2, image_width, image_height);
1111                                                 else
1112                                                         Con_Printf("loadimagepixelsrgba: corrupt or invalid alpha image %s_alpha\n", basename);
1113                                                 image_width = image_width_save;
1114                                                 image_height = image_height_save;
1115                                                 if(data2)
1116                                                         Mem_Free(data2);
1117                                                 Mem_Free(f);
1118                                         }
1119                                 }
1120                                 if (developer_loading.integer)
1121                                         Con_DPrintf("loaded image %s (%dx%d)\n", name, image_width, image_height);
1122                                 if(miplevel)
1123                                         *miplevel = mymiplevel;
1124                                 //if (developer_memorydebug.integer)
1125                                 //      Mem_CheckSentinelsGlobal();
1126                                 if(allowFixtrans && r_fixtrans_auto.integer)
1127                                 {
1128                                         int n = fixtransparentpixels(data, image_width, image_height);
1129                                         if(n)
1130                                         {
1131                                                 Con_Printf("- had to fix %s (%d pixels changed)\n", name, n);
1132                                                 if(r_fixtrans_auto.integer >= 2)
1133                                                 {
1134                                                         char outfilename[MAX_QPATH], buf[MAX_QPATH];
1135                                                         Image_StripImageExtension(name, buf, sizeof(buf));
1136                                                         dpsnprintf(outfilename, sizeof(outfilename), "fixtrans/%s.tga", buf);
1137                                                         Image_WriteTGABGRA(outfilename, image_width, image_height, data);
1138                                                         Con_Printf("- %s written.\n", outfilename);
1139                                                 }
1140                                         }
1141                                 }
1142                                 if (convertsRGB)
1143                                         Image_MakeLinearColorsFromsRGB(data, data, image_width * image_height);
1144                                 return data;
1145                         }
1146                         else
1147                                 Con_DPrintf("Error loading image %s (file loaded but decode failed)\n", name);
1148                 }
1149         }
1150         if (!strcasecmp(path, "gfx"))
1151         {
1152                 unsigned char *lmpdata;
1153                 if ((lmpdata = W_GetLumpName(afterpath, &filesize)))
1154                 {
1155                         if (developer_loading.integer)
1156                                 Con_Printf("loading gfx.wad lump \"%s\"\n", afterpath);
1157
1158                         mymiplevel = miplevel ? *miplevel : 0;
1159                         if (!strcmp(afterpath, "conchars"))
1160                         {
1161                                 // conchars is a raw image and with color 0 as transparent instead of 255
1162                                 data = LoadConChars_BGRA(lmpdata, filesize, &mymiplevel);
1163                         }
1164                         else
1165                                 data = LoadLMP_BGRA(lmpdata, filesize, &mymiplevel);
1166                         // no cleanup after looking up a wad lump - the whole gfx.wad is loaded at once
1167                         if (data)
1168                                 return data;
1169                         Con_DPrintf("Error loading image %s (file loaded but decode failed)\n", name);
1170                 }
1171         }
1172
1173         // check if the image name exists as an embedded pic
1174         if ((data = Image_GetEmbeddedPicBGRA(basename)))
1175                 return data;
1176
1177         if (complain)
1178         {
1179                 Con_Printf("Couldn't load %s using ", filename);
1180                 for (format = firstformat;format->formatstring;format++)
1181                 {
1182                         dpsnprintf (name, sizeof(name), format->formatstring, basename);
1183                         Con_Printf(format == firstformat ? "\"%s\"" : (format[1].formatstring ? ", \"%s\"" : " or \"%s\".\n"), format->formatstring);
1184                 }
1185         }
1186
1187         // texture loading can take a while, so make sure we're sending keepalives
1188         CL_KeepaliveMessage(false);
1189
1190         //if (developer_memorydebug.integer)
1191         //      Mem_CheckSentinelsGlobal();
1192
1193         return NULL;
1194 }
1195
1196 qbool Image_GetStockPicSize(const char *filename, int *returnwidth, int *returnheight)
1197 {
1198         unsigned char *data;
1199         fs_offset_t filesize;
1200         char lmppath[MAX_QPATH];
1201         if (!strcasecmp(filename, "gfx/conchars"))
1202         {
1203                 *returnwidth = 128;
1204                 *returnheight = 128;
1205                 return true;
1206         }
1207
1208         dpsnprintf(lmppath, sizeof(lmppath), "%s.lmp", filename);
1209         data = FS_LoadFile(lmppath, tempmempool, true, &filesize);
1210         if (data)
1211         {
1212                 if (filesize > 8)
1213                 {
1214                         int w = data[0] + data[1] * 0x100 + data[2] * 0x10000 + data[3] * 0x1000000;
1215                         int h = data[4] + data[5] * 0x100 + data[6] * 0x10000 + data[7] * 0x1000000;
1216                         if (w >= 1 && w <= 32768 && h >= 1 && h <= 32768)
1217                         {
1218                                 *returnwidth = w;
1219                                 *returnheight = h;
1220                                 Mem_Free(data);
1221                                 return true;
1222                         }
1223                 }
1224                 Mem_Free(data);
1225         }
1226         if (!strncasecmp(filename, "gfx/", 4))
1227         {
1228                 data = W_GetLumpName(filename + 4, &filesize);
1229                 if (data && filesize > 8)
1230                 {
1231                         int w = data[0] + data[1] * 0x100 + data[2] * 0x10000 + data[3] * 0x1000000;
1232                         int h = data[4] + data[5] * 0x100 + data[6] * 0x10000 + data[7] * 0x1000000;
1233                         if (w >= 1 && w <= 32768 && h >= 1 && h <= 32768)
1234                         {
1235                                 *returnwidth = w;
1236                                 *returnheight = h;
1237                                 return true;
1238                         }
1239                 }
1240         }
1241         return false;
1242 }
1243
1244 extern cvar_t gl_picmip;
1245 rtexture_t *loadtextureimage (rtexturepool_t *pool, const char *filename, qbool complain, int flags, qbool allowFixtrans, qbool sRGB)
1246 {
1247         unsigned char *data;
1248         rtexture_t *rt;
1249         int miplevel = R_PicmipForFlags(flags);
1250         if (!(data = loadimagepixelsbgra (filename, complain, allowFixtrans, false, &miplevel)))
1251                 return 0;
1252         rt = R_LoadTexture2D(pool, filename, image_width, image_height, data, sRGB ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, flags, miplevel, NULL);
1253         Mem_Free(data);
1254         return rt;
1255 }
1256
1257 int fixtransparentpixels(unsigned char *data, int w, int h)
1258 {
1259         int const FIXTRANS_NEEDED = 1;
1260         int const FIXTRANS_HAS_L = 2;
1261         int const FIXTRANS_HAS_R = 4;
1262         int const FIXTRANS_HAS_U = 8;
1263         int const FIXTRANS_HAS_D = 16;
1264         int const FIXTRANS_FIXED = 32;
1265         unsigned char *fixMask = (unsigned char *) Mem_Alloc(tempmempool, w * h);
1266         int fixPixels = 0;
1267         int changedPixels = 0;
1268         int x, y;
1269
1270 #define FIXTRANS_PIXEL (y*w+x)
1271 #define FIXTRANS_PIXEL_U (((y+h-1)%h)*w+x)
1272 #define FIXTRANS_PIXEL_D (((y+1)%h)*w+x)
1273 #define FIXTRANS_PIXEL_L (y*w+((x+w-1)%w))
1274 #define FIXTRANS_PIXEL_R (y*w+((x+1)%w))
1275
1276         memset(fixMask, 0, w * h);
1277         for(y = 0; y < h; ++y)
1278                 for(x = 0; x < w; ++x)
1279                 {
1280                         if(data[FIXTRANS_PIXEL * 4 + 3] == 0)
1281                         {
1282                                 fixMask[FIXTRANS_PIXEL] |= FIXTRANS_NEEDED;
1283                                 ++fixPixels;
1284                         }
1285                         else
1286                         {
1287                                 fixMask[FIXTRANS_PIXEL_D] |= FIXTRANS_HAS_U;
1288                                 fixMask[FIXTRANS_PIXEL_U] |= FIXTRANS_HAS_D;
1289                                 fixMask[FIXTRANS_PIXEL_R] |= FIXTRANS_HAS_L;
1290                                 fixMask[FIXTRANS_PIXEL_L] |= FIXTRANS_HAS_R;
1291                         }
1292                 }
1293         if(fixPixels == w * h)
1294                 return 0; // sorry, can't do anything about this
1295         while(fixPixels)
1296         {
1297                 for(y = 0; y < h; ++y)
1298                         for(x = 0; x < w; ++x)
1299                                 if(fixMask[FIXTRANS_PIXEL] & FIXTRANS_NEEDED)
1300                                 {
1301                                         unsigned int sumR = 0, sumG = 0, sumB = 0, sumA = 0, sumRA = 0, sumGA = 0, sumBA = 0, cnt = 0;
1302                                         unsigned char r, g, b, a, r0, g0, b0;
1303                                         if(fixMask[FIXTRANS_PIXEL] & FIXTRANS_HAS_U)
1304                                         {
1305                                                 r = data[FIXTRANS_PIXEL_U * 4 + 2];
1306                                                 g = data[FIXTRANS_PIXEL_U * 4 + 1];
1307                                                 b = data[FIXTRANS_PIXEL_U * 4 + 0];
1308                                                 a = data[FIXTRANS_PIXEL_U * 4 + 3];
1309                                                 sumR += r; sumG += g; sumB += b; sumA += a; sumRA += r*a; sumGA += g*a; sumBA += b*a; ++cnt;
1310                                         }
1311                                         if(fixMask[FIXTRANS_PIXEL] & FIXTRANS_HAS_D)
1312                                         {
1313                                                 r = data[FIXTRANS_PIXEL_D * 4 + 2];
1314                                                 g = data[FIXTRANS_PIXEL_D * 4 + 1];
1315                                                 b = data[FIXTRANS_PIXEL_D * 4 + 0];
1316                                                 a = data[FIXTRANS_PIXEL_D * 4 + 3];
1317                                                 sumR += r; sumG += g; sumB += b; sumA += a; sumRA += r*a; sumGA += g*a; sumBA += b*a; ++cnt;
1318                                         }
1319                                         if(fixMask[FIXTRANS_PIXEL] & FIXTRANS_HAS_L)
1320                                         {
1321                                                 r = data[FIXTRANS_PIXEL_L * 4 + 2];
1322                                                 g = data[FIXTRANS_PIXEL_L * 4 + 1];
1323                                                 b = data[FIXTRANS_PIXEL_L * 4 + 0];
1324                                                 a = data[FIXTRANS_PIXEL_L * 4 + 3];
1325                                                 sumR += r; sumG += g; sumB += b; sumA += a; sumRA += r*a; sumGA += g*a; sumBA += b*a; ++cnt;
1326                                         }
1327                                         if(fixMask[FIXTRANS_PIXEL] & FIXTRANS_HAS_R)
1328                                         {
1329                                                 r = data[FIXTRANS_PIXEL_R * 4 + 2];
1330                                                 g = data[FIXTRANS_PIXEL_R * 4 + 1];
1331                                                 b = data[FIXTRANS_PIXEL_R * 4 + 0];
1332                                                 a = data[FIXTRANS_PIXEL_R * 4 + 3];
1333                                                 sumR += r; sumG += g; sumB += b; sumA += a; sumRA += r*a; sumGA += g*a; sumBA += b*a; ++cnt;
1334                                         }
1335                                         if(!cnt)
1336                                                 continue;
1337                                         r0 = data[FIXTRANS_PIXEL * 4 + 2];
1338                                         g0 = data[FIXTRANS_PIXEL * 4 + 1];
1339                                         b0 = data[FIXTRANS_PIXEL * 4 + 0];
1340                                         if(sumA)
1341                                         {
1342                                                 // there is a surrounding non-alpha pixel
1343                                                 r = (sumRA + sumA / 2) / sumA;
1344                                                 g = (sumGA + sumA / 2) / sumA;
1345                                                 b = (sumBA + sumA / 2) / sumA;
1346                                         }
1347                                         else
1348                                         {
1349                                                 // need to use a "regular" average
1350                                                 r = (sumR + cnt / 2) / cnt;
1351                                                 g = (sumG + cnt / 2) / cnt;
1352                                                 b = (sumB + cnt / 2) / cnt;
1353                                         }
1354                                         if(r != r0 || g != g0 || b != b0)
1355                                                 ++changedPixels;
1356                                         data[FIXTRANS_PIXEL * 4 + 2] = r;
1357                                         data[FIXTRANS_PIXEL * 4 + 1] = g;
1358                                         data[FIXTRANS_PIXEL * 4 + 0] = b;
1359                                         fixMask[FIXTRANS_PIXEL] |= FIXTRANS_FIXED;
1360                                 }
1361                 for(y = 0; y < h; ++y)
1362                         for(x = 0; x < w; ++x)
1363                                 if(fixMask[FIXTRANS_PIXEL] & FIXTRANS_FIXED)
1364                                 {
1365                                         fixMask[FIXTRANS_PIXEL] &= ~(FIXTRANS_NEEDED | FIXTRANS_FIXED);
1366                                         fixMask[FIXTRANS_PIXEL_D] |= FIXTRANS_HAS_U;
1367                                         fixMask[FIXTRANS_PIXEL_U] |= FIXTRANS_HAS_D;
1368                                         fixMask[FIXTRANS_PIXEL_R] |= FIXTRANS_HAS_L;
1369                                         fixMask[FIXTRANS_PIXEL_L] |= FIXTRANS_HAS_R;
1370                                         --fixPixels;
1371                                 }
1372         }
1373         return changedPixels;
1374 }
1375
1376 void Image_FixTransparentPixels_f(cmd_state_t *cmd)
1377 {
1378         const char *filename, *filename_pattern;
1379         fssearch_t *search;
1380         int i, n;
1381         char outfilename[MAX_QPATH], buf[MAX_QPATH];
1382         unsigned char *data;
1383         if(Cmd_Argc(cmd) != 2)
1384         {
1385                 Con_Printf("Usage: %s imagefile\n", Cmd_Argv(cmd, 0));
1386                 return;
1387         }
1388         filename_pattern = Cmd_Argv(cmd, 1);
1389         search = FS_Search(filename_pattern, true, true, NULL);
1390         if(!search)
1391                 return;
1392         for(i = 0; i < search->numfilenames; ++i)
1393         {
1394                 filename = search->filenames[i];
1395                 Con_Printf("Processing %s... ", filename);
1396                 Image_StripImageExtension(filename, buf, sizeof(buf));
1397                 dpsnprintf(outfilename, sizeof(outfilename), "fixtrans/%s.tga", buf);
1398                 if(!(data = loadimagepixelsbgra(filename, true, false, false, NULL)))
1399                         return;
1400                 if((n = fixtransparentpixels(data, image_width, image_height)))
1401                 {
1402                         Image_WriteTGABGRA(outfilename, image_width, image_height, data);
1403                         Con_Printf("%s written (%d pixels changed).\n", outfilename, n);
1404                 }
1405                 else
1406                         Con_Printf("unchanged.\n");
1407                 Mem_Free(data);
1408         }
1409         FS_FreeSearch(search);
1410 }
1411
1412 qbool Image_WriteTGABGR_preflipped (const char *filename, int width, int height, const unsigned char *data)
1413 {
1414         qbool ret;
1415         unsigned char buffer[18];
1416         const void *buffers[2];
1417         fs_offset_t sizes[2];
1418
1419         memset (buffer, 0, 18);
1420         buffer[2] = 2;          // uncompressed type
1421         buffer[12] = (width >> 0) & 0xFF;
1422         buffer[13] = (width >> 8) & 0xFF;
1423         buffer[14] = (height >> 0) & 0xFF;
1424         buffer[15] = (height >> 8) & 0xFF;
1425         buffer[16] = 24;        // pixel size
1426
1427         buffers[0] = buffer;
1428         sizes[0] = 18;
1429         buffers[1] = data;
1430         sizes[1] = width*height*3;
1431         ret = FS_WriteFileInBlocks(filename, buffers, sizes, 2);
1432
1433         return ret;
1434 }
1435
1436 qbool Image_WriteTGABGRA (const char *filename, int width, int height, const unsigned char *data)
1437 {
1438         int y;
1439         unsigned char *buffer, *out;
1440         const unsigned char *in, *end;
1441         qbool ret;
1442
1443         buffer = (unsigned char *)Mem_Alloc(tempmempool, width*height*4 + 18);
1444
1445         memset (buffer, 0, 18);
1446         buffer[2] = 2;          // uncompressed type
1447         buffer[12] = (width >> 0) & 0xFF;
1448         buffer[13] = (width >> 8) & 0xFF;
1449         buffer[14] = (height >> 0) & 0xFF;
1450         buffer[15] = (height >> 8) & 0xFF;
1451
1452         for (y = 3;y < width*height*4;y += 4)
1453                 if (data[y] < 255)
1454                         break;
1455
1456         if (y < width*height*4)
1457         {
1458                 // save the alpha channel
1459                 buffer[16] = 32;        // pixel size
1460                 buffer[17] = 8; // 8 bits of alpha
1461
1462                 // flip upside down
1463                 out = buffer + 18;
1464                 for (y = height - 1;y >= 0;y--)
1465                 {
1466                         memcpy(out, data + y * width * 4, width * 4);
1467                         out += width*4;
1468                 }
1469         }
1470         else
1471         {
1472                 // save only the color channels
1473                 buffer[16] = 24;        // pixel size
1474                 buffer[17] = 0; // 8 bits of alpha
1475
1476                 // truncate bgra to bgr and flip upside down
1477                 out = buffer + 18;
1478                 for (y = height - 1;y >= 0;y--)
1479                 {
1480                         in = data + y * width * 4;
1481                         end = in + width * 4;
1482                         for (;in < end;in += 4)
1483                         {
1484                                 *out++ = in[0];
1485                                 *out++ = in[1];
1486                                 *out++ = in[2];
1487                         }
1488                 }
1489         }
1490         ret = FS_WriteFile (filename, buffer, out - buffer);
1491
1492         Mem_Free(buffer);
1493
1494         return ret;
1495 }
1496
1497 static void Image_Resample32LerpLine (const unsigned char *in, unsigned char *out, int inwidth, int outwidth)
1498 {
1499         int             j, xi, oldx = 0, f, fstep, endx, lerp;
1500         fstep = (int) (inwidth*65536.0f/outwidth);
1501         endx = (inwidth-1);
1502         for (j = 0,f = 0;j < outwidth;j++, f += fstep)
1503         {
1504                 xi = f >> 16;
1505                 if (xi != oldx)
1506                 {
1507                         in += (xi - oldx) * 4;
1508                         oldx = xi;
1509                 }
1510                 if (xi < endx)
1511                 {
1512                         lerp = f & 0xFFFF;
1513                         *out++ = (unsigned char) ((((in[4] - in[0]) * lerp) >> 16) + in[0]);
1514                         *out++ = (unsigned char) ((((in[5] - in[1]) * lerp) >> 16) + in[1]);
1515                         *out++ = (unsigned char) ((((in[6] - in[2]) * lerp) >> 16) + in[2]);
1516                         *out++ = (unsigned char) ((((in[7] - in[3]) * lerp) >> 16) + in[3]);
1517                 }
1518                 else // last pixel of the line has no pixel to lerp to
1519                 {
1520                         *out++ = in[0];
1521                         *out++ = in[1];
1522                         *out++ = in[2];
1523                         *out++ = in[3];
1524                 }
1525         }
1526 }
1527
1528 #define LERPBYTE(i) r = resamplerow1[i];out[i] = (unsigned char) ((((resamplerow2[i] - r) * lerp) >> 16) + r)
1529 static void Image_Resample32Lerp(const void *indata, int inwidth, int inheight, void *outdata, int outwidth, int outheight)
1530 {
1531         int i, j, r, yi, oldy, f, fstep, lerp, endy = (inheight-1), inwidth4 = inwidth*4, outwidth4 = outwidth*4;
1532         unsigned char *out;
1533         const unsigned char *inrow;
1534         unsigned char *resamplerow1;
1535         unsigned char *resamplerow2;
1536         out = (unsigned char *)outdata;
1537         fstep = (int) (inheight*65536.0f/outheight);
1538
1539         resamplerow1 = (unsigned char *)Mem_Alloc(tempmempool, outwidth*4*2);
1540         resamplerow2 = resamplerow1 + outwidth*4;
1541
1542         inrow = (const unsigned char *)indata;
1543         oldy = 0;
1544         Image_Resample32LerpLine (inrow, resamplerow1, inwidth, outwidth);
1545         Image_Resample32LerpLine (inrow + inwidth4, resamplerow2, inwidth, outwidth);
1546         for (i = 0, f = 0;i < outheight;i++,f += fstep)
1547         {
1548                 yi = f >> 16;
1549                 if (yi < endy)
1550                 {
1551                         lerp = f & 0xFFFF;
1552                         if (yi != oldy)
1553                         {
1554                                 inrow = (unsigned char *)indata + inwidth4*yi;
1555                                 if (yi == oldy+1)
1556                                         memcpy(resamplerow1, resamplerow2, outwidth4);
1557                                 else
1558                                         Image_Resample32LerpLine (inrow, resamplerow1, inwidth, outwidth);
1559                                 Image_Resample32LerpLine (inrow + inwidth4, resamplerow2, inwidth, outwidth);
1560                                 oldy = yi;
1561                         }
1562                         j = outwidth - 4;
1563                         while(j >= 0)
1564                         {
1565                                 LERPBYTE( 0);
1566                                 LERPBYTE( 1);
1567                                 LERPBYTE( 2);
1568                                 LERPBYTE( 3);
1569                                 LERPBYTE( 4);
1570                                 LERPBYTE( 5);
1571                                 LERPBYTE( 6);
1572                                 LERPBYTE( 7);
1573                                 LERPBYTE( 8);
1574                                 LERPBYTE( 9);
1575                                 LERPBYTE(10);
1576                                 LERPBYTE(11);
1577                                 LERPBYTE(12);
1578                                 LERPBYTE(13);
1579                                 LERPBYTE(14);
1580                                 LERPBYTE(15);
1581                                 out += 16;
1582                                 resamplerow1 += 16;
1583                                 resamplerow2 += 16;
1584                                 j -= 4;
1585                         }
1586                         if (j & 2)
1587                         {
1588                                 LERPBYTE( 0);
1589                                 LERPBYTE( 1);
1590                                 LERPBYTE( 2);
1591                                 LERPBYTE( 3);
1592                                 LERPBYTE( 4);
1593                                 LERPBYTE( 5);
1594                                 LERPBYTE( 6);
1595                                 LERPBYTE( 7);
1596                                 out += 8;
1597                                 resamplerow1 += 8;
1598                                 resamplerow2 += 8;
1599                         }
1600                         if (j & 1)
1601                         {
1602                                 LERPBYTE( 0);
1603                                 LERPBYTE( 1);
1604                                 LERPBYTE( 2);
1605                                 LERPBYTE( 3);
1606                                 out += 4;
1607                                 resamplerow1 += 4;
1608                                 resamplerow2 += 4;
1609                         }
1610                         resamplerow1 -= outwidth4;
1611                         resamplerow2 -= outwidth4;
1612                 }
1613                 else
1614                 {
1615                         if (yi != oldy)
1616                         {
1617                                 inrow = (unsigned char *)indata + inwidth4*yi;
1618                                 if (yi == oldy+1)
1619                                         memcpy(resamplerow1, resamplerow2, outwidth4);
1620                                 else
1621                                         Image_Resample32LerpLine (inrow, resamplerow1, inwidth, outwidth);
1622                                 oldy = yi;
1623                         }
1624                         memcpy(out, resamplerow1, outwidth4);
1625                 }
1626         }
1627
1628         Mem_Free(resamplerow1);
1629         resamplerow1 = NULL;
1630         resamplerow2 = NULL;
1631 }
1632
1633 static void Image_Resample32Nolerp(const void *indata, int inwidth, int inheight, void *outdata, int outwidth, int outheight)
1634 {
1635         int i, j;
1636         unsigned frac, fracstep;
1637         // relies on int being 4 bytes
1638         int *inrow, *out;
1639         out = (int *)outdata;
1640
1641         fracstep = inwidth*0x10000/outwidth;
1642         for (i = 0;i < outheight;i++)
1643         {
1644                 inrow = (int *)indata + inwidth*(i*inheight/outheight);
1645                 frac = fracstep >> 1;
1646                 j = outwidth - 4;
1647                 while (j >= 0)
1648                 {
1649                         out[0] = inrow[frac >> 16];frac += fracstep;
1650                         out[1] = inrow[frac >> 16];frac += fracstep;
1651                         out[2] = inrow[frac >> 16];frac += fracstep;
1652                         out[3] = inrow[frac >> 16];frac += fracstep;
1653                         out += 4;
1654                         j -= 4;
1655                 }
1656                 if (j & 2)
1657                 {
1658                         out[0] = inrow[frac >> 16];frac += fracstep;
1659                         out[1] = inrow[frac >> 16];frac += fracstep;
1660                         out += 2;
1661                 }
1662                 if (j & 1)
1663                 {
1664                         out[0] = inrow[frac >> 16];frac += fracstep;
1665                         out += 1;
1666                 }
1667         }
1668 }
1669
1670 /*
1671 ================
1672 Image_Resample
1673 ================
1674 */
1675 void Image_Resample32(const void *indata, int inwidth, int inheight, int indepth, void *outdata, int outwidth, int outheight, int outdepth, int quality)
1676 {
1677         if (indepth != 1 || outdepth != 1)
1678         {
1679                 Con_Printf ("Image_Resample: 3D resampling not supported\n");
1680                 return;
1681         }
1682         if (quality)
1683                 Image_Resample32Lerp(indata, inwidth, inheight, outdata, outwidth, outheight);
1684         else
1685                 Image_Resample32Nolerp(indata, inwidth, inheight, outdata, outwidth, outheight);
1686 }
1687
1688 // in can be the same as out
1689 void Image_MipReduce32(const unsigned char *in, unsigned char *out, int *width, int *height, int *depth, int destwidth, int destheight, int destdepth)
1690 {
1691         const unsigned char *inrow;
1692         int x, y, nextrow;
1693         if (*depth != 1 || destdepth != 1)
1694         {
1695                 Con_Printf ("Image_Resample: 3D resampling not supported\n");
1696                 if (*width > destwidth)
1697                         *width >>= 1;
1698                 if (*height > destheight)
1699                         *height >>= 1;
1700                 if (*depth > destdepth)
1701                         *depth >>= 1;
1702                 return;
1703         }
1704         // note: if given odd width/height this discards the last row/column of
1705         // pixels, rather than doing a proper box-filter scale down
1706         inrow = in;
1707         nextrow = *width * 4;
1708         if (*width > destwidth)
1709         {
1710                 *width >>= 1;
1711                 if (*height > destheight)
1712                 {
1713                         // reduce both
1714                         *height >>= 1;
1715                         for (y = 0;y < *height;y++, inrow += nextrow * 2)
1716                         {
1717                                 for (in = inrow, x = 0;x < *width;x++)
1718                                 {
1719                                         out[0] = (unsigned char) ((in[0] + in[4] + in[nextrow  ] + in[nextrow+4]) >> 2);
1720                                         out[1] = (unsigned char) ((in[1] + in[5] + in[nextrow+1] + in[nextrow+5]) >> 2);
1721                                         out[2] = (unsigned char) ((in[2] + in[6] + in[nextrow+2] + in[nextrow+6]) >> 2);
1722                                         out[3] = (unsigned char) ((in[3] + in[7] + in[nextrow+3] + in[nextrow+7]) >> 2);
1723                                         out += 4;
1724                                         in += 8;
1725                                 }
1726                         }
1727                 }
1728                 else
1729                 {
1730                         // reduce width
1731                         for (y = 0;y < *height;y++, inrow += nextrow)
1732                         {
1733                                 for (in = inrow, x = 0;x < *width;x++)
1734                                 {
1735                                         out[0] = (unsigned char) ((in[0] + in[4]) >> 1);
1736                                         out[1] = (unsigned char) ((in[1] + in[5]) >> 1);
1737                                         out[2] = (unsigned char) ((in[2] + in[6]) >> 1);
1738                                         out[3] = (unsigned char) ((in[3] + in[7]) >> 1);
1739                                         out += 4;
1740                                         in += 8;
1741                                 }
1742                         }
1743                 }
1744         }
1745         else
1746         {
1747                 if (*height > destheight)
1748                 {
1749                         // reduce height
1750                         *height >>= 1;
1751                         for (y = 0;y < *height;y++, inrow += nextrow * 2)
1752                         {
1753                                 for (in = inrow, x = 0;x < *width;x++)
1754                                 {
1755                                         out[0] = (unsigned char) ((in[0] + in[nextrow  ]) >> 1);
1756                                         out[1] = (unsigned char) ((in[1] + in[nextrow+1]) >> 1);
1757                                         out[2] = (unsigned char) ((in[2] + in[nextrow+2]) >> 1);
1758                                         out[3] = (unsigned char) ((in[3] + in[nextrow+3]) >> 1);
1759                                         out += 4;
1760                                         in += 4;
1761                                 }
1762                         }
1763                 }
1764                 else
1765                         Con_Printf ("Image_MipReduce: desired size already achieved\n");
1766         }
1767 }
1768
1769 void Image_HeightmapToNormalmap_BGRA(const unsigned char *inpixels, unsigned char *outpixels, int width, int height, int clamp, float bumpscale)
1770 {
1771         int x, y, x1, x2, y1, y2;
1772         const unsigned char *b, *row[3];
1773         int p[5];
1774         unsigned char *out;
1775         float ibumpscale, n[3];
1776         ibumpscale = (255.0f * 6.0f) / bumpscale;
1777         out = outpixels;
1778         for (y = 0, y1 = height-1;y < height;y1 = y, y++)
1779         {
1780                 y2 = y + 1;if (y2 >= height) y2 = 0;
1781                 row[0] = inpixels + (y1 * width) * 4;
1782                 row[1] = inpixels + (y  * width) * 4;
1783                 row[2] = inpixels + (y2 * width) * 4;
1784                 for (x = 0, x1 = width-1;x < width;x1 = x, x++)
1785                 {
1786                         x2 = x + 1;if (x2 >= width) x2 = 0;
1787                         // left, right
1788                         b = row[1] + x1 * 4;p[0] = (b[0] + b[1] + b[2]);
1789                         b = row[1] + x2 * 4;p[1] = (b[0] + b[1] + b[2]);
1790                         // above, below
1791                         b = row[0] + x  * 4;p[2] = (b[0] + b[1] + b[2]);
1792                         b = row[2] + x  * 4;p[3] = (b[0] + b[1] + b[2]);
1793                         // center
1794                         b = row[1] + x  * 4;p[4] = (b[0] + b[1] + b[2]);
1795                         // calculate a normal from the slopes
1796                         n[0] = p[0] - p[1];
1797                         n[1] = p[3] - p[2];
1798                         n[2] = ibumpscale;
1799                         VectorNormalize(n);
1800                         // turn it into a dot3 rgb vector texture
1801                         out[2] = (int)(128.0f + n[0] * 127.0f);
1802                         out[1] = (int)(128.0f + n[1] * 127.0f);
1803                         out[0] = (int)(128.0f + n[2] * 127.0f);
1804                         out[3] = (p[4]) / 3;
1805                         out += 4;
1806                 }
1807         }
1808 }
1809
1810
1811 #include "lhfont.h"
1812
1813 static unsigned char *Image_GenerateConChars(void)
1814 {
1815         int i;
1816         unsigned char *data;
1817         double random;
1818
1819         image_width = 256;
1820         image_height = 256;
1821
1822         data = LoadTGA_BGRA(concharimage, sizeof(concharimage), NULL);
1823         // Gold numbers
1824         for (i = 0; i < 8192; i++)
1825         {
1826                 random = lhrandom(0.0, 1.0);
1827                 data[i * 4 + 3] = data[i * 4 + 0];
1828                 data[i * 4 + 2] = 83 + (unsigned char)(random * 64);
1829                 data[i * 4 + 1] = 71 + (unsigned char)(random * 32);
1830                 data[i * 4 + 0] = 23 + (unsigned char)(random * 16);
1831         }
1832         // White chars
1833         for (i = 8192; i < 32768; i++)
1834         {
1835                 random = lhrandom(0.0, 1.0);
1836                 data[i * 4 + 3] = data[i * 4 + 0];
1837                 data[i * 4 + 2] = 95 + (unsigned char)(random * 64);
1838                 data[i * 4 + 1] = 95 + (unsigned char)(random * 64);
1839                 data[i * 4 + 0] = 95 + (unsigned char)(random * 64);
1840         }
1841         // Gold numbers
1842         for (i = 32768; i < 40960; i++)
1843         {
1844                 random = lhrandom(0.0, 1.0);
1845                 data[i * 4 + 3] = data[i * 4 + 0];
1846                 data[i * 4 + 2] = 83 + (unsigned char)(random * 64);
1847                 data[i * 4 + 1] = 71 + (unsigned char)(random * 32);
1848                 data[i * 4 + 0] = 23 + (unsigned char)(random * 16);
1849         }
1850         // Red chars
1851         for (i = 40960; i < 65536; i++)
1852         {
1853                 random = lhrandom(0.0, 1.0);
1854                 data[i * 4 + 3] = data[i * 4 + 0];
1855                 data[i * 4 + 2] = 96 + (unsigned char)(random * 64);
1856                 data[i * 4 + 1] = 43 + (unsigned char)(random * 32);
1857                 data[i * 4 + 0] = 27 + (unsigned char)(random * 32);
1858         }
1859
1860 #if 0
1861         Image_WriteTGABGRA("gfx/generated_conchars.tga", 256, 256, data);
1862 #endif
1863
1864         return data;
1865 }
1866
1867 static unsigned char *Image_GenerateDitherPattern(void)
1868 {
1869         int x, y;
1870         unsigned char *data = (unsigned char *)Mem_Alloc(tempmempool, 8 * 8 * 4);
1871         image_width = 8;
1872         image_height = 8;
1873         for (y = 0; y < 8; y++)
1874         {
1875                 for (x = 0; x < 8; x++)
1876                 {
1877                         data[(y * 8 + x) * 4 + 0] = ((x^y) & 4) ? 255 : 0;
1878                         data[(y * 8 + x) * 4 + 1] = ((x^y) & 4) ? 255 : 0;
1879                         data[(y * 8 + x) * 4 + 2] = ((x^y) & 4) ? 255 : 0;
1880                         data[(y * 8 + x) * 4 + 3] = 255;
1881                 }
1882         }
1883         return data;
1884 }
1885
1886 // also used in R_SkinFrame code
1887 unsigned char *Image_GenerateNoTexture(void)
1888 {
1889         int x, y;
1890         unsigned char *data = (unsigned char *)Mem_Alloc(tempmempool, 16 * 16 * 4);
1891         image_width = 16;
1892         image_height = 16;
1893         // this makes a light grey/dark grey checkerboard texture
1894         for (y = 0; y < 16; y++)
1895         {
1896                 for (x = 0; x < 16; x++)
1897                 {
1898                         data[(y * 16 + x) * 4 + 0] =
1899                         data[(y * 16 + x) * 4 + 1] =
1900                         data[(y * 16 + x) * 4 + 2] = (y < 8) ^ (x < 8) ? 128 : 64;
1901                         data[(y * 16 + x) * 4 + 3] = 255;
1902                 }
1903         }
1904         return data;
1905 }
1906
1907 static unsigned char *Image_GenerateWhite(void)
1908 {
1909         unsigned char *data = (unsigned char *)Mem_Alloc(tempmempool, 1 * 1 * 4);
1910         image_width = 1;
1911         image_height = 1;
1912         data[0] = data[1] = data[2] = data[3] = 255;
1913         return data;
1914 }
1915
1916 typedef struct embeddedpic_s
1917 {
1918 const char *name;
1919 int width;
1920 int height;
1921 const char *pixels;
1922 }
1923 embeddedpic_t;
1924
1925 static const embeddedpic_t embeddedpics[] =
1926 {
1927         {
1928                 "gfx/prydoncursor001", 16, 16,
1929                 "477777774......."
1930                 "77.....6........"
1931                 "7.....6........."
1932                 "7....6.........."
1933                 "7.....6........."
1934                 "7..6...6........"
1935                 "7.6.6...6......."
1936                 "76...6...6......"
1937                 "4.....6.6......."
1938                 ".......6........"
1939                 "................"
1940                 "................"
1941                 "................"
1942                 "................"
1943                 "................"
1944                 "................"
1945         },
1946         {
1947                 "ui/mousepointer", 16, 16,
1948                 "477777774......."
1949                 "77.....6........"
1950                 "7.....6........."
1951                 "7....6.........."
1952                 "7.....6........."
1953                 "7..6...6........"
1954                 "7.6.6...6......."
1955                 "76...6...6......"
1956                 "4.....6.6......."
1957                 ".......6........"
1958                 "................"
1959                 "................"
1960                 "................"
1961                 "................"
1962                 "................"
1963                 "................"
1964         },
1965         {
1966                 "gfx/crosshair1", 16, 16,
1967                 "................"
1968                 "................"
1969                 "................"
1970                 "...33......33..."
1971                 "...355....553..."
1972                 "....577..775...."
1973                 ".....77..77....."
1974                 "................"
1975                 "................"
1976                 ".....77..77....."
1977                 "....577..775...."
1978                 "...355....553..."
1979                 "...33......33..."
1980                 "................"
1981                 "................"
1982                 "................"
1983         },
1984         {
1985                 "gfx/crosshair2", 16, 16,
1986                 "................"
1987                 "................"
1988                 "................"
1989                 "...3........3..."
1990                 "....5......5...."
1991                 ".....7....7....."
1992                 "......7..7......"
1993                 "................"
1994                 "................"
1995                 "......7..7......"
1996                 ".....7....7....."
1997                 "....5......5...."
1998                 "...3........3..."
1999                 "................"
2000                 "................"
2001                 "................"
2002         },
2003         {
2004                 "gfx/crosshair3", 16, 16,
2005                 "................"
2006                 ".......77......."
2007                 ".......77......."
2008                 "................"
2009                 "................"
2010                 ".......44......."
2011                 ".......44......."
2012                 ".77..44..44..77."
2013                 ".77..44..44..77."
2014                 ".......44......."
2015                 ".......44......."
2016                 "................"
2017                 "................"
2018                 ".......77......."
2019                 ".......77......."
2020                 "................"
2021         },
2022         {
2023                 "gfx/crosshair4", 16, 16,
2024                 "................"
2025                 "................"
2026                 "................"
2027                 "................"
2028                 "................"
2029                 "................"
2030                 "................"
2031                 "................"
2032                 "........7777777."
2033                 "........752....."
2034                 "........72......"
2035                 "........7......."
2036                 "........7......."
2037                 "........7......."
2038                 "........7......."
2039                 "................"
2040         },
2041         {
2042                 "gfx/crosshair5", 8, 8,
2043                 "........"
2044                 "........"
2045                 "....7..."
2046                 "........"
2047                 "..7.7.7."
2048                 "........"
2049                 "....7..."
2050                 "........"
2051         },
2052         {
2053                 "gfx/crosshair6", 2, 2,
2054                 "77"
2055                 "77"
2056         },
2057         {
2058                 "gfx/crosshair7", 16, 16,
2059                 "................"
2060                 ".3............3."
2061                 "..5...2332...5.."
2062                 "...7.3....3.7..."
2063                 "....7......7...."
2064                 "...3.7....7.3..."
2065                 "..2...7..7...2.."
2066                 "..3..........3.."
2067                 "..3..........3.."
2068                 "..2...7..7...2.."
2069                 "...3.7....7.3..."
2070                 "....7......7...."
2071                 "...7.3....3.7..."
2072                 "..5...2332...5.."
2073                 ".3............3."
2074                 "................"
2075         },
2076         { NULL, 0, 0, NULL }
2077 };
2078
2079 unsigned char *Image_GetEmbeddedPicBGRA(const char *name)
2080 {
2081         const embeddedpic_t *p;
2082         for (p = embeddedpics; p->name; p++)
2083         {
2084                 if (!strcmp(name, p->name))
2085                 {
2086                         int i;
2087                         unsigned char *data = (unsigned char *)Mem_Alloc(tempmempool, p->width * p->height * 4);
2088                         image_width = p->width;
2089                         image_height = p->height;
2090                         for (i = 0; i < p->width * p->height; i++)
2091                         {
2092                                 const unsigned char *c = (const unsigned char *)palette_bgra_embeddedpic + 4 * p->pixels[i];
2093                                 Vector4Copy(c, data + 4 * i);
2094                         }
2095                         return data;
2096                 }
2097         }
2098         if (!strcmp(name, "white") || !strcmp(name, "#white") || !strcmp(name, "*white") || !strcmp(name, "$whiteimage"))
2099                 return Image_GenerateWhite();
2100         if (!strcmp(name, "gfx/conchars"))
2101                 return Image_GenerateConChars();
2102         if (!strcmp(name, "gfx/colorcontrol/ditherpattern"))
2103                 return Image_GenerateDitherPattern();
2104         return NULL;
2105 }