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