]> icculus.org git repositories - divverent/darkplaces.git/blob - gl_draw.c
from newtree. at worst will need a header tweek
[divverent/darkplaces.git] / gl_draw.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20
21 // draw.c -- this is the only file outside the refresh that touches the
22 // vid buffer
23
24 #include "quakedef.h"
25
26 #define GL_COLOR_INDEX8_EXT     0x80E5
27
28 extern unsigned char d_15to8table[65536];
29
30 cvar_t          qsg_version = {"qsg_version", "1"};
31 cvar_t          gl_max_size = {"gl_max_size", "1024"};
32 cvar_t          gl_picmip = {"gl_picmip", "0"};
33 cvar_t          gl_conalpha = {"gl_conalpha", "1"};
34 cvar_t          gl_lerpimages = {"gl_lerpimages", "1"};
35
36 byte            *draw_chars;                            // 8*8 graphic characters
37 qpic_t          *draw_disc;
38
39 int                     translate_texture;
40 int                     char_texture;
41
42 typedef struct
43 {
44         int             texnum;
45         float   sl, tl, sh, th;
46 } glpic_t;
47
48 byte            conback_buffer[sizeof(qpic_t) + sizeof(glpic_t)];
49 qpic_t          *conback = (qpic_t *)&conback_buffer;
50
51 int             gl_filter_min = GL_LINEAR_MIPMAP_LINEAR; //NEAREST;
52 int             gl_filter_max = GL_LINEAR;
53
54
55 int             texels;
56
57 typedef struct
58 {
59         int             texnum;
60         char    identifier[64];
61         int             width, height;
62         qboolean        mipmap;
63 // LordHavoc: 32bit textures
64         int             bytesperpixel;
65 // LordHavoc: CRC to identify cache mismatchs
66         int             crc;
67         int             lerped; // whether this texture was uploaded with or without interpolation
68 } gltexture_t;
69
70 #define MAX_GLTEXTURES  4096
71 gltexture_t     gltextures[MAX_GLTEXTURES];
72 int                     numgltextures;
73
74 /*
75 =============================================================================
76
77   scrap allocation
78
79   Allocate all the little status bar obejcts into a single texture
80   to crutch up stupid hardware / drivers
81
82 =============================================================================
83 */
84
85 #define MAX_SCRAPS              2
86 #define BLOCK_WIDTH             256
87 #define BLOCK_HEIGHT    256
88
89 int                     scrap_allocated[MAX_SCRAPS][BLOCK_WIDTH];
90 byte            scrap_texels[MAX_SCRAPS][BLOCK_WIDTH*BLOCK_HEIGHT*4];
91 qboolean        scrap_dirty;
92 int                     scrap_texnum;
93
94 // returns a texture number and the position inside it
95 int Scrap_AllocBlock (int w, int h, int *x, int *y)
96 {
97         int             i, j;
98         int             best, best2;
99         int             texnum;
100
101         for (texnum=0 ; texnum<MAX_SCRAPS ; texnum++)
102         {
103                 best = BLOCK_HEIGHT;
104
105                 for (i=0 ; i<BLOCK_WIDTH-w ; i++)
106                 {
107                         best2 = 0;
108
109                         for (j=0 ; j<w ; j++)
110                         {
111                                 if (scrap_allocated[texnum][i+j] >= best)
112                                         break;
113                                 if (scrap_allocated[texnum][i+j] > best2)
114                                         best2 = scrap_allocated[texnum][i+j];
115                         }
116                         if (j == w)
117                         {       // this is a valid spot
118                                 *x = i;
119                                 *y = best = best2;
120                         }
121                 }
122
123                 if (best + h > BLOCK_HEIGHT)
124                         continue;
125
126                 for (i=0 ; i<w ; i++)
127                         scrap_allocated[texnum][*x + i] = best + h;
128
129                 return texnum;
130         }
131
132         Sys_Error ("Scrap_AllocBlock: full");
133         return 0;
134 }
135
136 int     scrap_uploads;
137
138 void Scrap_Upload (void)
139 {
140         int             texnum;
141
142         scrap_uploads++;
143
144         for (texnum=0 ; texnum<MAX_SCRAPS ; texnum++)
145         {
146                 glBindTexture(GL_TEXTURE_2D, scrap_texnum + texnum);
147                 GL_Upload8 (scrap_texels[texnum], BLOCK_WIDTH, BLOCK_HEIGHT, false, true);
148         }
149         scrap_dirty = false;
150 }
151
152 //=============================================================================
153 /* Support Routines */
154
155 typedef struct cachepic_s
156 {
157         char            name[MAX_QPATH];
158         qpic_t          pic;
159         byte            padding[32];    // for appended glpic
160 } cachepic_t;
161
162 #define MAX_CACHED_PICS         128
163 cachepic_t      menu_cachepics[MAX_CACHED_PICS];
164 int                     menu_numcachepics;
165
166 byte            menuplyr_pixels[4096];
167
168 int             pic_texels;
169 int             pic_count;
170
171 int GL_LoadPicTexture (qpic_t *pic);
172
173 qpic_t *Draw_PicFromWad (char *name)
174 {
175         qpic_t  *p;
176         glpic_t *gl;
177
178         p = W_GetLumpName (name);
179         gl = (glpic_t *)p->data;
180
181         // load little ones into the scrap
182         if (p->width < 64 && p->height < 64)
183         {
184                 int             x, y;
185                 int             i, j, k;
186                 int             texnum;
187
188                 texnum = Scrap_AllocBlock (p->width, p->height, &x, &y);
189                 scrap_dirty = true;
190                 k = 0;
191                 for (i=0 ; i<p->height ; i++)
192                         for (j=0 ; j<p->width ; j++, k++)
193                                 scrap_texels[texnum][(y+i)*BLOCK_WIDTH + x + j] = p->data[k];
194                 texnum += scrap_texnum;
195                 gl->texnum = texnum;
196                 gl->sl = (x+0.01)/(float)BLOCK_WIDTH;
197                 gl->sh = (x+p->width-0.01)/(float)BLOCK_WIDTH;
198                 gl->tl = (y+0.01)/(float)BLOCK_WIDTH;
199                 gl->th = (y+p->height-0.01)/(float)BLOCK_WIDTH;
200
201                 pic_count++;
202                 pic_texels += p->width*p->height;
203                 // LordHavoc: LINEAR interpolation
204                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
205                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
206         }
207         else
208         {
209                 gl->texnum = GL_LoadPicTexture (p);
210                 gl->sl = 0;
211                 gl->sh = 1;
212                 gl->tl = 0;
213                 gl->th = 1;
214                 // LordHavoc: LINEAR interpolation
215                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); //NEAREST);
216                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); //NEAREST);
217         }
218         return p;
219 }
220
221
222 /*
223 ================
224 Draw_CachePic
225 ================
226 */
227 qpic_t  *Draw_CachePic (char *path)
228 {
229         cachepic_t      *pic;
230         int                     i;
231         qpic_t          *dat;
232         glpic_t         *gl;
233
234         for (pic=menu_cachepics, i=0 ; i<menu_numcachepics ; pic++, i++)
235                 if (!strcmp (path, pic->name))
236                         return &pic->pic;
237
238         if (menu_numcachepics == MAX_CACHED_PICS)
239                 Sys_Error ("menu_numcachepics == MAX_CACHED_PICS");
240         menu_numcachepics++;
241         strcpy (pic->name, path);
242
243 //
244 // load the pic from disk
245 //
246         dat = (qpic_t *)COM_LoadTempFile (path, false);
247         if (!dat)
248                 Sys_Error ("Draw_CachePic: failed to load %s", path);
249         SwapPic (dat);
250
251         // HACK HACK HACK --- we need to keep the bytes for
252         // the translatable player picture just for the menu
253         // configuration dialog
254         if (!strcmp (path, "gfx/menuplyr.lmp"))
255                 memcpy (menuplyr_pixels, dat->data, dat->width*dat->height);
256
257         pic->pic.width = dat->width;
258         pic->pic.height = dat->height;
259
260         gl = (glpic_t *)pic->pic.data;
261         gl->texnum = GL_LoadPicTexture (dat);
262         gl->sl = 0;
263         gl->sh = 1;
264         gl->tl = 0;
265         gl->th = 1;
266
267         return &pic->pic;
268 }
269
270
271 void Draw_CharToConback (int num, byte *dest)
272 {
273         int             row, col;
274         byte    *source;
275         int             drawline;
276         int             x;
277
278         row = num>>4;
279         col = num&15;
280         source = draw_chars + (row<<10) + (col<<3);
281
282         drawline = 8;
283
284         while (drawline--)
285         {
286                 for (x=0 ; x<8 ; x++)
287                         if (source[x] != 255)
288                                 dest[x] = 0x60 + source[x];
289                 source += 128;
290                 dest += 320;
291         }
292
293 }
294
295 typedef struct
296 {
297         char *name;
298         int     minimize, maximize;
299 } glmode_t;
300
301 glmode_t modes[] = {
302         {"GL_NEAREST", GL_NEAREST, GL_NEAREST},
303         {"GL_LINEAR", GL_LINEAR, GL_LINEAR},
304         {"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST},
305         {"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR},
306         {"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST},
307         {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR}
308 };
309
310 /*
311 ===============
312 Draw_TextureMode_f
313 ===============
314 */
315 void Draw_TextureMode_f (void)
316 {
317         int             i;
318         gltexture_t     *glt;
319
320         if (Cmd_Argc() == 1)
321         {
322                 for (i=0 ; i< 6 ; i++)
323                         if (gl_filter_min == modes[i].minimize)
324                         {
325                                 Con_Printf ("%s\n", modes[i].name);
326                                 return;
327                         }
328                 Con_Printf ("current filter is unknown???\n");
329                 return;
330         }
331
332         for (i=0 ; i< 6 ; i++)
333         {
334                 if (!Q_strcasecmp (modes[i].name, Cmd_Argv(1) ) )
335                         break;
336         }
337         if (i == 6)
338         {
339                 Con_Printf ("bad filter name\n");
340                 return;
341         }
342
343         gl_filter_min = modes[i].minimize;
344         gl_filter_max = modes[i].maximize;
345
346         // change all the existing mipmap texture objects
347         for (i=0, glt=gltextures ; i<numgltextures ; i++, glt++)
348         {
349                 if (glt->mipmap)
350                 {
351                         glBindTexture(GL_TEXTURE_2D, glt->texnum);
352                         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
353                         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
354                 }
355         }
356 }
357
358 extern void LoadSky_f(void);
359
360 extern char *QSG_EXTENSIONS;
361
362 /*
363 ===============
364 Draw_Init
365 ===============
366 */
367 void rmain_registercvars();
368 extern int buildnumber;
369 void Draw_Init (void)
370 {
371         int             i;
372         qpic_t  *cb;
373         byte    *dest;
374         int             x, y;
375         char    ver[40];
376         glpic_t *gl;
377         int             start;
378
379         Cvar_RegisterVariable (&qsg_version);
380         Cvar_RegisterVariable (&gl_max_size);
381         Cvar_RegisterVariable (&gl_picmip);
382         Cvar_RegisterVariable (&gl_conalpha);
383         Cvar_RegisterVariable (&gl_lerpimages);
384
385         // 3dfx can only handle 256 wide textures
386         if (!Q_strncasecmp ((char *)gl_renderer, "3dfx",4) ||
387                 strstr((char *)gl_renderer, "Glide"))
388                 Cvar_Set ("gl_max_size", "256");
389
390         Cmd_AddCommand ("gl_texturemode", &Draw_TextureMode_f);
391
392         Cmd_AddCommand ("loadsky", &LoadSky_f);
393
394         // load the console background and the charset
395         // by hand, because we need to write the version
396         // string into the background before turning
397         // it into a texture
398         draw_chars = W_GetLumpName ("conchars");
399         for (i=0 ; i<256*64 ; i++)
400                 if (draw_chars[i] == 0)
401                         draw_chars[i] = 255;    // proper transparent color
402
403         // now turn them into textures
404         char_texture = GL_LoadTexture ("charset", 128, 128, draw_chars, false, true, 1);
405
406         start = Hunk_LowMark();
407
408         cb = (qpic_t *)COM_LoadMallocFile ("gfx/conback.lmp", false);
409         if (!cb)
410                 Sys_Error ("Couldn't load gfx/conback.lmp");
411         SwapPic (cb);
412
413         // hack the version number directly into the pic
414 #ifdef NEHAHRA
415 #if defined(__linux__)
416         sprintf (ver, "DPNehahra Linux GL %.2f build %5i", (float) VERSION, buildnumber);
417 #elif defined(WIN32)
418         sprintf (ver, "DPNehahra Windows GL %.2f build %5i", (float) VERSION, buildnumber);
419 #else
420         sprintf (ver, "DPNehahra Unknown GL %.2f build %5i", (float) VERSION, buildnumber);
421 #endif
422 #else
423 #if defined(__linux__)
424         sprintf (ver, "DarkPlaces Linux GL %.2f build %5i", (float) VERSION, buildnumber);
425 #elif defined(WIN32)
426         sprintf (ver, "DarkPlaces Windows GL %.2f build %5i", (float) VERSION, buildnumber);
427 #else
428         sprintf (ver, "DarkPlaces Unknown GL %.2f build %5i", (float) VERSION, buildnumber);
429 #endif
430 #endif
431         dest = cb->data + 320*186 + 320 - 11 - 8*strlen(ver);
432         y = strlen(ver);
433         for (x=0 ; x<y ; x++)
434                 Draw_CharToConback (ver[x], dest+(x<<3));
435
436         gl = (glpic_t *)conback->data;
437         gl->texnum = GL_LoadTexture ("conback", cb->width, cb->height, cb->data, false, false, 1);
438         gl->sl = 0;
439         gl->sh = 1;
440         gl->tl = 0;
441         gl->th = 1;
442         conback->width = vid.width;
443         conback->height = vid.height;
444
445         // free loaded console
446         free(cb);
447
448         // save a texture slot for translated picture
449         translate_texture = texture_extension_number++;
450
451         // save slots for scraps
452         scrap_texnum = texture_extension_number;
453         texture_extension_number += MAX_SCRAPS;
454
455         //
456         // get the other pics we need
457         //
458         draw_disc = Draw_PicFromWad ("disc");
459
460         rmain_registercvars();
461 }
462
463
464 /*
465 ================
466 Draw_Character
467
468 Draws one 8*8 graphics character with 0 being transparent.
469 It can be clipped to the top of the screen to allow the console to be
470 smoothly scrolled off.
471 ================
472 */
473 void Draw_Character (int x, int y, int num)
474 {
475         int                             row, col;
476         float                   frow, fcol, size;
477
478         if (num == 32)
479                 return;         // space
480
481         num &= 255;
482         
483         if (y <= -8)
484                 return;                 // totally off screen
485
486         row = num>>4;
487         col = num&15;
488
489         frow = row*0.0625;
490         fcol = col*0.0625;
491         size = 0.0625;
492
493         glBindTexture(GL_TEXTURE_2D, char_texture);
494         // LordHavoc: NEAREST mode on text if not scaling up
495         if ((int) vid.width < glwidth)
496         {
497                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
498                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
499         }
500
501         glColor3f(1,1,1);
502         glBegin (GL_QUADS);
503         glTexCoord2f (fcol, frow);
504         glVertex2f (x, y);
505         glTexCoord2f (fcol + size, frow);
506         glVertex2f (x+8, y);
507         glTexCoord2f (fcol + size, frow + size);
508         glVertex2f (x+8, y+8);
509         glTexCoord2f (fcol, frow + size);
510         glVertex2f (x, y+8);
511         glEnd ();
512
513         // LordHavoc: revert to LINEAR mode
514         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
515         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
516 }
517
518 /*
519 ================
520 Draw_String
521 ================
522 */
523 // LordHavoc: sped this up a lot, and added maxlen
524 void Draw_String (int x, int y, char *str, int maxlen)
525 {
526         int num;
527         float frow, fcol;
528         if (y <= -8 || y >= (int) vid.height || x >= (int) vid.width || *str == 0) // completely offscreen or no text to print
529                 return;
530         if (maxlen < 1)
531                 maxlen = strlen(str);
532         else if (maxlen > (int) strlen(str))
533                 maxlen = strlen(str);
534         glBindTexture(GL_TEXTURE_2D, char_texture);
535
536         // LordHavoc: NEAREST mode on text if not scaling up
537         if ((int) vid.width < glwidth)
538         {
539                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
540                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
541         }
542
543         glColor3f(1,1,1);
544         glBegin (GL_QUADS);
545         while (maxlen-- && x < (int) vid.width) // stop rendering when out of characters or room
546         {
547                 if ((num = *str++) != 32) // skip spaces
548                 {
549                         frow = (float) ((int) num >> 4)*0.0625;
550                         fcol = (float) ((int) num & 15)*0.0625;
551                         glTexCoord2f (fcol, frow);
552                         glVertex2f (x, y);
553                         glTexCoord2f (fcol + 0.0625, frow);
554                         glVertex2f (x+8, y);
555                         glTexCoord2f (fcol + 0.0625, frow + 0.0625);
556                         glVertex2f (x+8, y+8);
557                         glTexCoord2f (fcol, frow + 0.0625);
558                         glVertex2f (x, y+8);
559                 }
560                 x += 8;
561         }
562         glEnd ();
563
564         // LordHavoc: revert to LINEAR mode
565         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
566         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
567 }
568
569 /*
570 =============
571 Draw_AlphaPic
572 =============
573 */
574 void Draw_AlphaPic (int x, int y, qpic_t *pic, float alpha)
575 {
576         glpic_t                 *gl;
577
578         if (scrap_dirty)
579                 Scrap_Upload ();
580         gl = (glpic_t *)pic->data;
581 //      glDisable(GL_ALPHA_TEST);
582 //      glEnable (GL_BLEND);
583 //      glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
584 //      glCullFace(GL_FRONT);
585         glColor4f(0.8,0.8,0.8,alpha);
586         glBindTexture(GL_TEXTURE_2D, gl->texnum);
587 //      glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
588         glBegin (GL_QUADS);
589         glTexCoord2f (gl->sl, gl->tl);
590         glVertex2f (x, y);
591         glTexCoord2f (gl->sh, gl->tl);
592         glVertex2f (x+pic->width, y);
593         glTexCoord2f (gl->sh, gl->th);
594         glVertex2f (x+pic->width, y+pic->height);
595         glTexCoord2f (gl->sl, gl->th);
596         glVertex2f (x, y+pic->height);
597         glEnd ();
598         glColor3f(1,1,1);
599 //      glEnable(GL_ALPHA_TEST);
600 //      glDisable (GL_BLEND);
601 }
602
603
604 /*
605 =============
606 Draw_Pic
607 =============
608 */
609 void Draw_Pic (int x, int y, qpic_t *pic)
610 {
611         glpic_t                 *gl;
612
613         if (scrap_dirty)
614                 Scrap_Upload ();
615         gl = (glpic_t *)pic->data;
616         glColor3f(0.8,0.8,0.8);
617         glBindTexture(GL_TEXTURE_2D, gl->texnum);
618         glBegin (GL_QUADS);
619         glTexCoord2f (gl->sl, gl->tl);
620         glVertex2f (x, y);
621         glTexCoord2f (gl->sh, gl->tl);
622         glVertex2f (x+pic->width, y);
623         glTexCoord2f (gl->sh, gl->th);
624         glVertex2f (x+pic->width, y+pic->height);
625         glTexCoord2f (gl->sl, gl->th);
626         glVertex2f (x, y+pic->height);
627         glEnd ();
628 }
629
630
631 /*
632 =============
633 Draw_TransPic
634 =============
635 */
636 void Draw_TransPic (int x, int y, qpic_t *pic)
637 {
638         if (x < 0 || (unsigned)(x + pic->width) > vid.width || y < 0 || (unsigned)(y + pic->height) > vid.height)
639                 Sys_Error ("Draw_TransPic: bad coordinates");
640
641 //      glEnable(GL_BLEND);
642 //      glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
643 //      glDisable(GL_ALPHA_TEST);
644         Draw_Pic (x, y, pic);
645 //      glDisable(GL_BLEND);
646 }
647
648
649 /*
650 =============
651 Draw_TransPicTranslate
652
653 Only used for the player color selection menu
654 =============
655 */
656 void Draw_TransPicTranslate (int x, int y, qpic_t *pic, byte *translation)
657 {
658         int                             v, u, c;
659         unsigned                trans[64*64], *dest;
660         byte                    *src;
661         int                             p;
662
663         glBindTexture(GL_TEXTURE_2D, translate_texture);
664
665         c = pic->width * pic->height;
666
667         dest = trans;
668         for (v=0 ; v<64 ; v++, dest += 64)
669         {
670                 src = &menuplyr_pixels[ ((v*pic->height)>>6) *pic->width];
671                 for (u=0 ; u<64 ; u++)
672                 {
673                         p = src[(u*pic->width)>>6];
674                         if (p == 255)
675                                 dest[u] = p;
676                         else
677                                 dest[u] =  d_8to24table[translation[p]];
678                 }
679         }
680
681         glTexImage2D (GL_TEXTURE_2D, 0, 4, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, trans);
682
683         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
684         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
685
686         glColor3f(0.8,0.8,0.8);
687         glBegin (GL_QUADS);
688         glTexCoord2f (0, 0);
689         glVertex2f (x, y);
690         glTexCoord2f (1, 0);
691         glVertex2f (x+pic->width, y);
692         glTexCoord2f (1, 1);
693         glVertex2f (x+pic->width, y+pic->height);
694         glTexCoord2f (0, 1);
695         glVertex2f (x, y+pic->height);
696         glEnd ();
697 }
698
699
700 /*
701 ================
702 Draw_ConsoleBackground
703
704 ================
705 */
706 void Draw_ConsoleBackground (int lines)
707 {
708         // LordHavoc: changed alpha
709         //int y = (vid.height >> 1);
710
711         if (lines >= (int) vid.height)
712                 Draw_Pic(0, lines - vid.height, conback);
713         else
714                 Draw_AlphaPic (0, lines - vid.height, conback, gl_conalpha.value*lines/vid.height);
715         //      Draw_AlphaPic (0, lines - vid.height, conback, (float)(1.2 * lines)/y);
716 }
717
718 /*
719 =============
720 Draw_Fill
721
722 Fills a box of pixels with a single color
723 =============
724 */
725 void Draw_Fill (int x, int y, int w, int h, int c)
726 {
727         glDisable (GL_TEXTURE_2D);
728         glColor3f (host_basepal[c*3]/255.0, host_basepal[c*3+1]/255.0, host_basepal[c*3+2]/255.0);
729
730         glBegin (GL_QUADS);
731
732         glVertex2f (x,y);
733         glVertex2f (x+w, y);
734         glVertex2f (x+w, y+h);
735         glVertex2f (x, y+h);
736
737         glEnd ();
738         glColor3f(1,1,1);
739         glEnable (GL_TEXTURE_2D);
740 }
741 //=============================================================================
742
743 //=============================================================================
744
745 /*
746 ================
747 GL_Set2D
748
749 Setup as if the screen was 320*200
750 ================
751 */
752 void GL_Set2D (void)
753 {
754         glViewport (glx, gly, glwidth, glheight);
755
756         glMatrixMode(GL_PROJECTION);
757     glLoadIdentity ();
758         glOrtho  (0, vid.width, vid.height, 0, -99999, 99999);
759
760         glMatrixMode(GL_MODELVIEW);
761     glLoadIdentity ();
762
763         glDisable (GL_DEPTH_TEST);
764         glDisable (GL_CULL_FACE);
765         glEnable (GL_BLEND); // was Disable
766 //      glEnable (GL_ALPHA_TEST);
767         glDisable (GL_ALPHA_TEST);
768         glEnable(GL_TEXTURE_2D);
769
770         // LordHavoc: added this
771         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
772         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
773
774         glColor3f(1,1,1);
775 }
776
777 // LordHavoc: SHOWLMP stuff
778 #define SHOWLMP_MAXLABELS 256
779 typedef struct showlmp_s
780 {
781         qboolean        isactive;
782         float           x;
783         float           y;
784         char            label[32];
785         char            pic[128];
786 } showlmp_t;
787
788 showlmp_t showlmp[SHOWLMP_MAXLABELS];
789
790 void SHOWLMP_decodehide()
791 {
792         int i;
793         byte *lmplabel;
794         lmplabel = MSG_ReadString();
795         for (i = 0;i < SHOWLMP_MAXLABELS;i++)
796                 if (showlmp[i].isactive && strcmp(showlmp[i].label, lmplabel) == 0)
797                 {
798                         showlmp[i].isactive = false;
799                         return;
800                 }
801 }
802
803 void SHOWLMP_decodeshow()
804 {
805         int i, k;
806         byte lmplabel[256], picname[256];
807         float x, y;
808         strcpy(lmplabel,MSG_ReadString());
809         strcpy(picname, MSG_ReadString());
810         x = MSG_ReadByte();
811         y = MSG_ReadByte();
812         k = -1;
813         for (i = 0;i < SHOWLMP_MAXLABELS;i++)
814                 if (showlmp[i].isactive)
815                 {
816                         if (strcmp(showlmp[i].label, lmplabel) == 0)
817                         {
818                                 k = i;
819                                 break; // drop out to replace it
820                         }
821                 }
822                 else if (k < 0) // find first empty one to replace
823                         k = i;
824         if (k < 0)
825                 return; // none found to replace
826         // change existing one
827         showlmp[k].isactive = true;
828         strcpy(showlmp[k].label, lmplabel);
829         strcpy(showlmp[k].pic, picname);
830         showlmp[k].x = x;
831         showlmp[k].y = y;
832 }
833
834 void SHOWLMP_drawall()
835 {
836         int i;
837         for (i = 0;i < SHOWLMP_MAXLABELS;i++)
838                 if (showlmp[i].isactive)
839                         Draw_TransPic(showlmp[i].x, showlmp[i].y, Draw_CachePic(showlmp[i].pic));
840 }
841
842 void SHOWLMP_clear()
843 {
844         int i;
845         for (i = 0;i < SHOWLMP_MAXLABELS;i++)
846                 showlmp[i].isactive = false;
847 }
848
849 //====================================================================
850
851 /*
852 ================
853 GL_FindTexture
854 ================
855 */
856 int GL_FindTexture (char *identifier)
857 {
858         int             i;
859         gltexture_t     *glt;
860
861         for (i=0, glt=gltextures ; i<numgltextures ; i++, glt++)
862         {
863                 if (!strcmp (identifier, glt->identifier))
864                         return gltextures[i].texnum;
865         }
866
867         return -1;
868 }
869
870 extern byte qgamma[];
871
872 // LordHavoc: gamma correction and improved resampling
873 void GL_ResampleTextureLerpLine (byte *in, byte *out, int inwidth, int outwidth)
874 {
875         int             j, xi, oldx = 0;
876         float   f, fstep, l1, l2;
877         fstep = (float) inwidth/outwidth;
878         for (j = 0,f = 0;j < outwidth;j++, f += fstep)
879         {
880                 xi = (int) f;
881                 if (xi != oldx)
882                 {
883                         in += (xi - oldx) * 4;
884                         oldx = xi;
885                 }
886                 if (xi < (inwidth-1))
887                 {
888                         l2 = f - xi;
889                         l1 = 1 - l2;
890                         *out++ = qgamma[(byte) (in[0] * l1 + in[4] * l2)];
891                         *out++ = qgamma[(byte) (in[1] * l1 + in[5] * l2)];
892                         *out++ = qgamma[(byte) (in[2] * l1 + in[6] * l2)];
893                         *out++ =        (byte) (in[3] * l1 + in[7] * l2) ;
894                 }
895                 else // last pixel of the line has no pixel to lerp to
896                 {
897                         *out++ = qgamma[in[0]];
898                         *out++ = qgamma[in[1]];
899                         *out++ = qgamma[in[2]];
900                         *out++ =        in[3] ;
901                 }
902         }
903 }
904
905 /*
906 ================
907 GL_ResampleTexture
908 ================
909 */
910 void GL_ResampleTexture (void *indata, int inwidth, int inheight, void *outdata,  int outwidth, int outheight)
911 {
912         // LordHavoc: gamma correction and greatly improved resampling
913         if (gl_lerpimages.value)
914         {
915                 int             i, j, yi, oldy;
916                 byte    *inrow, *out, *row1, *row2;
917                 float   f, fstep, l1, l2;
918                 out = outdata;
919                 fstep = (float) inheight/outheight;
920
921                 row1 = malloc(outwidth*4);
922                 row2 = malloc(outwidth*4);
923                 inrow = indata;
924                 oldy = 0;
925                 GL_ResampleTextureLerpLine (inrow, row1, inwidth, outwidth);
926                 GL_ResampleTextureLerpLine (inrow + inwidth*4, row2, inwidth, outwidth);
927                 for (i = 0, f = 0;i < outheight;i++,f += fstep)
928                 {
929                         yi = (int) f;
930                         if (yi != oldy)
931                         {
932                                 inrow = (byte *)((int)indata + inwidth*4*yi);
933                                 if (yi == oldy+1)
934                                         memcpy(row1, row2, outwidth*4);
935                                 else
936                                         GL_ResampleTextureLerpLine (inrow, row1, inwidth, outwidth);
937                                 if (yi < (inheight-1))
938                                         GL_ResampleTextureLerpLine (inrow + inwidth*4, row2, inwidth, outwidth);
939                                 else
940                                         memcpy(row2, row1, outwidth*4);
941                                 oldy = yi;
942                         }
943                         if (yi < (inheight-1))
944                         {
945                                 l2 = f - yi;
946                                 l1 = 1 - l2;
947                                 for (j = 0;j < outwidth;j++)
948                                 {
949                                         *out++ = (byte) (*row1++ * l1 + *row2++ * l2);
950                                         *out++ = (byte) (*row1++ * l1 + *row2++ * l2);
951                                         *out++ = (byte) (*row1++ * l1 + *row2++ * l2);
952                                         *out++ = (byte) (*row1++ * l1 + *row2++ * l2);
953                                 }
954                                 row1 -= outwidth*4;
955                                 row2 -= outwidth*4;
956                         }
957                         else // last line has no pixels to lerp to
958                         {
959                                 for (j = 0;j < outwidth;j++)
960                                 {
961                                         *out++ = *row1++;
962                                         *out++ = *row1++;
963                                         *out++ = *row1++;
964                                         *out++ = *row1++;
965                                 }
966                                 row1 -= outwidth*4;
967                         }
968                 }
969                 free(row1);
970                 free(row2);
971         }
972         else
973         {
974                 int             i, j;
975                 unsigned        frac, fracstep;
976                 byte    *inrow, *out, *inpix;
977                 out = outdata;
978
979                 fracstep = inwidth*0x10000/outwidth;
980                 for (i=0 ; i<outheight ; i++)
981                 {
982                         inrow = (byte *)indata + inwidth*(i*inheight/outheight)*4;
983                         frac = fracstep >> 1;
984                         for (j=0 ; j<outwidth ; j+=4)
985                         {
986                                 inpix = inrow + ((frac >> 14) & ~3);*out++ = qgamma[*inpix++];*out++ = qgamma[*inpix++];*out++ = qgamma[*inpix++];*out++ =       *inpix++ ;frac += fracstep;
987                                 inpix = inrow + ((frac >> 14) & ~3);*out++ = qgamma[*inpix++];*out++ = qgamma[*inpix++];*out++ = qgamma[*inpix++];*out++ =       *inpix++ ;frac += fracstep;
988                                 inpix = inrow + ((frac >> 14) & ~3);*out++ = qgamma[*inpix++];*out++ = qgamma[*inpix++];*out++ = qgamma[*inpix++];*out++ =       *inpix++ ;frac += fracstep;
989                                 inpix = inrow + ((frac >> 14) & ~3);*out++ = qgamma[*inpix++];*out++ = qgamma[*inpix++];*out++ = qgamma[*inpix++];*out++ =       *inpix++ ;frac += fracstep;
990                         }
991                 }
992         }
993 }
994
995 /*
996 ================
997 GL_Resample8BitTexture -- JACK
998 ================
999 */
1000 void GL_Resample8BitTexture (unsigned char *in, int inwidth, int inheight, unsigned char *out,  int outwidth, int outheight)
1001 {
1002         int             i, j;
1003         unsigned        char *inrow;
1004         unsigned        frac, fracstep;
1005
1006         fracstep = inwidth*0x10000/outwidth;
1007         for (i=0 ; i<outheight ; i++, out += outwidth)
1008         {
1009                 inrow = in + inwidth*(i*inheight/outheight);
1010                 frac = fracstep >> 1;
1011                 for (j=0 ; j<outwidth ; j+=4)
1012                 {
1013                         out[j] = inrow[frac>>16];
1014                         frac += fracstep;
1015                         out[j+1] = inrow[frac>>16];
1016                         frac += fracstep;
1017                         out[j+2] = inrow[frac>>16];
1018                         frac += fracstep;
1019                         out[j+3] = inrow[frac>>16];
1020                         frac += fracstep;
1021                 }
1022         }
1023 }
1024
1025
1026 /*
1027 ================
1028 GL_MipMap
1029
1030 Operates in place, quartering the size of the texture
1031 ================
1032 */
1033 void GL_MipMap (byte *in, int width, int height)
1034 {
1035         int             i, j;
1036         byte    *out;
1037
1038         width <<=2;
1039         height >>= 1;
1040         out = in;
1041         for (i=0 ; i<height ; i++, in+=width)
1042         {
1043                 for (j=0 ; j<width ; j+=8, out+=4, in+=8)
1044                 {
1045                         out[0] = (in[0] + in[4] + in[width+0] + in[width+4])>>2;
1046                         out[1] = (in[1] + in[5] + in[width+1] + in[width+5])>>2;
1047                         out[2] = (in[2] + in[6] + in[width+2] + in[width+6])>>2;
1048                         out[3] = (in[3] + in[7] + in[width+3] + in[width+7])>>2;
1049                 }
1050         }
1051 }
1052
1053 /*
1054 ================
1055 GL_MipMap8Bit
1056
1057 Mipping for 8 bit textures
1058 ================
1059 */
1060 void GL_MipMap8Bit (byte *in, int width, int height)
1061 {
1062         int             i, j;
1063         unsigned short     r,g,b;
1064         byte    *out, *at1, *at2, *at3, *at4;
1065
1066         height >>= 1;
1067         out = in;
1068         for (i=0 ; i<height ; i++, in+=width)
1069         {
1070                 for (j=0 ; j<width ; j+=2, out+=1, in+=2)
1071                 {
1072                         at1 = (byte *) (d_8to24table + in[0]);
1073                         at2 = (byte *) (d_8to24table + in[1]);
1074                         at3 = (byte *) (d_8to24table + in[width+0]);
1075                         at4 = (byte *) (d_8to24table + in[width+1]);
1076
1077                         r = (at1[0]+at2[0]+at3[0]+at4[0]); r>>=5;
1078                         g = (at1[1]+at2[1]+at3[1]+at4[1]); g>>=5;
1079                         b = (at1[2]+at2[2]+at3[2]+at4[2]); b>>=5;
1080
1081                         out[0] = d_15to8table[(r<<0) + (g<<5) + (b<<10)];
1082                 }
1083         }
1084 }
1085
1086 /*
1087 ===============
1088 GL_Upload32
1089 ===============
1090 */
1091 void GL_Upload32 (void *data, int width, int height,  qboolean mipmap, qboolean alpha)
1092 {
1093         int samples, scaled_width, scaled_height, i;
1094         byte *in, *out, *scaled;
1095
1096         for (scaled_width = 1 ; scaled_width < width ; scaled_width<<=1)
1097                 ;
1098         for (scaled_height = 1 ; scaled_height < height ; scaled_height<<=1)
1099                 ;
1100
1101         scaled_width >>= (int)gl_picmip.value;
1102         scaled_height >>= (int)gl_picmip.value;
1103
1104         if (scaled_width > gl_max_size.value)
1105                 scaled_width = gl_max_size.value;
1106         if (scaled_height > gl_max_size.value)
1107                 scaled_height = gl_max_size.value;
1108
1109         if (alpha)
1110         {
1111                 alpha = false;
1112                 in = data;
1113                 for (i = 3;i < width*height*4;i += 4)
1114                         if (in[i] != 255)
1115                         {
1116                                 alpha = true;
1117                                 break;
1118                         }
1119         }
1120
1121         samples = alpha ? gl_alpha_format : gl_solid_format;
1122
1123 #if 0
1124         if (mipmap)
1125                 gluBuild2DMipmaps (GL_TEXTURE_2D, samples, width, height, GL_RGBA, GL_UNSIGNED_BYTE, scaled);
1126         else if (scaled_width == width && scaled_height == height)
1127                 glTexImage2D (GL_TEXTURE_2D, 0, samples, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaled);
1128         else
1129         {
1130                 gluScaleImage (GL_RGBA, width, height, GL_UNSIGNED_BYTE, scaled, scaled_width, scaled_height, GL_UNSIGNED_BYTE, scaled);
1131                 glTexImage2D (GL_TEXTURE_2D, 0, samples, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaled);
1132         }
1133 #else
1134 texels += scaled_width * scaled_height;
1135
1136         scaled = malloc(scaled_width*scaled_height*4);
1137         if (scaled_width == width && scaled_height == height)
1138         {
1139                 // LordHavoc: gamma correct while copying
1140                 in = (byte *)data;
1141                 out = (byte *)scaled;
1142                 for (i = 0;i < width*height;i++)
1143                 {
1144                         *out++ = qgamma[*in++];
1145                         *out++ = qgamma[*in++];
1146                         *out++ = qgamma[*in++];
1147                         *out++ = *in++;
1148                 }
1149         }
1150         else
1151                 GL_ResampleTexture (data, width, height, scaled, scaled_width, scaled_height);
1152
1153         glTexImage2D (GL_TEXTURE_2D, 0, samples, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaled);
1154         if (mipmap)
1155         {
1156                 int             miplevel;
1157
1158                 miplevel = 0;
1159                 while (scaled_width > 1 || scaled_height > 1)
1160                 {
1161                         GL_MipMap ((byte *)scaled, scaled_width, scaled_height);
1162                         scaled_width >>= 1;
1163                         scaled_height >>= 1;
1164                         if (scaled_width < 1)
1165                                 scaled_width = 1;
1166                         if (scaled_height < 1)
1167                                 scaled_height = 1;
1168                         miplevel++;
1169                         glTexImage2D (GL_TEXTURE_2D, miplevel, samples, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaled);
1170                 }
1171         }
1172 #endif
1173
1174
1175         if (mipmap)
1176         {
1177                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
1178                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
1179         }
1180         else
1181         {
1182                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_max);
1183                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
1184         }
1185         free(scaled);
1186 }
1187
1188 void GL_Upload8_EXT (byte *data, int width, int height,  qboolean mipmap)
1189 {
1190         int             scaled_width, scaled_height;
1191         byte    *scaled = NULL;
1192
1193         for (scaled_width = 1 ; scaled_width < width ; scaled_width<<=1)
1194                 ;
1195         for (scaled_height = 1 ; scaled_height < height ; scaled_height<<=1)
1196                 ;
1197
1198         scaled_width >>= (int)gl_picmip.value;
1199         scaled_height >>= (int)gl_picmip.value;
1200
1201         if (scaled_width > gl_max_size.value)
1202                 scaled_width = gl_max_size.value;
1203         if (scaled_height > gl_max_size.value)
1204                 scaled_height = gl_max_size.value;
1205
1206         texels += scaled_width * scaled_height;
1207
1208         if (scaled_width == width && scaled_height == height)
1209         {
1210                 if (!mipmap)
1211                 {
1212                         glTexImage2D (GL_TEXTURE_2D, 0, GL_COLOR_INDEX8_EXT, scaled_width, scaled_height, 0, GL_COLOR_INDEX , GL_UNSIGNED_BYTE, data);
1213                         goto done;
1214                 }
1215                 scaled = malloc(scaled_width*scaled_height*4);
1216                 memcpy (scaled, data, width*height);
1217         }
1218         else
1219         {
1220                 scaled = malloc(scaled_width*scaled_height*4);
1221                 GL_Resample8BitTexture (data, width, height, (void*) scaled, scaled_width, scaled_height);
1222         }
1223
1224         glTexImage2D (GL_TEXTURE_2D, 0, GL_COLOR_INDEX8_EXT, scaled_width, scaled_height, 0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, scaled);
1225         if (mipmap)
1226         {
1227                 int             miplevel;
1228
1229                 miplevel = 0;
1230                 while (scaled_width > 1 || scaled_height > 1)
1231                 {
1232                         GL_MipMap8Bit ((byte *)scaled, scaled_width, scaled_height);
1233                         scaled_width >>= 1;
1234                         scaled_height >>= 1;
1235                         if (scaled_width < 1)
1236                                 scaled_width = 1;
1237                         if (scaled_height < 1)
1238                                 scaled_height = 1;
1239                         miplevel++;
1240                         glTexImage2D (GL_TEXTURE_2D, miplevel, GL_COLOR_INDEX8_EXT, scaled_width, scaled_height, 0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, scaled);
1241                 }
1242         }
1243 done: ;
1244
1245
1246         if (mipmap)
1247         {
1248                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
1249                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
1250         }
1251         else
1252         {
1253                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_max);
1254                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
1255         }
1256         free(scaled);
1257 }
1258
1259 qboolean VID_Is8bit();
1260
1261 /*
1262 ===============
1263 GL_Upload8
1264 ===============
1265 */
1266 void GL_Upload8 (byte *data, int width, int height,  qboolean mipmap, qboolean alpha)
1267 {
1268         static  unsigned *trans;
1269         int                     i, s;
1270         qboolean        noalpha;
1271         int                     p;
1272         byte    *indata;
1273         int             *outdata;
1274
1275         s = width*height;
1276         trans = malloc(s*4);
1277         // if there are no transparent pixels, make it a 3 component
1278         // texture even if it was specified as otherwise
1279         if (alpha)
1280         {
1281                 noalpha = true;
1282                 for (i=0 ; i<s ; i++)
1283                 {
1284                         p = data[i];
1285                         if (p != 255)
1286                                 trans[i] = d_8to24table[p];
1287                         else
1288                         {
1289                                 trans[i] = 0; // force to black
1290                                 noalpha = false;
1291                         }
1292                 }
1293
1294                 if (noalpha)
1295                 {
1296                         if (VID_Is8bit() && (data!=scrap_texels[0]))
1297                         {
1298                                 GL_Upload8_EXT (data, width, height, mipmap);
1299                                 free(trans);
1300                                 return;
1301                         }
1302                         alpha = false;
1303                 }
1304         }
1305         else
1306         {
1307                 // LordHavoc: dodge the copy if it will be uploaded as 8bit
1308                 if (VID_Is8bit() && (data!=scrap_texels[0]))
1309                 {
1310                         GL_Upload8_EXT (data, width, height, mipmap);
1311                         free(trans);
1312                         return;
1313                 }
1314                 //if (s&3)
1315                 //      Sys_Error ("GL_Upload8: s&3");
1316                 indata = data;
1317                 outdata = trans;
1318                 if (s&1)
1319                         *outdata++ = d_8to24table[*indata++];
1320                 if (s&2)
1321                 {
1322                         *outdata++ = d_8to24table[*indata++];
1323                         *outdata++ = d_8to24table[*indata++];
1324                 }
1325                 for (i = 0;i < s;i+=4)
1326                 {
1327                         *outdata++ = d_8to24table[*indata++];
1328                         *outdata++ = d_8to24table[*indata++];
1329                         *outdata++ = d_8to24table[*indata++];
1330                         *outdata++ = d_8to24table[*indata++];
1331                 }
1332         }
1333
1334         GL_Upload32 (trans, width, height, mipmap, alpha);
1335         free(trans);
1336 }
1337
1338 /*
1339 ================
1340 GL_LoadTexture
1341 ================
1342 */
1343 int GL_LoadTexture (char *identifier, int width, int height, byte *data, qboolean mipmap, qboolean alpha, int bytesperpixel)
1344 {
1345         unsigned short  crc;
1346         int                             i;
1347         gltexture_t             *glt;
1348
1349         if (isDedicated)
1350                 return 1;
1351
1352         // LordHavoc: do a CRC to confirm the data really is the same as previous occurances.
1353         crc = CRC_Block(data, width*height*bytesperpixel);
1354         // see if the texture is already present
1355         if (identifier[0])
1356         {
1357                 for (i=0, glt=gltextures ; i<numgltextures ; i++, glt++)
1358                 {
1359                         if (!strcmp (identifier, glt->identifier))
1360                         {
1361                                 // LordHavoc: everyone hates cache mismatchs, so I fixed it
1362                                 if (crc != glt->crc || width != glt->width || height != glt->height)
1363                                 {
1364                                         Con_DPrintf("GL_LoadTexture: cache mismatch, replacing old texture\n");
1365                                         goto GL_LoadTexture_setup; // drop out with glt pointing to the texture to replace
1366                                         //Sys_Error ("GL_LoadTexture: cache mismatch");
1367                                 }
1368                                 if ((gl_lerpimages.value != 0) != glt->lerped)
1369                                         goto GL_LoadTexture_setup; // drop out with glt pointing to the texture to replace
1370                                 return glt->texnum;
1371                         }
1372                 }
1373         }
1374         // LordHavoc: although this could be an else condition as it was in the original id code,
1375         //            it is more clear this way
1376         // LordHavoc: check if there are still slots available
1377         if (numgltextures >= MAX_GLTEXTURES)
1378                 Sys_Error ("GL_LoadTexture: ran out of texture slots (%d)\n", MAX_GLTEXTURES);
1379         glt = &gltextures[numgltextures++];
1380
1381         strcpy (glt->identifier, identifier);
1382         glt->texnum = texture_extension_number;
1383         texture_extension_number++;
1384 // LordHavoc: label to drop out of the loop into the setup code
1385 GL_LoadTexture_setup:
1386         glt->crc = crc; // LordHavoc: used to verify textures are identical
1387         glt->width = width;
1388         glt->height = height;
1389         glt->mipmap = mipmap;
1390         glt->bytesperpixel = bytesperpixel;
1391         glt->lerped = gl_lerpimages.value != 0;
1392
1393         glBindTexture(GL_TEXTURE_2D, glt->texnum);
1394
1395         if (bytesperpixel == 1) // 8bit
1396                 GL_Upload8 (data, width, height, mipmap, alpha);
1397         else // 32bit
1398                 GL_Upload32 (data, width, height, mipmap, true);
1399         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1400
1401         return glt->texnum;
1402 }
1403
1404 /*
1405 ================
1406 GL_LoadPicTexture
1407 ================
1408 */
1409 int GL_LoadPicTexture (qpic_t *pic)
1410 {
1411         return GL_LoadTexture ("", pic->width, pic->height, pic->data, false, true, 1);
1412 }
1413
1414 int GL_GetTextureSlots (int count)
1415 {
1416         gltexture_t             *glt, *first;
1417
1418         first = glt = &gltextures[numgltextures];
1419         while (count--)
1420         {
1421                 glt->identifier[0] = 0;
1422                 glt->texnum = texture_extension_number++;
1423                 glt->crc = 0;
1424                 glt->width = 0;
1425                 glt->height = 0;
1426                 glt->bytesperpixel = 0;
1427                 glt++;
1428                 numgltextures++;
1429         }
1430         return first->texnum;
1431 }