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