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