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