]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - gl_draw.c
make CSQC support the >0.05s/<0.0005s handling of standard player physics so CSQC...
[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) // see R_ResetViewRendering2D
1073 {
1074         if (r_refdef.draw2dstage == 1)
1075                 return;
1076         r_refdef.draw2dstage = 1;
1077
1078         R_ResetViewRendering2D_Common(0, NULL, NULL, vid_conwidth.integer, vid_conheight.integer);
1079 }
1080
1081 qboolean r_draw2d_force = false;
1082 static void _DrawQ_SetupAndProcessDrawFlag(int flags, cachepic_t *pic, float alpha)
1083 {
1084         _DrawQ_Setup();
1085         if(!r_draw2d.integer && !r_draw2d_force)
1086                 return;
1087         DrawQ_ProcessDrawFlag(flags, (alpha < 1) || (pic && pic->hasalpha));
1088 }
1089 void DrawQ_ProcessDrawFlag(int flags, qboolean alpha)
1090 {
1091         if(flags == DRAWFLAG_ADDITIVE)
1092         {
1093                 GL_DepthMask(false);
1094                 GL_BlendFunc(alpha ? GL_SRC_ALPHA : GL_ONE, GL_ONE);
1095         }
1096         else if(flags == DRAWFLAG_MODULATE)
1097         {
1098                 GL_DepthMask(false);
1099                 GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
1100         }
1101         else if(flags == DRAWFLAG_2XMODULATE)
1102         {
1103                 GL_DepthMask(false);
1104                 GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
1105         }
1106         else if(flags == DRAWFLAG_SCREEN)
1107         {
1108                 GL_DepthMask(false);
1109                 GL_BlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ONE);
1110         }
1111         else if(alpha)
1112         {
1113                 GL_DepthMask(false);
1114                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1115         }
1116         else
1117         {
1118                 GL_DepthMask(true);
1119                 GL_BlendFunc(GL_ONE, GL_ZERO);
1120         }
1121 }
1122
1123 void DrawQ_Pic(float x, float y, cachepic_t *pic, float width, float height, float red, float green, float blue, float alpha, int flags)
1124 {
1125         float floats[36];
1126
1127         _DrawQ_SetupAndProcessDrawFlag(flags, pic, alpha);
1128         if(!r_draw2d.integer && !r_draw2d_force)
1129                 return;
1130
1131 //      R_Mesh_ResetTextureState();
1132         floats[12] = 0.0f;floats[13] = 0.0f;
1133         floats[14] = 1.0f;floats[15] = 0.0f;
1134         floats[16] = 1.0f;floats[17] = 1.0f;
1135         floats[18] = 0.0f;floats[19] = 1.0f;
1136         floats[20] = floats[24] = floats[28] = floats[32] = red;
1137         floats[21] = floats[25] = floats[29] = floats[33] = green;
1138         floats[22] = floats[26] = floats[30] = floats[34] = blue;
1139         floats[23] = floats[27] = floats[31] = floats[35] = alpha;
1140         if (pic)
1141         {
1142                 if (width == 0)
1143                         width = pic->width;
1144                 if (height == 0)
1145                         height = pic->height;
1146                 R_SetupShader_Generic(Draw_GetPicTexture(pic), NULL, GL_MODULATE, 1, (flags & DRAWFLAGS_BLEND) ? false : true, true, false);
1147
1148 #if 0
1149       // AK07: lets be texel correct on the corners
1150       {
1151          float horz_offset = 0.5f / pic->width;
1152          float vert_offset = 0.5f / pic->height;
1153
1154                    floats[12] = 0.0f + horz_offset;floats[13] = 0.0f + vert_offset;
1155                    floats[14] = 1.0f - horz_offset;floats[15] = 0.0f + vert_offset;
1156                    floats[16] = 1.0f - horz_offset;floats[17] = 1.0f - vert_offset;
1157                    floats[18] = 0.0f + horz_offset;floats[19] = 1.0f - vert_offset;
1158       }
1159 #endif
1160         }
1161         else
1162                 R_SetupShader_Generic_NoTexture((flags & DRAWFLAGS_BLEND) ? false : true, true);
1163
1164         floats[2] = floats[5] = floats[8] = floats[11] = 0;
1165         floats[0] = floats[9] = x;
1166         floats[1] = floats[4] = y;
1167         floats[3] = floats[6] = x + width;
1168         floats[7] = floats[10] = y + height;
1169
1170         R_Mesh_PrepareVertices_Generic_Arrays(4, floats, floats + 20, floats + 12);
1171         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
1172 }
1173
1174 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)
1175 {
1176         float floats[36];
1177         float af = DEG2RAD(-angle); // forward
1178         float ar = DEG2RAD(-angle + 90); // right
1179         float sinaf = sin(af);
1180         float cosaf = cos(af);
1181         float sinar = sin(ar);
1182         float cosar = cos(ar);
1183
1184         _DrawQ_SetupAndProcessDrawFlag(flags, pic, alpha);
1185         if(!r_draw2d.integer && !r_draw2d_force)
1186                 return;
1187
1188 //      R_Mesh_ResetTextureState();
1189         if (pic)
1190         {
1191                 if (width == 0)
1192                         width = pic->width;
1193                 if (height == 0)
1194                         height = pic->height;
1195                 R_SetupShader_Generic(Draw_GetPicTexture(pic), NULL, GL_MODULATE, 1, (flags & DRAWFLAGS_BLEND) ? false : true, true, false);
1196         }
1197         else
1198                 R_SetupShader_Generic_NoTexture((flags & DRAWFLAGS_BLEND) ? false : true, true);
1199
1200         floats[2] = floats[5] = floats[8] = floats[11] = 0;
1201
1202 // top left
1203         floats[0] = x - cosaf*org_x - cosar*org_y;
1204         floats[1] = y - sinaf*org_x - sinar*org_y;
1205
1206 // top right
1207         floats[3] = x + cosaf*(width-org_x) - cosar*org_y;
1208         floats[4] = y + sinaf*(width-org_x) - sinar*org_y;
1209
1210 // bottom right
1211         floats[6] = x + cosaf*(width-org_x) + cosar*(height-org_y);
1212         floats[7] = y + sinaf*(width-org_x) + sinar*(height-org_y);
1213
1214 // bottom left
1215         floats[9]  = x - cosaf*org_x + cosar*(height-org_y);
1216         floats[10] = y - sinaf*org_x + sinar*(height-org_y);
1217
1218         floats[12] = 0.0f;floats[13] = 0.0f;
1219         floats[14] = 1.0f;floats[15] = 0.0f;
1220         floats[16] = 1.0f;floats[17] = 1.0f;
1221         floats[18] = 0.0f;floats[19] = 1.0f;
1222         floats[20] = floats[24] = floats[28] = floats[32] = red;
1223         floats[21] = floats[25] = floats[29] = floats[33] = green;
1224         floats[22] = floats[26] = floats[30] = floats[34] = blue;
1225         floats[23] = floats[27] = floats[31] = floats[35] = alpha;
1226
1227         R_Mesh_PrepareVertices_Generic_Arrays(4, floats, floats + 20, floats + 12);
1228         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
1229 }
1230
1231 void DrawQ_Fill(float x, float y, float width, float height, float red, float green, float blue, float alpha, int flags)
1232 {
1233         float floats[36];
1234
1235         _DrawQ_SetupAndProcessDrawFlag(flags, NULL, alpha);
1236         if(!r_draw2d.integer && !r_draw2d_force)
1237                 return;
1238
1239 //      R_Mesh_ResetTextureState();
1240         R_SetupShader_Generic_NoTexture((flags & DRAWFLAGS_BLEND) ? false : true, true);
1241
1242         floats[2] = floats[5] = floats[8] = floats[11] = 0;
1243         floats[0] = floats[9] = x;
1244         floats[1] = floats[4] = y;
1245         floats[3] = floats[6] = x + width;
1246         floats[7] = floats[10] = y + height;
1247         floats[12] = 0.0f;floats[13] = 0.0f;
1248         floats[14] = 1.0f;floats[15] = 0.0f;
1249         floats[16] = 1.0f;floats[17] = 1.0f;
1250         floats[18] = 0.0f;floats[19] = 1.0f;
1251         floats[20] = floats[24] = floats[28] = floats[32] = red;
1252         floats[21] = floats[25] = floats[29] = floats[33] = green;
1253         floats[22] = floats[26] = floats[30] = floats[34] = blue;
1254         floats[23] = floats[27] = floats[31] = floats[35] = alpha;
1255
1256         R_Mesh_PrepareVertices_Generic_Arrays(4, floats, floats + 20, floats + 12);
1257         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
1258 }
1259
1260 /// color tag printing
1261 static const vec4_t string_colors[] =
1262 {
1263         // Quake3 colors
1264         // LordHavoc: why on earth is cyan before magenta in Quake3?
1265         // LordHavoc: note: Doom3 uses white for [0] and [7]
1266         {0.0, 0.0, 0.0, 1.0}, // black
1267         {1.0, 0.0, 0.0, 1.0}, // red
1268         {0.0, 1.0, 0.0, 1.0}, // green
1269         {1.0, 1.0, 0.0, 1.0}, // yellow
1270         {0.0, 0.0, 1.0, 1.0}, // blue
1271         {0.0, 1.0, 1.0, 1.0}, // cyan
1272         {1.0, 0.0, 1.0, 1.0}, // magenta
1273         {1.0, 1.0, 1.0, 1.0}, // white
1274         // [515]'s BX_COLOREDTEXT extension
1275         {1.0, 1.0, 1.0, 0.5}, // half transparent
1276         {0.5, 0.5, 0.5, 1.0}  // half brightness
1277         // Black's color table
1278         //{1.0, 1.0, 1.0, 1.0},
1279         //{1.0, 0.0, 0.0, 1.0},
1280         //{0.0, 1.0, 0.0, 1.0},
1281         //{0.0, 0.0, 1.0, 1.0},
1282         //{1.0, 1.0, 0.0, 1.0},
1283         //{0.0, 1.0, 1.0, 1.0},
1284         //{1.0, 0.0, 1.0, 1.0},
1285         //{0.1, 0.1, 0.1, 1.0}
1286 };
1287
1288 #define STRING_COLORS_COUNT     (sizeof(string_colors) / sizeof(vec4_t))
1289
1290 static void DrawQ_GetTextColor(float color[4], int colorindex, float r, float g, float b, float a, qboolean shadow)
1291 {
1292         float C = r_textcontrast.value;
1293         float B = r_textbrightness.value;
1294         if (colorindex & 0x10000) // that bit means RGB color
1295         {
1296                 color[0] = ((colorindex >> 12) & 0xf) / 15.0;
1297                 color[1] = ((colorindex >> 8) & 0xf) / 15.0;
1298                 color[2] = ((colorindex >> 4) & 0xf) / 15.0;
1299                 color[3] = (colorindex & 0xf) / 15.0;
1300         }
1301         else
1302                 Vector4Copy(string_colors[colorindex], color);
1303         Vector4Set(color, color[0] * r * C + B, color[1] * g * C + B, color[2] * b * C + B, color[3] * a);
1304         if (shadow)
1305         {
1306                 float shadowalpha = (color[0]+color[1]+color[2]) * 0.8;
1307                 Vector4Set(color, 0, 0, 0, color[3] * bound(0, shadowalpha, 1));
1308         }
1309 }
1310
1311 // NOTE: this function always draws exactly one character if maxwidth <= 0
1312 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)
1313 {
1314         const char *text_start = text;
1315         int colorindex = STRING_COLOR_DEFAULT;
1316         size_t i;
1317         float x = 0;
1318         Uchar ch, mapch, nextch;
1319         Uchar prevch = 0; // used for kerning
1320         int tempcolorindex;
1321         float kx;
1322         int map_index = 0;
1323         size_t bytes_left;
1324         ft2_font_map_t *fontmap = NULL;
1325         ft2_font_map_t *map = NULL;
1326         //ft2_font_map_t *prevmap = NULL;
1327         ft2_font_t *ft2 = fnt->ft2;
1328         // float ftbase_x;
1329         qboolean snap = true;
1330         qboolean least_one = false;
1331         float dw; // display w
1332         //float dh; // display h
1333         const float *width_of;
1334
1335         if (!h) h = w;
1336         if (!h) {
1337                 w = h = 1;
1338                 snap = false;
1339         }
1340         // do this in the end
1341         w *= fnt->settings.scale;
1342         h *= fnt->settings.scale;
1343
1344         // find the most fitting size:
1345         if (ft2 != NULL)
1346         {
1347                 if (snap)
1348                         map_index = Font_IndexForSize(ft2, h, &w, &h);
1349                 else
1350                         map_index = Font_IndexForSize(ft2, h, NULL, NULL);
1351                 fontmap = Font_MapForIndex(ft2, map_index);
1352         }
1353
1354         dw = w * sw;
1355         //dh = h * sh;
1356
1357         if (*maxlen < 1)
1358                 *maxlen = 1<<30;
1359
1360         if (!outcolor || *outcolor == -1)
1361                 colorindex = STRING_COLOR_DEFAULT;
1362         else
1363                 colorindex = *outcolor;
1364
1365         // maxwidth /= fnt->scale; // w and h are multiplied by it already
1366         // ftbase_x = snap_to_pixel_x(0);
1367         
1368         if(maxwidth <= 0)
1369         {
1370                 least_one = true;
1371                 maxwidth = -maxwidth;
1372         }
1373
1374         //if (snap)
1375         //      x = snap_to_pixel_x(x, 0.4); // haha, it's 0 anyway
1376
1377         if (fontmap)
1378                 width_of = fontmap->width_of;
1379         else
1380                 width_of = fnt->width_of;
1381
1382         for (i = 0;((bytes_left = *maxlen - (text - text_start)) > 0) && *text;)
1383         {
1384                 size_t i0 = i;
1385                 nextch = ch = u8_getnchar(text, &text, bytes_left);
1386                 i = text - text_start;
1387                 if (!ch)
1388                         break;
1389                 if (ch == ' ' && !fontmap)
1390                 {
1391                         if(!least_one || i0) // never skip the first character
1392                         if(x + width_of[(int) ' '] * dw > maxwidth)
1393                         {
1394                                 i = i0;
1395                                 break; // oops, can't draw this
1396                         }
1397                         x += width_of[(int) ' '] * dw;
1398                         continue;
1399                 }
1400                 // i points to the char after ^
1401                 if (ch == STRING_COLOR_TAG && !ignorecolorcodes && i < *maxlen)
1402                 {
1403                         ch = *text; // colors are ascii, so no u8_ needed
1404                         if (ch <= '9' && ch >= '0') // ^[0-9] found
1405                         {
1406                                 colorindex = ch - '0';
1407                                 ++text;
1408                                 ++i;
1409                                 continue;
1410                         }
1411                         // i points to the char after ^...
1412                         // i+3 points to 3 in ^x123
1413                         // i+3 == *maxlen would mean that char is missing
1414                         else if (ch == STRING_COLOR_RGB_TAG_CHAR && i + 3 < *maxlen ) // ^x found
1415                         {
1416                                 // building colorindex...
1417                                 ch = tolower(text[1]);
1418                                 tempcolorindex = 0x10000; // binary: 1,0000,0000,0000,0000
1419                                 if (ch <= '9' && ch >= '0') tempcolorindex |= (ch - '0') << 12;
1420                                 else if (ch >= 'a' && ch <= 'f') tempcolorindex |= (ch - 87) << 12;
1421                                 else tempcolorindex = 0;
1422                                 if (tempcolorindex)
1423                                 {
1424                                         ch = tolower(text[2]);
1425                                         if (ch <= '9' && ch >= '0') tempcolorindex |= (ch - '0') << 8;
1426                                         else if (ch >= 'a' && ch <= 'f') tempcolorindex |= (ch - 87) << 8;
1427                                         else tempcolorindex = 0;
1428                                         if (tempcolorindex)
1429                                         {
1430                                                 ch = tolower(text[3]);
1431                                                 if (ch <= '9' && ch >= '0') tempcolorindex |= (ch - '0') << 4;
1432                                                 else if (ch >= 'a' && ch <= 'f') tempcolorindex |= (ch - 87) << 4;
1433                                                 else tempcolorindex = 0;
1434                                                 if (tempcolorindex)
1435                                                 {
1436                                                         colorindex = tempcolorindex | 0xf;
1437                                                         // ...done! now colorindex has rgba codes (1,rrrr,gggg,bbbb,aaaa)
1438                                                         i+=4;
1439                                                         text += 4;
1440                                                         continue;
1441                                                 }
1442                                         }
1443                                 }
1444                         }
1445                         else if (ch == STRING_COLOR_TAG) // ^^ found, ignore the first ^ and go to print the second
1446                         {
1447                                 i++;
1448                                 text++;
1449                         }
1450                         i--;
1451                 }
1452                 ch = nextch;
1453
1454                 if (!fontmap || (ch <= 0xFF && fontmap->glyphs[ch].image) || (ch >= 0xE000 && ch <= 0xE0FF))
1455                 {
1456                         if (ch > 0xE000)
1457                                 ch -= 0xE000;
1458                         if (ch > 0xFF)
1459                                 continue;
1460                         if (fontmap)
1461                                 map = ft2_oldstyle_map;
1462                         prevch = 0;
1463                         if(!least_one || i0) // never skip the first character
1464                         if(x + width_of[ch] * dw > maxwidth)
1465                         {
1466                                 i = i0;
1467                                 break; // oops, can't draw this
1468                         }
1469                         x += width_of[ch] * dw;
1470                 } else {
1471                         if (!map || map == ft2_oldstyle_map || ch < map->start || ch >= map->start + FONT_CHARS_PER_MAP)
1472                         {
1473                                 map = FontMap_FindForChar(fontmap, ch);
1474                                 if (!map)
1475                                 {
1476                                         if (!Font_LoadMapForIndex(ft2, map_index, ch, &map))
1477                                                 break;
1478                                         if (!map)
1479                                                 break;
1480                                 }
1481                         }
1482                         mapch = ch - map->start;
1483                         if (prevch && Font_GetKerningForMap(ft2, map_index, w, h, prevch, ch, &kx, NULL))
1484                                 x += kx * dw;
1485                         x += map->glyphs[mapch].advance_x * dw;
1486                         //prevmap = map;
1487                         prevch = ch;
1488                 }
1489         }
1490
1491         *maxlen = i;
1492
1493         if (outcolor)
1494                 *outcolor = colorindex;
1495
1496         return x;
1497 }
1498
1499 float DrawQ_Color[4];
1500 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)
1501 {
1502         int shadow, colorindex = STRING_COLOR_DEFAULT;
1503         size_t i;
1504         float x = startx, y, s, t, u, v, thisw;
1505         float *av, *at, *ac;
1506         int batchcount;
1507         static float vertex3f[QUADELEMENTS_MAXQUADS*4*3];
1508         static float texcoord2f[QUADELEMENTS_MAXQUADS*4*2];
1509         static float color4f[QUADELEMENTS_MAXQUADS*4*4];
1510         Uchar ch, mapch, nextch;
1511         Uchar prevch = 0; // used for kerning
1512         int tempcolorindex;
1513         int map_index = 0;
1514         //ft2_font_map_t *prevmap = NULL; // the previous map
1515         ft2_font_map_t *map = NULL;     // the currently used map
1516         ft2_font_map_t *fontmap = NULL; // the font map for the size
1517         float ftbase_y;
1518         const char *text_start = text;
1519         float kx, ky;
1520         ft2_font_t *ft2 = fnt->ft2;
1521         qboolean snap = true;
1522         float pix_x, pix_y;
1523         size_t bytes_left;
1524         float dw, dh;
1525         const float *width_of;
1526
1527         int tw, th;
1528         tw = R_TextureWidth(fnt->tex);
1529         th = R_TextureHeight(fnt->tex);
1530
1531         if (!h) h = w;
1532         if (!h) {
1533                 h = w = 1;
1534                 snap = false;
1535         }
1536
1537         starty -= (fnt->settings.scale - 1) * h * 0.5 - fnt->settings.voffset*h; // center & offset
1538         w *= fnt->settings.scale;
1539         h *= fnt->settings.scale;
1540
1541         if (ft2 != NULL)
1542         {
1543                 if (snap)
1544                         map_index = Font_IndexForSize(ft2, h, &w, &h);
1545                 else
1546                         map_index = Font_IndexForSize(ft2, h, NULL, NULL);
1547                 fontmap = Font_MapForIndex(ft2, map_index);
1548         }
1549
1550         dw = w * sw;
1551         dh = h * sh;
1552
1553         // draw the font at its baseline when using freetype
1554         //ftbase_x = 0;
1555         ftbase_y = dh * (4.5/6.0);
1556
1557         if (maxlen < 1)
1558                 maxlen = 1<<30;
1559
1560         _DrawQ_SetupAndProcessDrawFlag(flags, NULL, 0);
1561         if(!r_draw2d.integer && !r_draw2d_force)
1562                 return startx + DrawQ_TextWidth_UntilWidth_TrackColors_Scale(text, &maxlen, w, h, sw, sh, NULL, ignorecolorcodes, fnt, 1000000000);
1563
1564 //      R_Mesh_ResetTextureState();
1565         if (!fontmap)
1566                 R_Mesh_TexBind(0, fnt->tex);
1567         R_SetupShader_Generic(fnt->tex, NULL, GL_MODULATE, 1, (flags & DRAWFLAGS_BLEND) ? false : true, true, false);
1568
1569         ac = color4f;
1570         at = texcoord2f;
1571         av = vertex3f;
1572         batchcount = 0;
1573
1574         //ftbase_x = snap_to_pixel_x(ftbase_x);
1575         if(snap)
1576         {
1577                 startx = snap_to_pixel_x(startx, 0.4);
1578                 starty = snap_to_pixel_y(starty, 0.4);
1579                 ftbase_y = snap_to_pixel_y(ftbase_y, 0.3);
1580         }
1581
1582         pix_x = vid.width / vid_conwidth.value;
1583         pix_y = vid.height / vid_conheight.value;
1584
1585         if (fontmap)
1586                 width_of = fontmap->width_of;
1587         else
1588                 width_of = fnt->width_of;
1589
1590         for (shadow = r_textshadow.value != 0 && basealpha > 0;shadow >= 0;shadow--)
1591         {
1592                 prevch = 0;
1593                 text = text_start;
1594
1595                 if (!outcolor || *outcolor == -1)
1596                         colorindex = STRING_COLOR_DEFAULT;
1597                 else
1598                         colorindex = *outcolor;
1599
1600                 DrawQ_GetTextColor(DrawQ_Color, colorindex, basered, basegreen, baseblue, basealpha, shadow != 0);
1601
1602                 x = startx;
1603                 y = starty;
1604                 /*
1605                 if (shadow)
1606                 {
1607                         x += r_textshadow.value * vid.width / vid_conwidth.value;
1608                         y += r_textshadow.value * vid.height / vid_conheight.value;
1609                 }
1610                 */
1611                 for (i = 0;((bytes_left = maxlen - (text - text_start)) > 0) && *text;)
1612                 {
1613                         nextch = ch = u8_getnchar(text, &text, bytes_left);
1614                         i = text - text_start;
1615                         if (!ch)
1616                                 break;
1617                         if (ch == ' ' && !fontmap)
1618                         {
1619                                 x += width_of[(int) ' '] * dw;
1620                                 continue;
1621                         }
1622                         if (ch == STRING_COLOR_TAG && !ignorecolorcodes && i < maxlen)
1623                         {
1624                                 ch = *text; // colors are ascii, so no u8_ needed
1625                                 if (ch <= '9' && ch >= '0') // ^[0-9] found
1626                                 {
1627                                         colorindex = ch - '0';
1628                                         DrawQ_GetTextColor(DrawQ_Color, colorindex, basered, basegreen, baseblue, basealpha, shadow != 0);
1629                                         ++text;
1630                                         ++i;
1631                                         continue;
1632                                 }
1633                                 else if (ch == STRING_COLOR_RGB_TAG_CHAR && i+3 < maxlen ) // ^x found
1634                                 {
1635                                         // building colorindex...
1636                                         ch = tolower(text[1]);
1637                                         tempcolorindex = 0x10000; // binary: 1,0000,0000,0000,0000
1638                                         if (ch <= '9' && ch >= '0') tempcolorindex |= (ch - '0') << 12;
1639                                         else if (ch >= 'a' && ch <= 'f') tempcolorindex |= (ch - 87) << 12;
1640                                         else tempcolorindex = 0;
1641                                         if (tempcolorindex)
1642                                         {
1643                                                 ch = tolower(text[2]);
1644                                                 if (ch <= '9' && ch >= '0') tempcolorindex |= (ch - '0') << 8;
1645                                                 else if (ch >= 'a' && ch <= 'f') tempcolorindex |= (ch - 87) << 8;
1646                                                 else tempcolorindex = 0;
1647                                                 if (tempcolorindex)
1648                                                 {
1649                                                         ch = tolower(text[3]);
1650                                                         if (ch <= '9' && ch >= '0') tempcolorindex |= (ch - '0') << 4;
1651                                                         else if (ch >= 'a' && ch <= 'f') tempcolorindex |= (ch - 87) << 4;
1652                                                         else tempcolorindex = 0;
1653                                                         if (tempcolorindex)
1654                                                         {
1655                                                                 colorindex = tempcolorindex | 0xf;
1656                                                                 // ...done! now colorindex has rgba codes (1,rrrr,gggg,bbbb,aaaa)
1657                                                                 //Con_Printf("^1colorindex:^7 %x\n", colorindex);
1658                                                                 DrawQ_GetTextColor(DrawQ_Color, colorindex, basered, basegreen, baseblue, basealpha, shadow != 0);
1659                                                                 i+=4;
1660                                                                 text+=4;
1661                                                                 continue;
1662                                                         }
1663                                                 }
1664                                         }
1665                                 }
1666                                 else if (ch == STRING_COLOR_TAG)
1667                                 {
1668                                         i++;
1669                                         text++;
1670                                 }
1671                                 i--;
1672                         }
1673                         // get the backup
1674                         ch = nextch;
1675                         // using a value of -1 for the oldstyle map because NULL means uninitialized...
1676                         // this way we don't need to rebind fnt->tex for every old-style character
1677                         // E000..E0FF: emulate old-font characters (to still have smileys and such available)
1678                         if (shadow)
1679                         {
1680                                 x += 1.0/pix_x * r_textshadow.value;
1681                                 y += 1.0/pix_y * r_textshadow.value;
1682                         }
1683                         if (!fontmap || (ch <= 0xFF && fontmap->glyphs[ch].image) || (ch >= 0xE000 && ch <= 0xE0FF))
1684                         {
1685                                 if (ch >= 0xE000)
1686                                         ch -= 0xE000;
1687                                 if (ch > 0xFF)
1688                                         goto out;
1689                                 if (fontmap)
1690                                 {
1691                                         if (map != ft2_oldstyle_map)
1692                                         {
1693                                                 if (batchcount)
1694                                                 {
1695                                                         // switching from freetype to non-freetype rendering
1696                                                         R_Mesh_PrepareVertices_Generic_Arrays(batchcount * 4, vertex3f, color4f, texcoord2f);
1697                                                         R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, NULL, 0, quadelement3s, NULL, 0);
1698                                                         batchcount = 0;
1699                                                         ac = color4f;
1700                                                         at = texcoord2f;
1701                                                         av = vertex3f;
1702                                                 }
1703                                                 R_SetupShader_Generic(fnt->tex, NULL, GL_MODULATE, 1, (flags & DRAWFLAGS_BLEND) ? false : true, true, false);
1704                                                 map = ft2_oldstyle_map;
1705                                         }
1706                                 }
1707                                 prevch = 0;
1708                                 //num = (unsigned char) text[i];
1709                                 //thisw = fnt->width_of[num];
1710                                 thisw = fnt->width_of[ch];
1711                                 // FIXME make these smaller to just include the occupied part of the character for slightly faster rendering
1712                                 s = (ch & 15)*0.0625f + (0.5f / tw);
1713                                 t = (ch >> 4)*0.0625f + (0.5f / th);
1714                                 u = 0.0625f * thisw - (1.0f / tw);
1715                                 v = 0.0625f - (1.0f / th);
1716                                 ac[ 0] = DrawQ_Color[0];ac[ 1] = DrawQ_Color[1];ac[ 2] = DrawQ_Color[2];ac[ 3] = DrawQ_Color[3];
1717                                 ac[ 4] = DrawQ_Color[0];ac[ 5] = DrawQ_Color[1];ac[ 6] = DrawQ_Color[2];ac[ 7] = DrawQ_Color[3];
1718                                 ac[ 8] = DrawQ_Color[0];ac[ 9] = DrawQ_Color[1];ac[10] = DrawQ_Color[2];ac[11] = DrawQ_Color[3];
1719                                 ac[12] = DrawQ_Color[0];ac[13] = DrawQ_Color[1];ac[14] = DrawQ_Color[2];ac[15] = DrawQ_Color[3];
1720                                 at[ 0] = s              ; at[ 1] = t    ;
1721                                 at[ 2] = s+u    ; at[ 3] = t    ;
1722                                 at[ 4] = s+u    ; at[ 5] = t+v  ;
1723                                 at[ 6] = s              ; at[ 7] = t+v  ;
1724                                 av[ 0] = x                      ; av[ 1] = y    ; av[ 2] = 10;
1725                                 av[ 3] = x+dw*thisw     ; av[ 4] = y    ; av[ 5] = 10;
1726                                 av[ 6] = x+dw*thisw     ; av[ 7] = y+dh ; av[ 8] = 10;
1727                                 av[ 9] = x                      ; av[10] = y+dh ; av[11] = 10;
1728                                 ac += 16;
1729                                 at += 8;
1730                                 av += 12;
1731                                 batchcount++;
1732                                 if (batchcount >= QUADELEMENTS_MAXQUADS)
1733                                 {
1734                                         R_Mesh_PrepareVertices_Generic_Arrays(batchcount * 4, vertex3f, color4f, texcoord2f);
1735                                         R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, NULL, 0, quadelement3s, NULL, 0);
1736                                         batchcount = 0;
1737                                         ac = color4f;
1738                                         at = texcoord2f;
1739                                         av = vertex3f;
1740                                 }
1741                                 x += width_of[ch] * dw;
1742                         } else {
1743                                 if (!map || map == ft2_oldstyle_map || ch < map->start || ch >= map->start + FONT_CHARS_PER_MAP)
1744                                 {
1745                                         // new charmap - need to render
1746                                         if (batchcount)
1747                                         {
1748                                                 // we need a different character map, render what we currently have:
1749                                                 R_Mesh_PrepareVertices_Generic_Arrays(batchcount * 4, vertex3f, color4f, texcoord2f);
1750                                                 R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, NULL, 0, quadelement3s, NULL, 0);
1751                                                 batchcount = 0;
1752                                                 ac = color4f;
1753                                                 at = texcoord2f;
1754                                                 av = vertex3f;
1755                                         }
1756                                         // find the new map
1757                                         map = FontMap_FindForChar(fontmap, ch);
1758                                         if (!map)
1759                                         {
1760                                                 if (!Font_LoadMapForIndex(ft2, map_index, ch, &map))
1761                                                 {
1762                                                         shadow = -1;
1763                                                         break;
1764                                                 }
1765                                                 if (!map)
1766                                                 {
1767                                                         // this shouldn't happen
1768                                                         shadow = -1;
1769                                                         break;
1770                                                 }
1771                                         }
1772                                         R_SetupShader_Generic(map->pic->tex, NULL, GL_MODULATE, 1, (flags & DRAWFLAGS_BLEND) ? false : true, true, false);
1773                                 }
1774
1775                                 mapch = ch - map->start;
1776                                 thisw = map->glyphs[mapch].advance_x;
1777
1778                                 //x += ftbase_x;
1779                                 y += ftbase_y;
1780                                 if (prevch && Font_GetKerningForMap(ft2, map_index, w, h, prevch, ch, &kx, &ky))
1781                                 {
1782                                         x += kx * dw;
1783                                         y += ky * dh;
1784                                 }
1785                                 else
1786                                         kx = ky = 0;
1787                                 ac[ 0] = DrawQ_Color[0]; ac[ 1] = DrawQ_Color[1]; ac[ 2] = DrawQ_Color[2]; ac[ 3] = DrawQ_Color[3];
1788                                 ac[ 4] = DrawQ_Color[0]; ac[ 5] = DrawQ_Color[1]; ac[ 6] = DrawQ_Color[2]; ac[ 7] = DrawQ_Color[3];
1789                                 ac[ 8] = DrawQ_Color[0]; ac[ 9] = DrawQ_Color[1]; ac[10] = DrawQ_Color[2]; ac[11] = DrawQ_Color[3];
1790                                 ac[12] = DrawQ_Color[0]; ac[13] = DrawQ_Color[1]; ac[14] = DrawQ_Color[2]; ac[15] = DrawQ_Color[3];
1791                                 at[0] = map->glyphs[mapch].txmin; at[1] = map->glyphs[mapch].tymin;
1792                                 at[2] = map->glyphs[mapch].txmax; at[3] = map->glyphs[mapch].tymin;
1793                                 at[4] = map->glyphs[mapch].txmax; at[5] = map->glyphs[mapch].tymax;
1794                                 at[6] = map->glyphs[mapch].txmin; at[7] = map->glyphs[mapch].tymax;
1795                                 av[ 0] = x + dw * map->glyphs[mapch].vxmin; av[ 1] = y + dh * map->glyphs[mapch].vymin; av[ 2] = 10;
1796                                 av[ 3] = x + dw * map->glyphs[mapch].vxmax; av[ 4] = y + dh * map->glyphs[mapch].vymin; av[ 5] = 10;
1797                                 av[ 6] = x + dw * map->glyphs[mapch].vxmax; av[ 7] = y + dh * map->glyphs[mapch].vymax; av[ 8] = 10;
1798                                 av[ 9] = x + dw * map->glyphs[mapch].vxmin; av[10] = y + dh * map->glyphs[mapch].vymax; av[11] = 10;
1799                                 //x -= ftbase_x;
1800                                 y -= ftbase_y;
1801
1802                                 x += thisw * dw;
1803                                 ac += 16;
1804                                 at += 8;
1805                                 av += 12;
1806                                 batchcount++;
1807                                 if (batchcount >= QUADELEMENTS_MAXQUADS)
1808                                 {
1809                                         R_Mesh_PrepareVertices_Generic_Arrays(batchcount * 4, vertex3f, color4f, texcoord2f);
1810                                         R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, NULL, 0, quadelement3s, NULL, 0);
1811                                         batchcount = 0;
1812                                         ac = color4f;
1813                                         at = texcoord2f;
1814                                         av = vertex3f;
1815                                 }
1816
1817                                 //prevmap = map;
1818                                 prevch = ch;
1819                         }
1820 out:
1821                         if (shadow)
1822                         {
1823                                 x -= 1.0/pix_x * r_textshadow.value;
1824                                 y -= 1.0/pix_y * r_textshadow.value;
1825                         }
1826                 }
1827         }
1828         if (batchcount > 0)
1829         {
1830                 R_Mesh_PrepareVertices_Generic_Arrays(batchcount * 4, vertex3f, color4f, texcoord2f);
1831                 R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, NULL, 0, quadelement3s, NULL, 0);
1832         }
1833
1834         if (outcolor)
1835                 *outcolor = colorindex;
1836         
1837         // note: this relies on the proper text (not shadow) being drawn last
1838         return x;
1839 }
1840
1841 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)
1842 {
1843         return DrawQ_String_Scale(startx, starty, text, maxlen, w, h, 1, 1, basered, basegreen, baseblue, basealpha, flags, outcolor, ignorecolorcodes, fnt);
1844 }
1845
1846 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)
1847 {
1848         return DrawQ_TextWidth_UntilWidth_TrackColors_Scale(text, maxlen, w, h, 1, 1, outcolor, ignorecolorcodes, fnt, maxwidth);
1849 }
1850
1851 float DrawQ_TextWidth(const char *text, size_t maxlen, float w, float h, qboolean ignorecolorcodes, const dp_font_t *fnt)
1852 {
1853         return DrawQ_TextWidth_UntilWidth(text, &maxlen, w, h, ignorecolorcodes, fnt, 1000000000);
1854 }
1855
1856 float DrawQ_TextWidth_UntilWidth(const char *text, size_t *maxlen, float w, float h, qboolean ignorecolorcodes, const dp_font_t *fnt, float maxWidth)
1857 {
1858         return DrawQ_TextWidth_UntilWidth_TrackColors(text, maxlen, w, h, NULL, ignorecolorcodes, fnt, maxWidth);
1859 }
1860
1861 #if 0
1862 // not used
1863 // no ^xrgb management
1864 static int DrawQ_BuildColoredText(char *output2c, size_t maxoutchars, const char *text, int maxreadchars, qboolean ignorecolorcodes, int *outcolor)
1865 {
1866         int color, numchars = 0;
1867         char *outputend2c = output2c + maxoutchars - 2;
1868         if (!outcolor || *outcolor == -1)
1869                 color = STRING_COLOR_DEFAULT;
1870         else
1871                 color = *outcolor;
1872         if (!maxreadchars)
1873                 maxreadchars = 1<<30;
1874         textend = text + maxreadchars;
1875         while (text != textend && *text)
1876         {
1877                 if (*text == STRING_COLOR_TAG && !ignorecolorcodes && text + 1 != textend)
1878                 {
1879                         if (text[1] == STRING_COLOR_TAG)
1880                                 text++;
1881                         else if (text[1] >= '0' && text[1] <= '9')
1882                         {
1883                                 color = text[1] - '0';
1884                                 text += 2;
1885                                 continue;
1886                         }
1887                 }
1888                 if (output2c >= outputend2c)
1889                         break;
1890                 *output2c++ = *text++;
1891                 *output2c++ = color;
1892                 numchars++;
1893         }
1894         output2c[0] = output2c[1] = 0;
1895         if (outcolor)
1896                 *outcolor = color;
1897         return numchars;
1898 }
1899 #endif
1900
1901 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)
1902 {
1903         float floats[36];
1904
1905         _DrawQ_SetupAndProcessDrawFlag(flags, pic, a1*a2*a3*a4);
1906         if(!r_draw2d.integer && !r_draw2d_force)
1907                 return;
1908
1909 //      R_Mesh_ResetTextureState();
1910         if (pic)
1911         {
1912                 if (width == 0)
1913                         width = pic->width;
1914                 if (height == 0)
1915                         height = pic->height;
1916                 R_SetupShader_Generic(Draw_GetPicTexture(pic), NULL, GL_MODULATE, 1, (flags & DRAWFLAGS_BLEND) ? false : true, true, false);
1917         }
1918         else
1919                 R_SetupShader_Generic_NoTexture((flags & DRAWFLAGS_BLEND) ? false : true, true);
1920
1921         floats[2] = floats[5] = floats[8] = floats[11] = 0;
1922         floats[0] = floats[9] = x;
1923         floats[1] = floats[4] = y;
1924         floats[3] = floats[6] = x + width;
1925         floats[7] = floats[10] = y + height;
1926         floats[12] = s1;floats[13] = t1;
1927         floats[14] = s2;floats[15] = t2;
1928         floats[16] = s4;floats[17] = t4;
1929         floats[18] = s3;floats[19] = t3;
1930         floats[20] = r1;floats[21] = g1;floats[22] = b1;floats[23] = a1;
1931         floats[24] = r2;floats[25] = g2;floats[26] = b2;floats[27] = a2;
1932         floats[28] = r4;floats[29] = g4;floats[30] = b4;floats[31] = a4;
1933         floats[32] = r3;floats[33] = g3;floats[34] = b3;floats[35] = a3;
1934
1935         R_Mesh_PrepareVertices_Generic_Arrays(4, floats, floats + 20, floats + 12);
1936         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
1937 }
1938
1939 void DrawQ_Mesh (drawqueuemesh_t *mesh, int flags, qboolean hasalpha)
1940 {
1941         _DrawQ_Setup();
1942         if(!r_draw2d.integer && !r_draw2d_force)
1943                 return;
1944         DrawQ_ProcessDrawFlag(flags, hasalpha);
1945
1946 //      R_Mesh_ResetTextureState();
1947         R_SetupShader_Generic(mesh->texture, NULL, GL_MODULATE, 1, (flags & DRAWFLAGS_BLEND) ? false : true, true, false);
1948
1949         R_Mesh_PrepareVertices_Generic_Arrays(mesh->num_vertices, mesh->data_vertex3f, mesh->data_color4f, mesh->data_texcoord2f);
1950         R_Mesh_Draw(0, mesh->num_vertices, 0, mesh->num_triangles, mesh->data_element3i, NULL, 0, mesh->data_element3s, NULL, 0);
1951 }
1952
1953 void DrawQ_LineLoop (drawqueuemesh_t *mesh, int flags)
1954 {
1955         int num;
1956
1957         _DrawQ_SetupAndProcessDrawFlag(flags, NULL, 1);
1958         if(!r_draw2d.integer && !r_draw2d_force)
1959                 return;
1960
1961         GL_Color(1,1,1,1);
1962         switch(vid.renderpath)
1963         {
1964         case RENDERPATH_GL11:
1965         case RENDERPATH_GL13:
1966         case RENDERPATH_GL20:
1967 #ifndef USE_GLES2
1968                 CHECKGLERROR
1969                 qglBegin(GL_LINE_LOOP);
1970                 for (num = 0;num < mesh->num_vertices;num++)
1971                 {
1972                         if (mesh->data_color4f)
1973                                 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]);
1974                         qglVertex2f(mesh->data_vertex3f[num*3+0], mesh->data_vertex3f[num*3+1]);
1975                 }
1976                 qglEnd();
1977                 CHECKGLERROR
1978 #endif
1979                 break;
1980         case RENDERPATH_D3D9:
1981                 //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1982                 break;
1983         case RENDERPATH_D3D10:
1984                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1985                 break;
1986         case RENDERPATH_D3D11:
1987                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1988                 break;
1989         case RENDERPATH_SOFT:
1990                 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1991                 break;
1992         case RENDERPATH_GLES1:
1993         case RENDERPATH_GLES2:
1994                 //Con_DPrintf("FIXME GLES2 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1995                 return;
1996         }
1997 }
1998
1999 //[515]: this is old, delete
2000 void DrawQ_Line (float width, float x1, float y1, float x2, float y2, float r, float g, float b, float alpha, int flags)
2001 {
2002         _DrawQ_SetupAndProcessDrawFlag(flags, NULL, alpha);
2003         if(!r_draw2d.integer && !r_draw2d_force)
2004                 return;
2005
2006         R_SetupShader_Generic_NoTexture((flags & DRAWFLAGS_BLEND) ? false : true, true);
2007
2008         switch(vid.renderpath)
2009         {
2010         case RENDERPATH_GL11:
2011         case RENDERPATH_GL13:
2012         case RENDERPATH_GL20:
2013 #ifndef USE_GLES2
2014                 CHECKGLERROR
2015
2016                 //qglLineWidth(width);CHECKGLERROR
2017
2018                 GL_Color(r,g,b,alpha);
2019                 CHECKGLERROR
2020                 qglBegin(GL_LINES);
2021                 qglVertex2f(x1, y1);
2022                 qglVertex2f(x2, y2);
2023                 qglEnd();
2024                 CHECKGLERROR
2025 #endif
2026                 break;
2027         case RENDERPATH_D3D9:
2028                 //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2029                 break;
2030         case RENDERPATH_D3D10:
2031                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2032                 break;
2033         case RENDERPATH_D3D11:
2034                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2035                 break;
2036         case RENDERPATH_SOFT:
2037                 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2038                 break;
2039         case RENDERPATH_GLES1:
2040         case RENDERPATH_GLES2:
2041                 //Con_DPrintf("FIXME GLES2 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2042                 return;
2043         }
2044 }
2045
2046 void DrawQ_Lines (float width, int numlines, const float *vertex3f, const float *color4f, int flags)
2047 {
2048         int i;
2049         qboolean hasalpha = false;
2050         for (i = 0;i < numlines*2;i++)
2051                 if (color4f[i*4+3] < 1.0f)
2052                         hasalpha = true;
2053
2054         _DrawQ_SetupAndProcessDrawFlag(flags, NULL, hasalpha ? 0.5f : 1.0f);
2055
2056         if(!r_draw2d.integer && !r_draw2d_force)
2057                 return;
2058
2059         switch(vid.renderpath)
2060         {
2061         case RENDERPATH_GL11:
2062         case RENDERPATH_GL13:
2063         case RENDERPATH_GL20:
2064                 CHECKGLERROR
2065
2066                 R_SetupShader_Generic_NoTexture((flags & DRAWFLAGS_BLEND) ? false : true, true);
2067
2068                 //qglLineWidth(width);CHECKGLERROR
2069
2070                 CHECKGLERROR
2071                 R_Mesh_PrepareVertices_Generic_Arrays(numlines*2, vertex3f, color4f, NULL);
2072                 qglDrawArrays(GL_LINES, 0, numlines*2);
2073                 CHECKGLERROR
2074                 break;
2075         case RENDERPATH_D3D9:
2076                 //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2077                 break;
2078         case RENDERPATH_D3D10:
2079                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2080                 break;
2081         case RENDERPATH_D3D11:
2082                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2083                 break;
2084         case RENDERPATH_SOFT:
2085                 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2086                 break;
2087         case RENDERPATH_GLES1:
2088         case RENDERPATH_GLES2:
2089                 //Con_DPrintf("FIXME GLES2 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2090                 return;
2091         }
2092 }
2093
2094 void DrawQ_SetClipArea(float x, float y, float width, float height)
2095 {
2096         int ix, iy, iw, ih;
2097         _DrawQ_Setup();
2098
2099         // We have to convert the con coords into real coords
2100         // OGL uses top to bottom
2101         ix = (int)(0.5 + x * ((float)vid.width / vid_conwidth.integer));
2102         iy = (int)(0.5 + y * ((float) vid.height / vid_conheight.integer));
2103         iw = (int)(0.5 + (x+width) * ((float)vid.width / vid_conwidth.integer)) - ix;
2104         ih = (int)(0.5 + (y+height) * ((float) vid.height / vid_conheight.integer)) - iy;
2105         switch(vid.renderpath)
2106         {
2107         case RENDERPATH_GL11:
2108         case RENDERPATH_GL13:
2109         case RENDERPATH_GL20:
2110         case RENDERPATH_GLES1:
2111         case RENDERPATH_GLES2:
2112         case RENDERPATH_SOFT:
2113                 GL_Scissor(ix, vid.height - iy - ih, iw, ih);
2114                 break;
2115         case RENDERPATH_D3D9:
2116                 GL_Scissor(ix, iy, iw, ih);
2117                 break;
2118         case RENDERPATH_D3D10:
2119                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2120                 break;
2121         case RENDERPATH_D3D11:
2122                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2123                 break;
2124         }
2125
2126         GL_ScissorTest(true);
2127 }
2128
2129 void DrawQ_ResetClipArea(void)
2130 {
2131         _DrawQ_Setup();
2132         GL_ScissorTest(false);
2133 }
2134
2135 void DrawQ_Finish(void)
2136 {
2137         r_refdef.draw2dstage = 0;
2138 }
2139
2140 void DrawQ_RecalcView(void)
2141 {
2142         if(r_refdef.draw2dstage)
2143                 r_refdef.draw2dstage = -1; // next draw call will set viewport etc. again
2144 }
2145
2146 static float blendvertex3f[9] = {-5000, -5000, 10, 10000, -5000, 10, -5000, 10000, 10};
2147 void R_DrawGamma(void)
2148 {
2149         float c[4];
2150         switch(vid.renderpath)
2151         {
2152         case RENDERPATH_GL20:
2153         case RENDERPATH_D3D9:
2154         case RENDERPATH_D3D10:
2155         case RENDERPATH_D3D11:
2156         case RENDERPATH_GLES2:
2157                 if (vid_usinghwgamma || v_glslgamma.integer)
2158                         return;
2159                 break;
2160         case RENDERPATH_GL11:
2161         case RENDERPATH_GL13:
2162                 if (vid_usinghwgamma)
2163                         return;
2164                 break;
2165         case RENDERPATH_GLES1:
2166         case RENDERPATH_SOFT:
2167                 return;
2168         }
2169         // all the blends ignore depth
2170 //      R_Mesh_ResetTextureState();
2171         R_SetupShader_Generic_NoTexture(true, true);
2172         GL_DepthMask(true);
2173         GL_DepthRange(0, 1);
2174         GL_PolygonOffset(0, 0);
2175         GL_DepthTest(false);
2176
2177         // interpretation of brightness and contrast:
2178         //   color range := brightness .. (brightness + contrast)
2179         // i.e. "c *= contrast; c += brightness"
2180         // plausible values for brightness thus range from -contrast to 1
2181
2182         // apply pre-brightness (subtractive brightness, for where contrast was >= 1)
2183         if (vid.support.ext_blend_subtract)
2184         {
2185                 if (v_color_enable.integer)
2186                 {
2187                         c[0] = -v_color_black_r.value / v_color_white_r.value;
2188                         c[1] = -v_color_black_g.value / v_color_white_g.value;
2189                         c[2] = -v_color_black_b.value / v_color_white_b.value;
2190                 }
2191                 else
2192                         c[0] = c[1] = c[2] = -v_brightness.value / v_contrast.value;
2193                 if (c[0] >= 0.01f || c[1] >= 0.01f || c[2] >= 0.01f)
2194                 {
2195                         // need SUBTRACTIVE blending to do this!
2196                         GL_BlendEquationSubtract(true);
2197                         GL_BlendFunc(GL_ONE, GL_ONE);
2198                         GL_Color(c[0], c[1], c[2], 1);
2199                         R_Mesh_PrepareVertices_Generic_Arrays(3, blendvertex3f, NULL, NULL);
2200                         R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
2201                         GL_BlendEquationSubtract(false);
2202                 }
2203         }
2204
2205         // apply contrast
2206         if (v_color_enable.integer)
2207         {
2208                 c[0] = v_color_white_r.value;
2209                 c[1] = v_color_white_g.value;
2210                 c[2] = v_color_white_b.value;
2211         }
2212         else
2213                 c[0] = c[1] = c[2] = v_contrast.value;
2214         if (c[0] >= 1.003f || c[1] >= 1.003f || c[2] >= 1.003f)
2215         {
2216                 GL_BlendFunc(GL_DST_COLOR, GL_ONE);
2217                 while (c[0] >= 1.003f || c[1] >= 1.003f || c[2] >= 1.003f)
2218                 {
2219                         float cc[4];
2220                         cc[0] = bound(0, c[0] - 1, 1);
2221                         cc[1] = bound(0, c[1] - 1, 1);
2222                         cc[2] = bound(0, c[2] - 1, 1);
2223                         GL_Color(cc[0], cc[1], cc[2], 1);
2224                         R_Mesh_PrepareVertices_Generic_Arrays(3, blendvertex3f, NULL, NULL);
2225                         R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
2226                         c[0] /= 1 + cc[0];
2227                         c[1] /= 1 + cc[1];
2228                         c[2] /= 1 + cc[2];
2229                 }
2230         }
2231         if (c[0] <= 0.997f || c[1] <= 0.997f || c[2] <= 0.997f)
2232         {
2233                 GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
2234                 GL_Color(c[0], c[1], c[2], 1);
2235                 R_Mesh_PrepareVertices_Generic_Arrays(3, blendvertex3f, NULL, NULL);
2236                 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
2237         }
2238
2239         // apply post-brightness (additive brightness, for where contrast was <= 1)
2240         if (v_color_enable.integer)
2241         {
2242                 c[0] = v_color_black_r.value;
2243                 c[1] = v_color_black_g.value;
2244                 c[2] = v_color_black_b.value;
2245         }
2246         else
2247                 c[0] = c[1] = c[2] = v_brightness.value;
2248         if (c[0] >= 0.01f || c[1] >= 0.01f || c[2] >= 0.01f)
2249         {
2250                 GL_BlendFunc(GL_ONE, GL_ONE);
2251                 GL_Color(c[0], c[1], c[2], 1);
2252                 R_Mesh_PrepareVertices_Generic_Arrays(3, blendvertex3f, NULL, NULL);
2253                 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
2254         }
2255 }
2256