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