]> git.xonotic.org Git - xonotic/darkplaces.git/blob - image.c
Fix most compiler warnings.
[xonotic/darkplaces.git] / image.c
1
2 #include "quakedef.h"
3 #include "image.h"
4 #include "jpeg.h"
5 #include "image_png.h"
6 #include "r_shadow.h"
7 #include "wad.h"
8
9 int             image_width;
10 int             image_height;
11
12 static unsigned char *Image_GetEmbeddedPicBGRA(const char *name);
13
14 static void Image_CopyAlphaFromBlueBGRA(unsigned char *outpixels, const unsigned char *inpixels, int w, int h)
15 {
16         int i, n;
17         n = w * h;
18         for(i = 0; i < n; ++i)
19                 outpixels[4*i+3] = inpixels[4*i]; // blue channel
20 }
21
22 #if 1
23 // written by LadyHavoc in a readable way, optimized by Vic, further optimized by LadyHavoc (the non-special index case), readable version preserved below this
24 void Image_CopyMux(unsigned char *outpixels, const unsigned char *inpixels, int inputwidth, int inputheight, qboolean inputflipx, qboolean inputflipy, qboolean inputflipdiagonal, int numoutputcomponents, int numinputcomponents, int *outputinputcomponentindices)
25 {
26         int index, c, x, y;
27         const unsigned char *in, *line;
28         int row_inc = (inputflipy ? -inputwidth : inputwidth) * numinputcomponents, col_inc = (inputflipx ? -1 : 1) * numinputcomponents;
29         int row_ofs = (inputflipy ? (inputheight - 1) * inputwidth * numinputcomponents : 0), col_ofs = (inputflipx ? (inputwidth - 1) * numinputcomponents : 0);
30
31         for (c = 0; c < numoutputcomponents; c++)
32                 if (outputinputcomponentindices[c] & 0x80000000)
33                         break;
34         if (c < numoutputcomponents)
35         {
36                 // special indices used
37                 if (inputflipdiagonal)
38                 {
39                         for (x = 0, line = inpixels + col_ofs; x < inputwidth; x++, line += col_inc)
40                                 for (y = 0, in = line + row_ofs; y < inputheight; y++, in += row_inc, outpixels += numoutputcomponents)
41                                         for (c = 0; c < numoutputcomponents; c++)
42                                                 outpixels[c] = ((index = outputinputcomponentindices[c]) & 0x80000000) ? index : in[index];
43                 }
44                 else
45                 {
46                         for (y = 0, line = inpixels + row_ofs; y < inputheight; y++, line += row_inc)
47                                 for (x = 0, in = line + col_ofs; x < inputwidth; x++, in += col_inc, outpixels += numoutputcomponents)
48                                         for (c = 0; c < numoutputcomponents; c++)
49                                                 outpixels[c] = ((index = outputinputcomponentindices[c]) & 0x80000000) ? index : in[index];
50                 }
51         }
52         else
53         {
54                 // special indices not used
55                 if (inputflipdiagonal)
56                 {
57                         for (x = 0, line = inpixels + col_ofs; x < inputwidth; x++, line += col_inc)
58                                 for (y = 0, in = line + row_ofs; y < inputheight; y++, in += row_inc, outpixels += numoutputcomponents)
59                                         for (c = 0; c < numoutputcomponents; c++)
60                                                 outpixels[c] = in[outputinputcomponentindices[c]];
61                 }
62                 else
63                 {
64                         for (y = 0, line = inpixels + row_ofs; y < inputheight; y++, line += row_inc)
65                                 for (x = 0, in = line + col_ofs; x < inputwidth; x++, in += col_inc, outpixels += numoutputcomponents)
66                                         for (c = 0; c < numoutputcomponents; c++)
67                                                 outpixels[c] = in[outputinputcomponentindices[c]];
68                 }
69         }
70 }
71 #else
72 // intentionally readable version
73 void Image_CopyMux(unsigned char *outpixels, const unsigned char *inpixels, int inputwidth, int inputheight, qboolean inputflipx, qboolean inputflipy, qboolean inputflipdiagonal, int numoutputcomponents, int numinputcomponents, int *outputinputcomponentindices)
74 {
75         int index, c, x, y;
76         const unsigned char *in, *inrow, *incolumn;
77         if (inputflipdiagonal)
78         {
79                 for (x = 0;x < inputwidth;x++)
80                 {
81                         for (y = 0;y < inputheight;y++)
82                         {
83                                 in = inpixels + ((inputflipy ? inputheight - 1 - y : y) * inputwidth + (inputflipx ? inputwidth - 1 - x : x)) * numinputcomponents;
84                                 for (c = 0;c < numoutputcomponents;c++)
85                                 {
86                                         index = outputinputcomponentindices[c];
87                                         if (index & 0x80000000)
88                                                 *outpixels++ = index;
89                                         else
90                                                 *outpixels++ = in[index];
91                                 }
92                         }
93                 }
94         }
95         else
96         {
97                 for (y = 0;y < inputheight;y++)
98                 {
99                         for (x = 0;x < inputwidth;x++)
100                         {
101                                 in = inpixels + ((inputflipy ? inputheight - 1 - y : y) * inputwidth + (inputflipx ? inputwidth - 1 - x : x)) * numinputcomponents;
102                                 for (c = 0;c < numoutputcomponents;c++)
103                                 {
104                                         index = outputinputcomponentindices[c];
105                                         if (index & 0x80000000)
106                                                 *outpixels++ = index;
107                                         else
108                                                 *outpixels++ = in[index];
109                                 }
110                         }
111                 }
112         }
113 }
114 #endif
115
116 void Image_GammaRemapRGB(const unsigned char *in, unsigned char *out, int pixels, const unsigned char *gammar, const unsigned char *gammag, const unsigned char *gammab)
117 {
118         while (pixels--)
119         {
120                 out[0] = gammar[in[0]];
121                 out[1] = gammag[in[1]];
122                 out[2] = gammab[in[2]];
123                 in += 3;
124                 out += 3;
125         }
126 }
127
128 // note: pal must be 32bit color
129 void Image_Copy8bitBGRA(const unsigned char *in, unsigned char *out, int pixels, const unsigned int *pal)
130 {
131         int *iout = (int *)out;
132         while (pixels >= 8)
133         {
134                 iout[0] = pal[in[0]];
135                 iout[1] = pal[in[1]];
136                 iout[2] = pal[in[2]];
137                 iout[3] = pal[in[3]];
138                 iout[4] = pal[in[4]];
139                 iout[5] = pal[in[5]];
140                 iout[6] = pal[in[6]];
141                 iout[7] = pal[in[7]];
142                 in += 8;
143                 iout += 8;
144                 pixels -= 8;
145         }
146         if (pixels & 4)
147         {
148                 iout[0] = pal[in[0]];
149                 iout[1] = pal[in[1]];
150                 iout[2] = pal[in[2]];
151                 iout[3] = pal[in[3]];
152                 in += 4;
153                 iout += 4;
154         }
155         if (pixels & 2)
156         {
157                 iout[0] = pal[in[0]];
158                 iout[1] = pal[in[1]];
159                 in += 2;
160                 iout += 2;
161         }
162         if (pixels & 1)
163                 iout[0] = pal[in[0]];
164 }
165
166 /*
167 =================================================================
168
169   PCX Loading
170
171 =================================================================
172 */
173
174 typedef struct pcx_s
175 {
176     char        manufacturer;
177     char        version;
178     char        encoding;
179     char        bits_per_pixel;
180     unsigned short      xmin,ymin,xmax,ymax;
181     unsigned short      hres,vres;
182     unsigned char       palette[48];
183     char        reserved;
184     char        color_planes;
185     unsigned short      bytes_per_line;
186     unsigned short      palette_type;
187     char        filler[58];
188 } pcx_t;
189
190 /*
191 ============
192 LoadPCX
193 ============
194 */
195 static unsigned char* LoadPCX_BGRA (const unsigned char *f, int filesize, int *miplevel)
196 {
197         pcx_t pcx;
198         unsigned char *a, *b, *image_buffer, *pbuf;
199         const unsigned char *palette, *fin, *enddata;
200         int x, y, x2, dataByte;
201
202         if (filesize < (int)sizeof(pcx) + 768)
203         {
204                 Con_Print("Bad pcx file\n");
205                 return NULL;
206         }
207
208         fin = f;
209
210         memcpy(&pcx, fin, sizeof(pcx));
211         fin += sizeof(pcx);
212
213         // LadyHavoc: big-endian support ported from QF newtree
214         pcx.xmax = LittleShort (pcx.xmax);
215         pcx.xmin = LittleShort (pcx.xmin);
216         pcx.ymax = LittleShort (pcx.ymax);
217         pcx.ymin = LittleShort (pcx.ymin);
218         pcx.hres = LittleShort (pcx.hres);
219         pcx.vres = LittleShort (pcx.vres);
220         pcx.bytes_per_line = LittleShort (pcx.bytes_per_line);
221         pcx.palette_type = LittleShort (pcx.palette_type);
222
223         image_width = pcx.xmax + 1 - pcx.xmin;
224         image_height = pcx.ymax + 1 - pcx.ymin;
225         if (pcx.manufacturer != 0x0a || pcx.version != 5 || pcx.encoding != 1 || pcx.bits_per_pixel != 8 || image_width > 32768 || image_height > 32768 || image_width <= 0 || image_height <= 0)
226         {
227                 Con_Print("Bad pcx file\n");
228                 return NULL;
229         }
230
231         palette = f + filesize - 768;
232
233         image_buffer = (unsigned char *)Mem_Alloc(tempmempool, image_width*image_height*4);
234         if (!image_buffer)
235         {
236                 Con_Printf("LoadPCX: not enough memory for %i by %i image\n", image_width, image_height);
237                 return NULL;
238         }
239         pbuf = image_buffer + image_width*image_height*3;
240         enddata = palette;
241
242         for (y = 0;y < image_height && fin < enddata;y++)
243         {
244                 a = pbuf + y * image_width;
245                 for (x = 0;x < image_width && fin < enddata;)
246                 {
247                         dataByte = *fin++;
248                         if(dataByte >= 0xC0)
249                         {
250                                 if (fin >= enddata)
251                                         break;
252                                 x2 = x + (dataByte & 0x3F);
253                                 dataByte = *fin++;
254                                 if (x2 > image_width)
255                                         x2 = image_width; // technically an error
256                                 while(x < x2)
257                                         a[x++] = dataByte;
258                         }
259                         else
260                                 a[x++] = dataByte;
261                 }
262                 while(x < image_width)
263                         a[x++] = 0;
264         }
265
266         a = image_buffer;
267         b = pbuf;
268
269         for(x = 0;x < image_width*image_height;x++)
270         {
271                 y = *b++ * 3;
272                 *a++ = palette[y+2];
273                 *a++ = palette[y+1];
274                 *a++ = palette[y];
275                 *a++ = 255;
276         }
277
278         return image_buffer;
279 }
280
281 /*
282 ============
283 LoadPCX
284 ============
285 */
286 qboolean LoadPCX_QWSkin(const unsigned char *f, int filesize, unsigned char *pixels, int outwidth, int outheight)
287 {
288         pcx_t pcx;
289         unsigned char *a;
290         const unsigned char *fin, *enddata;
291         int x, y, x2, dataByte, pcxwidth, pcxheight;
292
293         if (filesize < (int)sizeof(pcx) + 768)
294                 return false;
295
296         image_width = outwidth;
297         image_height = outheight;
298         fin = f;
299
300         memcpy(&pcx, fin, sizeof(pcx));
301         fin += sizeof(pcx);
302
303         // LadyHavoc: big-endian support ported from QF newtree
304         pcx.xmax = LittleShort (pcx.xmax);
305         pcx.xmin = LittleShort (pcx.xmin);
306         pcx.ymax = LittleShort (pcx.ymax);
307         pcx.ymin = LittleShort (pcx.ymin);
308         pcx.hres = LittleShort (pcx.hres);
309         pcx.vres = LittleShort (pcx.vres);
310         pcx.bytes_per_line = LittleShort (pcx.bytes_per_line);
311         pcx.palette_type = LittleShort (pcx.palette_type);
312
313         pcxwidth = pcx.xmax + 1 - pcx.xmin;
314         pcxheight = pcx.ymax + 1 - pcx.ymin;
315         if (pcx.manufacturer != 0x0a || pcx.version != 5 || pcx.encoding != 1 || pcx.bits_per_pixel != 8 || pcxwidth > 4096 || pcxheight > 4096 || pcxwidth <= 0 || pcxheight <= 0)
316                 return false;
317
318         enddata = f + filesize - 768;
319
320         for (y = 0;y < outheight && fin < enddata;y++)
321         {
322                 a = pixels + y * outwidth;
323                 // pad the output with blank lines if needed
324                 if (y >= pcxheight)
325                 {
326                         memset(a, 0, outwidth);
327                         continue;
328                 }
329                 for (x = 0;x < pcxwidth;)
330                 {
331                         if (fin >= enddata)
332                                 return false;
333                         dataByte = *fin++;
334                         if(dataByte >= 0xC0)
335                         {
336                                 x2 = x + (dataByte & 0x3F);
337                                 if (fin >= enddata)
338                                         return false;
339                                 if (x2 > pcxwidth)
340                                         return false;
341                                 dataByte = *fin++;
342                                 for (;x < x2;x++)
343                                         if (x < outwidth)
344                                                 a[x] = dataByte;
345                         }
346                         else
347                         {
348                                 if (x < outwidth) // truncate to destination width
349                                         a[x] = dataByte;
350                                 x++;
351                         }
352                 }
353                 while(x < outwidth)
354                         a[x++] = 0;
355         }
356
357         return true;
358 }
359
360 /*
361 ============
362 LoadPCX
363 ============
364 */
365 qboolean LoadPCX_PaletteOnly(const unsigned char *f, int filesize, unsigned char *palette768b)
366 {
367         if (filesize < 768)
368                 return false;
369         memcpy(palette768b, f + filesize - 768, 768);
370         return true;
371 }
372
373 /*
374 =========================================================
375
376 TARGA LOADING
377
378 =========================================================
379 */
380
381 typedef struct _TargaHeader
382 {
383         unsigned char   id_length, colormap_type, image_type;
384         unsigned short  colormap_index, colormap_length;
385         unsigned char   colormap_size;
386         unsigned short  x_origin, y_origin, width, height;
387         unsigned char   pixel_size, attributes;
388 }
389 TargaHeader;
390
391 static void PrintTargaHeader(TargaHeader *t)
392 {
393         Con_Printf("TargaHeader:\nuint8 id_length = %i;\nuint8 colormap_type = %i;\nuint8 image_type = %i;\nuint16 colormap_index = %i;\nuint16 colormap_length = %i;\nuint8 colormap_size = %i;\nuint16 x_origin = %i;\nuint16 y_origin = %i;\nuint16 width = %i;\nuint16 height = %i;\nuint8 pixel_size = %i;\nuint8 attributes = %i;\n", t->id_length, t->colormap_type, t->image_type, t->colormap_index, t->colormap_length, t->colormap_size, t->x_origin, t->y_origin, t->width, t->height, t->pixel_size, t->attributes);
394 }
395
396 /*
397 =============
398 LoadTGA
399 =============
400 */
401 unsigned char *LoadTGA_BGRA (const unsigned char *f, int filesize, int *miplevel)
402 {
403         int x, y, pix_inc, row_inci, runlen, alphabits;
404         unsigned char *image_buffer;
405         unsigned int *pixbufi;
406         const unsigned char *fin, *enddata;
407         TargaHeader targa_header;
408         unsigned int palettei[256];
409         union
410         {
411                 unsigned int i;
412                 unsigned char b[4];
413         }
414         bgra;
415
416         if (filesize < 19)
417                 return NULL;
418
419         enddata = f + filesize;
420
421         targa_header.id_length = f[0];
422         targa_header.colormap_type = f[1];
423         targa_header.image_type = f[2];
424
425         targa_header.colormap_index = f[3] + f[4] * 256;
426         targa_header.colormap_length = f[5] + f[6] * 256;
427         targa_header.colormap_size = f[7];
428         targa_header.x_origin = f[8] + f[9] * 256;
429         targa_header.y_origin = f[10] + f[11] * 256;
430         targa_header.width = image_width = f[12] + f[13] * 256;
431         targa_header.height = image_height = f[14] + f[15] * 256;
432         targa_header.pixel_size = f[16];
433         targa_header.attributes = f[17];
434
435         if (image_width > 32768 || image_height > 32768 || image_width <= 0 || image_height <= 0)
436         {
437                 Con_Print("LoadTGA: invalid size\n");
438                 PrintTargaHeader(&targa_header);
439                 return NULL;
440         }
441
442         memset(palettei, 0, sizeof(palettei));
443
444         // advance to end of header
445         fin = f + 18;
446
447         // skip TARGA image comment (usually 0 bytes)
448         fin += targa_header.id_length;
449
450         // read/skip the colormap if present (note: according to the TARGA spec it
451         // can be present even on truecolor or greyscale images, just not used by
452         // the image data)
453         if (targa_header.colormap_type)
454         {
455                 if (targa_header.colormap_length > 256)
456                 {
457                         Con_Print("LoadTGA: only up to 256 colormap_length supported\n");
458                         PrintTargaHeader(&targa_header);
459                         return NULL;
460                 }
461                 if (targa_header.colormap_index)
462                 {
463                         Con_Print("LoadTGA: colormap_index not supported\n");
464                         PrintTargaHeader(&targa_header);
465                         return NULL;
466                 }
467                 if (targa_header.colormap_size == 24)
468                 {
469                         for (x = 0;x < targa_header.colormap_length;x++)
470                         {
471                                 bgra.b[0] = *fin++;
472                                 bgra.b[1] = *fin++;
473                                 bgra.b[2] = *fin++;
474                                 bgra.b[3] = 255;
475                                 palettei[x] = bgra.i;
476                         }
477                 }
478                 else if (targa_header.colormap_size == 32)
479                 {
480                         memcpy(palettei, fin, targa_header.colormap_length*4);
481                         fin += targa_header.colormap_length * 4;
482                 }
483                 else
484                 {
485                         Con_Print("LoadTGA: Only 32 and 24 bit colormap_size supported\n");
486                         PrintTargaHeader(&targa_header);
487                         return NULL;
488                 }
489         }
490
491         // check our pixel_size restrictions according to image_type
492         switch (targa_header.image_type & ~8)
493         {
494         case 2:
495                 if (targa_header.pixel_size != 24 && targa_header.pixel_size != 32)
496                 {
497                         Con_Print("LoadTGA: only 24bit and 32bit pixel sizes supported for type 2 and type 10 images\n");
498                         PrintTargaHeader(&targa_header);
499                         return NULL;
500                 }
501                 break;
502         case 3:
503                 // set up a palette to make the loader easier
504                 for (x = 0;x < 256;x++)
505                 {
506                         bgra.b[0] = bgra.b[1] = bgra.b[2] = x;
507                         bgra.b[3] = 255;
508                         palettei[x] = bgra.i;
509                 }
510                 // fall through to colormap case
511         case 1:
512                 if (targa_header.pixel_size != 8)
513                 {
514                         Con_Print("LoadTGA: only 8bit pixel size for type 1, 3, 9, and 11 images supported\n");
515                         PrintTargaHeader(&targa_header);
516                         return NULL;
517                 }
518                 break;
519         default:
520                 Con_Printf("LoadTGA: Only type 1, 2, 3, 9, 10, and 11 targa RGB images supported, image_type = %i\n", targa_header.image_type);
521                 PrintTargaHeader(&targa_header);
522                 return NULL;
523         }
524
525         if (targa_header.attributes & 0x10)
526         {
527                 Con_Print("LoadTGA: origin must be in top left or bottom left, top right and bottom right are not supported\n");
528                 return NULL;
529         }
530
531         // number of attribute bits per pixel, we only support 0 or 8
532         alphabits = targa_header.attributes & 0x0F;
533         if (alphabits != 8 && alphabits != 0)
534         {
535                 Con_Print("LoadTGA: only 0 or 8 attribute (alpha) bits supported\n");
536                 return NULL;
537         }
538
539         image_buffer = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
540         if (!image_buffer)
541         {
542                 Con_Printf("LoadTGA: not enough memory for %i by %i image\n", image_width, image_height);
543                 return NULL;
544         }
545
546         // If bit 5 of attributes isn't set, the image has been stored from bottom to top
547         if ((targa_header.attributes & 0x20) == 0)
548         {
549                 pixbufi = (unsigned int*)image_buffer + (image_height - 1)*image_width;
550                 row_inci = -image_width*2;
551         }
552         else
553         {
554                 pixbufi = (unsigned int*)image_buffer;
555                 row_inci = 0;
556         }
557
558         pix_inc = 1;
559         if ((targa_header.image_type & ~8) == 2)
560                 pix_inc = (targa_header.pixel_size + 7) / 8;
561         switch (targa_header.image_type)
562         {
563         case 1: // colormapped, uncompressed
564         case 3: // greyscale, uncompressed
565                 if (fin + image_width * image_height * pix_inc > enddata)
566                         break;
567                 for (y = 0;y < image_height;y++, pixbufi += row_inci)
568                         for (x = 0;x < image_width;x++)
569                                 *pixbufi++ = palettei[*fin++];
570                 break;
571         case 2:
572                 // BGR or BGRA, uncompressed
573                 if (fin + image_width * image_height * pix_inc > enddata)
574                         break;
575                 if (targa_header.pixel_size == 32 && alphabits)
576                 {
577                         for (y = 0;y < image_height;y++)
578                                 memcpy(pixbufi + y * (image_width + row_inci), fin + y * image_width * pix_inc, image_width*4);
579                 }
580                 else
581                 {
582                         for (y = 0;y < image_height;y++, pixbufi += row_inci)
583                         {
584                                 for (x = 0;x < image_width;x++, fin += pix_inc)
585                                 {
586                                         bgra.b[0] = fin[0];
587                                         bgra.b[1] = fin[1];
588                                         bgra.b[2] = fin[2];
589                                         bgra.b[3] = 255;
590                                         *pixbufi++ = bgra.i;
591                                 }
592                         }
593                 }
594                 break;
595         case 9: // colormapped, RLE
596         case 11: // greyscale, RLE
597                 for (y = 0;y < image_height;y++, pixbufi += row_inci)
598                 {
599                         for (x = 0;x < image_width;)
600                         {
601                                 if (fin >= enddata)
602                                         break; // error - truncated file
603                                 runlen = *fin++;
604                                 if (runlen & 0x80)
605                                 {
606                                         // RLE - all pixels the same color
607                                         runlen += 1 - 0x80;
608                                         if (fin + pix_inc > enddata)
609                                                 break; // error - truncated file
610                                         if (x + runlen > image_width)
611                                                 break; // error - line exceeds width
612                                         bgra.i = palettei[*fin++];
613                                         for (;runlen--;x++)
614                                                 *pixbufi++ = bgra.i;
615                                 }
616                                 else
617                                 {
618                                         // uncompressed - all pixels different color
619                                         runlen++;
620                                         if (fin + pix_inc * runlen > enddata)
621                                                 break; // error - truncated file
622                                         if (x + runlen > image_width)
623                                                 break; // error - line exceeds width
624                                         for (;runlen--;x++)
625                                                 *pixbufi++ = palettei[*fin++];
626                                 }
627                         }
628
629                         if (x != image_width)
630                         {
631                                 // pixbufi is useless now
632                                 Con_Printf("LoadTGA: corrupt file\n");
633                                 break;
634                         }
635                 }
636                 break;
637         case 10:
638                 // BGR or BGRA, RLE
639                 if (targa_header.pixel_size == 32 && alphabits)
640                 {
641                         for (y = 0;y < image_height;y++, pixbufi += row_inci)
642                         {
643                                 for (x = 0;x < image_width;)
644                                 {
645                                         if (fin >= enddata)
646                                                 break; // error - truncated file
647                                         runlen = *fin++;
648                                         if (runlen & 0x80)
649                                         {
650                                                 // RLE - all pixels the same color
651                                                 runlen += 1 - 0x80;
652                                                 if (fin + pix_inc > enddata)
653                                                         break; // error - truncated file
654                                                 if (x + runlen > image_width)
655                                                         break; // error - line exceeds width
656                                                 bgra.b[0] = fin[0];
657                                                 bgra.b[1] = fin[1];
658                                                 bgra.b[2] = fin[2];
659                                                 bgra.b[3] = fin[3];
660                                                 fin += pix_inc;
661                                                 for (;runlen--;x++)
662                                                         *pixbufi++ = bgra.i;
663                                         }
664                                         else
665                                         {
666                                                 // uncompressed - all pixels different color
667                                                 runlen++;
668                                                 if (fin + pix_inc * runlen > enddata)
669                                                         break; // error - truncated file
670                                                 if (x + runlen > image_width)
671                                                         break; // error - line exceeds width
672                                                 for (;runlen--;x++)
673                                                 {
674                                                         bgra.b[0] = fin[0];
675                                                         bgra.b[1] = fin[1];
676                                                         bgra.b[2] = fin[2];
677                                                         bgra.b[3] = fin[3];
678                                                         fin += pix_inc;
679                                                         *pixbufi++ = bgra.i;
680                                                 }
681                                         }
682                                 }
683
684                                 if (x != image_width)
685                                 {
686                                         // pixbufi is useless now
687                                         Con_Printf("LoadTGA: corrupt file\n");
688                                         break;
689                                 }
690                         }
691                 }
692                 else
693                 {
694                         for (y = 0;y < image_height;y++, pixbufi += row_inci)
695                         {
696                                 for (x = 0;x < image_width;)
697                                 {
698                                         if (fin >= enddata)
699                                                 break; // error - truncated file
700                                         runlen = *fin++;
701                                         if (runlen & 0x80)
702                                         {
703                                                 // RLE - all pixels the same color
704                                                 runlen += 1 - 0x80;
705                                                 if (fin + pix_inc > enddata)
706                                                         break; // error - truncated file
707                                                 if (x + runlen > image_width)
708                                                         break; // error - line exceeds width
709                                                 bgra.b[0] = fin[0];
710                                                 bgra.b[1] = fin[1];
711                                                 bgra.b[2] = fin[2];
712                                                 bgra.b[3] = 255;
713                                                 fin += pix_inc;
714                                                 for (;runlen--;x++)
715                                                         *pixbufi++ = bgra.i;
716                                         }
717                                         else
718                                         {
719                                                 // uncompressed - all pixels different color
720                                                 runlen++;
721                                                 if (fin + pix_inc * runlen > enddata)
722                                                         break; // error - truncated file
723                                                 if (x + runlen > image_width)
724                                                         break; // error - line exceeds width
725                                                 for (;runlen--;x++)
726                                                 {
727                                                         bgra.b[0] = fin[0];
728                                                         bgra.b[1] = fin[1];
729                                                         bgra.b[2] = fin[2];
730                                                         bgra.b[3] = 255;
731                                                         fin += pix_inc;
732                                                         *pixbufi++ = bgra.i;
733                                                 }
734                                         }
735                                 }
736
737                                 if (x != image_width)
738                                 {
739                                         // pixbufi is useless now
740                                         Con_Printf("LoadTGA: corrupt file\n");
741                                         break;
742                                 }
743                         }
744                 }
745                 break;
746         default:
747                 // unknown image_type
748                 break;
749         }
750
751         return image_buffer;
752 }
753
754 typedef struct q2wal_s
755 {
756         char            name[32];
757         unsigned        width, height;
758         unsigned        offsets[MIPLEVELS];             // four mip maps stored
759         char            animname[32];                   // next frame in animation chain
760         int                     flags;
761         int                     contents;
762         int                     value;
763 } q2wal_t;
764
765 static unsigned char *LoadWAL_BGRA (const unsigned char *f, int filesize, int *miplevel)
766 {
767         unsigned char *image_buffer;
768         const q2wal_t *inwal = (const q2wal_t *)f;
769
770         if (filesize < (int) sizeof(q2wal_t))
771         {
772                 Con_Print("LoadWAL: invalid WAL file\n");
773                 return NULL;
774         }
775
776         image_width = LittleLong(inwal->width);
777         image_height = LittleLong(inwal->height);
778         if (image_width > 32768 || image_height > 32768 || image_width <= 0 || image_height <= 0)
779         {
780                 Con_Printf("LoadWAL: invalid size %ix%i\n", image_width, image_height);
781                 return NULL;
782         }
783
784         if (filesize < (int) LittleLong(inwal->offsets[0]) + image_width * image_height)
785         {
786                 Con_Print("LoadWAL: invalid WAL file\n");
787                 return NULL;
788         }
789
790         image_buffer = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
791         if (!image_buffer)
792         {
793                 Con_Printf("LoadWAL: not enough memory for %i by %i image\n", image_width, image_height);
794                 return NULL;
795         }
796         Image_Copy8bitBGRA(f + LittleLong(inwal->offsets[0]), image_buffer, image_width * image_height, q2palette_bgra_complete);
797         return image_buffer;
798 }
799
800 qboolean LoadWAL_GetMetadata(const unsigned char *f, int filesize, int *retwidth, int *retheight, int *retflags, int *retvalue, int *retcontents, char *retanimname32c)
801 {
802         const q2wal_t *inwal = (const q2wal_t *)f;
803
804         if (filesize < (int) sizeof(q2wal_t))
805         {
806                 Con_Print("LoadWAL: invalid WAL file\n");
807                 if (retwidth)
808                         *retwidth = 16;
809                 if (retheight)
810                         *retheight = 16;
811                 if (retflags)
812                         *retflags = 0;
813                 if (retvalue)
814                         *retvalue = 0;
815                 if (retcontents)
816                         *retcontents = 0;
817                 if (retanimname32c)
818                         memset(retanimname32c, 0, 32);
819                 return false;
820         }
821
822         if (retwidth)
823                 *retwidth = LittleLong(inwal->width);
824         if (retheight)
825                 *retheight = LittleLong(inwal->height);
826         if (retflags)
827                 *retflags = LittleLong(inwal->flags);
828         if (retvalue)
829                 *retvalue = LittleLong(inwal->value);
830         if (retcontents)
831                 *retcontents = LittleLong(inwal->contents);
832         if (retanimname32c)
833         {
834                 memcpy(retanimname32c, inwal->animname, 32);
835                 retanimname32c[31] = 0;
836         }
837         return true;
838 }
839
840 // gfx/* wad lumps and gfx/*.lmp files are simply width and height and paletted pixels, with color 255 as transparent
841 static unsigned char* LoadLMP_BGRA(const unsigned char *f, int filesize, int *miplevel)
842 {
843         unsigned char *image_buffer;
844         int i;
845
846         if (filesize < 9)
847         {
848                 Con_Print("Bad lmp file\n");
849                 return NULL;
850         }
851
852         image_width = f[0] + f[1] * 0x100 + f[2] * 0x10000 + f[3] * 0x1000000;
853         image_height = f[4] + f[5] * 0x100 + f[6] * 0x10000 + f[7] * 0x1000000;
854
855         if (image_width > 32768 || image_height > 32768 || image_width <= 0 || image_height <= 0 || image_width * image_height > filesize - 8)
856         {
857                 Con_Print("Bad lmp file\n");
858                 return NULL;
859         }
860
861         image_buffer = (unsigned char *)Mem_Alloc(tempmempool, image_width*image_height * 4);
862         if (!image_buffer)
863         {
864                 Con_Printf("LoadLMP: not enough memory for %i by %i image\n", image_width, image_height);
865                 return NULL;
866         }
867
868         for (i = 0; i < image_width * image_height; i++)
869         {
870                 const unsigned char *p = (const unsigned char *)palette_bgra_transparent + 4 * f[8 + i];
871                 image_buffer[i * 4 + 0] = p[0];
872                 image_buffer[i * 4 + 1] = p[1];
873                 image_buffer[i * 4 + 2] = p[2];
874                 image_buffer[i * 4 + 3] = p[3];
875         }
876
877         return image_buffer;
878 }
879
880 // gfx/conchars is a raw 128x128 image with 0 as transparent color rather than 255
881 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, qboolean complain, qboolean allowFixtrans, qboolean 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                 f = FS_LoadFile(name, tempmempool, true, &filesize);
1088                 if (f)
1089                 {
1090                         mymiplevel = miplevel ? *miplevel : 0;
1091                         image_width = 0;
1092                         image_height = 0;
1093                         data = format->loadfunc(f, (int)filesize, &mymiplevel);
1094                         Mem_Free(f);
1095                         if (data)
1096                         {
1097                                 if(format->loadfunc == JPEG_LoadImage_BGRA) // jpeg can't do alpha, so let's simulate it by loading another jpeg
1098                                 {
1099                                         dpsnprintf (name2, sizeof(name2), format->formatstring, va(vabuf, sizeof(vabuf), "%s_alpha", basename));
1100                                         f = FS_LoadFile(name2, tempmempool, true, &filesize);
1101                                         if(f)
1102                                         {
1103                                                 int mymiplevel2 = miplevel ? *miplevel : 0;
1104                                                 int image_width_save = image_width;
1105                                                 int image_height_save = image_height;
1106                                                 data2 = format->loadfunc(f, (int)filesize, &mymiplevel2);
1107                                                 if(data2 && mymiplevel == mymiplevel2 && image_width == image_width_save && image_height == image_height_save)
1108                                                         Image_CopyAlphaFromBlueBGRA(data, data2, image_width, image_height);
1109                                                 else
1110                                                         Con_Printf("loadimagepixelsrgba: corrupt or invalid alpha image %s_alpha\n", basename);
1111                                                 image_width = image_width_save;
1112                                                 image_height = image_height_save;
1113                                                 if(data2)
1114                                                         Mem_Free(data2);
1115                                                 Mem_Free(f);
1116                                         }
1117                                 }
1118                                 if (developer_loading.integer)
1119                                         Con_DPrintf("loaded image %s (%dx%d)\n", name, image_width, image_height);
1120                                 if(miplevel)
1121                                         *miplevel = mymiplevel;
1122                                 //if (developer_memorydebug.integer)
1123                                 //      Mem_CheckSentinelsGlobal();
1124                                 if(allowFixtrans && r_fixtrans_auto.integer)
1125                                 {
1126                                         int n = fixtransparentpixels(data, image_width, image_height);
1127                                         if(n)
1128                                         {
1129                                                 Con_Printf("- had to fix %s (%d pixels changed)\n", name, n);
1130                                                 if(r_fixtrans_auto.integer >= 2)
1131                                                 {
1132                                                         char outfilename[MAX_QPATH], buf[MAX_QPATH];
1133                                                         Image_StripImageExtension(name, buf, sizeof(buf));
1134                                                         dpsnprintf(outfilename, sizeof(outfilename), "fixtrans/%s.tga", buf);
1135                                                         Image_WriteTGABGRA(outfilename, image_width, image_height, data);
1136                                                         Con_Printf("- %s written.\n", outfilename);
1137                                                 }
1138                                         }
1139                                 }
1140                                 if (convertsRGB)
1141                                         Image_MakeLinearColorsFromsRGB(data, data, image_width * image_height);
1142                                 return data;
1143                         }
1144                         else
1145                                 Con_DPrintf("Error loading image %s (file loaded but decode failed)\n", name);
1146                 }
1147         }
1148         if (!strcasecmp(path, "gfx"))
1149         {
1150                 unsigned char *lmpdata;
1151                 if ((lmpdata = W_GetLumpName(afterpath, &filesize)))
1152                 {
1153                         if (developer_loading.integer)
1154                                 Con_Printf("loading gfx.wad lump \"%s\"\n", afterpath);
1155
1156                         mymiplevel = miplevel ? *miplevel : 0;
1157                         if (!strcmp(afterpath, "conchars"))
1158                         {
1159                                 // conchars is a raw image and with color 0 as transparent instead of 255
1160                                 data = LoadConChars_BGRA(lmpdata, filesize, &mymiplevel);
1161                         }
1162                         else
1163                                 data = LoadLMP_BGRA(lmpdata, filesize, &mymiplevel);
1164                         // no cleanup after looking up a wad lump - the whole gfx.wad is loaded at once
1165                         if (data)
1166                                 return data;
1167                         Con_DPrintf("Error loading image %s (file loaded but decode failed)\n", name);
1168                 }
1169         }
1170
1171         // check if the image name exists as an embedded pic
1172         if ((data = Image_GetEmbeddedPicBGRA(basename)))
1173                 return data;
1174
1175         if (complain)
1176         {
1177                 Con_Printf("Couldn't load %s using ", filename);
1178                 for (format = firstformat;format->formatstring;format++)
1179                 {
1180                         dpsnprintf (name, sizeof(name), format->formatstring, basename);
1181                         Con_Printf(format == firstformat ? "\"%s\"" : (format[1].formatstring ? ", \"%s\"" : " or \"%s\".\n"), format->formatstring);
1182                 }
1183         }
1184
1185         // texture loading can take a while, so make sure we're sending keepalives
1186         CL_KeepaliveMessage(false);
1187
1188         //if (developer_memorydebug.integer)
1189         //      Mem_CheckSentinelsGlobal();
1190
1191         return NULL;
1192 }
1193
1194 qboolean Image_GetStockPicSize(const char *filename, int *returnwidth, int *returnheight)
1195 {
1196         unsigned char *data;
1197         fs_offset_t filesize;
1198         char lmppath[MAX_QPATH];
1199         if (!strcasecmp(filename, "gfx/conchars"))
1200         {
1201                 *returnwidth = 128;
1202                 *returnheight = 128;
1203                 return true;
1204         }
1205
1206         dpsnprintf(lmppath, sizeof(lmppath), "%s.lmp", filename);
1207         data = FS_LoadFile(lmppath, tempmempool, true, &filesize);
1208         if (data)
1209         {
1210                 if (filesize > 8)
1211                 {
1212                         int w = data[0] + data[1] * 0x100 + data[2] * 0x10000 + data[3] * 0x1000000;
1213                         int h = data[4] + data[5] * 0x100 + data[6] * 0x10000 + data[7] * 0x1000000;
1214                         if (w >= 1 && w <= 32768 && h >= 1 && h <= 32768)
1215                         {
1216                                 *returnwidth = w;
1217                                 *returnheight = h;
1218                                 Mem_Free(data);
1219                                 return true;
1220                         }
1221                 }
1222                 Mem_Free(data);
1223         }
1224         if (!strncasecmp(filename, "gfx/", 4))
1225         {
1226                 data = W_GetLumpName(filename + 4, &filesize);
1227                 if (data && filesize > 8)
1228                 {
1229                         int w = data[0] + data[1] * 0x100 + data[2] * 0x10000 + data[3] * 0x1000000;
1230                         int h = data[4] + data[5] * 0x100 + data[6] * 0x10000 + data[7] * 0x1000000;
1231                         if (w >= 1 && w <= 32768 && h >= 1 && h <= 32768)
1232                         {
1233                                 *returnwidth = w;
1234                                 *returnheight = h;
1235                                 return true;
1236                         }
1237                 }
1238         }
1239         return false;
1240 }
1241
1242 extern cvar_t gl_picmip;
1243 rtexture_t *loadtextureimage (rtexturepool_t *pool, const char *filename, qboolean complain, int flags, qboolean allowFixtrans, qboolean sRGB)
1244 {
1245         unsigned char *data;
1246         rtexture_t *rt;
1247         int miplevel = R_PicmipForFlags(flags);
1248         if (!(data = loadimagepixelsbgra (filename, complain, allowFixtrans, false, &miplevel)))
1249                 return 0;
1250         rt = R_LoadTexture2D(pool, filename, image_width, image_height, data, sRGB ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, flags, miplevel, NULL);
1251         Mem_Free(data);
1252         return rt;
1253 }
1254
1255 int fixtransparentpixels(unsigned char *data, int w, int h)
1256 {
1257         int const FIXTRANS_NEEDED = 1;
1258         int const FIXTRANS_HAS_L = 2;
1259         int const FIXTRANS_HAS_R = 4;
1260         int const FIXTRANS_HAS_U = 8;
1261         int const FIXTRANS_HAS_D = 16;
1262         int const FIXTRANS_FIXED = 32;
1263         unsigned char *fixMask = (unsigned char *) Mem_Alloc(tempmempool, w * h);
1264         int fixPixels = 0;
1265         int changedPixels = 0;
1266         int x, y;
1267
1268 #define FIXTRANS_PIXEL (y*w+x)
1269 #define FIXTRANS_PIXEL_U (((y+h-1)%h)*w+x)
1270 #define FIXTRANS_PIXEL_D (((y+1)%h)*w+x)
1271 #define FIXTRANS_PIXEL_L (y*w+((x+w-1)%w))
1272 #define FIXTRANS_PIXEL_R (y*w+((x+1)%w))
1273
1274         memset(fixMask, 0, w * h);
1275         for(y = 0; y < h; ++y)
1276                 for(x = 0; x < w; ++x)
1277                 {
1278                         if(data[FIXTRANS_PIXEL * 4 + 3] == 0)
1279                         {
1280                                 fixMask[FIXTRANS_PIXEL] |= FIXTRANS_NEEDED;
1281                                 ++fixPixels;
1282                         }
1283                         else
1284                         {
1285                                 fixMask[FIXTRANS_PIXEL_D] |= FIXTRANS_HAS_U;
1286                                 fixMask[FIXTRANS_PIXEL_U] |= FIXTRANS_HAS_D;
1287                                 fixMask[FIXTRANS_PIXEL_R] |= FIXTRANS_HAS_L;
1288                                 fixMask[FIXTRANS_PIXEL_L] |= FIXTRANS_HAS_R;
1289                         }
1290                 }
1291         if(fixPixels == w * h)
1292                 return 0; // sorry, can't do anything about this
1293         while(fixPixels)
1294         {
1295                 for(y = 0; y < h; ++y)
1296                         for(x = 0; x < w; ++x)
1297                                 if(fixMask[FIXTRANS_PIXEL] & FIXTRANS_NEEDED)
1298                                 {
1299                                         unsigned int sumR = 0, sumG = 0, sumB = 0, sumA = 0, sumRA = 0, sumGA = 0, sumBA = 0, cnt = 0;
1300                                         unsigned char r, g, b, a, r0, g0, b0;
1301                                         if(fixMask[FIXTRANS_PIXEL] & FIXTRANS_HAS_U)
1302                                         {
1303                                                 r = data[FIXTRANS_PIXEL_U * 4 + 2];
1304                                                 g = data[FIXTRANS_PIXEL_U * 4 + 1];
1305                                                 b = data[FIXTRANS_PIXEL_U * 4 + 0];
1306                                                 a = data[FIXTRANS_PIXEL_U * 4 + 3];
1307                                                 sumR += r; sumG += g; sumB += b; sumA += a; sumRA += r*a; sumGA += g*a; sumBA += b*a; ++cnt;
1308                                         }
1309                                         if(fixMask[FIXTRANS_PIXEL] & FIXTRANS_HAS_D)
1310                                         {
1311                                                 r = data[FIXTRANS_PIXEL_D * 4 + 2];
1312                                                 g = data[FIXTRANS_PIXEL_D * 4 + 1];
1313                                                 b = data[FIXTRANS_PIXEL_D * 4 + 0];
1314                                                 a = data[FIXTRANS_PIXEL_D * 4 + 3];
1315                                                 sumR += r; sumG += g; sumB += b; sumA += a; sumRA += r*a; sumGA += g*a; sumBA += b*a; ++cnt;
1316                                         }
1317                                         if(fixMask[FIXTRANS_PIXEL] & FIXTRANS_HAS_L)
1318                                         {
1319                                                 r = data[FIXTRANS_PIXEL_L * 4 + 2];
1320                                                 g = data[FIXTRANS_PIXEL_L * 4 + 1];
1321                                                 b = data[FIXTRANS_PIXEL_L * 4 + 0];
1322                                                 a = data[FIXTRANS_PIXEL_L * 4 + 3];
1323                                                 sumR += r; sumG += g; sumB += b; sumA += a; sumRA += r*a; sumGA += g*a; sumBA += b*a; ++cnt;
1324                                         }
1325                                         if(fixMask[FIXTRANS_PIXEL] & FIXTRANS_HAS_R)
1326                                         {
1327                                                 r = data[FIXTRANS_PIXEL_R * 4 + 2];
1328                                                 g = data[FIXTRANS_PIXEL_R * 4 + 1];
1329                                                 b = data[FIXTRANS_PIXEL_R * 4 + 0];
1330                                                 a = data[FIXTRANS_PIXEL_R * 4 + 3];
1331                                                 sumR += r; sumG += g; sumB += b; sumA += a; sumRA += r*a; sumGA += g*a; sumBA += b*a; ++cnt;
1332                                         }
1333                                         if(!cnt)
1334                                                 continue;
1335                                         r0 = data[FIXTRANS_PIXEL * 4 + 2];
1336                                         g0 = data[FIXTRANS_PIXEL * 4 + 1];
1337                                         b0 = data[FIXTRANS_PIXEL * 4 + 0];
1338                                         if(sumA)
1339                                         {
1340                                                 // there is a surrounding non-alpha pixel
1341                                                 r = (sumRA + sumA / 2) / sumA;
1342                                                 g = (sumGA + sumA / 2) / sumA;
1343                                                 b = (sumBA + sumA / 2) / sumA;
1344                                         }
1345                                         else
1346                                         {
1347                                                 // need to use a "regular" average
1348                                                 r = (sumR + cnt / 2) / cnt;
1349                                                 g = (sumG + cnt / 2) / cnt;
1350                                                 b = (sumB + cnt / 2) / cnt;
1351                                         }
1352                                         if(r != r0 || g != g0 || b != b0)
1353                                                 ++changedPixels;
1354                                         data[FIXTRANS_PIXEL * 4 + 2] = r;
1355                                         data[FIXTRANS_PIXEL * 4 + 1] = g;
1356                                         data[FIXTRANS_PIXEL * 4 + 0] = b;
1357                                         fixMask[FIXTRANS_PIXEL] |= FIXTRANS_FIXED;
1358                                 }
1359                 for(y = 0; y < h; ++y)
1360                         for(x = 0; x < w; ++x)
1361                                 if(fixMask[FIXTRANS_PIXEL] & FIXTRANS_FIXED)
1362                                 {
1363                                         fixMask[FIXTRANS_PIXEL] &= ~(FIXTRANS_NEEDED | FIXTRANS_FIXED);
1364                                         fixMask[FIXTRANS_PIXEL_D] |= FIXTRANS_HAS_U;
1365                                         fixMask[FIXTRANS_PIXEL_U] |= FIXTRANS_HAS_D;
1366                                         fixMask[FIXTRANS_PIXEL_R] |= FIXTRANS_HAS_L;
1367                                         fixMask[FIXTRANS_PIXEL_L] |= FIXTRANS_HAS_R;
1368                                         --fixPixels;
1369                                 }
1370         }
1371         return changedPixels;
1372 }
1373
1374 void Image_FixTransparentPixels_f(cmd_state_t *cmd)
1375 {
1376         const char *filename, *filename_pattern;
1377         fssearch_t *search;
1378         int i, n;
1379         char outfilename[MAX_QPATH], buf[MAX_QPATH];
1380         unsigned char *data;
1381         if(Cmd_Argc(cmd) != 2)
1382         {
1383                 Con_Printf("Usage: %s imagefile\n", Cmd_Argv(cmd, 0));
1384                 return;
1385         }
1386         filename_pattern = Cmd_Argv(cmd, 1);
1387         search = FS_Search(filename_pattern, true, true);
1388         if(!search)
1389                 return;
1390         for(i = 0; i < search->numfilenames; ++i)
1391         {
1392                 filename = search->filenames[i];
1393                 Con_Printf("Processing %s... ", filename);
1394                 Image_StripImageExtension(filename, buf, sizeof(buf));
1395                 dpsnprintf(outfilename, sizeof(outfilename), "fixtrans/%s.tga", buf);
1396                 if(!(data = loadimagepixelsbgra(filename, true, false, false, NULL)))
1397                         return;
1398                 if((n = fixtransparentpixels(data, image_width, image_height)))
1399                 {
1400                         Image_WriteTGABGRA(outfilename, image_width, image_height, data);
1401                         Con_Printf("%s written (%d pixels changed).\n", outfilename, n);
1402                 }
1403                 else
1404                         Con_Printf("unchanged.\n");
1405                 Mem_Free(data);
1406         }
1407         FS_FreeSearch(search);
1408 }
1409
1410 qboolean Image_WriteTGABGR_preflipped (const char *filename, int width, int height, const unsigned char *data)
1411 {
1412         qboolean ret;
1413         unsigned char buffer[18];
1414         const void *buffers[2];
1415         fs_offset_t sizes[2];
1416
1417         memset (buffer, 0, 18);
1418         buffer[2] = 2;          // uncompressed type
1419         buffer[12] = (width >> 0) & 0xFF;
1420         buffer[13] = (width >> 8) & 0xFF;
1421         buffer[14] = (height >> 0) & 0xFF;
1422         buffer[15] = (height >> 8) & 0xFF;
1423         buffer[16] = 24;        // pixel size
1424
1425         buffers[0] = buffer;
1426         sizes[0] = 18;
1427         buffers[1] = data;
1428         sizes[1] = width*height*3;
1429         ret = FS_WriteFileInBlocks(filename, buffers, sizes, 2);
1430
1431         return ret;
1432 }
1433
1434 qboolean Image_WriteTGABGRA (const char *filename, int width, int height, const unsigned char *data)
1435 {
1436         int y;
1437         unsigned char *buffer, *out;
1438         const unsigned char *in, *end;
1439         qboolean ret;
1440
1441         buffer = (unsigned char *)Mem_Alloc(tempmempool, width*height*4 + 18);
1442
1443         memset (buffer, 0, 18);
1444         buffer[2] = 2;          // uncompressed type
1445         buffer[12] = (width >> 0) & 0xFF;
1446         buffer[13] = (width >> 8) & 0xFF;
1447         buffer[14] = (height >> 0) & 0xFF;
1448         buffer[15] = (height >> 8) & 0xFF;
1449
1450         for (y = 3;y < width*height*4;y += 4)
1451                 if (data[y] < 255)
1452                         break;
1453
1454         if (y < width*height*4)
1455         {
1456                 // save the alpha channel
1457                 buffer[16] = 32;        // pixel size
1458                 buffer[17] = 8; // 8 bits of alpha
1459
1460                 // flip upside down
1461                 out = buffer + 18;
1462                 for (y = height - 1;y >= 0;y--)
1463                 {
1464                         memcpy(out, data + y * width * 4, width * 4);
1465                         out += width*4;
1466                 }
1467         }
1468         else
1469         {
1470                 // save only the color channels
1471                 buffer[16] = 24;        // pixel size
1472                 buffer[17] = 0; // 8 bits of alpha
1473
1474                 // truncate bgra to bgr and flip upside down
1475                 out = buffer + 18;
1476                 for (y = height - 1;y >= 0;y--)
1477                 {
1478                         in = data + y * width * 4;
1479                         end = in + width * 4;
1480                         for (;in < end;in += 4)
1481                         {
1482                                 *out++ = in[0];
1483                                 *out++ = in[1];
1484                                 *out++ = in[2];
1485                         }
1486                 }
1487         }
1488         ret = FS_WriteFile (filename, buffer, out - buffer);
1489
1490         Mem_Free(buffer);
1491
1492         return ret;
1493 }
1494
1495 static void Image_Resample32LerpLine (const unsigned char *in, unsigned char *out, int inwidth, int outwidth)
1496 {
1497         int             j, xi, oldx = 0, f, fstep, endx, lerp;
1498         fstep = (int) (inwidth*65536.0f/outwidth);
1499         endx = (inwidth-1);
1500         for (j = 0,f = 0;j < outwidth;j++, f += fstep)
1501         {
1502                 xi = f >> 16;
1503                 if (xi != oldx)
1504                 {
1505                         in += (xi - oldx) * 4;
1506                         oldx = xi;
1507                 }
1508                 if (xi < endx)
1509                 {
1510                         lerp = f & 0xFFFF;
1511                         *out++ = (unsigned char) ((((in[4] - in[0]) * lerp) >> 16) + in[0]);
1512                         *out++ = (unsigned char) ((((in[5] - in[1]) * lerp) >> 16) + in[1]);
1513                         *out++ = (unsigned char) ((((in[6] - in[2]) * lerp) >> 16) + in[2]);
1514                         *out++ = (unsigned char) ((((in[7] - in[3]) * lerp) >> 16) + in[3]);
1515                 }
1516                 else // last pixel of the line has no pixel to lerp to
1517                 {
1518                         *out++ = in[0];
1519                         *out++ = in[1];
1520                         *out++ = in[2];
1521                         *out++ = in[3];
1522                 }
1523         }
1524 }
1525
1526 #define LERPBYTE(i) r = resamplerow1[i];out[i] = (unsigned char) ((((resamplerow2[i] - r) * lerp) >> 16) + r)
1527 static void Image_Resample32Lerp(const void *indata, int inwidth, int inheight, void *outdata, int outwidth, int outheight)
1528 {
1529         int i, j, r, yi, oldy, f, fstep, lerp, endy = (inheight-1), inwidth4 = inwidth*4, outwidth4 = outwidth*4;
1530         unsigned char *out;
1531         const unsigned char *inrow;
1532         unsigned char *resamplerow1;
1533         unsigned char *resamplerow2;
1534         out = (unsigned char *)outdata;
1535         fstep = (int) (inheight*65536.0f/outheight);
1536
1537         resamplerow1 = (unsigned char *)Mem_Alloc(tempmempool, outwidth*4*2);
1538         resamplerow2 = resamplerow1 + outwidth*4;
1539
1540         inrow = (const unsigned char *)indata;
1541         oldy = 0;
1542         Image_Resample32LerpLine (inrow, resamplerow1, inwidth, outwidth);
1543         Image_Resample32LerpLine (inrow + inwidth4, resamplerow2, inwidth, outwidth);
1544         for (i = 0, f = 0;i < outheight;i++,f += fstep)
1545         {
1546                 yi = f >> 16;
1547                 if (yi < endy)
1548                 {
1549                         lerp = f & 0xFFFF;
1550                         if (yi != oldy)
1551                         {
1552                                 inrow = (unsigned char *)indata + inwidth4*yi;
1553                                 if (yi == oldy+1)
1554                                         memcpy(resamplerow1, resamplerow2, outwidth4);
1555                                 else
1556                                         Image_Resample32LerpLine (inrow, resamplerow1, inwidth, outwidth);
1557                                 Image_Resample32LerpLine (inrow + inwidth4, resamplerow2, inwidth, outwidth);
1558                                 oldy = yi;
1559                         }
1560                         j = outwidth - 4;
1561                         while(j >= 0)
1562                         {
1563                                 LERPBYTE( 0);
1564                                 LERPBYTE( 1);
1565                                 LERPBYTE( 2);
1566                                 LERPBYTE( 3);
1567                                 LERPBYTE( 4);
1568                                 LERPBYTE( 5);
1569                                 LERPBYTE( 6);
1570                                 LERPBYTE( 7);
1571                                 LERPBYTE( 8);
1572                                 LERPBYTE( 9);
1573                                 LERPBYTE(10);
1574                                 LERPBYTE(11);
1575                                 LERPBYTE(12);
1576                                 LERPBYTE(13);
1577                                 LERPBYTE(14);
1578                                 LERPBYTE(15);
1579                                 out += 16;
1580                                 resamplerow1 += 16;
1581                                 resamplerow2 += 16;
1582                                 j -= 4;
1583                         }
1584                         if (j & 2)
1585                         {
1586                                 LERPBYTE( 0);
1587                                 LERPBYTE( 1);
1588                                 LERPBYTE( 2);
1589                                 LERPBYTE( 3);
1590                                 LERPBYTE( 4);
1591                                 LERPBYTE( 5);
1592                                 LERPBYTE( 6);
1593                                 LERPBYTE( 7);
1594                                 out += 8;
1595                                 resamplerow1 += 8;
1596                                 resamplerow2 += 8;
1597                         }
1598                         if (j & 1)
1599                         {
1600                                 LERPBYTE( 0);
1601                                 LERPBYTE( 1);
1602                                 LERPBYTE( 2);
1603                                 LERPBYTE( 3);
1604                                 out += 4;
1605                                 resamplerow1 += 4;
1606                                 resamplerow2 += 4;
1607                         }
1608                         resamplerow1 -= outwidth4;
1609                         resamplerow2 -= outwidth4;
1610                 }
1611                 else
1612                 {
1613                         if (yi != oldy)
1614                         {
1615                                 inrow = (unsigned char *)indata + inwidth4*yi;
1616                                 if (yi == oldy+1)
1617                                         memcpy(resamplerow1, resamplerow2, outwidth4);
1618                                 else
1619                                         Image_Resample32LerpLine (inrow, resamplerow1, inwidth, outwidth);
1620                                 oldy = yi;
1621                         }
1622                         memcpy(out, resamplerow1, outwidth4);
1623                 }
1624         }
1625
1626         Mem_Free(resamplerow1);
1627         resamplerow1 = NULL;
1628         resamplerow2 = NULL;
1629 }
1630
1631 static void Image_Resample32Nolerp(const void *indata, int inwidth, int inheight, void *outdata, int outwidth, int outheight)
1632 {
1633         int i, j;
1634         unsigned frac, fracstep;
1635         // relies on int being 4 bytes
1636         int *inrow, *out;
1637         out = (int *)outdata;
1638
1639         fracstep = inwidth*0x10000/outwidth;
1640         for (i = 0;i < outheight;i++)
1641         {
1642                 inrow = (int *)indata + inwidth*(i*inheight/outheight);
1643                 frac = fracstep >> 1;
1644                 j = outwidth - 4;
1645                 while (j >= 0)
1646                 {
1647                         out[0] = inrow[frac >> 16];frac += fracstep;
1648                         out[1] = inrow[frac >> 16];frac += fracstep;
1649                         out[2] = inrow[frac >> 16];frac += fracstep;
1650                         out[3] = inrow[frac >> 16];frac += fracstep;
1651                         out += 4;
1652                         j -= 4;
1653                 }
1654                 if (j & 2)
1655                 {
1656                         out[0] = inrow[frac >> 16];frac += fracstep;
1657                         out[1] = inrow[frac >> 16];frac += fracstep;
1658                         out += 2;
1659                 }
1660                 if (j & 1)
1661                 {
1662                         out[0] = inrow[frac >> 16];frac += fracstep;
1663                         out += 1;
1664                 }
1665         }
1666 }
1667
1668 /*
1669 ================
1670 Image_Resample
1671 ================
1672 */
1673 void Image_Resample32(const void *indata, int inwidth, int inheight, int indepth, void *outdata, int outwidth, int outheight, int outdepth, int quality)
1674 {
1675         if (indepth != 1 || outdepth != 1)
1676         {
1677                 Con_Printf ("Image_Resample: 3D resampling not supported\n");
1678                 return;
1679         }
1680         if (quality)
1681                 Image_Resample32Lerp(indata, inwidth, inheight, outdata, outwidth, outheight);
1682         else
1683                 Image_Resample32Nolerp(indata, inwidth, inheight, outdata, outwidth, outheight);
1684 }
1685
1686 // in can be the same as out
1687 void Image_MipReduce32(const unsigned char *in, unsigned char *out, int *width, int *height, int *depth, int destwidth, int destheight, int destdepth)
1688 {
1689         const unsigned char *inrow;
1690         int x, y, nextrow;
1691         if (*depth != 1 || destdepth != 1)
1692         {
1693                 Con_Printf ("Image_Resample: 3D resampling not supported\n");
1694                 if (*width > destwidth)
1695                         *width >>= 1;
1696                 if (*height > destheight)
1697                         *height >>= 1;
1698                 if (*depth > destdepth)
1699                         *depth >>= 1;
1700                 return;
1701         }
1702         // note: if given odd width/height this discards the last row/column of
1703         // pixels, rather than doing a proper box-filter scale down
1704         inrow = in;
1705         nextrow = *width * 4;
1706         if (*width > destwidth)
1707         {
1708                 *width >>= 1;
1709                 if (*height > destheight)
1710                 {
1711                         // reduce both
1712                         *height >>= 1;
1713                         for (y = 0;y < *height;y++, inrow += nextrow * 2)
1714                         {
1715                                 for (in = inrow, x = 0;x < *width;x++)
1716                                 {
1717                                         out[0] = (unsigned char) ((in[0] + in[4] + in[nextrow  ] + in[nextrow+4]) >> 2);
1718                                         out[1] = (unsigned char) ((in[1] + in[5] + in[nextrow+1] + in[nextrow+5]) >> 2);
1719                                         out[2] = (unsigned char) ((in[2] + in[6] + in[nextrow+2] + in[nextrow+6]) >> 2);
1720                                         out[3] = (unsigned char) ((in[3] + in[7] + in[nextrow+3] + in[nextrow+7]) >> 2);
1721                                         out += 4;
1722                                         in += 8;
1723                                 }
1724                         }
1725                 }
1726                 else
1727                 {
1728                         // reduce width
1729                         for (y = 0;y < *height;y++, inrow += nextrow)
1730                         {
1731                                 for (in = inrow, x = 0;x < *width;x++)
1732                                 {
1733                                         out[0] = (unsigned char) ((in[0] + in[4]) >> 1);
1734                                         out[1] = (unsigned char) ((in[1] + in[5]) >> 1);
1735                                         out[2] = (unsigned char) ((in[2] + in[6]) >> 1);
1736                                         out[3] = (unsigned char) ((in[3] + in[7]) >> 1);
1737                                         out += 4;
1738                                         in += 8;
1739                                 }
1740                         }
1741                 }
1742         }
1743         else
1744         {
1745                 if (*height > destheight)
1746                 {
1747                         // reduce height
1748                         *height >>= 1;
1749                         for (y = 0;y < *height;y++, inrow += nextrow * 2)
1750                         {
1751                                 for (in = inrow, x = 0;x < *width;x++)
1752                                 {
1753                                         out[0] = (unsigned char) ((in[0] + in[nextrow  ]) >> 1);
1754                                         out[1] = (unsigned char) ((in[1] + in[nextrow+1]) >> 1);
1755                                         out[2] = (unsigned char) ((in[2] + in[nextrow+2]) >> 1);
1756                                         out[3] = (unsigned char) ((in[3] + in[nextrow+3]) >> 1);
1757                                         out += 4;
1758                                         in += 4;
1759                                 }
1760                         }
1761                 }
1762                 else
1763                         Con_Printf ("Image_MipReduce: desired size already achieved\n");
1764         }
1765 }
1766
1767 void Image_HeightmapToNormalmap_BGRA(const unsigned char *inpixels, unsigned char *outpixels, int width, int height, int clamp, float bumpscale)
1768 {
1769         int x, y, x1, x2, y1, y2;
1770         const unsigned char *b, *row[3];
1771         int p[5];
1772         unsigned char *out;
1773         float ibumpscale, n[3];
1774         ibumpscale = (255.0f * 6.0f) / bumpscale;
1775         out = outpixels;
1776         for (y = 0, y1 = height-1;y < height;y1 = y, y++)
1777         {
1778                 y2 = y + 1;if (y2 >= height) y2 = 0;
1779                 row[0] = inpixels + (y1 * width) * 4;
1780                 row[1] = inpixels + (y  * width) * 4;
1781                 row[2] = inpixels + (y2 * width) * 4;
1782                 for (x = 0, x1 = width-1;x < width;x1 = x, x++)
1783                 {
1784                         x2 = x + 1;if (x2 >= width) x2 = 0;
1785                         // left, right
1786                         b = row[1] + x1 * 4;p[0] = (b[0] + b[1] + b[2]);
1787                         b = row[1] + x2 * 4;p[1] = (b[0] + b[1] + b[2]);
1788                         // above, below
1789                         b = row[0] + x  * 4;p[2] = (b[0] + b[1] + b[2]);
1790                         b = row[2] + x  * 4;p[3] = (b[0] + b[1] + b[2]);
1791                         // center
1792                         b = row[1] + x  * 4;p[4] = (b[0] + b[1] + b[2]);
1793                         // calculate a normal from the slopes
1794                         n[0] = p[0] - p[1];
1795                         n[1] = p[3] - p[2];
1796                         n[2] = ibumpscale;
1797                         VectorNormalize(n);
1798                         // turn it into a dot3 rgb vector texture
1799                         out[2] = (int)(128.0f + n[0] * 127.0f);
1800                         out[1] = (int)(128.0f + n[1] * 127.0f);
1801                         out[0] = (int)(128.0f + n[2] * 127.0f);
1802                         out[3] = (p[4]) / 3;
1803                         out += 4;
1804                 }
1805         }
1806 }
1807
1808 static const unsigned char concharimage[] =
1809 {
1810 #include "lhfont.h"
1811 };
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 }