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