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