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