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