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