7534ab4bd28ec00460eb42ea903550ffd49d9fa9
[xonotic/darkplaces.git] / gl_textures.c
1 #include "quakedef.h"
2
3 cvar_t          gl_max_size = {"gl_max_size", "1024"};
4 cvar_t          gl_picmip = {"gl_picmip", "0"};
5 cvar_t          gl_lerpimages = {"gl_lerpimages", "1"};
6
7 int             gl_filter_min = GL_LINEAR_MIPMAP_LINEAR; //NEAREST;
8 int             gl_filter_max = GL_LINEAR;
9
10
11 int             texels;
12
13 // 4096x4096
14 #define MAXMIPS 12
15
16 typedef struct
17 {
18         int             texnum;
19         byte    *texels[MAXMIPS];
20         unsigned short texelsize[MAXMIPS][2];
21         char    identifier[64];
22         short   width, height;
23 // LordHavoc: CRC to identify cache mismatchs
24         unsigned short crc;
25         char    mipmap;
26         char    alpha;
27         char    bytesperpixel;
28         char    lerped; // whether this texture was uploaded with or without interpolation
29 } gltexture_t;
30
31 #define MAX_GLTEXTURES  4096
32 gltexture_t     gltextures[MAX_GLTEXTURES];
33 int                     numgltextures;
34
35 typedef struct
36 {
37         char *name;
38         int     minimize, maximize;
39 } glmode_t;
40
41 glmode_t modes[] = {
42         {"GL_NEAREST", GL_NEAREST, GL_NEAREST},
43         {"GL_LINEAR", GL_LINEAR, GL_LINEAR},
44         {"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST},
45         {"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR},
46         {"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST},
47         {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR}
48 };
49
50 /*
51 ===============
52 Draw_TextureMode_f
53 ===============
54 */
55 void Draw_TextureMode_f (void)
56 {
57         int             i;
58         gltexture_t     *glt;
59
60         if (Cmd_Argc() == 1)
61         {
62                 for (i=0 ; i< 6 ; i++)
63                         if (gl_filter_min == modes[i].minimize)
64                         {
65                                 Con_Printf ("%s\n", modes[i].name);
66                                 return;
67                         }
68                 Con_Printf ("current filter is unknown???\n");
69                 return;
70         }
71
72         for (i=0 ; i< 6 ; i++)
73         {
74                 if (!Q_strcasecmp (modes[i].name, Cmd_Argv(1) ) )
75                         break;
76         }
77         if (i == 6)
78         {
79                 Con_Printf ("bad filter name\n");
80                 return;
81         }
82
83         gl_filter_min = modes[i].minimize;
84         gl_filter_max = modes[i].maximize;
85
86         // change all the existing mipmap texture objects
87         for (i=0, glt=gltextures ; i<numgltextures ; i++, glt++)
88         {
89                 if (glt->mipmap)
90                 {
91                         glBindTexture(GL_TEXTURE_2D, glt->texnum);
92                         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
93                         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
94                 }
95         }
96 }
97
98 extern int buildnumber;
99
100 char engineversion[40];
101
102 void GL_UploadTexture (gltexture_t *glt);
103 void gl_textures_start()
104 {
105         int i;
106         gltexture_t *glt;
107         for (i=0, glt=gltextures ; i<numgltextures ; i++, glt++)
108                 GL_UploadTexture(glt);
109 }
110
111 void gl_textures_shutdown()
112 {
113 }
114
115 void GL_Textures_Init (void)
116 {
117         Cvar_RegisterVariable (&gl_max_size);
118         Cvar_RegisterVariable (&gl_picmip);
119         Cvar_RegisterVariable (&gl_lerpimages);
120
121         // 3dfx can only handle 256 wide textures
122         if (!Q_strncasecmp ((char *)gl_renderer, "3dfx",4) || strstr((char *)gl_renderer, "Glide"))
123                 Cvar_Set ("gl_max_size", "256");
124
125         Cmd_AddCommand ("gl_texturemode", &Draw_TextureMode_f);
126
127         R_RegisterModule("GL_Textures", gl_textures_start, gl_textures_shutdown);
128 }
129
130 /*
131 ================
132 GL_FindTexture
133 ================
134 */
135 int GL_FindTexture (char *identifier)
136 {
137         int             i;
138         gltexture_t     *glt;
139
140         for (i=0, glt=gltextures ; i<numgltextures ; i++, glt++)
141         {
142                 if (!strcmp (identifier, glt->identifier))
143                         return gltextures[i].texnum;
144         }
145
146         return -1;
147 }
148
149 extern byte qgamma[];
150
151 // LordHavoc: gamma correction and improved resampling
152 void GL_ResampleTextureLerpLine (byte *in, byte *out, int inwidth, int outwidth)
153 {
154         int             j, xi, oldx = 0, f, fstep, l1, l2, endx;
155         fstep = (int) (inwidth*65536.0f/outwidth);
156         endx = (inwidth-1);
157         for (j = 0,f = 0;j < outwidth;j++, f += fstep)
158         {
159                 xi = (int) f >> 16;
160                 if (xi != oldx)
161                 {
162                         in += (xi - oldx) * 4;
163                         oldx = xi;
164                 }
165                 if (xi < endx)
166                 {
167                         l2 = f & 0xFFFF;
168                         l1 = 0x10000 - l2;
169                         *out++ = qgamma[(byte) ((in[0] * l1 + in[4] * l2) >> 16)];
170                         *out++ = qgamma[(byte) ((in[1] * l1 + in[5] * l2) >> 16)];
171                         *out++ = qgamma[(byte) ((in[2] * l1 + in[6] * l2) >> 16)];
172                         *out++ =        (byte) ((in[3] * l1 + in[7] * l2) >> 16) ;
173                 }
174                 else // last pixel of the line has no pixel to lerp to
175                 {
176                         *out++ = qgamma[in[0]];
177                         *out++ = qgamma[in[1]];
178                         *out++ = qgamma[in[2]];
179                         *out++ =        in[3] ;
180                 }
181         }
182 }
183
184 /*
185 ================
186 GL_ResampleTexture
187 ================
188 */
189 void GL_ResampleTexture (void *indata, int inwidth, int inheight, void *outdata,  int outwidth, int outheight)
190 {
191         // LordHavoc: gamma correction and greatly improved resampling
192         if (gl_lerpimages.value)
193         {
194                 int             i, j, yi, oldy, f, fstep, l1, l2, endy = (inheight-1);
195                 byte    *inrow, *out, *row1, *row2;
196                 out = outdata;
197                 fstep = (int) (inheight*65536.0f/outheight);
198
199                 row1 = malloc(outwidth*4);
200                 row2 = malloc(outwidth*4);
201                 inrow = indata;
202                 oldy = 0;
203                 GL_ResampleTextureLerpLine (inrow, row1, inwidth, outwidth);
204                 GL_ResampleTextureLerpLine (inrow + inwidth*4, row2, inwidth, outwidth);
205                 for (i = 0, f = 0;i < outheight;i++,f += fstep)
206                 {
207                         yi = f >> 16;
208                         if (yi != oldy)
209                         {
210                                 inrow = (byte *)indata + inwidth*4*yi;
211                                 if (yi == oldy+1)
212                                         memcpy(row1, row2, outwidth*4);
213                                 else
214                                         GL_ResampleTextureLerpLine (inrow, row1, inwidth, outwidth);
215                                 if (yi < endy)
216                                         GL_ResampleTextureLerpLine (inrow + inwidth*4, row2, inwidth, outwidth);
217                                 else
218                                         memcpy(row2, row1, outwidth*4);
219                                 oldy = yi;
220                         }
221                         if (yi < endy)
222                         {
223                                 l2 = f & 0xFFFF;
224                                 l1 = 0x10000 - l2;
225                                 for (j = 0;j < outwidth;j++)
226                                 {
227                                         *out++ = (byte) ((*row1++ * l1 + *row2++ * l2) >> 16);
228                                         *out++ = (byte) ((*row1++ * l1 + *row2++ * l2) >> 16);
229                                         *out++ = (byte) ((*row1++ * l1 + *row2++ * l2) >> 16);
230                                         *out++ = (byte) ((*row1++ * l1 + *row2++ * l2) >> 16);
231                                 }
232                                 row1 -= outwidth*4;
233                                 row2 -= outwidth*4;
234                         }
235                         else // last line has no pixels to lerp to
236                         {
237                                 for (j = 0;j < outwidth;j++)
238                                 {
239                                         *out++ = *row1++;
240                                         *out++ = *row1++;
241                                         *out++ = *row1++;
242                                         *out++ = *row1++;
243                                 }
244                                 row1 -= outwidth*4;
245                         }
246                 }
247                 free(row1);
248                 free(row2);
249         }
250         else
251         {
252                 int             i, j;
253                 unsigned        frac, fracstep;
254                 byte    *inrow, *out, *inpix;
255                 out = outdata;
256
257                 fracstep = inwidth*0x10000/outwidth;
258                 for (i=0 ; i<outheight ; i++)
259                 {
260                         inrow = (byte *)indata + inwidth*(i*inheight/outheight)*4;
261                         frac = fracstep >> 1;
262                         for (j=0 ; j<outwidth ; j+=4)
263                         {
264                                 inpix = inrow + ((frac >> 14) & ~3);*out++ = qgamma[*inpix++];*out++ = qgamma[*inpix++];*out++ = qgamma[*inpix++];*out++ =       *inpix++ ;frac += fracstep;
265                                 inpix = inrow + ((frac >> 14) & ~3);*out++ = qgamma[*inpix++];*out++ = qgamma[*inpix++];*out++ = qgamma[*inpix++];*out++ =       *inpix++ ;frac += fracstep;
266                                 inpix = inrow + ((frac >> 14) & ~3);*out++ = qgamma[*inpix++];*out++ = qgamma[*inpix++];*out++ = qgamma[*inpix++];*out++ =       *inpix++ ;frac += fracstep;
267                                 inpix = inrow + ((frac >> 14) & ~3);*out++ = qgamma[*inpix++];*out++ = qgamma[*inpix++];*out++ = qgamma[*inpix++];*out++ =       *inpix++ ;frac += fracstep;
268                         }
269                 }
270         }
271 }
272
273 /*
274 ================
275 GL_Resample8BitTexture -- JACK
276 ================
277 */
278 /*
279 void GL_Resample8BitTexture (unsigned char *in, int inwidth, int inheight, unsigned char *out,  int outwidth, int outheight)
280 {
281         int             i, j;
282         unsigned        char *inrow;
283         unsigned        frac, fracstep;
284
285         fracstep = inwidth*0x10000/outwidth;
286         for (i=0 ; i<outheight ; i++, out += outwidth)
287         {
288                 inrow = in + inwidth*(i*inheight/outheight);
289                 frac = fracstep >> 1;
290                 for (j=0 ; j<outwidth ; j+=4)
291                 {
292                         out[j  ] = inrow[frac>>16];frac += fracstep;
293                         out[j+1] = inrow[frac>>16];frac += fracstep;
294                         out[j+2] = inrow[frac>>16];frac += fracstep;
295                         out[j+3] = inrow[frac>>16];frac += fracstep;
296                 }
297         }
298 }
299 */
300
301
302 /*
303 ================
304 GL_MipMap
305
306 Operates in place, quartering the size of the texture
307 ================
308 */
309 /*
310 void GL_MipMap (byte *in, int width, int height)
311 {
312         int             i, j;
313         byte    *out;
314
315         width <<=2;
316         height >>= 1;
317         out = in;
318         for (i=0 ; i<height ; i++, in+=width)
319         {
320                 for (j=0 ; j<width ; j+=8, out+=4, in+=8)
321                 {
322                         out[0] = (in[0] + in[4] + in[width+0] + in[width+4])>>2;
323                         out[1] = (in[1] + in[5] + in[width+1] + in[width+5])>>2;
324                         out[2] = (in[2] + in[6] + in[width+2] + in[width+6])>>2;
325                         out[3] = (in[3] + in[7] + in[width+3] + in[width+7])>>2;
326                 }
327         }
328 }
329 */
330
331 /*
332 ================
333 GL_MipMap8Bit
334
335 Mipping for 8 bit textures
336 ================
337 */
338 /*
339 void GL_MipMap8Bit (byte *in, int width, int height)
340 {
341         int             i, j;
342         unsigned short     r,g,b;
343         byte    *out, *at1, *at2, *at3, *at4;
344
345         height >>= 1;
346         out = in;
347         for (i=0 ; i<height ; i++, in+=width)
348         {
349                 for (j=0 ; j<width ; j+=2, out+=1, in+=2)
350                 {
351                         at1 = (byte *) (d_8to24table + in[0]);
352                         at2 = (byte *) (d_8to24table + in[1]);
353                         at3 = (byte *) (d_8to24table + in[width+0]);
354                         at4 = (byte *) (d_8to24table + in[width+1]);
355
356                         r = (at1[0]+at2[0]+at3[0]+at4[0]); r>>=5;
357                         g = (at1[1]+at2[1]+at3[1]+at4[1]); g>>=5;
358                         b = (at1[2]+at2[2]+at3[2]+at4[2]); b>>=5;
359
360                         out[0] = d_15to8table[(r<<0) + (g<<5) + (b<<10)];
361                 }
362         }
363 }
364 */
365
366 /*
367 ===============
368 GL_Upload32
369 ===============
370 */
371 /*
372 void GL_Upload32 (void *data, int width, int height,  qboolean mipmap, qboolean alpha)
373 {
374         int samples, scaled_width, scaled_height, i;
375         byte *in, *out, *scaled;
376
377         for (scaled_width = 1 ; scaled_width < width ; scaled_width<<=1)
378                 ;
379         for (scaled_height = 1 ; scaled_height < height ; scaled_height<<=1)
380                 ;
381
382         scaled_width >>= (int)gl_picmip.value;
383         scaled_height >>= (int)gl_picmip.value;
384
385         if (scaled_width > gl_max_size.value)
386                 scaled_width = gl_max_size.value;
387         if (scaled_height > gl_max_size.value)
388                 scaled_height = gl_max_size.value;
389
390         if (alpha)
391         {
392                 alpha = false;
393                 in = data;
394                 for (i = 3;i < width*height*4;i += 4)
395                         if (in[i] != 255)
396                         {
397                                 alpha = true;
398                                 break;
399                         }
400         }
401
402         samples = alpha ? gl_alpha_format : gl_solid_format;
403
404         texels += scaled_width * scaled_height;
405
406         scaled = malloc(scaled_width*scaled_height*4);
407         if (scaled_width == width && scaled_height == height)
408         {
409                 // LordHavoc: gamma correct while copying
410                 in = (byte *)data;
411                 out = (byte *)scaled;
412                 for (i = 0;i < width*height;i++)
413                 {
414                         *out++ = qgamma[*in++];
415                         *out++ = qgamma[*in++];
416                         *out++ = qgamma[*in++];
417                         *out++ = *in++;
418                 }
419         }
420         else
421                 GL_ResampleTexture (data, width, height, scaled, scaled_width, scaled_height);
422
423         glTexImage2D (GL_TEXTURE_2D, 0, samples, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaled);
424         if (mipmap)
425         {
426                 int             miplevel;
427
428                 miplevel = 0;
429                 while (scaled_width > 1 || scaled_height > 1)
430                 {
431                         GL_MipMap ((byte *)scaled, scaled_width, scaled_height);
432                         scaled_width >>= 1;
433                         scaled_height >>= 1;
434                         if (scaled_width < 1)
435                                 scaled_width = 1;
436                         if (scaled_height < 1)
437                                 scaled_height = 1;
438                         miplevel++;
439                         glTexImage2D (GL_TEXTURE_2D, miplevel, samples, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaled);
440                 }
441         }
442
443         if (mipmap)
444         {
445                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
446                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
447         }
448         else
449         {
450                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_max);
451                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
452         }
453         free(scaled);
454 }
455
456 void GL_Upload8_EXT (byte *data, int width, int height,  qboolean mipmap)
457 {
458         int             scaled_width, scaled_height;
459         byte    *scaled = NULL;
460
461         for (scaled_width = 1 ; scaled_width < width ; scaled_width<<=1)
462                 ;
463         for (scaled_height = 1 ; scaled_height < height ; scaled_height<<=1)
464                 ;
465
466         scaled_width >>= (int)gl_picmip.value;
467         scaled_height >>= (int)gl_picmip.value;
468
469         if (scaled_width > gl_max_size.value)
470                 scaled_width = gl_max_size.value;
471         if (scaled_height > gl_max_size.value)
472                 scaled_height = gl_max_size.value;
473
474         texels += scaled_width * scaled_height;
475
476         if (scaled_width == width && scaled_height == height)
477         {
478                 if (!mipmap)
479                 {
480                         glTexImage2D (GL_TEXTURE_2D, 0, GL_COLOR_INDEX8_EXT, scaled_width, scaled_height, 0, GL_COLOR_INDEX , GL_UNSIGNED_BYTE, data);
481                         goto done;
482                 }
483                 scaled = malloc(scaled_width*scaled_height*4);
484                 memcpy (scaled, data, width*height);
485         }
486         else
487         {
488                 scaled = malloc(scaled_width*scaled_height*4);
489                 GL_Resample8BitTexture (data, width, height, (void*) scaled, scaled_width, scaled_height);
490         }
491
492         glTexImage2D (GL_TEXTURE_2D, 0, GL_COLOR_INDEX8_EXT, scaled_width, scaled_height, 0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, scaled);
493         if (mipmap)
494         {
495                 int             miplevel;
496
497                 miplevel = 0;
498                 while (scaled_width > 1 || scaled_height > 1)
499                 {
500                         GL_MipMap8Bit ((byte *)scaled, scaled_width, scaled_height);
501                         scaled_width >>= 1;
502                         scaled_height >>= 1;
503                         if (scaled_width < 1)
504                                 scaled_width = 1;
505                         if (scaled_height < 1)
506                                 scaled_height = 1;
507                         miplevel++;
508                         glTexImage2D (GL_TEXTURE_2D, miplevel, GL_COLOR_INDEX8_EXT, scaled_width, scaled_height, 0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, scaled);
509                 }
510         }
511 done: ;
512
513
514         if (mipmap)
515         {
516                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
517                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
518         }
519         else
520         {
521                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_max);
522                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
523         }
524         free(scaled);
525 }
526 */
527
528 extern qboolean VID_Is8bit();
529
530 /*
531 ===============
532 GL_Upload8
533 ===============
534 */
535 /*
536 void GL_Upload8 (byte *data, int width, int height,  qboolean mipmap, qboolean alpha)
537 {
538         static  unsigned *trans;
539         int                     i, s;
540         qboolean        noalpha;
541         int                     p;
542         byte    *indata;
543         int             *outdata;
544
545         s = width*height;
546         trans = malloc(s*4);
547         // if there are no transparent pixels, make it a 3 component
548         // texture even if it was specified as otherwise
549         if (alpha)
550         {
551                 noalpha = true;
552                 for (i=0 ; i<s ; i++)
553                 {
554                         p = data[i];
555                         if (p != 255)
556                                 trans[i] = d_8to24table[p];
557                         else
558                         {
559                                 trans[i] = 0; // force to black
560                                 noalpha = false;
561                         }
562                 }
563
564                 if (noalpha)
565                 {
566                         if (VID_Is8bit() && (data!=scrap_texels[0]))
567                         {
568                                 GL_Upload8_EXT (data, width, height, mipmap);
569                                 free(trans);
570                                 return;
571                         }
572                         alpha = false;
573                 }
574         }
575         else
576         {
577                 // LordHavoc: dodge the copy if it will be uploaded as 8bit
578                 if (VID_Is8bit() && (data!=scrap_texels[0]))
579                 {
580                         GL_Upload8_EXT (data, width, height, mipmap);
581                         free(trans);
582                         return;
583                 }
584                 //if (s&3)
585                 //      Sys_Error ("GL_Upload8: s&3");
586                 indata = data;
587                 outdata = trans;
588                 if (s&1)
589                         *outdata++ = d_8to24table[*indata++];
590                 if (s&2)
591                 {
592                         *outdata++ = d_8to24table[*indata++];
593                         *outdata++ = d_8to24table[*indata++];
594                 }
595                 for (i = 0;i < s;i+=4)
596                 {
597                         *outdata++ = d_8to24table[*indata++];
598                         *outdata++ = d_8to24table[*indata++];
599                         *outdata++ = d_8to24table[*indata++];
600                         *outdata++ = d_8to24table[*indata++];
601                 }
602         }
603
604         GL_Upload32 (trans, width, height, mipmap, alpha);
605         free(trans);
606 }
607 */
608
609 void GL_AllocTexels(gltexture_t *glt, int width, int height, int mipmapped)
610 {
611         int i, w, h, size, done;
612         if (glt->texels[0])
613                 free(glt->texels[0]);
614         glt->texelsize[0][0] = width;
615         glt->texelsize[0][1] = height;
616         if (mipmapped)
617         {
618                 size = 0;
619                 w = width;h = height;
620                 i = 0;
621                 done = false;
622                 for (i = 0;i < MAXMIPS;i++)
623                 {
624                         glt->texelsize[i][0] = w;
625                         glt->texelsize[i][1] = h;
626                         glt->texels[i] = (void *)size;
627                         size += w*h*4;
628                         if (w > 1)
629                         {
630                                 w >>= 1;
631                                 if (h > 1)
632                                         h >>= 1;
633                         }
634                         else if (h > 1)
635                                 h >>= 1;
636                         else
637                         {
638                                 i++;
639                                 break;
640                         }
641                 }
642                 while (i < MAXMIPS)
643                         glt->texels[i++] = NULL;
644                 glt->texels[0] = malloc(size);
645                 for (i = 1;i < MAXMIPS && glt->texels[i];i++)
646                         glt->texels[i] += (int) glt->texels[0];
647         }
648         else
649         {
650                 glt->texels[0] = malloc(width*height*4);
651                 for (i = 1;i < MAXMIPS;i++)
652                         glt->texels[i] = NULL;
653         }
654         if (!glt->texels[0])
655                 Sys_Error("GL_AllocTexels: out of memory\n");
656 }
657
658 // in can be the same as out
659 void GL_MipReduce(byte *in, byte *out, int width, int height, int destwidth, int destheight)
660 {
661         int x, y, width2, height2, nextrow;
662         if (width > destwidth)
663         {
664                 if (height > destheight)
665                 {
666                         // reduce both
667                         width2 = width >> 1;
668                         height2 = height >> 1;
669                         nextrow = width << 2;
670                         for (y = 0;y < height2;y++)
671                         {
672                                 for (x = 0;x < width2;x++)
673                                 {
674                                         out[0] = (byte) ((in[0] + in[4] + in[nextrow  ] + in[nextrow+4]) >> 2);
675                                         out[1] = (byte) ((in[1] + in[5] + in[nextrow+1] + in[nextrow+5]) >> 2);
676                                         out[2] = (byte) ((in[2] + in[6] + in[nextrow+2] + in[nextrow+6]) >> 2);
677                                         out[3] = (byte) ((in[3] + in[7] + in[nextrow+3] + in[nextrow+7]) >> 2);
678                                         out += 4;
679                                         in += 8;
680                                 }
681                                 in += nextrow; // skip a line
682                         }
683                 }
684                 else
685                 {
686                         // reduce width
687                         width2 = width >> 1;
688                         for (y = 0;y < height;y++)
689                         {
690                                 for (x = 0;x < width2;x++)
691                                 {
692                                         out[0] = (byte) ((in[0] + in[4]) >> 1);
693                                         out[1] = (byte) ((in[1] + in[5]) >> 1);
694                                         out[2] = (byte) ((in[2] + in[6]) >> 1);
695                                         out[3] = (byte) ((in[3] + in[7]) >> 1);
696                                         out += 4;
697                                         in += 8;
698                                 }
699                         }
700                 }
701         }
702         else
703         {
704                 if (height > destheight)
705                 {
706                         // reduce height
707                         height2 = height >> 1;
708                         nextrow = width << 2;
709                         for (y = 0;y < height2;y++)
710                         {
711                                 for (x = 0;x < width;x++)
712                                 {
713                                         out[0] = (byte) ((in[0] + in[nextrow  ]) >> 1);
714                                         out[1] = (byte) ((in[1] + in[nextrow+1]) >> 1);
715                                         out[2] = (byte) ((in[2] + in[nextrow+2]) >> 1);
716                                         out[3] = (byte) ((in[3] + in[nextrow+3]) >> 1);
717                                         out += 4;
718                                         in += 4;
719                                 }
720                                 in += nextrow; // skip a line
721                         }
722                 }
723                 else
724                         Sys_Error("GL_MipReduce: desired size already achieved\n");
725         }
726 }
727
728 void GL_UploadTexture (gltexture_t *glt)
729 {
730         int mip, width, height;
731         glBindTexture(GL_TEXTURE_2D, glt->texnum);
732         width = glt->width;
733         height = glt->height;
734         for (mip = 0;mip < MAXMIPS && glt->texels[mip];mip++)
735                 glTexImage2D(GL_TEXTURE_2D, mip, glt->alpha ? 4 : 3, glt->texelsize[mip][0], glt->texelsize[mip][1], 0, GL_RGBA, GL_UNSIGNED_BYTE, glt->texels[mip]);
736         if (glt->mipmap)
737         {
738                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
739                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
740         }
741         else
742         {
743                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_max);
744                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
745         }
746         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
747 }
748
749 /*
750 ================
751 GL_LoadTexture
752 ================
753 */
754 int GL_LoadTexture (char *identifier, int width, int height, byte *data, qboolean mipmap, qboolean alpha, int bytesperpixel)
755 {
756         unsigned short  crc;
757         int                             i, width2, height2, width3, height3, w, h, mip;
758         gltexture_t             *glt;
759
760         if (isDedicated)
761                 return 1;
762
763         // LordHavoc: do a CRC to confirm the data really is the same as previous occurances.
764         crc = CRC_Block(data, width*height*bytesperpixel);
765         // see if the texture is already present
766         if (identifier[0])
767         {
768                 for (i=0, glt=gltextures ; i<numgltextures ; i++, glt++)
769                 {
770                         if (!strcmp (identifier, glt->identifier))
771                         {
772                                 // LordHavoc: everyone hates cache mismatchs, so I fixed it
773                                 if (crc != glt->crc || width != glt->width || height != glt->height)
774                                 {
775                                         Con_DPrintf("GL_LoadTexture: cache mismatch, replacing old texture\n");
776                                         goto GL_LoadTexture_setup; // drop out with glt pointing to the texture to replace
777                                         //Sys_Error ("GL_LoadTexture: cache mismatch");
778                                 }
779                                 if ((gl_lerpimages.value != 0) != glt->lerped)
780                                         goto GL_LoadTexture_setup; // drop out with glt pointing to the texture to replace
781                                 return glt->texnum;
782                         }
783                 }
784         }
785         // LordHavoc: although this could be an else condition as it was in the original id code,
786         //            it is more clear this way
787         // LordHavoc: check if there are still slots available
788         if (numgltextures >= MAX_GLTEXTURES)
789                 Sys_Error ("GL_LoadTexture: ran out of texture slots (%d)\n", MAX_GLTEXTURES);
790         glt = &gltextures[numgltextures++];
791
792         strcpy (glt->identifier, identifier);
793         glt->texnum = texture_extension_number;
794         texture_extension_number++;
795 // LordHavoc: label to drop out of the loop into the setup code
796 GL_LoadTexture_setup:
797         // calculate power of 2 size
798         width2 = 1;while (width2 < width) width2 <<= 1;
799         height2 = 1;while (height2 < height) height2 <<= 1;
800         // calculate final size (mipmapped downward to this)
801         width3 = width2 >> (int) gl_picmip.value;
802         height3 = height2 >> (int) gl_picmip.value;
803         while (width3 > (int) gl_max_size.value) width3 >>= 1;
804         while (height3 > (int) gl_max_size.value) height3 >>= 1;
805         if (width3 < 1) width3 = 1;
806         if (height3 < 1) height3 = 1;
807
808         // final storage
809         GL_AllocTexels(glt, width3, height3, mipmap);
810         glt->crc = crc; // LordHavoc: used to verify textures are identical
811         glt->width = width;
812         glt->height = height;
813         glt->mipmap = mipmap;
814         glt->bytesperpixel = bytesperpixel;
815         glt->lerped = gl_lerpimages.value != 0;
816         glt->alpha = false; // updated later
817         if (width == width3 && height == height3) // perfect match
818         {
819                 if (bytesperpixel == 1) // 8bit
820                         Image_Copy8bitRGBA(data, glt->texels[0], width*height, d_8to24table);
821                 else
822                         Image_CopyRGBAGamma(data, glt->texels[0], width*height);
823         }
824         else if (width == width2 && height == height2) // perfect match for top level, but needs to be reduced
825         {
826                 byte *temptexels2;
827                 temptexels2 = malloc(width2*height2*4); // scaleup buffer
828                 if (bytesperpixel == 1) // 8bit
829                         Image_Copy8bitRGBA(data, temptexels2, width*height, d_8to24table);
830                 else
831                         Image_CopyRGBAGamma(data, temptexels2, width*height);
832                 while (width2 > width3 || height2 > height3)
833                 {
834                         w = width2;h = height2;
835                         if (width2 > width3) width2 >>= 1;
836                         if (height2 > height3) height2 >>= 1;
837                         if (width2 <= width3 && height2 <= height3) // size achieved
838                                 GL_MipReduce(temptexels2, glt->texels[0], w, h, width3, height3);
839                         else
840                                 GL_MipReduce(temptexels2, temptexels2, w, h, width3, height3);
841                 }
842                 free(temptexels2);
843         }
844         else // scaling...
845         {
846                 byte *temptexels;
847                 // pre-scaleup buffer
848                 temptexels = malloc(width*height*4);
849                 if (bytesperpixel == 1) // 8bit
850                         Image_Copy8bitRGBA(data, temptexels, width*height, d_8to24table);
851                 else
852                         Image_CopyRGBAGamma(data, temptexels, width*height);
853                 if (width2 != width3 || height2 != height3) // reduced by gl_pic_mip or gl_max_size
854                 {
855                         byte *temptexels2;
856                         temptexels2 = malloc(width2*height2*4); // scaleup buffer
857                         GL_ResampleTexture(temptexels, width, height, temptexels2, width2, height2);
858                         while (width2 > width3 || height2 > height3)
859                         {
860                                 w = width2;h = height2;
861                                 if (width2 > width3) width2 >>= 1;
862                                 if (height2 > height3) height2 >>= 1;
863                                 if (width2 <= width3 && height2 <= height3) // size achieved
864                                         GL_MipReduce(temptexels2, glt->texels[0], w, h, width3, height3);
865                                 else
866                                         GL_MipReduce(temptexels2, temptexels2, w, h, width3, height3);
867                         }
868                         free(temptexels2);
869                 }
870                 else // copy directly
871                         GL_ResampleTexture(temptexels, width, height, glt->texels[0], width2, height2);
872                 free(temptexels);
873         }
874         if (alpha)
875         {
876                 byte    *in = glt->texels[0] + 3;
877                 for (i = 0;i < width*height;i++, in += 4)
878                         if (*in < 255)
879                         {
880                                 glt->alpha = true;
881                                 break;
882                         }
883         }
884         // this loop is skipped if there are no mipmaps to generate
885         for (mip = 1;mip < MAXMIPS && glt->texels[mip];mip++)
886                 GL_MipReduce(glt->texels[mip-1], glt->texels[mip], glt->texelsize[mip-1][0], glt->texelsize[mip-1][1], 1, 1);
887         GL_UploadTexture(glt);
888
889 //      if (bytesperpixel == 1) // 8bit
890 //              GL_Upload8 (data, width, height, mipmap, alpha);
891 //      else // 32bit
892 //              GL_Upload32 (data, width, height, mipmap, true);
893
894         return glt->texnum;
895 }
896
897 /*
898 ================
899 GL_LoadPicTexture
900 ================
901 */
902 int GL_LoadPicTexture (qpic_t *pic)
903 {
904         return GL_LoadTexture ("", pic->width, pic->height, pic->data, false, true, 1);
905 }
906
907 int GL_GetTextureSlots (int count)
908 {
909         gltexture_t             *glt, *first;
910
911         first = glt = &gltextures[numgltextures];
912         while (count--)
913         {
914                 glt->identifier[0] = 0;
915                 glt->texnum = texture_extension_number++;
916                 glt->crc = 0;
917                 glt->width = 0;
918                 glt->height = 0;
919                 glt->bytesperpixel = 0;
920                 glt++;
921                 numgltextures++;
922         }
923         return first->texnum;
924 }