some color tag cleanups by terencehill
[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 #include "quakedef.h"
22 #include "image.h"
23 #include "wad.h"
24
25 #include "cl_video.h"
26 #include "cl_dyntexture.h"
27
28 dp_font_t dp_fonts[MAX_FONTS] = {{0}};
29
30 cvar_t r_textshadow = {CVAR_SAVE, "r_textshadow", "0", "draws a shadow on all text to improve readability (note: value controls offset, 1 = 1 pixel, 1.5 = 1.5 pixels, etc)"};
31 cvar_t r_textbrightness = {CVAR_SAVE, "r_textbrightness", "0", "additional brightness for text color codes (0 keeps colors as is, 1 makes them all white)"};
32 cvar_t r_textcontrast = {CVAR_SAVE, "r_textcontrast", "1", "additional contrast for text color codes (1 keeps colors as is, 0 makes them all black)"};
33
34 extern cvar_t v_glslgamma;
35
36 //=============================================================================
37 /* Support Routines */
38
39 #define FONT_FILESIZE 13468
40 #define MAX_CACHED_PICS 1024
41 #define CACHEPICHASHSIZE 256
42 static cachepic_t *cachepichash[CACHEPICHASHSIZE];
43 static cachepic_t cachepics[MAX_CACHED_PICS];
44 static int numcachepics;
45
46 static rtexturepool_t *drawtexturepool;
47
48 static const unsigned char concharimage[FONT_FILESIZE] =
49 {
50 #include "lhfont.h"
51 };
52
53 static rtexture_t *draw_generateconchars(void)
54 {
55         int i;
56         unsigned char buffer[65536][4], *data = NULL;
57         double random;
58
59         data = LoadTGA_BGRA (concharimage, FONT_FILESIZE);
60 // Gold numbers
61         for (i = 0;i < 8192;i++)
62         {
63                 random = lhrandom (0.0,1.0);
64                 buffer[i][2] = 83 + (unsigned char)(random * 64);
65                 buffer[i][1] = 71 + (unsigned char)(random * 32);
66                 buffer[i][0] = 23 + (unsigned char)(random * 16);
67                 buffer[i][3] = data[i*4+0];
68         }
69 // White chars
70         for (i = 8192;i < 32768;i++)
71         {
72                 random = lhrandom (0.0,1.0);
73                 buffer[i][2] = 95 + (unsigned char)(random * 64);
74                 buffer[i][1] = 95 + (unsigned char)(random * 64);
75                 buffer[i][0] = 95 + (unsigned char)(random * 64);
76                 buffer[i][3] = data[i*4+0];
77         }
78 // Gold numbers
79         for (i = 32768;i < 40960;i++)
80         {
81                 random = lhrandom (0.0,1.0);
82                 buffer[i][2] = 83 + (unsigned char)(random * 64);
83                 buffer[i][1] = 71 + (unsigned char)(random * 32);
84                 buffer[i][0] = 23 + (unsigned char)(random * 16);
85                 buffer[i][3] = data[i*4+0];
86         }
87 // Red chars
88         for (i = 40960;i < 65536;i++)
89         {
90                 random = lhrandom (0.0,1.0);
91                 buffer[i][2] = 96 + (unsigned char)(random * 64);
92                 buffer[i][1] = 43 + (unsigned char)(random * 32);
93                 buffer[i][0] = 27 + (unsigned char)(random * 32);
94                 buffer[i][3] = data[i*4+0];
95         }
96
97 #if 0
98         Image_WriteTGABGRA ("gfx/generated_conchars.tga", 256, 256, &buffer[0][0]);
99 #endif
100
101         Mem_Free(data);
102         return R_LoadTexture2D(drawtexturepool, "conchars", 256, 256, &buffer[0][0], TEXTYPE_BGRA, TEXF_ALPHA | TEXF_PRECACHE, NULL);
103 }
104
105 static rtexture_t *draw_generateditherpattern(void)
106 {
107         int x, y;
108         unsigned char pixels[8][8];
109         for (y = 0;y < 8;y++)
110                 for (x = 0;x < 8;x++)
111                         pixels[y][x] = ((x^y) & 4) ? 254 : 0;
112         return R_LoadTexture2D(drawtexturepool, "ditherpattern", 8, 8, pixels[0], TEXTYPE_PALETTE, TEXF_FORCENEAREST | TEXF_PRECACHE, palette_bgra_transparent);
113 }
114
115 typedef struct embeddedpic_s
116 {
117         const char *name;
118         int width;
119         int height;
120         const char *pixels;
121 }
122 embeddedpic_t;
123
124 static const embeddedpic_t embeddedpics[] =
125 {
126         {
127         "gfx/prydoncursor001", 16, 16,
128         "477777774......."
129         "77.....6........"
130         "7.....6........."
131         "7....6.........."
132         "7.....6........."
133         "7..6...6........"
134         "7.6.6...6......."
135         "76...6...6......"
136         "4.....6.6......."
137         ".......6........"
138         "................"
139         "................"
140         "................"
141         "................"
142         "................"
143         "................"
144         },
145         {
146         "ui/mousepointer", 16, 16,
147         "477777774......."
148         "77.....6........"
149         "7.....6........."
150         "7....6.........."
151         "7.....6........."
152         "7..6...6........"
153         "7.6.6...6......."
154         "76...6...6......"
155         "4.....6.6......."
156         ".......6........"
157         "................"
158         "................"
159         "................"
160         "................"
161         "................"
162         "................"
163         },
164         {
165         "gfx/crosshair1", 16, 16,
166         "................"
167         "................"
168         "................"
169         "...33......33..."
170         "...355....553..."
171         "....577..775...."
172         ".....77..77....."
173         "................"
174         "................"
175         ".....77..77....."
176         "....577..775...."
177         "...355....553..."
178         "...33......33..."
179         "................"
180         "................"
181         "................"
182         },
183         {
184         "gfx/crosshair2", 16, 16,
185         "................"
186         "................"
187         "................"
188         "...3........3..."
189         "....5......5...."
190         ".....7....7....."
191         "......7..7......"
192         "................"
193         "................"
194         "......7..7......"
195         ".....7....7....."
196         "....5......5...."
197         "...3........3..."
198         "................"
199         "................"
200         "................"
201         },
202         {
203         "gfx/crosshair3", 16, 16,
204         "................"
205         ".......77......."
206         ".......77......."
207         "................"
208         "................"
209         ".......44......."
210         ".......44......."
211         ".77..44..44..77."
212         ".77..44..44..77."
213         ".......44......."
214         ".......44......."
215         "................"
216         "................"
217         ".......77......."
218         ".......77......."
219         "................"
220         },
221         {
222         "gfx/crosshair4", 16, 16,
223         "................"
224         "................"
225         "................"
226         "................"
227         "................"
228         "................"
229         "................"
230         "................"
231         "........7777777."
232         "........752....."
233         "........72......"
234         "........7......."
235         "........7......."
236         "........7......."
237         "........7......."
238         "................"
239         },
240         {
241         "gfx/crosshair5", 8, 8,
242         "........"
243         "........"
244         "....7..."
245         "........"
246         "..7.7.7."
247         "........"
248         "....7..."
249         "........"
250         },
251         {
252         "gfx/crosshair6", 2, 2,
253         "77"
254         "77"
255         },
256         {
257         "gfx/crosshair7", 16, 16,
258         "................"
259         ".3............3."
260         "..5...2332...5.."
261         "...7.3....3.7..."
262         "....7......7...."
263         "...3.7....7.3..."
264         "..2...7..7...2.."
265         "..3..........3.."
266         "..3..........3.."
267         "..2...7..7...2.."
268         "...3.7....7.3..."
269         "....7......7...."
270         "...7.3....3.7..."
271         "..5...2332...5.."
272         ".3............3."
273         "................"
274         },
275         {
276         "gfx/editlights/cursor", 16, 16,
277         "................"
278         ".3............3."
279         "..5...2332...5.."
280         "...7.3....3.7..."
281         "....7......7...."
282         "...3.7....7.3..."
283         "..2...7..7...2.."
284         "..3..........3.."
285         "..3..........3.."
286         "..2...7..7...2.."
287         "...3.7....7.3..."
288         "....7......7...."
289         "...7.3....3.7..."
290         "..5...2332...5.."
291         ".3............3."
292         "................"
293         },
294         {
295         "gfx/editlights/light", 16, 16,
296         "................"
297         "................"
298         "......1111......"
299         "....11233211...."
300         "...1234554321..."
301         "...1356776531..."
302         "..124677776421.."
303         "..135777777531.."
304         "..135777777531.."
305         "..124677776421.."
306         "...1356776531..."
307         "...1234554321..."
308         "....11233211...."
309         "......1111......"
310         "................"
311         "................"
312         },
313         {
314         "gfx/editlights/noshadow", 16, 16,
315         "................"
316         "................"
317         "......1111......"
318         "....11233211...."
319         "...1234554321..."
320         "...1356226531..."
321         "..12462..26421.."
322         "..1352....2531.."
323         "..1352....2531.."
324         "..12462..26421.."
325         "...1356226531..."
326         "...1234554321..."
327         "....11233211...."
328         "......1111......"
329         "................"
330         "................"
331         },
332         {
333         "gfx/editlights/selection", 16, 16,
334         "................"
335         ".777752..257777."
336         ".742........247."
337         ".72..........27."
338         ".7............7."
339         ".5............5."
340         ".2............2."
341         "................"
342         "................"
343         ".2............2."
344         ".5............5."
345         ".7............7."
346         ".72..........27."
347         ".742........247."
348         ".777752..257777."
349         "................"
350         },
351         {
352         "gfx/editlights/cubemaplight", 16, 16,
353         "................"
354         "................"
355         "......2772......"
356         "....27755772...."
357         "..277533335772.."
358         "..753333333357.."
359         "..777533335777.."
360         "..735775577537.."
361         "..733357753337.."
362         "..733337733337.."
363         "..753337733357.."
364         "..277537735772.."
365         "....27777772...."
366         "......2772......"
367         "................"
368         "................"
369         },
370         {
371         "gfx/editlights/cubemapnoshadowlight", 16, 16,
372         "................"
373         "................"
374         "......2772......"
375         "....27722772...."
376         "..2772....2772.."
377         "..72........27.."
378         "..7772....2777.."
379         "..7.27722772.7.."
380         "..7...2772...7.."
381         "..7....77....7.."
382         "..72...77...27.."
383         "..2772.77.2772.."
384         "....27777772...."
385         "......2772......"
386         "................"
387         "................"
388         },
389         {NULL, 0, 0, NULL}
390 };
391
392 static rtexture_t *draw_generatepic(const char *name, qboolean quiet)
393 {
394         const embeddedpic_t *p;
395         for (p = embeddedpics;p->name;p++)
396                 if (!strcmp(name, p->name))
397                         return R_LoadTexture2D(drawtexturepool, p->name, p->width, p->height, (const unsigned char *)p->pixels, TEXTYPE_PALETTE, TEXF_ALPHA | TEXF_PRECACHE, palette_bgra_embeddedpic);
398         if (!strcmp(name, "gfx/conchars"))
399                 return draw_generateconchars();
400         if (!strcmp(name, "gfx/colorcontrol/ditherpattern"))
401                 return draw_generateditherpattern();
402         if (!quiet)
403                 Con_Printf("Draw_CachePic: failed to load %s\n", name);
404         return r_texture_notexture;
405 }
406
407
408 /*
409 ================
410 Draw_CachePic
411 ================
412 */
413 // FIXME: move this to client somehow
414 cachepic_t *Draw_CachePic_Flags(const char *path, unsigned int cachepicflags)
415 {
416         int crc, hashkey;
417         cachepic_t *pic;
418         int flags;
419         fs_offset_t lmpsize;
420         unsigned char *lmpdata;
421         char lmpname[MAX_QPATH];
422
423         // check whether the picture has already been cached
424         crc = CRC_Block((unsigned char *)path, strlen(path));
425         hashkey = ((crc >> 8) ^ crc) % CACHEPICHASHSIZE;
426         for (pic = cachepichash[hashkey];pic;pic = pic->chain)
427                 if (!strcmp (path, pic->name))
428                         return pic;
429
430         if (numcachepics == MAX_CACHED_PICS)
431         {
432                 Con_Printf ("Draw_CachePic: numcachepics == MAX_CACHED_PICS\n");
433                 // FIXME: support NULL in callers?
434                 return cachepics; // return the first one
435         }
436         pic = cachepics + (numcachepics++);
437         strlcpy (pic->name, path, sizeof(pic->name));
438         // link into list
439         pic->chain = cachepichash[hashkey];
440         cachepichash[hashkey] = pic;
441
442         // check whether it is an dynamic texture (if so, we can directly use its texture handler)
443         pic->tex = CL_GetDynTexture( path );
444         // if so, set the width/height, too
445         if( pic->tex ) {
446                 pic->width = R_TextureWidth(pic->tex);
447                 pic->height = R_TextureHeight(pic->tex);
448                 // we're done now (early-out)
449                 return pic;
450         }
451
452         flags = TEXF_ALPHA;
453         if (!(cachepicflags & CACHEPICFLAG_NOTPERSISTENT))
454                 flags |= TEXF_PRECACHE;
455         if (!(cachepicflags & CACHEPICFLAG_NOCLAMP))
456                 flags |= TEXF_CLAMP;
457         if (!(cachepicflags & CACHEPICFLAG_NOCOMPRESSION) && gl_texturecompression_2d.integer)
458                 flags |= TEXF_COMPRESS;
459
460         // load a high quality image from disk if possible
461         pic->tex = loadtextureimage(drawtexturepool, path, false, flags, true);
462         if (pic->tex == NULL && !strncmp(path, "gfx/", 4))
463         {
464                 // compatibility with older versions which did not require gfx/ prefix
465                 pic->tex = loadtextureimage(drawtexturepool, path + 4, false, flags, true);
466         }
467         // if a high quality image was loaded, set the pic's size to match it, just
468         // in case there's no low quality version to get the size from
469         if (pic->tex)
470         {
471                 pic->width = R_TextureWidth(pic->tex);
472                 pic->height = R_TextureHeight(pic->tex);
473         }
474
475         // now read the low quality version (wad or lmp file), and take the pic
476         // size from that even if we don't upload the texture, this way the pics
477         // show up the right size in the menu even if they were replaced with
478         // higher or lower resolution versions
479         dpsnprintf(lmpname, sizeof(lmpname), "%s.lmp", path);
480         if (!strncmp(path, "gfx/", 4) && (lmpdata = FS_LoadFile(lmpname, tempmempool, false, &lmpsize)))
481         {
482                 if (developer_loading.integer)
483                         Con_Printf("loading lump \"%s\"\n", path);
484
485                 if (lmpsize >= 9)
486                 {
487                         pic->width = lmpdata[0] + lmpdata[1] * 256 + lmpdata[2] * 65536 + lmpdata[3] * 16777216;
488                         pic->height = lmpdata[4] + lmpdata[5] * 256 + lmpdata[6] * 65536 + lmpdata[7] * 16777216;
489                         // if no high quality replacement image was found, upload the original low quality texture
490                         if (!pic->tex)
491                                 pic->tex = R_LoadTexture2D(drawtexturepool, path, pic->width, pic->height, lmpdata + 8, TEXTYPE_PALETTE, flags & ~TEXF_COMPRESS, palette_bgra_transparent);
492                 }
493                 Mem_Free(lmpdata);
494         }
495         else if ((lmpdata = W_GetLumpName (path + 4)))
496         {
497                 if (developer_loading.integer)
498                         Con_Printf("loading gfx.wad lump \"%s\"\n", path + 4);
499
500                 if (!strcmp(path, "gfx/conchars"))
501                 {
502                         // conchars is a raw image and with color 0 as transparent instead of 255
503                         pic->width = 128;
504                         pic->height = 128;
505                         // if no high quality replacement image was found, upload the original low quality texture
506                         if (!pic->tex)
507                                 pic->tex = R_LoadTexture2D(drawtexturepool, path, 128, 128, lmpdata, TEXTYPE_PALETTE, flags & ~TEXF_COMPRESS, palette_bgra_font);
508                 }
509                 else
510                 {
511                         pic->width = lmpdata[0] + lmpdata[1] * 256 + lmpdata[2] * 65536 + lmpdata[3] * 16777216;
512                         pic->height = lmpdata[4] + lmpdata[5] * 256 + lmpdata[6] * 65536 + lmpdata[7] * 16777216;
513                         // if no high quality replacement image was found, upload the original low quality texture
514                         if (!pic->tex)
515                                 pic->tex = R_LoadTexture2D(drawtexturepool, path, pic->width, pic->height, lmpdata + 8, TEXTYPE_PALETTE, flags & ~TEXF_COMPRESS, palette_bgra_transparent);
516                 }
517         }
518
519         // if it's not found on disk, generate an image
520         if (pic->tex == NULL)
521         {
522                 pic->tex = draw_generatepic(path, (cachepicflags & CACHEPICFLAG_QUIET) != 0);
523                 pic->width = R_TextureWidth(pic->tex);
524                 pic->height = R_TextureHeight(pic->tex);
525         }
526
527         return pic;
528 }
529
530 cachepic_t *Draw_CachePic (const char *path)
531 {
532         return Draw_CachePic_Flags (path, 0);
533 }
534
535 cachepic_t *Draw_NewPic(const char *picname, int width, int height, int alpha, unsigned char *pixels_bgra)
536 {
537         int crc, hashkey;
538         cachepic_t *pic;
539
540         crc = CRC_Block((unsigned char *)picname, strlen(picname));
541         hashkey = ((crc >> 8) ^ crc) % CACHEPICHASHSIZE;
542         for (pic = cachepichash[hashkey];pic;pic = pic->chain)
543                 if (!strcmp (picname, pic->name))
544                         break;
545
546         if (pic)
547         {
548                 if (pic->tex && pic->width == width && pic->height == height)
549                 {
550                         R_UpdateTexture(pic->tex, pixels_bgra, 0, 0, width, height);
551                         return pic;
552                 }
553         }
554         else
555         {
556                 if (pic == NULL)
557                 {
558                         if (numcachepics == MAX_CACHED_PICS)
559                         {
560                                 Con_Printf ("Draw_NewPic: numcachepics == MAX_CACHED_PICS\n");
561                                 // FIXME: support NULL in callers?
562                                 return cachepics; // return the first one
563                         }
564                         pic = cachepics + (numcachepics++);
565                         strlcpy (pic->name, picname, sizeof(pic->name));
566                         // link into list
567                         pic->chain = cachepichash[hashkey];
568                         cachepichash[hashkey] = pic;
569                 }
570         }
571
572         pic->width = width;
573         pic->height = height;
574         if (pic->tex)
575                 R_FreeTexture(pic->tex);
576         pic->tex = R_LoadTexture2D(drawtexturepool, picname, width, height, pixels_bgra, TEXTYPE_BGRA, alpha ? TEXF_ALPHA : 0, NULL);
577         return pic;
578 }
579
580 void Draw_FreePic(const char *picname)
581 {
582         int crc;
583         int hashkey;
584         cachepic_t *pic;
585         // this doesn't really free the pic, but does free it's texture
586         crc = CRC_Block((unsigned char *)picname, strlen(picname));
587         hashkey = ((crc >> 8) ^ crc) % CACHEPICHASHSIZE;
588         for (pic = cachepichash[hashkey];pic;pic = pic->chain)
589         {
590                 if (!strcmp (picname, pic->name) && pic->tex)
591                 {
592                         R_FreeTexture(pic->tex);
593                         pic->width = 0;
594                         pic->height = 0;
595                         return;
596                 }
597         }
598 }
599
600 extern int con_linewidth; // to force rewrapping
601 static void LoadFont(qboolean override, const char *name, dp_font_t *fnt)
602 {
603         int i;
604         float maxwidth, scale;
605         char widthfile[MAX_QPATH];
606         char *widthbuf;
607         fs_offset_t widthbufsize;
608
609         if(override || !fnt->texpath[0])
610                 strlcpy(fnt->texpath, name, sizeof(fnt->texpath));
611
612         if(drawtexturepool == NULL)
613                 return; // before gl_draw_start, so will be loaded later
614
615         fnt->tex = Draw_CachePic_Flags(fnt->texpath, CACHEPICFLAG_QUIET | CACHEPICFLAG_NOCOMPRESSION)->tex;
616         if(fnt->tex == r_texture_notexture)
617         {
618                 fnt->tex = Draw_CachePic_Flags("gfx/conchars", CACHEPICFLAG_NOCOMPRESSION)->tex;
619                 strlcpy(widthfile, "gfx/conchars.width", sizeof(widthfile));
620         }
621         else
622                 dpsnprintf(widthfile, sizeof(widthfile), "%s.width", fnt->texpath);
623
624         // unspecified width == 1 (base width)
625         for(i = 1; i < 256; ++i)
626                 fnt->width_of[i] = 1;
627         scale = 1;
628
629         // FIXME load "name.width", if it fails, fill all with 1
630         if((widthbuf = (char *) FS_LoadFile(widthfile, tempmempool, true, &widthbufsize)))
631         {
632                 float extraspacing = 0;
633                 const char *p = widthbuf;
634                 int ch = 0;
635
636                 while(ch < 256)
637                 {
638                         if(!COM_ParseToken_Simple(&p, false, false))
639                                 return;
640
641                         switch(*com_token)
642                         {
643                                 case '0':
644                                 case '1':
645                                 case '2':
646                                 case '3':
647                                 case '4':
648                                 case '5':
649                                 case '6':
650                                 case '7':
651                                 case '8':
652                                 case '9':
653                                 case '+':
654                                 case '-':
655                                 case '.':
656                                         fnt->width_of[ch++] = atof(com_token) + extraspacing;
657                                         break;
658                                 default:
659                                         if(!strcmp(com_token, "extraspacing"))
660                                         {
661                                                 if(!COM_ParseToken_Simple(&p, false, false))
662                                                         return;
663                                                 extraspacing = atof(com_token);
664                                         }
665                                         else if(!strcmp(com_token, "scale"))
666                                         {
667                                                 if(!COM_ParseToken_Simple(&p, false, false))
668                                                         return;
669                                                 scale = atof(com_token);
670                                         }
671                                         else
672                                         {
673                                                 Con_Printf("Warning: skipped unknown font property %s\n", com_token);
674                                                 if(!COM_ParseToken_Simple(&p, false, false))
675                                                         return;
676                                         }
677                                         break;
678                         }
679                 }
680
681                 Mem_Free(widthbuf);
682         }
683
684         maxwidth = fnt->width_of[1];
685         for(i = 2; i < 256; ++i)
686                 maxwidth = max(maxwidth, fnt->width_of[i]);
687         fnt->maxwidth = maxwidth;
688
689         // fix up maxwidth for overlap
690         fnt->maxwidth *= scale;
691         fnt->scale = scale;
692
693         if(fnt == FONT_CONSOLE)
694                 con_linewidth = -1; // rewrap console in next frame
695 }
696
697 static dp_font_t *FindFont(const char *title)
698 {
699         int i;
700         for(i = 0; i < MAX_FONTS; ++i)
701                 if(!strcmp(dp_fonts[i].title, title))
702                         return &dp_fonts[i];
703         return NULL;
704 }
705
706 static void LoadFont_f(void)
707 {
708         dp_font_t *f;
709         int i;
710         if(Cmd_Argc() < 2)
711         {
712                 Con_Printf("Available font commands:\n");
713                 for(i = 0; i < MAX_FONTS; ++i)
714                         Con_Printf("  loadfont %s gfx/tgafile\n", dp_fonts[i].title);
715                 return;
716         }
717         f = FindFont(Cmd_Argv(1));
718         if(f == NULL)
719         {
720                 Con_Printf("font function not found\n");
721                 return;
722         }
723         LoadFont(true, (Cmd_Argc() < 3) ? "gfx/conchars" : Cmd_Argv(2), f);
724 }
725
726 /*
727 ===============
728 Draw_Init
729 ===============
730 */
731 static void gl_draw_start(void)
732 {
733         int i;
734         drawtexturepool = R_AllocTexturePool();
735
736         numcachepics = 0;
737         memset(cachepichash, 0, sizeof(cachepichash));
738
739         for(i = 0; i < MAX_FONTS; ++i)
740                 LoadFont(false, va("gfx/font_%s", dp_fonts[i].title), &dp_fonts[i]);
741
742         // draw the loading screen so people have something to see in the newly opened window
743         SCR_UpdateLoadingScreen(true);
744 }
745
746 static void gl_draw_shutdown(void)
747 {
748         R_FreeTexturePool(&drawtexturepool);
749
750         numcachepics = 0;
751         memset(cachepichash, 0, sizeof(cachepichash));
752 }
753
754 static void gl_draw_newmap(void)
755 {
756 }
757
758 void GL_Draw_Init (void)
759 {
760         int i, j;
761         Cvar_RegisterVariable(&r_textshadow);
762         Cvar_RegisterVariable(&r_textbrightness);
763         Cvar_RegisterVariable(&r_textcontrast);
764         Cmd_AddCommand ("loadfont",LoadFont_f, "loadfont function tganame loads a font; example: loadfont console gfx/veramono; loadfont without arguments lists the available functions");
765         R_RegisterModule("GL_Draw", gl_draw_start, gl_draw_shutdown, gl_draw_newmap);
766
767         strlcpy(FONT_DEFAULT->title, "default", sizeof(FONT_DEFAULT->title));
768                 strlcpy(FONT_DEFAULT->texpath, "gfx/conchars", sizeof(FONT_DEFAULT->texpath));
769         strlcpy(FONT_CONSOLE->title, "console", sizeof(FONT_CONSOLE->title));
770         strlcpy(FONT_SBAR->title, "sbar", sizeof(FONT_SBAR->title));
771         strlcpy(FONT_NOTIFY->title, "notify", sizeof(FONT_NOTIFY->title));
772         strlcpy(FONT_CHAT->title, "chat", sizeof(FONT_CHAT->title));
773         strlcpy(FONT_CENTERPRINT->title, "centerprint", sizeof(FONT_CENTERPRINT->title));
774         strlcpy(FONT_INFOBAR->title, "infobar", sizeof(FONT_INFOBAR->title));
775         strlcpy(FONT_MENU->title, "menu", sizeof(FONT_MENU->title));
776         for(i = 0, j = 0; i < MAX_USERFONTS; ++i)
777                 if(!FONT_USER[i].title[0])
778                         dpsnprintf(FONT_USER[i].title, sizeof(FONT_USER[i].title), "user%d", j++);
779 }
780
781 void _DrawQ_Setup(void)
782 {
783         if (r_refdef.draw2dstage)
784                 return;
785         r_refdef.draw2dstage = true;
786         CHECKGLERROR
787         qglViewport(r_refdef.view.x, vid.height - (r_refdef.view.y + r_refdef.view.height), r_refdef.view.width, r_refdef.view.height);CHECKGLERROR
788         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
789         GL_SetupView_Mode_Ortho(0, 0, vid_conwidth.integer, vid_conheight.integer, -10, 100);
790         qglDepthFunc(GL_LEQUAL);CHECKGLERROR
791         qglDisable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
792         GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
793         R_Mesh_Matrix(&identitymatrix);
794
795         GL_DepthMask(true);
796         GL_DepthRange(0, 1);
797         GL_PolygonOffset(0, 0);
798         GL_DepthTest(false);
799         GL_Color(1,1,1,1);
800         GL_AlphaTest(false);
801         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
802
803         R_SetupGenericShader(true);
804 }
805
806 static void _DrawQ_ProcessDrawFlag(int flags)
807 {
808         _DrawQ_Setup();
809         CHECKGLERROR
810         if(flags == DRAWFLAG_ADDITIVE)
811                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
812         else if(flags == DRAWFLAG_MODULATE)
813                 GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
814         else if(flags == DRAWFLAG_2XMODULATE)
815                 GL_BlendFunc(GL_DST_COLOR,GL_SRC_COLOR);
816         else if(flags == DRAWFLAG_SCREEN)
817                 GL_BlendFunc(GL_ONE_MINUS_DST_COLOR,GL_ONE);
818         else
819                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
820 }
821
822 void DrawQ_Pic(float x, float y, cachepic_t *pic, float width, float height, float red, float green, float blue, float alpha, int flags)
823 {
824         float floats[20];
825
826         _DrawQ_ProcessDrawFlag(flags);
827         GL_Color(red, green, blue, alpha);
828
829         R_Mesh_VertexPointer(floats, 0, 0);
830         R_Mesh_ColorPointer(NULL, 0, 0);
831         R_Mesh_ResetTextureState();
832         R_SetupGenericShader(pic != NULL);
833         if (pic)
834         {
835                 if (width == 0)
836                         width = pic->width;
837                 if (height == 0)
838                         height = pic->height;
839                 R_Mesh_TexBind(0, R_GetTexture(pic->tex));
840                 R_Mesh_TexCoordPointer(0, 2, floats + 12, 0, 0);
841
842 #if 1
843                 floats[12] = 0.0f;floats[13] = 0.0f;
844                 floats[14] = 1.0f;floats[15] = 0.0f;
845                 floats[16] = 1.0f;floats[17] = 1.0f;
846                 floats[18] = 0.0f;floats[19] = 1.0f;
847 #else
848       // AK07: lets be texel correct on the corners
849       {
850          float horz_offset = 0.5f / pic->width;
851          float vert_offset = 0.5f / pic->height;
852
853                    floats[12] = 0.0f + horz_offset;floats[13] = 0.0f + vert_offset;
854                    floats[14] = 1.0f - horz_offset;floats[15] = 0.0f + vert_offset;
855                    floats[16] = 1.0f - horz_offset;floats[17] = 1.0f - vert_offset;
856                    floats[18] = 0.0f + horz_offset;floats[19] = 1.0f - vert_offset;
857       }
858 #endif
859         }
860
861         floats[2] = floats[5] = floats[8] = floats[11] = 0;
862         floats[0] = floats[9] = x;
863         floats[1] = floats[4] = y;
864         floats[3] = floats[6] = x + width;
865         floats[7] = floats[10] = y + height;
866
867         R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
868 }
869
870 void DrawQ_Fill(float x, float y, float width, float height, float red, float green, float blue, float alpha, int flags)
871 {
872         float floats[12];
873
874         _DrawQ_ProcessDrawFlag(flags);
875         GL_Color(red, green, blue, alpha);
876
877         R_Mesh_VertexPointer(floats, 0, 0);
878         R_Mesh_ColorPointer(NULL, 0, 0);
879         R_Mesh_ResetTextureState();
880         R_SetupGenericShader(false);
881
882         floats[2] = floats[5] = floats[8] = floats[11] = 0;
883         floats[0] = floats[9] = x;
884         floats[1] = floats[4] = y;
885         floats[3] = floats[6] = x + width;
886         floats[7] = floats[10] = y + height;
887
888         R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
889 }
890
891 // color tag printing
892 static const vec4_t string_colors[] =
893 {
894         // Quake3 colors
895         // LordHavoc: why on earth is cyan before magenta in Quake3?
896         // LordHavoc: note: Doom3 uses white for [0] and [7]
897         {0.0, 0.0, 0.0, 1.0}, // black
898         {1.0, 0.0, 0.0, 1.0}, // red
899         {0.0, 1.0, 0.0, 1.0}, // green
900         {1.0, 1.0, 0.0, 1.0}, // yellow
901         {0.0, 0.0, 1.0, 1.0}, // blue
902         {0.0, 1.0, 1.0, 1.0}, // cyan
903         {1.0, 0.0, 1.0, 1.0}, // magenta
904         {1.0, 1.0, 1.0, 1.0}, // white
905         // [515]'s BX_COLOREDTEXT extension
906         {1.0, 1.0, 1.0, 0.5}, // half transparent
907         {0.5, 0.5, 0.5, 1.0}  // half brightness
908         // Black's color table
909         //{1.0, 1.0, 1.0, 1.0},
910         //{1.0, 0.0, 0.0, 1.0},
911         //{0.0, 1.0, 0.0, 1.0},
912         //{0.0, 0.0, 1.0, 1.0},
913         //{1.0, 1.0, 0.0, 1.0},
914         //{0.0, 1.0, 1.0, 1.0},
915         //{1.0, 0.0, 1.0, 1.0},
916         //{0.1, 0.1, 0.1, 1.0}
917 };
918
919 #define STRING_COLORS_COUNT     (sizeof(string_colors) / sizeof(vec4_t))
920
921 static void DrawQ_GetTextColor(float color[4], int colorindex, float r, float g, float b, float a, qboolean shadow)
922 {
923         float C = r_textcontrast.value;
924         float B = r_textbrightness.value;
925         if (colorindex & 0x10000) // that bit means RGB color
926         {
927                 color[0] = ((colorindex >> 12) & 0xf) / 15.0;
928                 color[1] = ((colorindex >> 8) & 0xf) / 15.0;
929                 color[2] = ((colorindex >> 4) & 0xf) / 15.0;
930                 color[3] = (colorindex & 0xf) / 15.0;
931         }
932         else
933                 Vector4Copy(string_colors[colorindex], color);
934         Vector4Set(color, color[0] * r * C + B, color[1] * g * C + B, color[2] * b * C + B, color[3] * a);
935         if (shadow)
936         {
937                 float shadowalpha = (color[0]+color[1]+color[2]) * 0.8;
938                 Vector4Set(color, 0, 0, 0, color[3] * bound(0, shadowalpha, 1));
939         }
940 }
941
942 float DrawQ_TextWidth_Font_UntilWidth_TrackColors(const char *text, size_t *maxlen, int *outcolor, qboolean ignorecolorcodes, const dp_font_t *fnt, float maxwidth)
943 {
944         int num, colorindex = STRING_COLOR_DEFAULT;
945         size_t i;
946         float x = 0;
947         char ch;
948         int tempcolorindex;
949
950         if (*maxlen < 1)
951                 *maxlen = 1<<30;
952
953         if (!outcolor || *outcolor == -1)
954                 colorindex = STRING_COLOR_DEFAULT;
955         else
956                 colorindex = *outcolor;
957
958         maxwidth /= fnt->scale;
959
960         for (i = 0;i < *maxlen && text[i];i++)
961         {
962                 if (text[i] == ' ')
963                 {
964                         if(x + fnt->width_of[(int) ' '] > maxwidth)
965                                 break; // oops, can't draw this
966                         x += fnt->width_of[(int) ' '];
967                         continue;
968                 }
969                 if (text[i] == STRING_COLOR_TAG && !ignorecolorcodes && i + 1 < *maxlen)
970                 {
971                         ch = text[++i];
972             if (ch <= '9' && ch >= '0') // ^[0-9] found
973                         {
974                                 colorindex = ch - '0';
975                 continue;
976                         }
977                         else if (ch == STRING_COLOR_RGB_TAG_CHAR && i + 3 < *maxlen ) // ^x found
978                         {
979                                 // building colorindex...
980                                 ch = tolower(text[i+1]);
981                                 tempcolorindex = 0x10000; // binary: 1,0000,0000,0000,0000
982                                 if (ch <= '9' && ch >= '0') tempcolorindex |= (ch - '0') << 12;
983                                 else if (ch >= 'a' && ch <= 'f') tempcolorindex |= (ch - 87) << 12;
984                                 else tempcolorindex = 0;
985                                 if (tempcolorindex)
986                                 {
987                                         ch = tolower(text[i+2]);
988                                         if (ch <= '9' && ch >= '0') tempcolorindex |= (ch - '0') << 8;
989                                         else if (ch >= 'a' && ch <= 'f') tempcolorindex |= (ch - 87) << 8;
990                                         else tempcolorindex = 0;
991                                         if (tempcolorindex)
992                                         {
993                                                 ch = tolower(text[i+3]);
994                                                 if (ch <= '9' && ch >= '0') tempcolorindex |= (ch - '0') << 4;
995                                                 else if (ch >= 'a' && ch <= 'f') tempcolorindex |= (ch - 87) << 4;
996                                                 else tempcolorindex = 0;
997                                                 if (tempcolorindex)
998                                                 {
999                                                         colorindex = tempcolorindex | 0xf;
1000                                                         // ...done! now colorindex has rgba codes (1,rrrr,gggg,bbbb,aaaa)
1001                                                         i+=3;
1002                                                         continue;
1003                                                 }
1004                                         }
1005                                 }
1006                         }
1007                         else if (ch == STRING_COLOR_TAG) // ^^ found, ignore the first ^ and go to print the second
1008                                 i++;
1009                         i--;
1010                 }
1011                 num = (unsigned char) text[i];
1012                 if(x + fnt->width_of[num] > maxwidth)
1013                         break; // oops, can't draw this
1014                 x += fnt->width_of[num];
1015         }
1016
1017         *maxlen = i;
1018
1019         if (outcolor)
1020                 *outcolor = colorindex;
1021
1022         return x * fnt->scale;
1023 }
1024
1025 float DrawQ_String_Font(float startx, float starty, const char *text, size_t maxlen, float w, float h, float basered, float basegreen, float baseblue, float basealpha, int flags, int *outcolor, qboolean ignorecolorcodes, const dp_font_t *fnt)
1026 {
1027         int num, shadow, colorindex = STRING_COLOR_DEFAULT;
1028         size_t i;
1029         float x = startx, y, s, t, u, v, thisw;
1030         float *av, *at, *ac;
1031         float color[4];
1032         int batchcount;
1033         float vertex3f[QUADELEMENTS_MAXQUADS*4*3];
1034         float texcoord2f[QUADELEMENTS_MAXQUADS*4*2];
1035         float color4f[QUADELEMENTS_MAXQUADS*4*4];
1036         int ch;
1037         int tempcolorindex;
1038
1039         int tw, th;
1040         tw = R_TextureWidth(fnt->tex);
1041         th = R_TextureHeight(fnt->tex);
1042
1043         starty -= (fnt->scale - 1) * h * 0.5; // center
1044         w *= fnt->scale;
1045         h *= fnt->scale;
1046
1047         if (maxlen < 1)
1048                 maxlen = 1<<30;
1049
1050         _DrawQ_ProcessDrawFlag(flags);
1051
1052         R_Mesh_ColorPointer(color4f, 0, 0);
1053         R_Mesh_ResetTextureState();
1054         R_Mesh_TexBind(0, R_GetTexture(fnt->tex));
1055         R_Mesh_TexCoordPointer(0, 2, texcoord2f, 0, 0);
1056         R_Mesh_VertexPointer(vertex3f, 0, 0);
1057         R_SetupGenericShader(true);
1058
1059         ac = color4f;
1060         at = texcoord2f;
1061         av = vertex3f;
1062         batchcount = 0;
1063
1064         for (shadow = r_textshadow.value != 0 && basealpha > 0;shadow >= 0;shadow--)
1065         {
1066                 if (!outcolor || *outcolor == -1)
1067                         colorindex = STRING_COLOR_DEFAULT;
1068                 else
1069                         colorindex = *outcolor;
1070
1071                 DrawQ_GetTextColor(color, colorindex, basered, basegreen, baseblue, basealpha, shadow);
1072
1073                 x = startx;
1074                 y = starty;
1075                 if (shadow)
1076                 {
1077                         x += r_textshadow.value;
1078                         y += r_textshadow.value;
1079                 }
1080                 for (i = 0;i < maxlen && text[i];i++)
1081                 {
1082                         if (text[i] == ' ')
1083                         {
1084                                 x += fnt->width_of[(int) ' '] * w;
1085                                 continue;
1086                         }
1087                         if (text[i] == STRING_COLOR_TAG && !ignorecolorcodes && i + 1 < maxlen)
1088                         {
1089                                 ch = text[++i];
1090                                 if (ch <= '9' && ch >= '0') // ^[0-9] found
1091                                 {
1092                                         colorindex = ch - '0';
1093                                         DrawQ_GetTextColor(color, colorindex, basered, basegreen, baseblue, basealpha, shadow);
1094                                         continue;
1095                                 }
1096                                 else if (ch == STRING_COLOR_RGB_TAG_CHAR && i+3 < maxlen ) // ^x found
1097                                 {
1098                                         // building colorindex...
1099                                         ch = tolower(text[i+1]);
1100                                         tempcolorindex = 0x10000; // binary: 1,0000,0000,0000,0000
1101                                         if (ch <= '9' && ch >= '0') tempcolorindex |= (ch - '0') << 12;
1102                                         else if (ch >= 'a' && ch <= 'f') tempcolorindex |= (ch - 87) << 12;
1103                                         else tempcolorindex = 0;
1104                                         if (tempcolorindex)
1105                                         {
1106                                                 ch = tolower(text[i+2]);
1107                                                 if (ch <= '9' && ch >= '0') tempcolorindex |= (ch - '0') << 8;
1108                                                 else if (ch >= 'a' && ch <= 'f') tempcolorindex |= (ch - 87) << 8;
1109                                                 else tempcolorindex = 0;
1110                                                 if (tempcolorindex)
1111                                                 {
1112                                                         ch = tolower(text[i+3]);
1113                                                         if (ch <= '9' && ch >= '0') tempcolorindex |= (ch - '0') << 4;
1114                                                         else if (ch >= 'a' && ch <= 'f') tempcolorindex |= (ch - 87) << 4;
1115                                                         else tempcolorindex = 0;
1116                                                         if (tempcolorindex)
1117                                                         {
1118                                                                 colorindex = tempcolorindex | 0xf;
1119                                                                 // ...done! now colorindex has rgba codes (1,rrrr,gggg,bbbb,aaaa)
1120                                                                 //Con_Printf("^1colorindex:^7 %x\n", colorindex);
1121                                                                 DrawQ_GetTextColor(color, colorindex, basered, basegreen, baseblue, basealpha, shadow);
1122                                                                 i+=3;
1123                                                                 continue;
1124                                                         }
1125                                                 }
1126                                         }
1127                                 }
1128                                 else if (ch == STRING_COLOR_TAG)
1129                                         i++;
1130                                 i--;
1131                         }
1132                         num = (unsigned char) text[i];
1133                         thisw = fnt->width_of[num];
1134                         // FIXME make these smaller to just include the occupied part of the character for slightly faster rendering
1135                         s = (num & 15)*0.0625f + (0.5f / tw);
1136                         t = (num >> 4)*0.0625f + (0.5f / th);
1137                         u = 0.0625f * thisw - (1.0f / tw);
1138                         v = 0.0625f - (1.0f / th);
1139                         ac[ 0] = color[0];ac[ 1] = color[1];ac[ 2] = color[2];ac[ 3] = color[3];
1140                         ac[ 4] = color[0];ac[ 5] = color[1];ac[ 6] = color[2];ac[ 7] = color[3];
1141                         ac[ 8] = color[0];ac[ 9] = color[1];ac[10] = color[2];ac[11] = color[3];
1142                         ac[12] = color[0];ac[13] = color[1];ac[14] = color[2];ac[15] = color[3];
1143                         at[ 0] = s              ; at[ 1] = t    ;
1144                         at[ 2] = s+u    ; at[ 3] = t    ;
1145                         at[ 4] = s+u    ; at[ 5] = t+v  ;
1146                         at[ 6] = s              ; at[ 7] = t+v  ;
1147                         av[ 0] = x                      ; av[ 1] = y    ; av[ 2] = 10;
1148                         av[ 3] = x+w*thisw      ; av[ 4] = y    ; av[ 5] = 10;
1149                         av[ 6] = x+w*thisw      ; av[ 7] = y+h  ; av[ 8] = 10;
1150                         av[ 9] = x                      ; av[10] = y+h  ; av[11] = 10;
1151                         ac += 16;
1152                         at += 8;
1153                         av += 12;
1154                         batchcount++;
1155                         if (batchcount >= QUADELEMENTS_MAXQUADS)
1156                         {
1157                                 GL_LockArrays(0, batchcount * 4);
1158                                 R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, NULL, quadelements, 0, 0);
1159                                 GL_LockArrays(0, 0);
1160                                 batchcount = 0;
1161                                 ac = color4f;
1162                                 at = texcoord2f;
1163                                 av = vertex3f;
1164                         }
1165                         x += thisw * w;
1166                 }
1167         }
1168         if (batchcount > 0)
1169         {
1170                 GL_LockArrays(0, batchcount * 4);
1171                 R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, NULL, quadelements, 0, 0);
1172                 GL_LockArrays(0, 0);
1173         }
1174
1175         if (outcolor)
1176                 *outcolor = colorindex;
1177
1178         // note: this relies on the proper text (not shadow) being drawn last
1179         return x;
1180 }
1181
1182 float DrawQ_String(float startx, float starty, const char *text, size_t maxlen, float w, float h, float basered, float basegreen, float baseblue, float basealpha, int flags, int *outcolor, qboolean ignorecolorcodes)
1183 {
1184         return DrawQ_String_Font(startx, starty, text, maxlen, w, h, basered, basegreen, baseblue, basealpha, flags, outcolor, ignorecolorcodes, &dp_fonts[0]);
1185 }
1186
1187 float DrawQ_TextWidth_Font(const char *text, size_t maxlen, qboolean ignorecolorcodes, const dp_font_t *fnt)
1188 {
1189         return DrawQ_TextWidth_Font_UntilWidth(text, &maxlen, ignorecolorcodes, fnt, 1000000000);
1190 }
1191
1192 float DrawQ_TextWidth_Font_UntilWidth(const char *text, size_t *maxlen, qboolean ignorecolorcodes, const dp_font_t *fnt, float maxWidth)
1193 {
1194         return DrawQ_TextWidth_Font_UntilWidth_TrackColors(text, maxlen, NULL, ignorecolorcodes, fnt, maxWidth);
1195 }
1196
1197 #if 0
1198 // not used
1199 // no ^xrgb management
1200 static int DrawQ_BuildColoredText(char *output2c, size_t maxoutchars, const char *text, int maxreadchars, qboolean ignorecolorcodes, int *outcolor)
1201 {
1202         int color, numchars = 0;
1203         char *outputend2c = output2c + maxoutchars - 2;
1204         if (!outcolor || *outcolor == -1)
1205                 color = STRING_COLOR_DEFAULT;
1206         else
1207                 color = *outcolor;
1208         if (!maxreadchars)
1209                 maxreadchars = 1<<30;
1210         textend = text + maxreadchars;
1211         while (text != textend && *text)
1212         {
1213                 if (*text == STRING_COLOR_TAG && !ignorecolorcodes && text + 1 != textend)
1214                 {
1215                         if (text[1] == STRING_COLOR_TAG)
1216                                 text++;
1217                         else if (text[1] >= '0' && text[1] <= '9')
1218                         {
1219                                 color = text[1] - '0';
1220                                 text += 2;
1221                                 continue;
1222                         }
1223                 }
1224                 if (output2c >= outputend2c)
1225                         break;
1226                 *output2c++ = *text++;
1227                 *output2c++ = color;
1228                 numchars++;
1229         }
1230         output2c[0] = output2c[1] = 0;
1231         if (outcolor)
1232                 *outcolor = color;
1233         return numchars;
1234 }
1235 #endif
1236
1237 void DrawQ_SuperPic(float x, float y, cachepic_t *pic, float width, float height, float s1, float t1, float r1, float g1, float b1, float a1, float s2, float t2, float r2, float g2, float b2, float a2, float s3, float t3, float r3, float g3, float b3, float a3, float s4, float t4, float r4, float g4, float b4, float a4, int flags)
1238 {
1239         float floats[36];
1240
1241         _DrawQ_ProcessDrawFlag(flags);
1242
1243         R_Mesh_VertexPointer(floats, 0, 0);
1244         R_Mesh_ColorPointer(floats + 20, 0, 0);
1245         R_Mesh_ResetTextureState();
1246         R_SetupGenericShader(pic != NULL);
1247         if (pic)
1248         {
1249                 if (width == 0)
1250                         width = pic->width;
1251                 if (height == 0)
1252                         height = pic->height;
1253                 R_Mesh_TexBind(0, R_GetTexture(pic->tex));
1254                 R_Mesh_TexCoordPointer(0, 2, floats + 12, 0, 0);
1255                 floats[12] = s1;floats[13] = t1;
1256                 floats[14] = s2;floats[15] = t2;
1257                 floats[16] = s4;floats[17] = t4;
1258                 floats[18] = s3;floats[19] = t3;
1259         }
1260
1261         floats[2] = floats[5] = floats[8] = floats[11] = 0;
1262         floats[0] = floats[9] = x;
1263         floats[1] = floats[4] = y;
1264         floats[3] = floats[6] = x + width;
1265         floats[7] = floats[10] = y + height;
1266         floats[20] = r1;floats[21] = g1;floats[22] = b1;floats[23] = a1;
1267         floats[24] = r2;floats[25] = g2;floats[26] = b2;floats[27] = a2;
1268         floats[28] = r4;floats[29] = g4;floats[30] = b4;floats[31] = a4;
1269         floats[32] = r3;floats[33] = g3;floats[34] = b3;floats[35] = a3;
1270
1271         R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
1272 }
1273
1274 void DrawQ_Mesh (drawqueuemesh_t *mesh, int flags)
1275 {
1276         _DrawQ_ProcessDrawFlag(flags);
1277
1278         R_Mesh_VertexPointer(mesh->data_vertex3f, 0, 0);
1279         R_Mesh_ColorPointer(mesh->data_color4f, 0, 0);
1280         R_Mesh_ResetTextureState();
1281         R_Mesh_TexBind(0, R_GetTexture(mesh->texture));
1282         R_Mesh_TexCoordPointer(0, 2, mesh->data_texcoord2f, 0, 0);
1283         R_SetupGenericShader(mesh->texture != NULL);
1284
1285         GL_LockArrays(0, mesh->num_vertices);
1286         R_Mesh_Draw(0, mesh->num_vertices, 0, mesh->num_triangles, NULL, mesh->data_element3s, 0, 0);
1287         GL_LockArrays(0, 0);
1288 }
1289
1290 void DrawQ_LineLoop (drawqueuemesh_t *mesh, int flags)
1291 {
1292         int num;
1293
1294         _DrawQ_ProcessDrawFlag(flags);
1295
1296         GL_Color(1,1,1,1);
1297         CHECKGLERROR
1298         qglBegin(GL_LINE_LOOP);
1299         for (num = 0;num < mesh->num_vertices;num++)
1300         {
1301                 if (mesh->data_color4f)
1302                         GL_Color(mesh->data_color4f[num*4+0], mesh->data_color4f[num*4+1], mesh->data_color4f[num*4+2], mesh->data_color4f[num*4+3]);
1303                 qglVertex2f(mesh->data_vertex3f[num*3+0], mesh->data_vertex3f[num*3+1]);
1304         }
1305         qglEnd();
1306         CHECKGLERROR
1307 }
1308
1309 //[515]: this is old, delete
1310 void DrawQ_Line (float width, float x1, float y1, float x2, float y2, float r, float g, float b, float alpha, int flags)
1311 {
1312         _DrawQ_ProcessDrawFlag(flags);
1313
1314         R_SetupGenericShader(false);
1315
1316         CHECKGLERROR
1317         qglLineWidth(width);CHECKGLERROR
1318
1319         GL_Color(r,g,b,alpha);
1320         CHECKGLERROR
1321         qglBegin(GL_LINES);
1322         qglVertex2f(x1, y1);
1323         qglVertex2f(x2, y2);
1324         qglEnd();
1325         CHECKGLERROR
1326 }
1327
1328 void DrawQ_SetClipArea(float x, float y, float width, float height)
1329 {
1330         _DrawQ_Setup();
1331
1332         // We have to convert the con coords into real coords
1333         // OGL uses top to bottom
1334         GL_Scissor((int)(x * ((float)vid.width / vid_conwidth.integer)), (int)(y * ((float) vid.height / vid_conheight.integer)), (int)(width * ((float)vid.width / vid_conwidth.integer)), (int)(height * ((float)vid.height / vid_conheight.integer)));
1335
1336         GL_ScissorTest(true);
1337 }
1338
1339 void DrawQ_ResetClipArea(void)
1340 {
1341         _DrawQ_Setup();
1342         GL_ScissorTest(false);
1343 }
1344
1345 void DrawQ_Finish(void)
1346 {
1347         r_refdef.draw2dstage = false;
1348 }
1349
1350 static float blendvertex3f[9] = {-5000, -5000, 10, 10000, -5000, 10, -5000, 10000, 10};
1351 void R_DrawGamma(void)
1352 {
1353         float c[4];
1354         if (!vid_usinghwgamma && !(r_glsl.integer && v_glslgamma.integer))
1355         {
1356                 // all the blends ignore depth
1357                 R_Mesh_VertexPointer(blendvertex3f, 0, 0);
1358                 R_Mesh_ColorPointer(NULL, 0, 0);
1359                 R_Mesh_ResetTextureState();
1360                 R_SetupGenericShader(false);
1361                 GL_DepthMask(true);
1362                 GL_DepthRange(0, 1);
1363                 GL_PolygonOffset(0, 0);
1364                 GL_DepthTest(false);
1365                 if (v_color_enable.integer)
1366                 {
1367                         c[0] = v_color_white_r.value;
1368                         c[1] = v_color_white_g.value;
1369                         c[2] = v_color_white_b.value;
1370                 }
1371                 else
1372                         c[0] = c[1] = c[2] = v_contrast.value;
1373                 if (c[0] >= 1.01f || c[1] >= 1.01f || c[2] >= 1.01f)
1374                 {
1375                         GL_BlendFunc(GL_DST_COLOR, GL_ONE);
1376                         while (c[0] >= 1.01f || c[1] >= 1.01f || c[2] >= 1.01f)
1377                         {
1378                                 GL_Color(bound(0, c[0] - 1, 1), bound(0, c[1] - 1, 1), bound(0, c[2] - 1, 1), 1);
1379                                 R_Mesh_Draw(0, 3, 0, 1, NULL, polygonelements, 0, 0);
1380                                 VectorScale(c, 0.5, c);
1381                         }
1382                 }
1383                 if (v_color_enable.integer)
1384                 {
1385                         c[0] = v_color_black_r.value;
1386                         c[1] = v_color_black_g.value;
1387                         c[2] = v_color_black_b.value;
1388                 }
1389                 else
1390                         c[0] = c[1] = c[2] = v_brightness.value;
1391                 if (c[0] >= 0.01f || c[1] >= 0.01f || c[2] >= 0.01f)
1392                 {
1393                         GL_BlendFunc(GL_ONE, GL_ONE);
1394                         GL_Color(c[0], c[1], c[2], 1);
1395                         R_Mesh_Draw(0, 3, 0, 1, NULL, polygonelements, 0, 0);
1396                 }
1397         }
1398 }
1399