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