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