]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - gl_draw.c
more redundant suffix elimination
[xonotic/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 #include "ft2.h"
29 #include "ft2_fontdefs.h"
30
31 dp_font_t dp_fonts[MAX_FONTS] = {{0}};
32
33 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)"};
34 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)"};
35 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)"};
36
37 extern cvar_t v_glslgamma;
38
39 //=============================================================================
40 /* Support Routines */
41
42 #define FONT_FILESIZE 13468
43 static cachepic_t *cachepichash[CACHEPICHASHSIZE];
44 static cachepic_t cachepics[MAX_CACHED_PICS];
45 static int numcachepics;
46
47 static rtexturepool_t *drawtexturepool;
48
49 static const unsigned char concharimage[FONT_FILESIZE] =
50 {
51 #include "lhfont.h"
52 };
53
54 static rtexture_t *draw_generateconchars(void)
55 {
56         int i;
57         unsigned char *data;
58         double random;
59         rtexture_t *tex;
60
61         data = LoadTGA_BGRA (concharimage, FONT_FILESIZE);
62 // Gold numbers
63         for (i = 0;i < 8192;i++)
64         {
65                 random = lhrandom (0.0,1.0);
66                 data[i*4+3] = data[i*4+0];
67                 data[i*4+2] = 83 + (unsigned char)(random * 64);
68                 data[i*4+1] = 71 + (unsigned char)(random * 32);
69                 data[i*4+0] = 23 + (unsigned char)(random * 16);
70         }
71 // White chars
72         for (i = 8192;i < 32768;i++)
73         {
74                 random = lhrandom (0.0,1.0);
75                 data[i*4+3] = data[i*4+0];
76                 data[i*4+2] = 95 + (unsigned char)(random * 64);
77                 data[i*4+1] = 95 + (unsigned char)(random * 64);
78                 data[i*4+0] = 95 + (unsigned char)(random * 64);
79         }
80 // Gold numbers
81         for (i = 32768;i < 40960;i++)
82         {
83                 random = lhrandom (0.0,1.0);
84                 data[i*4+3] = data[i*4+0];
85                 data[i*4+2] = 83 + (unsigned char)(random * 64);
86                 data[i*4+1] = 71 + (unsigned char)(random * 32);
87                 data[i*4+0] = 23 + (unsigned char)(random * 16);
88         }
89 // Red chars
90         for (i = 40960;i < 65536;i++)
91         {
92                 random = lhrandom (0.0,1.0);
93                 data[i*4+3] = data[i*4+0];
94                 data[i*4+2] = 96 + (unsigned char)(random * 64);
95                 data[i*4+1] = 43 + (unsigned char)(random * 32);
96                 data[i*4+0] = 27 + (unsigned char)(random * 32);
97         }
98
99 #if 0
100         Image_WriteTGABGRA ("gfx/generated_conchars.tga", 256, 256, data);
101 #endif
102
103         tex = R_LoadTexture2D(drawtexturepool, "conchars", 256, 256, data, TEXTYPE_BGRA, TEXF_ALPHA, NULL);
104         Mem_Free(data);
105         return tex;
106 }
107
108 static rtexture_t *draw_generateditherpattern(void)
109 {
110         int x, y;
111         unsigned char pixels[8][8];
112         for (y = 0;y < 8;y++)
113                 for (x = 0;x < 8;x++)
114                         pixels[y][x] = ((x^y) & 4) ? 254 : 0;
115         return R_LoadTexture2D(drawtexturepool, "ditherpattern", 8, 8, pixels[0], TEXTYPE_PALETTE, TEXF_FORCENEAREST, palette_bgra_transparent);
116 }
117
118 typedef struct embeddedpic_s
119 {
120         const char *name;
121         int width;
122         int height;
123         const char *pixels;
124 }
125 embeddedpic_t;
126
127 static const embeddedpic_t embeddedpics[] =
128 {
129         {
130         "gfx/prydoncursor001", 16, 16,
131         "477777774......."
132         "77.....6........"
133         "7.....6........."
134         "7....6.........."
135         "7.....6........."
136         "7..6...6........"
137         "7.6.6...6......."
138         "76...6...6......"
139         "4.....6.6......."
140         ".......6........"
141         "................"
142         "................"
143         "................"
144         "................"
145         "................"
146         "................"
147         },
148         {
149         "ui/mousepointer", 16, 16,
150         "477777774......."
151         "77.....6........"
152         "7.....6........."
153         "7....6.........."
154         "7.....6........."
155         "7..6...6........"
156         "7.6.6...6......."
157         "76...6...6......"
158         "4.....6.6......."
159         ".......6........"
160         "................"
161         "................"
162         "................"
163         "................"
164         "................"
165         "................"
166         },
167         {
168         "gfx/crosshair1", 16, 16,
169         "................"
170         "................"
171         "................"
172         "...33......33..."
173         "...355....553..."
174         "....577..775...."
175         ".....77..77....."
176         "................"
177         "................"
178         ".....77..77....."
179         "....577..775...."
180         "...355....553..."
181         "...33......33..."
182         "................"
183         "................"
184         "................"
185         },
186         {
187         "gfx/crosshair2", 16, 16,
188         "................"
189         "................"
190         "................"
191         "...3........3..."
192         "....5......5...."
193         ".....7....7....."
194         "......7..7......"
195         "................"
196         "................"
197         "......7..7......"
198         ".....7....7....."
199         "....5......5...."
200         "...3........3..."
201         "................"
202         "................"
203         "................"
204         },
205         {
206         "gfx/crosshair3", 16, 16,
207         "................"
208         ".......77......."
209         ".......77......."
210         "................"
211         "................"
212         ".......44......."
213         ".......44......."
214         ".77..44..44..77."
215         ".77..44..44..77."
216         ".......44......."
217         ".......44......."
218         "................"
219         "................"
220         ".......77......."
221         ".......77......."
222         "................"
223         },
224         {
225         "gfx/crosshair4", 16, 16,
226         "................"
227         "................"
228         "................"
229         "................"
230         "................"
231         "................"
232         "................"
233         "................"
234         "........7777777."
235         "........752....."
236         "........72......"
237         "........7......."
238         "........7......."
239         "........7......."
240         "........7......."
241         "................"
242         },
243         {
244         "gfx/crosshair5", 8, 8,
245         "........"
246         "........"
247         "....7..."
248         "........"
249         "..7.7.7."
250         "........"
251         "....7..."
252         "........"
253         },
254         {
255         "gfx/crosshair6", 2, 2,
256         "77"
257         "77"
258         },
259         {
260         "gfx/crosshair7", 16, 16,
261         "................"
262         ".3............3."
263         "..5...2332...5.."
264         "...7.3....3.7..."
265         "....7......7...."
266         "...3.7....7.3..."
267         "..2...7..7...2.."
268         "..3..........3.."
269         "..3..........3.."
270         "..2...7..7...2.."
271         "...3.7....7.3..."
272         "....7......7...."
273         "...7.3....3.7..."
274         "..5...2332...5.."
275         ".3............3."
276         "................"
277         },
278         {NULL, 0, 0, NULL}
279 };
280
281 static rtexture_t *draw_generatepic(const char *name, qboolean quiet)
282 {
283         const embeddedpic_t *p;
284         for (p = embeddedpics;p->name;p++)
285                 if (!strcmp(name, p->name))
286                         return R_LoadTexture2D(drawtexturepool, p->name, p->width, p->height, (const unsigned char *)p->pixels, TEXTYPE_PALETTE, TEXF_ALPHA, palette_bgra_embeddedpic);
287         if (!strcmp(name, "gfx/conchars"))
288                 return draw_generateconchars();
289         if (!strcmp(name, "gfx/colorcontrol/ditherpattern"))
290                 return draw_generateditherpattern();
291         if (!quiet)
292                 Con_DPrintf("Draw_CachePic: failed to load %s\n", name);
293         return r_texture_notexture;
294 }
295
296
297 /*
298 ================
299 Draw_CachePic
300 ================
301 */
302 // FIXME: move this to client somehow
303 cachepic_t *Draw_CachePic_Flags(const char *path, unsigned int cachepicflags)
304 {
305         int crc, hashkey;
306         unsigned char *pixels;
307         cachepic_t *pic;
308         fs_offset_t lmpsize;
309         unsigned char *lmpdata;
310         char lmpname[MAX_QPATH];
311
312         // check whether the picture has already been cached
313         crc = CRC_Block((unsigned char *)path, strlen(path));
314         hashkey = ((crc >> 8) ^ crc) % CACHEPICHASHSIZE;
315         for (pic = cachepichash[hashkey];pic;pic = pic->chain)
316                 if (!strcmp (path, pic->name))
317                         return pic;
318
319         if (numcachepics == MAX_CACHED_PICS)
320         {
321                 Con_Printf ("Draw_CachePic: numcachepics == MAX_CACHED_PICS\n");
322                 // FIXME: support NULL in callers?
323                 return cachepics; // return the first one
324         }
325         pic = cachepics + (numcachepics++);
326         strlcpy (pic->name, path, sizeof(pic->name));
327         // link into list
328         pic->chain = cachepichash[hashkey];
329         cachepichash[hashkey] = pic;
330
331         // check whether it is an dynamic texture (if so, we can directly use its texture handler)
332         pic->tex = CL_GetDynTexture( path );
333         // if so, set the width/height, too
334         if( pic->tex ) {
335                 pic->width = R_TextureWidth(pic->tex);
336                 pic->height = R_TextureHeight(pic->tex);
337                 // we're done now (early-out)
338                 return pic;
339         }
340
341         pic->texflags = TEXF_ALPHA;
342         if (!(cachepicflags & CACHEPICFLAG_NOCLAMP))
343                 pic->texflags |= TEXF_CLAMP;
344         if (!(cachepicflags & CACHEPICFLAG_NOCOMPRESSION) && gl_texturecompression_2d.integer)
345                 pic->texflags |= TEXF_COMPRESS;
346
347         pic->autoload = (cachepicflags & CACHEPICFLAG_NOTPERSISTENT);
348
349         // load a high quality image from disk if possible
350         pixels = loadimagepixelsbgra(path, false, true);
351         if (pixels == NULL && !strncmp(path, "gfx/", 4))
352                 pixels = loadimagepixelsbgra(path+4, false, true);
353         if (pixels)
354         {
355                 pic->width = image_width;
356                 pic->height = image_height;
357                 if (!pic->autoload)
358                         pic->tex = R_LoadTexture2D(drawtexturepool, path, image_width, image_height, pixels, TEXTYPE_BGRA, pic->texflags, NULL);
359         }
360         else
361         {
362                 pic->autoload = false;
363                 // never compress the fallback images
364                 pic->texflags &= ~TEXF_COMPRESS;
365         }
366
367         // now read the low quality version (wad or lmp file), and take the pic
368         // size from that even if we don't upload the texture, this way the pics
369         // show up the right size in the menu even if they were replaced with
370         // higher or lower resolution versions
371         dpsnprintf(lmpname, sizeof(lmpname), "%s.lmp", path);
372         if (!strncmp(path, "gfx/", 4) && (lmpdata = FS_LoadFile(lmpname, tempmempool, false, &lmpsize)))
373         {
374                 if (developer_loading.integer)
375                         Con_Printf("loading lump \"%s\"\n", path);
376
377                 if (lmpsize >= 9)
378                 {
379                         pic->width = lmpdata[0] + lmpdata[1] * 256 + lmpdata[2] * 65536 + lmpdata[3] * 16777216;
380                         pic->height = lmpdata[4] + lmpdata[5] * 256 + lmpdata[6] * 65536 + lmpdata[7] * 16777216;
381                         // if no high quality replacement image was found, upload the original low quality texture
382                         if (!pixels)
383                                 pic->tex = R_LoadTexture2D(drawtexturepool, path, pic->width, pic->height, lmpdata + 8, TEXTYPE_PALETTE, pic->texflags, palette_bgra_transparent);
384                 }
385                 Mem_Free(lmpdata);
386         }
387         else if ((lmpdata = W_GetLumpName (path + 4)))
388         {
389                 if (developer_loading.integer)
390                         Con_Printf("loading gfx.wad lump \"%s\"\n", path + 4);
391
392                 if (!strcmp(path, "gfx/conchars"))
393                 {
394                         // conchars is a raw image and with color 0 as transparent instead of 255
395                         pic->width = 128;
396                         pic->height = 128;
397                         // if no high quality replacement image was found, upload the original low quality texture
398                         if (!pixels)
399                                 pic->tex = R_LoadTexture2D(drawtexturepool, path, 128, 128, lmpdata, TEXTYPE_PALETTE, pic->texflags, palette_bgra_font);
400                 }
401                 else
402                 {
403                         pic->width = lmpdata[0] + lmpdata[1] * 256 + lmpdata[2] * 65536 + lmpdata[3] * 16777216;
404                         pic->height = lmpdata[4] + lmpdata[5] * 256 + lmpdata[6] * 65536 + lmpdata[7] * 16777216;
405                         // if no high quality replacement image was found, upload the original low quality texture
406                         if (!pixels)
407                                 pic->tex = R_LoadTexture2D(drawtexturepool, path, pic->width, pic->height, lmpdata + 8, TEXTYPE_PALETTE, pic->texflags, palette_bgra_transparent);
408                 }
409         }
410
411         if (pixels)
412         {
413                 Mem_Free(pixels);
414                 pixels = NULL;
415         }
416         else if (pic->tex == NULL)
417         {
418                 // if it's not found on disk, generate an image
419                 pic->tex = draw_generatepic(path, (cachepicflags & CACHEPICFLAG_QUIET) != 0);
420                 pic->width = R_TextureWidth(pic->tex);
421                 pic->height = R_TextureHeight(pic->tex);
422         }
423
424         return pic;
425 }
426
427 cachepic_t *Draw_CachePic (const char *path)
428 {
429         return Draw_CachePic_Flags (path, 0);
430 }
431
432 int draw_frame = 1;
433
434 rtexture_t *Draw_GetPicTexture(cachepic_t *pic)
435 {
436         if (pic->autoload && !pic->tex)
437         {
438                 pic->tex = loadtextureimage(drawtexturepool, pic->name, false, pic->texflags, true);
439                 if (pic->tex == NULL && !strncmp(pic->name, "gfx/", 4))
440                         pic->tex = loadtextureimage(drawtexturepool, pic->name+4, false, pic->texflags, true);
441                 if (pic->tex == NULL)
442                         pic->tex = draw_generatepic(pic->name, true);
443         }
444         pic->lastusedframe = draw_frame;
445         return pic->tex;
446 }
447
448 void Draw_Frame(void)
449 {
450         int i;
451         cachepic_t *pic;
452         static double nextpurgetime;
453         int purgeframe;
454         if (nextpurgetime > realtime)
455                 return;
456         nextpurgetime = realtime + 0.05;
457         purgeframe = draw_frame - 1;
458         for (i = 0, pic = cachepics;i < numcachepics;i++, pic++)
459         {
460                 if (pic->autoload && pic->tex && pic->lastusedframe < draw_frame)
461                 {
462                         R_FreeTexture(pic->tex);
463                         pic->tex = NULL;
464                 }
465         }
466         draw_frame++;
467 }
468
469 cachepic_t *Draw_NewPic(const char *picname, int width, int height, int alpha, unsigned char *pixels_bgra)
470 {
471         int crc, hashkey;
472         cachepic_t *pic;
473
474         crc = CRC_Block((unsigned char *)picname, strlen(picname));
475         hashkey = ((crc >> 8) ^ crc) % CACHEPICHASHSIZE;
476         for (pic = cachepichash[hashkey];pic;pic = pic->chain)
477                 if (!strcmp (picname, pic->name))
478                         break;
479
480         if (pic)
481         {
482                 if (pic->tex && pic->width == width && pic->height == height)
483                 {
484                         R_UpdateTexture(pic->tex, pixels_bgra, 0, 0, width, height);
485                         return pic;
486                 }
487         }
488         else
489         {
490                 if (pic == NULL)
491                 {
492                         if (numcachepics == MAX_CACHED_PICS)
493                         {
494                                 Con_Printf ("Draw_NewPic: numcachepics == MAX_CACHED_PICS\n");
495                                 // FIXME: support NULL in callers?
496                                 return cachepics; // return the first one
497                         }
498                         pic = cachepics + (numcachepics++);
499                         strlcpy (pic->name, picname, sizeof(pic->name));
500                         // link into list
501                         pic->chain = cachepichash[hashkey];
502                         cachepichash[hashkey] = pic;
503                 }
504         }
505
506         pic->width = width;
507         pic->height = height;
508         if (pic->tex)
509                 R_FreeTexture(pic->tex);
510         pic->tex = R_LoadTexture2D(drawtexturepool, picname, width, height, pixels_bgra, TEXTYPE_BGRA, (alpha ? TEXF_ALPHA : 0) | TEXF_ALLOWUPDATES, NULL);
511         return pic;
512 }
513
514 void Draw_FreePic(const char *picname)
515 {
516         int crc;
517         int hashkey;
518         cachepic_t *pic;
519         // this doesn't really free the pic, but does free it's texture
520         crc = CRC_Block((unsigned char *)picname, strlen(picname));
521         hashkey = ((crc >> 8) ^ crc) % CACHEPICHASHSIZE;
522         for (pic = cachepichash[hashkey];pic;pic = pic->chain)
523         {
524                 if (!strcmp (picname, pic->name) && pic->tex)
525                 {
526                         R_FreeTexture(pic->tex);
527                         pic->tex = NULL;
528                         pic->width = 0;
529                         pic->height = 0;
530                         return;
531                 }
532         }
533 }
534
535 extern int con_linewidth; // to force rewrapping
536 static void LoadFont(qboolean override, const char *name, dp_font_t *fnt)
537 {
538         int i;
539         float maxwidth, scale;
540         char widthfile[MAX_QPATH];
541         char *widthbuf;
542         fs_offset_t widthbufsize;
543
544         if(override || !fnt->texpath[0])
545                 strlcpy(fnt->texpath, name, sizeof(fnt->texpath));
546
547         if(drawtexturepool == NULL)
548                 return; // before gl_draw_start, so will be loaded later
549
550         if(fnt->ft2)
551         {
552                 // clear freetype font
553                 Font_UnloadFont(fnt->ft2);
554                 Mem_Free(fnt->ft2);
555                 fnt->ft2 = NULL;
556         }
557
558         if(fnt->req_face != -1)
559         {
560                 if(!Font_LoadFont(fnt->texpath, fnt))
561                         Con_DPrintf("Failed to load font-file for '%s', it will not support as many characters.\n", fnt->texpath);
562         }
563
564         fnt->tex = Draw_CachePic_Flags(fnt->texpath, CACHEPICFLAG_QUIET | CACHEPICFLAG_NOCOMPRESSION)->tex;
565         if(fnt->tex == r_texture_notexture)
566         {
567                 for (i = 0; i < MAX_FONT_FALLBACKS; ++i)
568                 {
569                         if (!fnt->fallbacks[i][0])
570                                 break;
571                         fnt->tex = Draw_CachePic_Flags(fnt->fallbacks[i], CACHEPICFLAG_QUIET | CACHEPICFLAG_NOCOMPRESSION)->tex;
572                         if(fnt->tex != r_texture_notexture)
573                                 break;
574                 }
575                 if(fnt->tex == r_texture_notexture)
576                 {
577                         fnt->tex = Draw_CachePic_Flags("gfx/conchars", CACHEPICFLAG_NOCOMPRESSION)->tex;
578                         strlcpy(widthfile, "gfx/conchars.width", sizeof(widthfile));
579                 }
580                 else
581                         dpsnprintf(widthfile, sizeof(widthfile), "%s.width", fnt->fallbacks[i]);
582         }
583         else
584                 dpsnprintf(widthfile, sizeof(widthfile), "%s.width", fnt->texpath);
585
586         // unspecified width == 1 (base width)
587         for(i = 1; i < 256; ++i)
588                 fnt->width_of[i] = 1;
589         scale = 1;
590
591         // FIXME load "name.width", if it fails, fill all with 1
592         if((widthbuf = (char *) FS_LoadFile(widthfile, tempmempool, true, &widthbufsize)))
593         {
594                 float extraspacing = 0;
595                 const char *p = widthbuf;
596                 int ch = 0;
597
598                 while(ch < 256)
599                 {
600                         if(!COM_ParseToken_Simple(&p, false, false))
601                                 return;
602
603                         switch(*com_token)
604                         {
605                                 case '0':
606                                 case '1':
607                                 case '2':
608                                 case '3':
609                                 case '4':
610                                 case '5':
611                                 case '6':
612                                 case '7':
613                                 case '8':
614                                 case '9':
615                                 case '+':
616                                 case '-':
617                                 case '.':
618                                         fnt->width_of[ch++] = atof(com_token) + extraspacing;
619                                         break;
620                                 default:
621                                         if(!strcmp(com_token, "extraspacing"))
622                                         {
623                                                 if(!COM_ParseToken_Simple(&p, false, false))
624                                                         return;
625                                                 extraspacing = atof(com_token);
626                                         }
627                                         else if(!strcmp(com_token, "scale"))
628                                         {
629                                                 if(!COM_ParseToken_Simple(&p, false, false))
630                                                         return;
631                                                 scale = atof(com_token);
632                                         }
633                                         else
634                                         {
635                                                 Con_Printf("Warning: skipped unknown font property %s\n", com_token);
636                                                 if(!COM_ParseToken_Simple(&p, false, false))
637                                                         return;
638                                         }
639                                         break;
640                         }
641                 }
642
643                 Mem_Free(widthbuf);
644         }
645
646         maxwidth = fnt->width_of[1];
647         for(i = 2; i < 256; ++i)
648                 maxwidth = max(maxwidth, fnt->width_of[i]);
649         fnt->maxwidth = maxwidth;
650
651         // fix up maxwidth for overlap
652         fnt->maxwidth *= scale;
653         fnt->scale = scale;
654
655         if(fnt == FONT_CONSOLE)
656                 con_linewidth = -1; // rewrap console in next frame
657 }
658
659 static dp_font_t *FindFont(const char *title)
660 {
661         int i;
662         for(i = 0; i < MAX_FONTS; ++i)
663                 if(!strcmp(dp_fonts[i].title, title))
664                         return &dp_fonts[i];
665         return NULL;
666 }
667
668 static float snap_to_pixel_x(float x, float roundUpAt)
669 {
670         float pixelpos = x * vid.width / vid_conwidth.value;
671         int snap = (int) pixelpos;
672         if (pixelpos - snap >= roundUpAt) ++snap;
673         return ((float)snap * vid_conwidth.value / vid.width);
674         /*
675         x = (int)(x * vid.width / vid_conwidth.value);
676         x = (x * vid_conwidth.value / vid.width);
677         return x;
678         */
679 }
680
681 static float snap_to_pixel_y(float y, float roundUpAt)
682 {
683         float pixelpos = y * vid.height / vid_conheight.value;
684         int snap = (int) pixelpos;
685         if (pixelpos - snap > roundUpAt) ++snap;
686         return ((float)snap * vid_conheight.value / vid.height);
687         /*
688         y = (int)(y * vid.height / vid_conheight.value);
689         y = (y * vid_conheight.value / vid.height);
690         return y;
691         */
692 }
693
694 static void LoadFont_f(void)
695 {
696         dp_font_t *f;
697         int i;
698         const char *filelist, *c, *cm;
699         float sz;
700         char mainfont[MAX_QPATH];
701
702         if(Cmd_Argc() < 2)
703         {
704                 Con_Printf("Available font commands:\n");
705                 for(i = 0; i < MAX_FONTS; ++i)
706                         Con_Printf("  loadfont %s gfx/tgafile[...] [sizes...]\n", dp_fonts[i].title);
707                 Con_Printf("A font can simply be gfx/tgafile, or alternatively you\n"
708                            "can specify multiple fonts and faces\n"
709                            "Like this: gfx/vera-sans:2,gfx/fallback:1\n"
710                            "to load face 2 of the font gfx/vera-sans and use face 1\n"
711                            "of gfx/fallback as fallback font.\n"
712                            "You can also specify a list of font sizes to load, like this:\n"
713                            "loadfont console gfx/conchars,gfx/fallback 8 12 16 24 32\n"
714                            "In many cases, 8 12 16 24 32 should be a good choice.\n"
715                         );
716                 return;
717         }
718         f = FindFont(Cmd_Argv(1));
719         if(f == NULL)
720         {
721                 Con_Printf("font function not found\n");
722                 return;
723         }
724
725         if(Cmd_Argc() < 3)
726                 filelist = "gfx/conchars";
727         else
728                 filelist = Cmd_Argv(2);
729
730         memset(f->fallbacks, 0, sizeof(f->fallbacks));
731         memset(f->fallback_faces, 0, sizeof(f->fallback_faces));
732
733         // first font is handled "normally"
734         c = strchr(filelist, ':');
735         cm = strchr(filelist, ',');
736         if(c && (!cm || c < cm))
737                 f->req_face = atoi(c+1);
738         else
739         {
740                 f->req_face = 0;
741                 c = cm;
742         }
743
744         if(!c || (c - filelist) > MAX_QPATH)
745                 strlcpy(mainfont, filelist, sizeof(mainfont));
746         else
747         {
748                 memcpy(mainfont, filelist, c - filelist);
749                 mainfont[c - filelist] = 0;
750         }
751
752         for(i = 0; i < MAX_FONT_FALLBACKS; ++i)
753         {
754                 c = strchr(filelist, ',');
755                 if(!c)
756                         break;
757                 filelist = c + 1;
758                 if(!*filelist)
759                         break;
760                 c = strchr(filelist, ':');
761                 cm = strchr(filelist, ',');
762                 if(c && (!cm || c < cm))
763                         f->fallback_faces[i] = atoi(c+1);
764                 else
765                 {
766                         f->fallback_faces[i] = 0; // f->req_face; could make it stick to the default-font's face index
767                         c = cm;
768                 }
769                 if(!c || (c-filelist) > MAX_QPATH)
770                 {
771                         strlcpy(f->fallbacks[i], filelist, sizeof(mainfont));
772                 }
773                 else
774                 {
775                         memcpy(f->fallbacks[i], filelist, c - filelist);
776                         f->fallbacks[i][c - filelist] = 0;
777                 }
778         }
779
780         // for now: by default load only one size: the default size
781         f->req_sizes[0] = 0;
782         for(i = 1; i < MAX_FONT_SIZES; ++i)
783                 f->req_sizes[i] = -1;
784
785         // for some reason this argc is 3 even when using 2 arguments here, maybe nexuiz screws up
786         if(Cmd_Argc() >= 3)
787         {
788                 for(i = 0; i < Cmd_Argc()-3; ++i)
789                 {
790                         sz = atof(Cmd_Argv(i+3));
791                         if (sz > 0.001f && sz < 1000.0f) // do not use crap sizes
792                                 f->req_sizes[i] = sz;
793                 }
794         }
795         LoadFont(true, mainfont, f);
796 }
797
798 /*
799 ===============
800 Draw_Init
801 ===============
802 */
803 static void gl_draw_start(void)
804 {
805         int i;
806         drawtexturepool = R_AllocTexturePool();
807
808         numcachepics = 0;
809         memset(cachepichash, 0, sizeof(cachepichash));
810
811         font_start();
812
813         for(i = 0; i < MAX_FONTS; ++i)
814                 LoadFont(false, va("gfx/font_%s", dp_fonts[i].title), &dp_fonts[i]);
815
816         // draw the loading screen so people have something to see in the newly opened window
817         SCR_UpdateLoadingScreen(true);
818 }
819
820 static void gl_draw_shutdown(void)
821 {
822         font_shutdown();
823
824         R_FreeTexturePool(&drawtexturepool);
825
826         numcachepics = 0;
827         memset(cachepichash, 0, sizeof(cachepichash));
828 }
829
830 static void gl_draw_newmap(void)
831 {
832         font_newmap();
833 }
834
835 void GL_Draw_Init (void)
836 {
837         int i, j;
838         Cvar_RegisterVariable(&r_textshadow);
839         Cvar_RegisterVariable(&r_textbrightness);
840         Cvar_RegisterVariable(&r_textcontrast);
841         Cmd_AddCommand ("loadfont",LoadFont_f, "loadfont function tganame loads a font; example: loadfont console gfx/veramono; loadfont without arguments lists the available functions");
842         R_RegisterModule("GL_Draw", gl_draw_start, gl_draw_shutdown, gl_draw_newmap);
843
844         strlcpy(FONT_DEFAULT->title, "default", sizeof(FONT_DEFAULT->title));
845                 strlcpy(FONT_DEFAULT->texpath, "gfx/conchars", sizeof(FONT_DEFAULT->texpath));
846         strlcpy(FONT_CONSOLE->title, "console", sizeof(FONT_CONSOLE->title));
847         strlcpy(FONT_SBAR->title, "sbar", sizeof(FONT_SBAR->title));
848         strlcpy(FONT_NOTIFY->title, "notify", sizeof(FONT_NOTIFY->title));
849         strlcpy(FONT_CHAT->title, "chat", sizeof(FONT_CHAT->title));
850         strlcpy(FONT_CENTERPRINT->title, "centerprint", sizeof(FONT_CENTERPRINT->title));
851         strlcpy(FONT_INFOBAR->title, "infobar", sizeof(FONT_INFOBAR->title));
852         strlcpy(FONT_MENU->title, "menu", sizeof(FONT_MENU->title));
853         for(i = 0, j = 0; i < MAX_USERFONTS; ++i)
854                 if(!FONT_USER[i].title[0])
855                         dpsnprintf(FONT_USER[i].title, sizeof(FONT_USER[i].title), "user%d", j++);
856         Font_Init();
857 }
858
859 void _DrawQ_Setup(void)
860 {
861         r_viewport_t viewport;
862         if (r_refdef.draw2dstage)
863                 return;
864         r_refdef.draw2dstage = true;
865         CHECKGLERROR
866         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);
867         R_SetViewport(&viewport);
868         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
869         qglDepthFunc(GL_LEQUAL);CHECKGLERROR
870         qglDisable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
871         GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
872         R_EntityMatrix(&identitymatrix);
873
874         GL_DepthMask(true);
875         GL_DepthRange(0, 1);
876         GL_PolygonOffset(0, 0);
877         GL_DepthTest(false);
878         GL_Color(1,1,1,1);
879         GL_AlphaTest(false);
880         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
881 }
882
883 static void _DrawQ_ProcessDrawFlag(int flags)
884 {
885         _DrawQ_Setup();
886         CHECKGLERROR
887         if(flags == DRAWFLAG_ADDITIVE)
888                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
889         else if(flags == DRAWFLAG_MODULATE)
890                 GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
891         else if(flags == DRAWFLAG_2XMODULATE)
892                 GL_BlendFunc(GL_DST_COLOR,GL_SRC_COLOR);
893         else if(flags == DRAWFLAG_SCREEN)
894                 GL_BlendFunc(GL_ONE_MINUS_DST_COLOR,GL_ONE);
895         else
896                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
897 }
898
899 void DrawQ_Pic(float x, float y, cachepic_t *pic, float width, float height, float red, float green, float blue, float alpha, int flags)
900 {
901         float floats[20];
902
903         _DrawQ_ProcessDrawFlag(flags);
904         GL_Color(red, green, blue, alpha);
905
906         R_Mesh_VertexPointer(floats, 0, 0);
907         R_Mesh_ColorPointer(NULL, 0, 0);
908         R_Mesh_ResetTextureState();
909         if (pic)
910         {
911                 if (width == 0)
912                         width = pic->width;
913                 if (height == 0)
914                         height = pic->height;
915                 R_SetupShader_Generic(Draw_GetPicTexture(pic), NULL, GL_MODULATE, 1);
916                 R_Mesh_TexCoordPointer(0, 2, floats + 12, 0, 0);
917
918 #if 1
919                 floats[12] = 0.0f;floats[13] = 0.0f;
920                 floats[14] = 1.0f;floats[15] = 0.0f;
921                 floats[16] = 1.0f;floats[17] = 1.0f;
922                 floats[18] = 0.0f;floats[19] = 1.0f;
923 #else
924       // AK07: lets be texel correct on the corners
925       {
926          float horz_offset = 0.5f / pic->width;
927          float vert_offset = 0.5f / pic->height;
928
929                    floats[12] = 0.0f + horz_offset;floats[13] = 0.0f + vert_offset;
930                    floats[14] = 1.0f - horz_offset;floats[15] = 0.0f + vert_offset;
931                    floats[16] = 1.0f - horz_offset;floats[17] = 1.0f - vert_offset;
932                    floats[18] = 0.0f + horz_offset;floats[19] = 1.0f - vert_offset;
933       }
934 #endif
935         }
936         else
937                 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
938
939         floats[2] = floats[5] = floats[8] = floats[11] = 0;
940         floats[0] = floats[9] = x;
941         floats[1] = floats[4] = y;
942         floats[3] = floats[6] = x + width;
943         floats[7] = floats[10] = y + height;
944
945         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
946 }
947
948 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)
949 {
950         float floats[20];
951         float af = DEG2RAD(-angle); // forward
952         float ar = DEG2RAD(-angle + 90); // right
953         float sinaf = sin(af);
954         float cosaf = cos(af);
955         float sinar = sin(ar);
956         float cosar = cos(ar);
957
958         _DrawQ_ProcessDrawFlag(flags);
959         GL_Color(red, green, blue, alpha);
960
961         R_Mesh_VertexPointer(floats, 0, 0);
962         R_Mesh_ColorPointer(NULL, 0, 0);
963         R_Mesh_ResetTextureState();
964         if (pic)
965         {
966                 if (width == 0)
967                         width = pic->width;
968                 if (height == 0)
969                         height = pic->height;
970                 R_SetupShader_Generic(Draw_GetPicTexture(pic), NULL, GL_MODULATE, 1);
971                 R_Mesh_TexCoordPointer(0, 2, floats + 12, 0, 0);
972
973                 floats[12] = 0.0f;floats[13] = 0.0f;
974                 floats[14] = 1.0f;floats[15] = 0.0f;
975                 floats[16] = 1.0f;floats[17] = 1.0f;
976                 floats[18] = 0.0f;floats[19] = 1.0f;
977         }
978         else
979                 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
980
981         floats[2] = floats[5] = floats[8] = floats[11] = 0;
982
983 // top left
984         floats[0] = x - cosaf*org_x - cosar*org_y;
985         floats[1] = y - sinaf*org_x - sinar*org_y;
986
987 // top right
988         floats[3] = x + cosaf*(width-org_x) - cosar*org_y;
989         floats[4] = y + sinaf*(width-org_x) - sinar*org_y;
990
991 // bottom right
992         floats[6] = x + cosaf*(width-org_x) + cosar*(height-org_y);
993         floats[7] = y + sinaf*(width-org_x) + sinar*(height-org_y);
994
995 // bottom left
996         floats[9]  = x - cosaf*org_x + cosar*(height-org_y);
997         floats[10] = y - sinaf*org_x + sinar*(height-org_y);
998
999         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
1000 }
1001
1002 void DrawQ_Fill(float x, float y, float width, float height, float red, float green, float blue, float alpha, int flags)
1003 {
1004         float floats[12];
1005
1006         _DrawQ_ProcessDrawFlag(flags);
1007         GL_Color(red, green, blue, alpha);
1008
1009         R_Mesh_VertexPointer(floats, 0, 0);
1010         R_Mesh_ColorPointer(NULL, 0, 0);
1011         R_Mesh_ResetTextureState();
1012         R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
1013
1014         floats[2] = floats[5] = floats[8] = floats[11] = 0;
1015         floats[0] = floats[9] = x;
1016         floats[1] = floats[4] = y;
1017         floats[3] = floats[6] = x + width;
1018         floats[7] = floats[10] = y + height;
1019
1020         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
1021 }
1022
1023 /// color tag printing
1024 static const vec4_t string_colors[] =
1025 {
1026         // Quake3 colors
1027         // LordHavoc: why on earth is cyan before magenta in Quake3?
1028         // LordHavoc: note: Doom3 uses white for [0] and [7]
1029         {0.0, 0.0, 0.0, 1.0}, // black
1030         {1.0, 0.0, 0.0, 1.0}, // red
1031         {0.0, 1.0, 0.0, 1.0}, // green
1032         {1.0, 1.0, 0.0, 1.0}, // yellow
1033         {0.0, 0.0, 1.0, 1.0}, // blue
1034         {0.0, 1.0, 1.0, 1.0}, // cyan
1035         {1.0, 0.0, 1.0, 1.0}, // magenta
1036         {1.0, 1.0, 1.0, 1.0}, // white
1037         // [515]'s BX_COLOREDTEXT extension
1038         {1.0, 1.0, 1.0, 0.5}, // half transparent
1039         {0.5, 0.5, 0.5, 1.0}  // half brightness
1040         // Black's color table
1041         //{1.0, 1.0, 1.0, 1.0},
1042         //{1.0, 0.0, 0.0, 1.0},
1043         //{0.0, 1.0, 0.0, 1.0},
1044         //{0.0, 0.0, 1.0, 1.0},
1045         //{1.0, 1.0, 0.0, 1.0},
1046         //{0.0, 1.0, 1.0, 1.0},
1047         //{1.0, 0.0, 1.0, 1.0},
1048         //{0.1, 0.1, 0.1, 1.0}
1049 };
1050
1051 #define STRING_COLORS_COUNT     (sizeof(string_colors) / sizeof(vec4_t))
1052
1053 static void DrawQ_GetTextColor(float color[4], int colorindex, float r, float g, float b, float a, qboolean shadow)
1054 {
1055         float C = r_textcontrast.value;
1056         float B = r_textbrightness.value;
1057         if (colorindex & 0x10000) // that bit means RGB color
1058         {
1059                 color[0] = ((colorindex >> 12) & 0xf) / 15.0;
1060                 color[1] = ((colorindex >> 8) & 0xf) / 15.0;
1061                 color[2] = ((colorindex >> 4) & 0xf) / 15.0;
1062                 color[3] = (colorindex & 0xf) / 15.0;
1063         }
1064         else
1065                 Vector4Copy(string_colors[colorindex], color);
1066         Vector4Set(color, color[0] * r * C + B, color[1] * g * C + B, color[2] * b * C + B, color[3] * a);
1067         if (shadow)
1068         {
1069                 float shadowalpha = (color[0]+color[1]+color[2]) * 0.8;
1070                 Vector4Set(color, 0, 0, 0, color[3] * bound(0, shadowalpha, 1));
1071         }
1072 }
1073
1074 // NOTE: this function always draws exactly one character if maxwidth <= 0
1075 float DrawQ_TextWidth_UntilWidth_TrackColors_Scale(const char *text, size_t *maxlen, float w, float h, float sw, float sh, int *outcolor, qboolean ignorecolorcodes, const dp_font_t *fnt, float maxwidth)
1076 {
1077         const char *text_start = text;
1078         int colorindex = STRING_COLOR_DEFAULT;
1079         size_t i;
1080         float x = 0;
1081         Uchar ch, mapch, nextch;
1082         Uchar prevch = 0; // used for kerning
1083         int tempcolorindex;
1084         float kx;
1085         int map_index = 0;
1086         size_t bytes_left;
1087         ft2_font_map_t *fontmap = NULL;
1088         ft2_font_map_t *map = NULL;
1089         ft2_font_map_t *prevmap = NULL;
1090         ft2_font_t *ft2 = fnt->ft2;
1091         // float ftbase_x;
1092         qboolean snap = true;
1093         qboolean least_one = false;
1094         float dw, dh; // display w/h
1095
1096         if (!h) h = w;
1097         if (!h) {
1098                 w = h = 1;
1099                 snap = false;
1100         }
1101         // do this in the end
1102         w *= fnt->scale;
1103         h *= fnt->scale;
1104
1105         // find the most fitting size:
1106         if (ft2 != NULL)
1107         {
1108                 if (snap)
1109                         map_index = Font_IndexForSize(ft2, h, &w, &h);
1110                 else
1111                         map_index = Font_IndexForSize(ft2, h, NULL, NULL);
1112                 fontmap = Font_MapForIndex(ft2, map_index);
1113         }
1114         if(snap)
1115         {
1116                 if(fabs(sw - 1) > 0.001 || fabs(sh - 1) > 0.001)
1117                         snap = false; // turn off pixel snapping for better animation
1118                 else
1119                         sw = sh = 1;
1120         }
1121
1122         dw = w * sw;
1123         dh = h * sh;
1124
1125         if (*maxlen < 1)
1126                 *maxlen = 1<<30;
1127
1128         if (!outcolor || *outcolor == -1)
1129                 colorindex = STRING_COLOR_DEFAULT;
1130         else
1131                 colorindex = *outcolor;
1132
1133         // maxwidth /= fnt->scale; // w and h are multiplied by it already
1134         // ftbase_x = snap_to_pixel_x(0);
1135         
1136         if(maxwidth <= 0)
1137         {
1138                 least_one = true;
1139                 maxwidth = -maxwidth;
1140         }
1141
1142         for (i = 0;((bytes_left = *maxlen - (text - text_start)) > 0) && *text;)
1143         {
1144                 size_t i0 = i;
1145                 nextch = ch = u8_getnchar(text, &text, bytes_left);
1146                 i = text - text_start;
1147                 if (!ch)
1148                         break;
1149                 if (snap)
1150                         x = snap_to_pixel_x(x, 0.4);
1151                 if (ch == ' ' && !fontmap)
1152                 {
1153                         if(!least_one || i0) // never skip the first character
1154                         if(x + fnt->width_of[(int) ' '] * dw > maxwidth)
1155                         {
1156                                 i = i0;
1157                                 break; // oops, can't draw this
1158                         }
1159                         x += fnt->width_of[(int) ' '] * dw;
1160                         continue;
1161                 }
1162                 // i points to the char after ^
1163                 if (ch == STRING_COLOR_TAG && !ignorecolorcodes && i < *maxlen)
1164                 {
1165                         ch = *text; // colors are ascii, so no u8_ needed
1166                         if (ch <= '9' && ch >= '0') // ^[0-9] found
1167                         {
1168                                 colorindex = ch - '0';
1169                                 ++text;
1170                                 ++i;
1171                                 continue;
1172                         }
1173                         // i points to the char after ^...
1174                         // i+3 points to 3 in ^x123
1175                         // i+3 == *maxlen would mean that char is missing
1176                         else if (ch == STRING_COLOR_RGB_TAG_CHAR && i + 3 < *maxlen ) // ^x found
1177                         {
1178                                 // building colorindex...
1179                                 ch = tolower(text[1]);
1180                                 tempcolorindex = 0x10000; // binary: 1,0000,0000,0000,0000
1181                                 if (ch <= '9' && ch >= '0') tempcolorindex |= (ch - '0') << 12;
1182                                 else if (ch >= 'a' && ch <= 'f') tempcolorindex |= (ch - 87) << 12;
1183                                 else tempcolorindex = 0;
1184                                 if (tempcolorindex)
1185                                 {
1186                                         ch = tolower(text[2]);
1187                                         if (ch <= '9' && ch >= '0') tempcolorindex |= (ch - '0') << 8;
1188                                         else if (ch >= 'a' && ch <= 'f') tempcolorindex |= (ch - 87) << 8;
1189                                         else tempcolorindex = 0;
1190                                         if (tempcolorindex)
1191                                         {
1192                                                 ch = tolower(text[3]);
1193                                                 if (ch <= '9' && ch >= '0') tempcolorindex |= (ch - '0') << 4;
1194                                                 else if (ch >= 'a' && ch <= 'f') tempcolorindex |= (ch - 87) << 4;
1195                                                 else tempcolorindex = 0;
1196                                                 if (tempcolorindex)
1197                                                 {
1198                                                         colorindex = tempcolorindex | 0xf;
1199                                                         // ...done! now colorindex has rgba codes (1,rrrr,gggg,bbbb,aaaa)
1200                                                         i+=4;
1201                                                         text += 4;
1202                                                         continue;
1203                                                 }
1204                                         }
1205                                 }
1206                         }
1207                         else if (ch == STRING_COLOR_TAG) // ^^ found, ignore the first ^ and go to print the second
1208                         {
1209                                 i++;
1210                                 text++;
1211                         }
1212                         i--;
1213                 }
1214                 ch = nextch;
1215
1216                 if (!fontmap || (ch <= 0xFF && fontmap->glyphs[ch].image) || (ch >= 0xE000 && ch <= 0xE0FF))
1217                 {
1218                         if (ch > 0xE000)
1219                                 ch -= 0xE000;
1220                         if (ch > 0xFF)
1221                                 continue;
1222                         if (fontmap)
1223                                 map = ft2_oldstyle_map;
1224                         prevch = 0;
1225                         if(!least_one || i0) // never skip the first character
1226                         if(x + fnt->width_of[ch] * dw > maxwidth)
1227                         {
1228                                 i = i0;
1229                                 break; // oops, can't draw this
1230                         }
1231                         x += fnt->width_of[ch] * dw;
1232                 } else {
1233                         if (!map || map == ft2_oldstyle_map || map->start < ch || map->start + FONT_CHARS_PER_MAP >= ch)
1234                         {
1235                                 map = FontMap_FindForChar(fontmap, ch);
1236                                 if (!map)
1237                                 {
1238                                         if (!Font_LoadMapForIndex(ft2, map_index, ch, &map))
1239                                                 break;
1240                                         if (!map)
1241                                                 break;
1242                                 }
1243                         }
1244                         mapch = ch - map->start;
1245                         if (prevch && Font_GetKerningForMap(ft2, map_index, w, h, prevch, ch, &kx, NULL))
1246                                 x += kx * dw;
1247                         x += map->glyphs[mapch].advance_x * dw;
1248                         prevmap = map;
1249                         prevch = ch;
1250                 }
1251         }
1252
1253         *maxlen = i;
1254
1255         if (outcolor)
1256                 *outcolor = colorindex;
1257
1258         return x;
1259 }
1260
1261 float DrawQ_String_Scale(float startx, float starty, const char *text, size_t maxlen, float w, float h, float sw, float sh, float basered, float basegreen, float baseblue, float basealpha, int flags, int *outcolor, qboolean ignorecolorcodes, const dp_font_t *fnt)
1262 {
1263         int shadow, colorindex = STRING_COLOR_DEFAULT;
1264         size_t i;
1265         float x = startx, y, s, t, u, v, thisw;
1266         float *av, *at, *ac;
1267         float color[4];
1268         int batchcount;
1269         static float vertex3f[QUADELEMENTS_MAXQUADS*4*3];
1270         static float texcoord2f[QUADELEMENTS_MAXQUADS*4*2];
1271         static float color4f[QUADELEMENTS_MAXQUADS*4*4];
1272         Uchar ch, mapch, nextch;
1273         Uchar prevch = 0; // used for kerning
1274         int tempcolorindex;
1275         int map_index = 0;
1276         ft2_font_map_t *prevmap = NULL; // the previous map
1277         ft2_font_map_t *map = NULL;     // the currently used map
1278         ft2_font_map_t *fontmap = NULL; // the font map for the size
1279         float ftbase_y;
1280         const char *text_start = text;
1281         float kx, ky;
1282         ft2_font_t *ft2 = fnt->ft2;
1283         qboolean snap = true;
1284         float pix_x, pix_y;
1285         size_t bytes_left;
1286         float dw, dh;
1287
1288         int tw, th;
1289         tw = R_TextureWidth(fnt->tex);
1290         th = R_TextureHeight(fnt->tex);
1291
1292         if (!h) h = w;
1293         if (!h) {
1294                 h = w = 1;
1295                 snap = false;
1296         }
1297
1298         starty -= (fnt->scale - 1) * h * 0.5; // center
1299         w *= fnt->scale;
1300         h *= fnt->scale;
1301
1302         if (ft2 != NULL)
1303         {
1304                 if (snap)
1305                         map_index = Font_IndexForSize(ft2, h, &w, &h);
1306                 else
1307                         map_index = Font_IndexForSize(ft2, h, NULL, NULL);
1308                 fontmap = Font_MapForIndex(ft2, map_index);
1309         }
1310         if(snap)
1311         {
1312                 if(fabs(sw - 1) > 0.001 || fabs(sh - 1) > 0.001)
1313                         snap = false; // turn off pixel snapping for better animation
1314                 else
1315                         sw = sh = 1;
1316         }
1317
1318         dw = w * sw;
1319         dh = h * sh;
1320
1321         // draw the font at its baseline when using freetype
1322         //ftbase_x = 0;
1323         ftbase_y = dh * (4.5/6.0);
1324
1325         if (maxlen < 1)
1326                 maxlen = 1<<30;
1327
1328         _DrawQ_ProcessDrawFlag(flags);
1329
1330         R_Mesh_ColorPointer(color4f, 0, 0);
1331         R_Mesh_ResetTextureState();
1332         if (!fontmap)
1333                 R_Mesh_TexBind(0, fnt->tex);
1334         R_Mesh_TexCoordPointer(0, 2, texcoord2f, 0, 0);
1335         R_Mesh_VertexPointer(vertex3f, 0, 0);
1336         R_SetupShader_Generic(fnt->tex, NULL, GL_MODULATE, 1);
1337
1338         ac = color4f;
1339         at = texcoord2f;
1340         av = vertex3f;
1341         batchcount = 0;
1342
1343         //ftbase_x = snap_to_pixel_x(ftbase_x);
1344         if(snap)
1345                 ftbase_y = snap_to_pixel_y(ftbase_y, 0.3);
1346
1347         pix_x = vid.width / vid_conwidth.value;
1348         pix_y = vid.height / vid_conheight.value;
1349         for (shadow = r_textshadow.value != 0 && basealpha > 0;shadow >= 0;shadow--)
1350         {
1351                 text = text_start;
1352
1353                 if (!outcolor || *outcolor == -1)
1354                         colorindex = STRING_COLOR_DEFAULT;
1355                 else
1356                         colorindex = *outcolor;
1357
1358                 DrawQ_GetTextColor(color, colorindex, basered, basegreen, baseblue, basealpha, shadow != 0);
1359
1360                 x = startx;
1361                 y = starty;
1362                 /*
1363                 if (shadow)
1364                 {
1365                         x += r_textshadow.value * vid.width / vid_conwidth.value;
1366                         y += r_textshadow.value * vid.height / vid_conheight.value;
1367                 }
1368                 */
1369                 for (i = 0;((bytes_left = maxlen - (text - text_start)) > 0) && *text;)
1370                 {
1371                         nextch = ch = u8_getnchar(text, &text, bytes_left);
1372                         i = text - text_start;
1373                         if (!ch)
1374                                 break;
1375                         if (snap)
1376                         {
1377                                 x = snap_to_pixel_x(x, 0.4);
1378                                 y = snap_to_pixel_y(y, 0.4);
1379                         }
1380                         if (ch == ' ' && !fontmap)
1381                         {
1382                                 x += fnt->width_of[(int) ' '] * dw;
1383                                 continue;
1384                         }
1385                         if (ch == STRING_COLOR_TAG && !ignorecolorcodes && i < maxlen)
1386                         {
1387                                 ch = *text; // colors are ascii, so no u8_ needed
1388                                 if (ch <= '9' && ch >= '0') // ^[0-9] found
1389                                 {
1390                                         colorindex = ch - '0';
1391                                         DrawQ_GetTextColor(color, colorindex, basered, basegreen, baseblue, basealpha, shadow != 0);
1392                                         ++text;
1393                                         ++i;
1394                                         continue;
1395                                 }
1396                                 else if (ch == STRING_COLOR_RGB_TAG_CHAR && i+3 < maxlen ) // ^x found
1397                                 {
1398                                         // building colorindex...
1399                                         ch = tolower(text[1]);
1400                                         tempcolorindex = 0x10000; // binary: 1,0000,0000,0000,0000
1401                                         if (ch <= '9' && ch >= '0') tempcolorindex |= (ch - '0') << 12;
1402                                         else if (ch >= 'a' && ch <= 'f') tempcolorindex |= (ch - 87) << 12;
1403                                         else tempcolorindex = 0;
1404                                         if (tempcolorindex)
1405                                         {
1406                                                 ch = tolower(text[2]);
1407                                                 if (ch <= '9' && ch >= '0') tempcolorindex |= (ch - '0') << 8;
1408                                                 else if (ch >= 'a' && ch <= 'f') tempcolorindex |= (ch - 87) << 8;
1409                                                 else tempcolorindex = 0;
1410                                                 if (tempcolorindex)
1411                                                 {
1412                                                         ch = tolower(text[3]);
1413                                                         if (ch <= '9' && ch >= '0') tempcolorindex |= (ch - '0') << 4;
1414                                                         else if (ch >= 'a' && ch <= 'f') tempcolorindex |= (ch - 87) << 4;
1415                                                         else tempcolorindex = 0;
1416                                                         if (tempcolorindex)
1417                                                         {
1418                                                                 colorindex = tempcolorindex | 0xf;
1419                                                                 // ...done! now colorindex has rgba codes (1,rrrr,gggg,bbbb,aaaa)
1420                                                                 //Con_Printf("^1colorindex:^7 %x\n", colorindex);
1421                                                                 DrawQ_GetTextColor(color, colorindex, basered, basegreen, baseblue, basealpha, shadow != 0);
1422                                                                 i+=4;
1423                                                                 text+=4;
1424                                                                 continue;
1425                                                         }
1426                                                 }
1427                                         }
1428                                 }
1429                                 else if (ch == STRING_COLOR_TAG)
1430                                 {
1431                                         i++;
1432                                         text++;
1433                                 }
1434                                 i--;
1435                         }
1436                         // get the backup
1437                         ch = nextch;
1438                         // using a value of -1 for the oldstyle map because NULL means uninitialized...
1439                         // this way we don't need to rebind fnt->tex for every old-style character
1440                         // E000..E0FF: emulate old-font characters (to still have smileys and such available)
1441                         if (shadow)
1442                         {
1443                                 x += 1.0/pix_x * r_textshadow.value;
1444                                 y += 1.0/pix_y * r_textshadow.value;
1445                         }
1446                         if (!fontmap || (ch <= 0xFF && fontmap->glyphs[ch].image) || (ch >= 0xE000 && ch <= 0xE0FF))
1447                         {
1448                                 if (ch > 0xE000)
1449                                         ch -= 0xE000;
1450                                 if (ch > 0xFF)
1451                                         continue;
1452                                 if (fontmap)
1453                                 {
1454                                         if (map != ft2_oldstyle_map)
1455                                         {
1456                                                 if (batchcount)
1457                                                 {
1458                                                         // switching from freetype to non-freetype rendering
1459                                                         GL_LockArrays(0, batchcount * 4);
1460                                                         R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, quadelement3s, 0, 0);
1461                                                         GL_LockArrays(0, 0);
1462                                                         batchcount = 0;
1463                                                         ac = color4f;
1464                                                         at = texcoord2f;
1465                                                         av = vertex3f;
1466                                                 }
1467                                                 R_SetupShader_Generic(fnt->tex, NULL, GL_MODULATE, 1);
1468                                                 map = ft2_oldstyle_map;
1469                                         }
1470                                 }
1471                                 prevch = 0;
1472                                 //num = (unsigned char) text[i];
1473                                 //thisw = fnt->width_of[num];
1474                                 thisw = fnt->width_of[ch];
1475                                 // FIXME make these smaller to just include the occupied part of the character for slightly faster rendering
1476                                 s = (ch & 15)*0.0625f + (0.5f / tw);
1477                                 t = (ch >> 4)*0.0625f + (0.5f / th);
1478                                 u = 0.0625f * thisw - (1.0f / tw);
1479                                 v = 0.0625f - (1.0f / th);
1480                                 ac[ 0] = color[0];ac[ 1] = color[1];ac[ 2] = color[2];ac[ 3] = color[3];
1481                                 ac[ 4] = color[0];ac[ 5] = color[1];ac[ 6] = color[2];ac[ 7] = color[3];
1482                                 ac[ 8] = color[0];ac[ 9] = color[1];ac[10] = color[2];ac[11] = color[3];
1483                                 ac[12] = color[0];ac[13] = color[1];ac[14] = color[2];ac[15] = color[3];
1484                                 at[ 0] = s              ; at[ 1] = t    ;
1485                                 at[ 2] = s+u    ; at[ 3] = t    ;
1486                                 at[ 4] = s+u    ; at[ 5] = t+v  ;
1487                                 at[ 6] = s              ; at[ 7] = t+v  ;
1488                                 av[ 0] = x                      ; av[ 1] = y    ; av[ 2] = 10;
1489                                 av[ 3] = x+dw*thisw     ; av[ 4] = y    ; av[ 5] = 10;
1490                                 av[ 6] = x+dw*thisw     ; av[ 7] = y+dh ; av[ 8] = 10;
1491                                 av[ 9] = x                      ; av[10] = y+dh ; av[11] = 10;
1492                                 ac += 16;
1493                                 at += 8;
1494                                 av += 12;
1495                                 batchcount++;
1496                                 if (batchcount >= QUADELEMENTS_MAXQUADS)
1497                                 {
1498                                         GL_LockArrays(0, batchcount * 4);
1499                                         R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, quadelement3s, 0, 0);
1500                                         GL_LockArrays(0, 0);
1501                                         batchcount = 0;
1502                                         ac = color4f;
1503                                         at = texcoord2f;
1504                                         av = vertex3f;
1505                                 }
1506                                 x += thisw * dw;
1507                         } else {
1508                                 if (!map || map == ft2_oldstyle_map || map->start < ch || map->start + FONT_CHARS_PER_MAP >= ch)
1509                                 {
1510                                         // new charmap - need to render
1511                                         if (batchcount)
1512                                         {
1513                                                 // we need a different character map, render what we currently have:
1514                                                 GL_LockArrays(0, batchcount * 4);
1515                                                 R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, quadelement3s, 0, 0);
1516                                                 GL_LockArrays(0, 0);
1517                                                 batchcount = 0;
1518                                                 ac = color4f;
1519                                                 at = texcoord2f;
1520                                                 av = vertex3f;
1521                                         }
1522                                         // find the new map
1523                                         map = FontMap_FindForChar(fontmap, ch);
1524                                         if (!map)
1525                                         {
1526                                                 if (!Font_LoadMapForIndex(ft2, map_index, ch, &map))
1527                                                 {
1528                                                         shadow = -1;
1529                                                         break;
1530                                                 }
1531                                                 if (!map)
1532                                                 {
1533                                                         // this shouldn't happen
1534                                                         shadow = -1;
1535                                                         break;
1536                                                 }
1537                                         }
1538                                         R_SetupShader_Generic(map->texture, NULL, GL_MODULATE, 1);
1539                                 }
1540
1541                                 mapch = ch - map->start;
1542                                 thisw = map->glyphs[mapch].advance_x;
1543
1544                                 //x += ftbase_x;
1545                                 y += ftbase_y;
1546                                 if (prevch && Font_GetKerningForMap(ft2, map_index, w, h, prevch, ch, &kx, &ky))
1547                                 {
1548                                         x += kx * dw;
1549                                         y += ky * dh;
1550                                 }
1551                                 else
1552                                         kx = ky = 0;
1553                                 ac[ 0] = color[0]; ac[ 1] = color[1]; ac[ 2] = color[2]; ac[ 3] = color[3];
1554                                 ac[ 4] = color[0]; ac[ 5] = color[1]; ac[ 6] = color[2]; ac[ 7] = color[3];
1555                                 ac[ 8] = color[0]; ac[ 9] = color[1]; ac[10] = color[2]; ac[11] = color[3];
1556                                 ac[12] = color[0]; ac[13] = color[1]; ac[14] = color[2]; ac[15] = color[3];
1557                                 at[0] = map->glyphs[mapch].txmin; at[1] = map->glyphs[mapch].tymin;
1558                                 at[2] = map->glyphs[mapch].txmax; at[3] = map->glyphs[mapch].tymin;
1559                                 at[4] = map->glyphs[mapch].txmax; at[5] = map->glyphs[mapch].tymax;
1560                                 at[6] = map->glyphs[mapch].txmin; at[7] = map->glyphs[mapch].tymax;
1561                                 av[ 0] = x + dw * map->glyphs[mapch].vxmin; av[ 1] = y + dh * map->glyphs[mapch].vymin; av[ 2] = 10;
1562                                 av[ 3] = x + dw * map->glyphs[mapch].vxmax; av[ 4] = y + dh * map->glyphs[mapch].vymin; av[ 5] = 10;
1563                                 av[ 6] = x + dw * map->glyphs[mapch].vxmax; av[ 7] = y + dh * map->glyphs[mapch].vymax; av[ 8] = 10;
1564                                 av[ 9] = x + dw * map->glyphs[mapch].vxmin; av[10] = y + dh * map->glyphs[mapch].vymax; av[11] = 10;
1565                                 //x -= ftbase_x;
1566                                 y -= ftbase_y;
1567
1568                                 x += thisw * dw;
1569                                 ac += 16;
1570                                 at += 8;
1571                                 av += 12;
1572                                 batchcount++;
1573                                 if (batchcount >= QUADELEMENTS_MAXQUADS)
1574                                 {
1575                                         GL_LockArrays(0, batchcount * 4);
1576                                         R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, quadelement3s, 0, 0);
1577                                         GL_LockArrays(0, 0);
1578                                         batchcount = 0;
1579                                         ac = color4f;
1580                                         at = texcoord2f;
1581                                         av = vertex3f;
1582                                 }
1583
1584                                 prevmap = map;
1585                                 prevch = ch;
1586                         }
1587                         if (shadow)
1588                         {
1589                                 x -= 1.0/pix_x * r_textshadow.value;
1590                                 y -= 1.0/pix_y * r_textshadow.value;
1591                         }
1592                 }
1593         }
1594         if (batchcount > 0)
1595         {
1596                 GL_LockArrays(0, batchcount * 4);
1597                 R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, quadelement3s, 0, 0);
1598                 GL_LockArrays(0, 0);
1599         }
1600
1601         if (outcolor)
1602                 *outcolor = colorindex;
1603
1604         // note: this relies on the proper text (not shadow) being drawn last
1605         return x;
1606 }
1607
1608 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, const dp_font_t *fnt)
1609 {
1610         return DrawQ_String_Scale(startx, starty, text, maxlen, w, h, 1, 1, basered, basegreen, baseblue, basealpha, flags, outcolor, ignorecolorcodes, fnt);
1611 }
1612
1613 float DrawQ_TextWidth_UntilWidth_TrackColors(const char *text, size_t *maxlen, float w, float h, int *outcolor, qboolean ignorecolorcodes, const dp_font_t *fnt, float maxwidth)
1614 {
1615         return DrawQ_TextWidth_UntilWidth_TrackColors_Scale(text, maxlen, w, h, 1, 1, outcolor, ignorecolorcodes, fnt, maxwidth);
1616 }
1617
1618 float DrawQ_TextWidth(const char *text, size_t maxlen, float w, float h, qboolean ignorecolorcodes, const dp_font_t *fnt)
1619 {
1620         return DrawQ_TextWidth_UntilWidth(text, &maxlen, w, h, ignorecolorcodes, fnt, 1000000000);
1621 }
1622
1623 float DrawQ_TextWidth_UntilWidth(const char *text, size_t *maxlen, float w, float h, qboolean ignorecolorcodes, const dp_font_t *fnt, float maxWidth)
1624 {
1625         return DrawQ_TextWidth_UntilWidth_TrackColors(text, maxlen, w, h, NULL, ignorecolorcodes, fnt, maxWidth);
1626 }
1627
1628 #if 0
1629 // not used
1630 // no ^xrgb management
1631 static int DrawQ_BuildColoredText(char *output2c, size_t maxoutchars, const char *text, int maxreadchars, qboolean ignorecolorcodes, int *outcolor)
1632 {
1633         int color, numchars = 0;
1634         char *outputend2c = output2c + maxoutchars - 2;
1635         if (!outcolor || *outcolor == -1)
1636                 color = STRING_COLOR_DEFAULT;
1637         else
1638                 color = *outcolor;
1639         if (!maxreadchars)
1640                 maxreadchars = 1<<30;
1641         textend = text + maxreadchars;
1642         while (text != textend && *text)
1643         {
1644                 if (*text == STRING_COLOR_TAG && !ignorecolorcodes && text + 1 != textend)
1645                 {
1646                         if (text[1] == STRING_COLOR_TAG)
1647                                 text++;
1648                         else if (text[1] >= '0' && text[1] <= '9')
1649                         {
1650                                 color = text[1] - '0';
1651                                 text += 2;
1652                                 continue;
1653                         }
1654                 }
1655                 if (output2c >= outputend2c)
1656                         break;
1657                 *output2c++ = *text++;
1658                 *output2c++ = color;
1659                 numchars++;
1660         }
1661         output2c[0] = output2c[1] = 0;
1662         if (outcolor)
1663                 *outcolor = color;
1664         return numchars;
1665 }
1666 #endif
1667
1668 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)
1669 {
1670         float floats[36];
1671
1672         _DrawQ_ProcessDrawFlag(flags);
1673
1674         R_Mesh_VertexPointer(floats, 0, 0);
1675         R_Mesh_ColorPointer(floats + 20, 0, 0);
1676         R_Mesh_ResetTextureState();
1677         if (pic)
1678         {
1679                 if (width == 0)
1680                         width = pic->width;
1681                 if (height == 0)
1682                         height = pic->height;
1683                 R_SetupShader_Generic(Draw_GetPicTexture(pic), NULL, GL_MODULATE, 1);
1684                 R_Mesh_TexCoordPointer(0, 2, floats + 12, 0, 0);
1685                 floats[12] = s1;floats[13] = t1;
1686                 floats[14] = s2;floats[15] = t2;
1687                 floats[16] = s4;floats[17] = t4;
1688                 floats[18] = s3;floats[19] = t3;
1689         }
1690         else
1691                 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
1692
1693         floats[2] = floats[5] = floats[8] = floats[11] = 0;
1694         floats[0] = floats[9] = x;
1695         floats[1] = floats[4] = y;
1696         floats[3] = floats[6] = x + width;
1697         floats[7] = floats[10] = y + height;
1698         floats[20] = r1;floats[21] = g1;floats[22] = b1;floats[23] = a1;
1699         floats[24] = r2;floats[25] = g2;floats[26] = b2;floats[27] = a2;
1700         floats[28] = r4;floats[29] = g4;floats[30] = b4;floats[31] = a4;
1701         floats[32] = r3;floats[33] = g3;floats[34] = b3;floats[35] = a3;
1702
1703         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
1704 }
1705
1706 void DrawQ_Mesh (drawqueuemesh_t *mesh, int flags)
1707 {
1708         _DrawQ_ProcessDrawFlag(flags);
1709
1710         R_Mesh_VertexPointer(mesh->data_vertex3f, 0, 0);
1711         R_Mesh_ColorPointer(mesh->data_color4f, 0, 0);
1712         R_Mesh_ResetTextureState();
1713         R_Mesh_TexCoordPointer(0, 2, mesh->data_texcoord2f, 0, 0);
1714         R_SetupShader_Generic(mesh->texture, NULL, GL_MODULATE, 1);
1715
1716         GL_LockArrays(0, mesh->num_vertices);
1717         R_Mesh_Draw(0, mesh->num_vertices, 0, mesh->num_triangles, mesh->data_element3i, mesh->data_element3s, 0, 0);
1718         GL_LockArrays(0, 0);
1719 }
1720
1721 void DrawQ_LineLoop (drawqueuemesh_t *mesh, int flags)
1722 {
1723         int num;
1724
1725         _DrawQ_ProcessDrawFlag(flags);
1726
1727         GL_Color(1,1,1,1);
1728         CHECKGLERROR
1729         qglBegin(GL_LINE_LOOP);
1730         for (num = 0;num < mesh->num_vertices;num++)
1731         {
1732                 if (mesh->data_color4f)
1733                         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]);
1734                 qglVertex2f(mesh->data_vertex3f[num*3+0], mesh->data_vertex3f[num*3+1]);
1735         }
1736         qglEnd();
1737         CHECKGLERROR
1738 }
1739
1740 //[515]: this is old, delete
1741 void DrawQ_Line (float width, float x1, float y1, float x2, float y2, float r, float g, float b, float alpha, int flags)
1742 {
1743         _DrawQ_ProcessDrawFlag(flags);
1744
1745         R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
1746
1747         CHECKGLERROR
1748         //qglLineWidth(width);CHECKGLERROR
1749
1750         GL_Color(r,g,b,alpha);
1751         CHECKGLERROR
1752         qglBegin(GL_LINES);
1753         qglVertex2f(x1, y1);
1754         qglVertex2f(x2, y2);
1755         qglEnd();
1756         CHECKGLERROR
1757 }
1758
1759 void DrawQ_SetClipArea(float x, float y, float width, float height)
1760 {
1761         int ix, iy, iw, ih;
1762         _DrawQ_Setup();
1763
1764         // We have to convert the con coords into real coords
1765         // OGL uses top to bottom
1766         ix = (int)(0.5 + x * ((float)vid.width / vid_conwidth.integer));
1767         iy = (int)(0.5 + y * ((float) vid.height / vid_conheight.integer));
1768         iw = (int)(width * ((float)vid.width / vid_conwidth.integer));
1769         ih = (int)(height * ((float)vid.height / vid_conheight.integer));
1770         GL_Scissor(ix, vid.height - iy - ih, iw, ih);
1771
1772         GL_ScissorTest(true);
1773 }
1774
1775 void DrawQ_ResetClipArea(void)
1776 {
1777         _DrawQ_Setup();
1778         GL_ScissorTest(false);
1779 }
1780
1781 void DrawQ_Finish(void)
1782 {
1783         r_refdef.draw2dstage = false;
1784 }
1785
1786 static float blendvertex3f[9] = {-5000, -5000, 10, 10000, -5000, 10, -5000, 10000, 10};
1787 void R_DrawGamma(void)
1788 {
1789         float c[4];
1790         switch(vid.renderpath)
1791         {
1792         case RENDERPATH_GL20:
1793         case RENDERPATH_CGGL:
1794                 if (vid_usinghwgamma || v_glslgamma.integer)
1795                         return;
1796                 break;
1797         case RENDERPATH_GL13:
1798         case RENDERPATH_GL11:
1799                 if (vid_usinghwgamma)
1800                         return;
1801                 break;
1802         }
1803         // all the blends ignore depth
1804         R_Mesh_VertexPointer(blendvertex3f, 0, 0);
1805         R_Mesh_ColorPointer(NULL, 0, 0);
1806         R_Mesh_ResetTextureState();
1807         R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
1808         GL_DepthMask(true);
1809         GL_DepthRange(0, 1);
1810         GL_PolygonOffset(0, 0);
1811         GL_DepthTest(false);
1812         if (v_color_enable.integer)
1813         {
1814                 c[0] = v_color_white_r.value;
1815                 c[1] = v_color_white_g.value;
1816                 c[2] = v_color_white_b.value;
1817         }
1818         else
1819                 c[0] = c[1] = c[2] = v_contrast.value;
1820         if (c[0] >= 1.01f || c[1] >= 1.01f || c[2] >= 1.01f)
1821         {
1822                 GL_BlendFunc(GL_DST_COLOR, GL_ONE);
1823                 while (c[0] >= 1.01f || c[1] >= 1.01f || c[2] >= 1.01f)
1824                 {
1825                         GL_Color(bound(0, c[0] - 1, 1), bound(0, c[1] - 1, 1), bound(0, c[2] - 1, 1), 1);
1826                         R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, polygonelement3s, 0, 0);
1827                         VectorScale(c, 0.5, c);
1828                 }
1829         }
1830         if (v_color_enable.integer)
1831         {
1832                 c[0] = v_color_black_r.value;
1833                 c[1] = v_color_black_g.value;
1834                 c[2] = v_color_black_b.value;
1835         }
1836         else
1837                 c[0] = c[1] = c[2] = v_brightness.value;
1838         if (c[0] >= 0.01f || c[1] >= 0.01f || c[2] >= 0.01f)
1839         {
1840                 GL_BlendFunc(GL_ONE, GL_ONE);
1841                 GL_Color(c[0], c[1], c[2], 1);
1842                 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, polygonelement3s, 0, 0);
1843         }
1844 }
1845