2 Copyright (C) 1996-1997 Id Software, Inc.
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.
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.
13 See the GNU General Public License for more details.
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.
26 #include "cl_dyntexture.h"
29 #include "ft2_fontdefs.h"
31 dp_font_t dp_fonts[MAX_FONTS] = {{0}};
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)"};
37 extern cvar_t v_glslgamma;
39 //=============================================================================
40 /* Support Routines */
42 #define FONT_FILESIZE 13468
43 static cachepic_t *cachepichash[CACHEPICHASHSIZE];
44 static cachepic_t cachepics[MAX_CACHED_PICS];
45 static int numcachepics;
47 static rtexturepool_t *drawtexturepool;
49 static const unsigned char concharimage[FONT_FILESIZE] =
54 static rtexture_t *draw_generateconchars(void)
61 data = LoadTGA_BGRA (concharimage, FONT_FILESIZE);
63 for (i = 0;i < 8192;i++)
65 random = lhrandom (0.0,1.0);
66 data[i*4+3] = data[i*4+0];
67 data[i*4+2] = 83 + (unsigned char)(random * 64);
68 data[i*4+1] = 71 + (unsigned char)(random * 32);
69 data[i*4+0] = 23 + (unsigned char)(random * 16);
72 for (i = 8192;i < 32768;i++)
74 random = lhrandom (0.0,1.0);
75 data[i*4+3] = data[i*4+0];
76 data[i*4+2] = 95 + (unsigned char)(random * 64);
77 data[i*4+1] = 95 + (unsigned char)(random * 64);
78 data[i*4+0] = 95 + (unsigned char)(random * 64);
81 for (i = 32768;i < 40960;i++)
83 random = lhrandom (0.0,1.0);
84 data[i*4+3] = data[i*4+0];
85 data[i*4+2] = 83 + (unsigned char)(random * 64);
86 data[i*4+1] = 71 + (unsigned char)(random * 32);
87 data[i*4+0] = 23 + (unsigned char)(random * 16);
90 for (i = 40960;i < 65536;i++)
92 random = lhrandom (0.0,1.0);
93 data[i*4+3] = data[i*4+0];
94 data[i*4+2] = 96 + (unsigned char)(random * 64);
95 data[i*4+1] = 43 + (unsigned char)(random * 32);
96 data[i*4+0] = 27 + (unsigned char)(random * 32);
100 Image_WriteTGABGRA ("gfx/generated_conchars.tga", 256, 256, data);
103 tex = R_LoadTexture2D(drawtexturepool, "conchars", 256, 256, data, TEXTYPE_BGRA, TEXF_ALPHA, NULL);
108 static rtexture_t *draw_generateditherpattern(void)
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, palette_bgra_transparent);
118 typedef struct embeddedpic_s
127 static const embeddedpic_t embeddedpics[] =
130 "gfx/prydoncursor001", 16, 16,
149 "ui/mousepointer", 16, 16,
168 "gfx/crosshair1", 16, 16,
187 "gfx/crosshair2", 16, 16,
206 "gfx/crosshair3", 16, 16,
225 "gfx/crosshair4", 16, 16,
244 "gfx/crosshair5", 8, 8,
255 "gfx/crosshair6", 2, 2,
260 "gfx/crosshair7", 16, 16,
281 static rtexture_t *draw_generatepic(const char *name, qboolean quiet)
283 const embeddedpic_t *p;
284 for (p = embeddedpics;p->name;p++)
285 if (!strcmp(name, p->name))
286 return R_LoadTexture2D(drawtexturepool, p->name, p->width, p->height, (const unsigned char *)p->pixels, TEXTYPE_PALETTE, TEXF_ALPHA, palette_bgra_embeddedpic);
287 if (!strcmp(name, "gfx/conchars"))
288 return draw_generateconchars();
289 if (!strcmp(name, "gfx/colorcontrol/ditherpattern"))
290 return draw_generateditherpattern();
292 Con_DPrintf("Draw_CachePic: failed to load %s\n", name);
293 return r_texture_notexture;
302 // FIXME: move this to client somehow
303 cachepic_t *Draw_CachePic_Flags(const char *path, unsigned int cachepicflags)
306 unsigned char *pixels;
309 unsigned char *lmpdata;
310 char lmpname[MAX_QPATH];
312 // check whether the picture has already been cached
313 crc = CRC_Block((unsigned char *)path, strlen(path));
314 hashkey = ((crc >> 8) ^ crc) % CACHEPICHASHSIZE;
315 for (pic = cachepichash[hashkey];pic;pic = pic->chain)
316 if (!strcmp (path, pic->name))
319 if (numcachepics == MAX_CACHED_PICS)
321 Con_Printf ("Draw_CachePic: numcachepics == MAX_CACHED_PICS\n");
322 // FIXME: support NULL in callers?
323 return cachepics; // return the first one
325 pic = cachepics + (numcachepics++);
326 strlcpy (pic->name, path, sizeof(pic->name));
328 pic->chain = cachepichash[hashkey];
329 cachepichash[hashkey] = pic;
331 // check whether it is an dynamic texture (if so, we can directly use its texture handler)
332 pic->tex = CL_GetDynTexture( path );
333 // if so, set the width/height, too
335 pic->width = R_TextureWidth(pic->tex);
336 pic->height = R_TextureHeight(pic->tex);
337 // we're done now (early-out)
341 pic->texflags = TEXF_ALPHA;
342 if (!(cachepicflags & CACHEPICFLAG_NOCLAMP))
343 pic->texflags |= TEXF_CLAMP;
344 if (!(cachepicflags & CACHEPICFLAG_NOCOMPRESSION) && gl_texturecompression_2d.integer)
345 pic->texflags |= TEXF_COMPRESS;
347 pic->autoload = (cachepicflags & CACHEPICFLAG_NOTPERSISTENT);
349 // load a high quality image from disk if possible
350 pixels = loadimagepixelsbgra(path, false, true);
351 if (pixels == NULL && !strncmp(path, "gfx/", 4))
352 pixels = loadimagepixelsbgra(path+4, false, true);
355 pic->width = image_width;
356 pic->height = image_height;
358 pic->tex = R_LoadTexture2D(drawtexturepool, path, image_width, image_height, pixels, TEXTYPE_BGRA, pic->texflags, NULL);
362 pic->autoload = false;
363 // never compress the fallback images
364 pic->texflags &= ~TEXF_COMPRESS;
367 // now read the low quality version (wad or lmp file), and take the pic
368 // size from that even if we don't upload the texture, this way the pics
369 // show up the right size in the menu even if they were replaced with
370 // higher or lower resolution versions
371 dpsnprintf(lmpname, sizeof(lmpname), "%s.lmp", path);
372 if (!strncmp(path, "gfx/", 4) && (lmpdata = FS_LoadFile(lmpname, tempmempool, false, &lmpsize)))
374 if (developer_loading.integer)
375 Con_Printf("loading lump \"%s\"\n", path);
379 pic->width = lmpdata[0] + lmpdata[1] * 256 + lmpdata[2] * 65536 + lmpdata[3] * 16777216;
380 pic->height = lmpdata[4] + lmpdata[5] * 256 + lmpdata[6] * 65536 + lmpdata[7] * 16777216;
381 // if no high quality replacement image was found, upload the original low quality texture
383 pic->tex = R_LoadTexture2D(drawtexturepool, path, pic->width, pic->height, lmpdata + 8, TEXTYPE_PALETTE, pic->texflags, palette_bgra_transparent);
387 else if ((lmpdata = W_GetLumpName (path + 4)))
389 if (developer_loading.integer)
390 Con_Printf("loading gfx.wad lump \"%s\"\n", path + 4);
392 if (!strcmp(path, "gfx/conchars"))
394 // conchars is a raw image and with color 0 as transparent instead of 255
397 // if no high quality replacement image was found, upload the original low quality texture
399 pic->tex = R_LoadTexture2D(drawtexturepool, path, 128, 128, lmpdata, TEXTYPE_PALETTE, pic->texflags, palette_bgra_font);
403 pic->width = lmpdata[0] + lmpdata[1] * 256 + lmpdata[2] * 65536 + lmpdata[3] * 16777216;
404 pic->height = lmpdata[4] + lmpdata[5] * 256 + lmpdata[6] * 65536 + lmpdata[7] * 16777216;
405 // if no high quality replacement image was found, upload the original low quality texture
407 pic->tex = R_LoadTexture2D(drawtexturepool, path, pic->width, pic->height, lmpdata + 8, TEXTYPE_PALETTE, pic->texflags, palette_bgra_transparent);
416 else if (pic->tex == NULL)
418 // if it's not found on disk, generate an image
419 pic->tex = draw_generatepic(path, (cachepicflags & CACHEPICFLAG_QUIET) != 0);
420 pic->width = R_TextureWidth(pic->tex);
421 pic->height = R_TextureHeight(pic->tex);
427 cachepic_t *Draw_CachePic (const char *path)
429 return Draw_CachePic_Flags (path, 0);
434 rtexture_t *Draw_GetPicTexture(cachepic_t *pic)
436 if (pic->autoload && !pic->tex)
438 pic->tex = loadtextureimage(drawtexturepool, pic->name, false, pic->texflags, true);
439 if (pic->tex == NULL && !strncmp(pic->name, "gfx/", 4))
440 pic->tex = loadtextureimage(drawtexturepool, pic->name+4, false, pic->texflags, true);
441 if (pic->tex == NULL)
442 pic->tex = draw_generatepic(pic->name, true);
444 pic->lastusedframe = draw_frame;
448 void Draw_Frame(void)
452 static double nextpurgetime;
454 if (nextpurgetime > realtime)
456 nextpurgetime = realtime + 0.05;
457 purgeframe = draw_frame - 1;
458 for (i = 0, pic = cachepics;i < numcachepics;i++, pic++)
460 if (pic->autoload && pic->tex && pic->lastusedframe < draw_frame)
462 R_FreeTexture(pic->tex);
469 cachepic_t *Draw_NewPic(const char *picname, int width, int height, int alpha, unsigned char *pixels_bgra)
474 crc = CRC_Block((unsigned char *)picname, strlen(picname));
475 hashkey = ((crc >> 8) ^ crc) % CACHEPICHASHSIZE;
476 for (pic = cachepichash[hashkey];pic;pic = pic->chain)
477 if (!strcmp (picname, pic->name))
482 if (pic->tex && pic->width == width && pic->height == height)
484 R_UpdateTexture(pic->tex, pixels_bgra, 0, 0, width, height);
492 if (numcachepics == MAX_CACHED_PICS)
494 Con_Printf ("Draw_NewPic: numcachepics == MAX_CACHED_PICS\n");
495 // FIXME: support NULL in callers?
496 return cachepics; // return the first one
498 pic = cachepics + (numcachepics++);
499 strlcpy (pic->name, picname, sizeof(pic->name));
501 pic->chain = cachepichash[hashkey];
502 cachepichash[hashkey] = pic;
507 pic->height = height;
509 R_FreeTexture(pic->tex);
510 pic->tex = R_LoadTexture2D(drawtexturepool, picname, width, height, pixels_bgra, TEXTYPE_BGRA, (alpha ? TEXF_ALPHA : 0) | TEXF_ALLOWUPDATES, NULL);
514 void Draw_FreePic(const char *picname)
519 // this doesn't really free the pic, but does free it's texture
520 crc = CRC_Block((unsigned char *)picname, strlen(picname));
521 hashkey = ((crc >> 8) ^ crc) % CACHEPICHASHSIZE;
522 for (pic = cachepichash[hashkey];pic;pic = pic->chain)
524 if (!strcmp (picname, pic->name) && pic->tex)
526 R_FreeTexture(pic->tex);
535 static float snap_to_pixel_x(float x, float roundUpAt);
536 extern int con_linewidth; // to force rewrapping
537 static void LoadFont(qboolean override, const char *name, dp_font_t *fnt)
540 float maxwidth, scale;
541 char widthfile[MAX_QPATH];
543 fs_offset_t widthbufsize;
545 if(override || !fnt->texpath[0])
546 strlcpy(fnt->texpath, name, sizeof(fnt->texpath));
548 if(drawtexturepool == NULL)
549 return; // before gl_draw_start, so will be loaded later
553 // clear freetype font
554 Font_UnloadFont(fnt->ft2);
559 if(fnt->req_face != -1)
561 if(!Font_LoadFont(fnt->texpath, fnt))
562 Con_DPrintf("Failed to load font-file for '%s', it will not support as many characters.\n", fnt->texpath);
565 fnt->tex = Draw_CachePic_Flags(fnt->texpath, CACHEPICFLAG_QUIET | CACHEPICFLAG_NOCOMPRESSION)->tex;
566 if(fnt->tex == r_texture_notexture)
568 for (i = 0; i < MAX_FONT_FALLBACKS; ++i)
570 if (!fnt->fallbacks[i][0])
572 fnt->tex = Draw_CachePic_Flags(fnt->fallbacks[i], CACHEPICFLAG_QUIET | CACHEPICFLAG_NOCOMPRESSION)->tex;
573 if(fnt->tex != r_texture_notexture)
576 if(fnt->tex == r_texture_notexture)
578 fnt->tex = Draw_CachePic_Flags("gfx/conchars", CACHEPICFLAG_NOCOMPRESSION)->tex;
579 strlcpy(widthfile, "gfx/conchars.width", sizeof(widthfile));
582 dpsnprintf(widthfile, sizeof(widthfile), "%s.width", fnt->fallbacks[i]);
585 dpsnprintf(widthfile, sizeof(widthfile), "%s.width", fnt->texpath);
587 // unspecified width == 1 (base width)
588 for(i = 1; i < 256; ++i)
589 fnt->width_of[i] = 1;
592 // FIXME load "name.width", if it fails, fill all with 1
593 if((widthbuf = (char *) FS_LoadFile(widthfile, tempmempool, true, &widthbufsize)))
595 float extraspacing = 0;
596 const char *p = widthbuf;
601 if(!COM_ParseToken_Simple(&p, false, false))
619 fnt->width_of[ch] = atof(com_token) + extraspacing;
622 for (i = 0; i < MAX_FONT_SIZES && fnt->req_sizes[i] >= 0; ++i)
623 Font_MapForIndex(fnt->ft2, i)->width_of[ch] = snap_to_pixel_x(fnt->width_of[ch] * fnt->req_sizes[i], 0.4);
628 if(!strcmp(com_token, "extraspacing"))
630 if(!COM_ParseToken_Simple(&p, false, false))
632 extraspacing = atof(com_token);
634 else if(!strcmp(com_token, "scale"))
636 if(!COM_ParseToken_Simple(&p, false, false))
638 scale = atof(com_token);
642 Con_Printf("Warning: skipped unknown font property %s\n", com_token);
643 if(!COM_ParseToken_Simple(&p, false, false))
653 maxwidth = fnt->width_of[1];
654 for(i = 2; i < 256; ++i)
655 maxwidth = max(maxwidth, fnt->width_of[i]);
656 fnt->maxwidth = maxwidth;
658 // fix up maxwidth for overlap
659 fnt->maxwidth *= scale;
662 if(fnt == FONT_CONSOLE)
663 con_linewidth = -1; // rewrap console in next frame
666 static dp_font_t *FindFont(const char *title)
669 for(i = 0; i < MAX_FONTS; ++i)
670 if(!strcmp(dp_fonts[i].title, title))
675 static float snap_to_pixel_x(float x, float roundUpAt)
677 float pixelpos = x * vid.width / vid_conwidth.value;
678 int snap = (int) pixelpos;
679 if (pixelpos - snap >= roundUpAt) ++snap;
680 return ((float)snap * vid_conwidth.value / vid.width);
682 x = (int)(x * vid.width / vid_conwidth.value);
683 x = (x * vid_conwidth.value / vid.width);
688 static float snap_to_pixel_y(float y, float roundUpAt)
690 float pixelpos = y * vid.height / vid_conheight.value;
691 int snap = (int) pixelpos;
692 if (pixelpos - snap > roundUpAt) ++snap;
693 return ((float)snap * vid_conheight.value / vid.height);
695 y = (int)(y * vid.height / vid_conheight.value);
696 y = (y * vid_conheight.value / vid.height);
701 static void LoadFont_f(void)
705 const char *filelist, *c, *cm;
707 char mainfont[MAX_QPATH];
711 Con_Printf("Available font commands:\n");
712 for(i = 0; i < MAX_FONTS; ++i)
713 Con_Printf(" loadfont %s gfx/tgafile[...] [sizes...]\n", dp_fonts[i].title);
714 Con_Printf("A font can simply be gfx/tgafile, or alternatively you\n"
715 "can specify multiple fonts and faces\n"
716 "Like this: gfx/vera-sans:2,gfx/fallback:1\n"
717 "to load face 2 of the font gfx/vera-sans and use face 1\n"
718 "of gfx/fallback as fallback font.\n"
719 "You can also specify a list of font sizes to load, like this:\n"
720 "loadfont console gfx/conchars,gfx/fallback 8 12 16 24 32\n"
721 "In many cases, 8 12 16 24 32 should be a good choice.\n"
725 f = FindFont(Cmd_Argv(1));
728 Con_Printf("font function not found\n");
733 filelist = "gfx/conchars";
735 filelist = Cmd_Argv(2);
737 memset(f->fallbacks, 0, sizeof(f->fallbacks));
738 memset(f->fallback_faces, 0, sizeof(f->fallback_faces));
740 // first font is handled "normally"
741 c = strchr(filelist, ':');
742 cm = strchr(filelist, ',');
743 if(c && (!cm || c < cm))
744 f->req_face = atoi(c+1);
751 if(!c || (c - filelist) > MAX_QPATH)
752 strlcpy(mainfont, filelist, sizeof(mainfont));
755 memcpy(mainfont, filelist, c - filelist);
756 mainfont[c - filelist] = 0;
759 for(i = 0; i < MAX_FONT_FALLBACKS; ++i)
761 c = strchr(filelist, ',');
767 c = strchr(filelist, ':');
768 cm = strchr(filelist, ',');
769 if(c && (!cm || c < cm))
770 f->fallback_faces[i] = atoi(c+1);
773 f->fallback_faces[i] = 0; // f->req_face; could make it stick to the default-font's face index
776 if(!c || (c-filelist) > MAX_QPATH)
778 strlcpy(f->fallbacks[i], filelist, sizeof(mainfont));
782 memcpy(f->fallbacks[i], filelist, c - filelist);
783 f->fallbacks[i][c - filelist] = 0;
787 // for now: by default load only one size: the default size
789 for(i = 1; i < MAX_FONT_SIZES; ++i)
790 f->req_sizes[i] = -1;
792 // for some reason this argc is 3 even when using 2 arguments here, maybe nexuiz screws up
795 for(i = 0; i < Cmd_Argc()-3; ++i)
797 sz = atof(Cmd_Argv(i+3));
798 if (sz > 0.001f && sz < 1000.0f) // do not use crap sizes
799 f->req_sizes[i] = sz;
802 LoadFont(true, mainfont, f);
810 static void gl_draw_start(void)
813 drawtexturepool = R_AllocTexturePool();
816 memset(cachepichash, 0, sizeof(cachepichash));
820 for(i = 0; i < MAX_FONTS; ++i)
821 LoadFont(false, va("gfx/font_%s", dp_fonts[i].title), &dp_fonts[i]);
823 // draw the loading screen so people have something to see in the newly opened window
824 SCR_UpdateLoadingScreen(true);
827 static void gl_draw_shutdown(void)
831 R_FreeTexturePool(&drawtexturepool);
834 memset(cachepichash, 0, sizeof(cachepichash));
837 static void gl_draw_newmap(void)
842 void GL_Draw_Init (void)
845 Cvar_RegisterVariable(&r_textshadow);
846 Cvar_RegisterVariable(&r_textbrightness);
847 Cvar_RegisterVariable(&r_textcontrast);
848 Cmd_AddCommand ("loadfont",LoadFont_f, "loadfont function tganame loads a font; example: loadfont console gfx/veramono; loadfont without arguments lists the available functions");
849 R_RegisterModule("GL_Draw", gl_draw_start, gl_draw_shutdown, gl_draw_newmap);
851 strlcpy(FONT_DEFAULT->title, "default", sizeof(FONT_DEFAULT->title));
852 strlcpy(FONT_DEFAULT->texpath, "gfx/conchars", sizeof(FONT_DEFAULT->texpath));
853 strlcpy(FONT_CONSOLE->title, "console", sizeof(FONT_CONSOLE->title));
854 strlcpy(FONT_SBAR->title, "sbar", sizeof(FONT_SBAR->title));
855 strlcpy(FONT_NOTIFY->title, "notify", sizeof(FONT_NOTIFY->title));
856 strlcpy(FONT_CHAT->title, "chat", sizeof(FONT_CHAT->title));
857 strlcpy(FONT_CENTERPRINT->title, "centerprint", sizeof(FONT_CENTERPRINT->title));
858 strlcpy(FONT_INFOBAR->title, "infobar", sizeof(FONT_INFOBAR->title));
859 strlcpy(FONT_MENU->title, "menu", sizeof(FONT_MENU->title));
860 for(i = 0, j = 0; i < MAX_USERFONTS; ++i)
861 if(!FONT_USER[i].title[0])
862 dpsnprintf(FONT_USER[i].title, sizeof(FONT_USER[i].title), "user%d", j++);
866 void _DrawQ_Setup(void)
868 r_viewport_t viewport;
869 if (r_refdef.draw2dstage)
871 r_refdef.draw2dstage = true;
873 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);
874 R_SetViewport(&viewport);
875 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
876 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
877 qglDisable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
878 GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
879 R_EntityMatrix(&identitymatrix);
883 GL_PolygonOffset(0, 0);
887 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
890 static void _DrawQ_ProcessDrawFlag(int flags)
894 if(flags == DRAWFLAG_ADDITIVE)
895 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
896 else if(flags == DRAWFLAG_MODULATE)
897 GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
898 else if(flags == DRAWFLAG_2XMODULATE)
899 GL_BlendFunc(GL_DST_COLOR,GL_SRC_COLOR);
900 else if(flags == DRAWFLAG_SCREEN)
901 GL_BlendFunc(GL_ONE_MINUS_DST_COLOR,GL_ONE);
903 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
906 void DrawQ_Pic(float x, float y, cachepic_t *pic, float width, float height, float red, float green, float blue, float alpha, int flags)
910 _DrawQ_ProcessDrawFlag(flags);
911 GL_Color(red, green, blue, alpha);
913 R_Mesh_VertexPointer(floats, 0, 0);
914 R_Mesh_ColorPointer(NULL, 0, 0);
915 R_Mesh_ResetTextureState();
921 height = pic->height;
922 R_SetupShader_Generic(Draw_GetPicTexture(pic), NULL, GL_MODULATE, 1);
923 R_Mesh_TexCoordPointer(0, 2, floats + 12, 0, 0);
926 floats[12] = 0.0f;floats[13] = 0.0f;
927 floats[14] = 1.0f;floats[15] = 0.0f;
928 floats[16] = 1.0f;floats[17] = 1.0f;
929 floats[18] = 0.0f;floats[19] = 1.0f;
931 // AK07: lets be texel correct on the corners
933 float horz_offset = 0.5f / pic->width;
934 float vert_offset = 0.5f / pic->height;
936 floats[12] = 0.0f + horz_offset;floats[13] = 0.0f + vert_offset;
937 floats[14] = 1.0f - horz_offset;floats[15] = 0.0f + vert_offset;
938 floats[16] = 1.0f - horz_offset;floats[17] = 1.0f - vert_offset;
939 floats[18] = 0.0f + horz_offset;floats[19] = 1.0f - vert_offset;
944 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
946 floats[2] = floats[5] = floats[8] = floats[11] = 0;
947 floats[0] = floats[9] = x;
948 floats[1] = floats[4] = y;
949 floats[3] = floats[6] = x + width;
950 floats[7] = floats[10] = y + height;
952 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
955 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)
958 float af = DEG2RAD(-angle); // forward
959 float ar = DEG2RAD(-angle + 90); // right
960 float sinaf = sin(af);
961 float cosaf = cos(af);
962 float sinar = sin(ar);
963 float cosar = cos(ar);
965 _DrawQ_ProcessDrawFlag(flags);
966 GL_Color(red, green, blue, alpha);
968 R_Mesh_VertexPointer(floats, 0, 0);
969 R_Mesh_ColorPointer(NULL, 0, 0);
970 R_Mesh_ResetTextureState();
976 height = pic->height;
977 R_SetupShader_Generic(Draw_GetPicTexture(pic), NULL, GL_MODULATE, 1);
978 R_Mesh_TexCoordPointer(0, 2, floats + 12, 0, 0);
980 floats[12] = 0.0f;floats[13] = 0.0f;
981 floats[14] = 1.0f;floats[15] = 0.0f;
982 floats[16] = 1.0f;floats[17] = 1.0f;
983 floats[18] = 0.0f;floats[19] = 1.0f;
986 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
988 floats[2] = floats[5] = floats[8] = floats[11] = 0;
991 floats[0] = x - cosaf*org_x - cosar*org_y;
992 floats[1] = y - sinaf*org_x - sinar*org_y;
995 floats[3] = x + cosaf*(width-org_x) - cosar*org_y;
996 floats[4] = y + sinaf*(width-org_x) - sinar*org_y;
999 floats[6] = x + cosaf*(width-org_x) + cosar*(height-org_y);
1000 floats[7] = y + sinaf*(width-org_x) + sinar*(height-org_y);
1003 floats[9] = x - cosaf*org_x + cosar*(height-org_y);
1004 floats[10] = y - sinaf*org_x + sinar*(height-org_y);
1006 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
1009 void DrawQ_Fill(float x, float y, float width, float height, float red, float green, float blue, float alpha, int flags)
1013 _DrawQ_ProcessDrawFlag(flags);
1014 GL_Color(red, green, blue, alpha);
1016 R_Mesh_VertexPointer(floats, 0, 0);
1017 R_Mesh_ColorPointer(NULL, 0, 0);
1018 R_Mesh_ResetTextureState();
1019 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
1021 floats[2] = floats[5] = floats[8] = floats[11] = 0;
1022 floats[0] = floats[9] = x;
1023 floats[1] = floats[4] = y;
1024 floats[3] = floats[6] = x + width;
1025 floats[7] = floats[10] = y + height;
1027 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
1030 /// color tag printing
1031 static const vec4_t string_colors[] =
1034 // LordHavoc: why on earth is cyan before magenta in Quake3?
1035 // LordHavoc: note: Doom3 uses white for [0] and [7]
1036 {0.0, 0.0, 0.0, 1.0}, // black
1037 {1.0, 0.0, 0.0, 1.0}, // red
1038 {0.0, 1.0, 0.0, 1.0}, // green
1039 {1.0, 1.0, 0.0, 1.0}, // yellow
1040 {0.0, 0.0, 1.0, 1.0}, // blue
1041 {0.0, 1.0, 1.0, 1.0}, // cyan
1042 {1.0, 0.0, 1.0, 1.0}, // magenta
1043 {1.0, 1.0, 1.0, 1.0}, // white
1044 // [515]'s BX_COLOREDTEXT extension
1045 {1.0, 1.0, 1.0, 0.5}, // half transparent
1046 {0.5, 0.5, 0.5, 1.0} // half brightness
1047 // Black's color table
1048 //{1.0, 1.0, 1.0, 1.0},
1049 //{1.0, 0.0, 0.0, 1.0},
1050 //{0.0, 1.0, 0.0, 1.0},
1051 //{0.0, 0.0, 1.0, 1.0},
1052 //{1.0, 1.0, 0.0, 1.0},
1053 //{0.0, 1.0, 1.0, 1.0},
1054 //{1.0, 0.0, 1.0, 1.0},
1055 //{0.1, 0.1, 0.1, 1.0}
1058 #define STRING_COLORS_COUNT (sizeof(string_colors) / sizeof(vec4_t))
1060 static void DrawQ_GetTextColor(float color[4], int colorindex, float r, float g, float b, float a, qboolean shadow)
1062 float C = r_textcontrast.value;
1063 float B = r_textbrightness.value;
1064 if (colorindex & 0x10000) // that bit means RGB color
1066 color[0] = ((colorindex >> 12) & 0xf) / 15.0;
1067 color[1] = ((colorindex >> 8) & 0xf) / 15.0;
1068 color[2] = ((colorindex >> 4) & 0xf) / 15.0;
1069 color[3] = (colorindex & 0xf) / 15.0;
1072 Vector4Copy(string_colors[colorindex], color);
1073 Vector4Set(color, color[0] * r * C + B, color[1] * g * C + B, color[2] * b * C + B, color[3] * a);
1076 float shadowalpha = (color[0]+color[1]+color[2]) * 0.8;
1077 Vector4Set(color, 0, 0, 0, color[3] * bound(0, shadowalpha, 1));
1081 // NOTE: this function always draws exactly one character if maxwidth <= 0
1082 float DrawQ_TextWidth_UntilWidth_TrackColors_Scale(const char *text, size_t *maxlen, float w, float h, float sw, float sh, int *outcolor, qboolean ignorecolorcodes, const dp_font_t *fnt, float maxwidth)
1084 const char *text_start = text;
1085 int colorindex = STRING_COLOR_DEFAULT;
1088 Uchar ch, mapch, nextch;
1089 Uchar prevch = 0; // used for kerning
1094 ft2_font_map_t *fontmap = NULL;
1095 ft2_font_map_t *map = NULL;
1096 ft2_font_map_t *prevmap = NULL;
1097 ft2_font_t *ft2 = fnt->ft2;
1099 qboolean snap = true;
1100 qboolean least_one = false;
1101 float dw, dh; // display w/h
1102 float width_of_factor;
1103 const float *width_of;
1110 // do this in the end
1114 // find the most fitting size:
1118 map_index = Font_IndexForSize(ft2, h, &w, &h);
1120 map_index = Font_IndexForSize(ft2, h, NULL, NULL);
1121 fontmap = Font_MapForIndex(ft2, map_index);
1130 if (!outcolor || *outcolor == -1)
1131 colorindex = STRING_COLOR_DEFAULT;
1133 colorindex = *outcolor;
1135 // maxwidth /= fnt->scale; // w and h are multiplied by it already
1136 // ftbase_x = snap_to_pixel_x(0);
1141 maxwidth = -maxwidth;
1145 // x = snap_to_pixel_x(x, 0.4); // haha, it's 0 anyway
1149 width_of_factor = 1;
1150 width_of = fontmap->width_of;
1154 width_of_factor = dw;
1155 width_of = fnt->width_of;
1158 for (i = 0;((bytes_left = *maxlen - (text - text_start)) > 0) && *text;)
1161 nextch = ch = u8_getnchar(text, &text, bytes_left);
1162 i = text - text_start;
1165 if (ch == ' ' && !fontmap)
1167 if(!least_one || i0) // never skip the first character
1168 if(x + width_of[(int) ' '] * width_of_factor > maxwidth)
1171 break; // oops, can't draw this
1173 x += width_of[(int) ' '] * width_of_factor;
1176 // i points to the char after ^
1177 if (ch == STRING_COLOR_TAG && !ignorecolorcodes && i < *maxlen)
1179 ch = *text; // colors are ascii, so no u8_ needed
1180 if (ch <= '9' && ch >= '0') // ^[0-9] found
1182 colorindex = ch - '0';
1187 // i points to the char after ^...
1188 // i+3 points to 3 in ^x123
1189 // i+3 == *maxlen would mean that char is missing
1190 else if (ch == STRING_COLOR_RGB_TAG_CHAR && i + 3 < *maxlen ) // ^x found
1192 // building colorindex...
1193 ch = tolower(text[1]);
1194 tempcolorindex = 0x10000; // binary: 1,0000,0000,0000,0000
1195 if (ch <= '9' && ch >= '0') tempcolorindex |= (ch - '0') << 12;
1196 else if (ch >= 'a' && ch <= 'f') tempcolorindex |= (ch - 87) << 12;
1197 else tempcolorindex = 0;
1200 ch = tolower(text[2]);
1201 if (ch <= '9' && ch >= '0') tempcolorindex |= (ch - '0') << 8;
1202 else if (ch >= 'a' && ch <= 'f') tempcolorindex |= (ch - 87) << 8;
1203 else tempcolorindex = 0;
1206 ch = tolower(text[3]);
1207 if (ch <= '9' && ch >= '0') tempcolorindex |= (ch - '0') << 4;
1208 else if (ch >= 'a' && ch <= 'f') tempcolorindex |= (ch - 87) << 4;
1209 else tempcolorindex = 0;
1212 colorindex = tempcolorindex | 0xf;
1213 // ...done! now colorindex has rgba codes (1,rrrr,gggg,bbbb,aaaa)
1221 else if (ch == STRING_COLOR_TAG) // ^^ found, ignore the first ^ and go to print the second
1230 if (!fontmap || (ch <= 0xFF && fontmap->glyphs[ch].image) || (ch >= 0xE000 && ch <= 0xE0FF))
1237 map = ft2_oldstyle_map;
1239 if(!least_one || i0) // never skip the first character
1240 if(x + width_of[ch] * width_of_factor > maxwidth)
1243 break; // oops, can't draw this
1245 x += width_of[ch] * width_of_factor;
1247 if (!map || map == ft2_oldstyle_map || map->start < ch || map->start + FONT_CHARS_PER_MAP >= ch)
1249 map = FontMap_FindForChar(fontmap, ch);
1252 if (!Font_LoadMapForIndex(ft2, map_index, ch, &map))
1258 mapch = ch - map->start;
1259 if (prevch && Font_GetKerningForMap(ft2, map_index, w, h, prevch, ch, &kx, NULL))
1261 x += map->glyphs[mapch].advance_x * dw;
1270 *outcolor = colorindex;
1275 float DrawQ_String_Scale(float startx, float starty, const char *text, size_t maxlen, float w, float h, float sw, float sh, float basered, float basegreen, float baseblue, float basealpha, int flags, int *outcolor, qboolean ignorecolorcodes, const dp_font_t *fnt)
1277 int shadow, colorindex = STRING_COLOR_DEFAULT;
1279 float x = startx, y, s, t, u, v, thisw;
1280 float *av, *at, *ac;
1283 static float vertex3f[QUADELEMENTS_MAXQUADS*4*3];
1284 static float texcoord2f[QUADELEMENTS_MAXQUADS*4*2];
1285 static float color4f[QUADELEMENTS_MAXQUADS*4*4];
1286 Uchar ch, mapch, nextch;
1287 Uchar prevch = 0; // used for kerning
1290 ft2_font_map_t *prevmap = NULL; // the previous map
1291 ft2_font_map_t *map = NULL; // the currently used map
1292 ft2_font_map_t *fontmap = NULL; // the font map for the size
1294 const char *text_start = text;
1296 ft2_font_t *ft2 = fnt->ft2;
1297 qboolean snap = true;
1301 float width_of_factor;
1302 const float *width_of;
1305 tw = R_TextureWidth(fnt->tex);
1306 th = R_TextureHeight(fnt->tex);
1314 starty -= (fnt->scale - 1) * h * 0.5; // center
1321 map_index = Font_IndexForSize(ft2, h, &w, &h);
1323 map_index = Font_IndexForSize(ft2, h, NULL, NULL);
1324 fontmap = Font_MapForIndex(ft2, map_index);
1330 // draw the font at its baseline when using freetype
1332 ftbase_y = dh * (4.5/6.0);
1337 _DrawQ_ProcessDrawFlag(flags);
1339 R_Mesh_ColorPointer(color4f, 0, 0);
1340 R_Mesh_ResetTextureState();
1342 R_Mesh_TexBind(0, fnt->tex);
1343 R_Mesh_TexCoordPointer(0, 2, texcoord2f, 0, 0);
1344 R_Mesh_VertexPointer(vertex3f, 0, 0);
1345 R_SetupShader_Generic(fnt->tex, NULL, GL_MODULATE, 1);
1352 //ftbase_x = snap_to_pixel_x(ftbase_x);
1355 startx = snap_to_pixel_x(startx, 0.4);
1356 starty = snap_to_pixel_y(starty, 0.4);
1357 ftbase_y = snap_to_pixel_y(ftbase_y, 0.3);
1360 pix_x = vid.width / vid_conwidth.value;
1361 pix_y = vid.height / vid_conheight.value;
1365 width_of_factor = 1;
1366 width_of = fontmap->width_of;
1370 width_of_factor = dw;
1371 width_of = fnt->width_of;
1374 for (shadow = r_textshadow.value != 0 && basealpha > 0;shadow >= 0;shadow--)
1379 if (!outcolor || *outcolor == -1)
1380 colorindex = STRING_COLOR_DEFAULT;
1382 colorindex = *outcolor;
1384 DrawQ_GetTextColor(color, colorindex, basered, basegreen, baseblue, basealpha, shadow != 0);
1391 x += r_textshadow.value * vid.width / vid_conwidth.value;
1392 y += r_textshadow.value * vid.height / vid_conheight.value;
1395 for (i = 0;((bytes_left = maxlen - (text - text_start)) > 0) && *text;)
1397 nextch = ch = u8_getnchar(text, &text, bytes_left);
1398 i = text - text_start;
1401 if (ch == ' ' && !fontmap)
1403 x += width_of[(int) ' '] * width_of_factor;
1406 if (ch == STRING_COLOR_TAG && !ignorecolorcodes && i < maxlen)
1408 ch = *text; // colors are ascii, so no u8_ needed
1409 if (ch <= '9' && ch >= '0') // ^[0-9] found
1411 colorindex = ch - '0';
1412 DrawQ_GetTextColor(color, colorindex, basered, basegreen, baseblue, basealpha, shadow != 0);
1417 else if (ch == STRING_COLOR_RGB_TAG_CHAR && i+3 < maxlen ) // ^x found
1419 // building colorindex...
1420 ch = tolower(text[1]);
1421 tempcolorindex = 0x10000; // binary: 1,0000,0000,0000,0000
1422 if (ch <= '9' && ch >= '0') tempcolorindex |= (ch - '0') << 12;
1423 else if (ch >= 'a' && ch <= 'f') tempcolorindex |= (ch - 87) << 12;
1424 else tempcolorindex = 0;
1427 ch = tolower(text[2]);
1428 if (ch <= '9' && ch >= '0') tempcolorindex |= (ch - '0') << 8;
1429 else if (ch >= 'a' && ch <= 'f') tempcolorindex |= (ch - 87) << 8;
1430 else tempcolorindex = 0;
1433 ch = tolower(text[3]);
1434 if (ch <= '9' && ch >= '0') tempcolorindex |= (ch - '0') << 4;
1435 else if (ch >= 'a' && ch <= 'f') tempcolorindex |= (ch - 87) << 4;
1436 else tempcolorindex = 0;
1439 colorindex = tempcolorindex | 0xf;
1440 // ...done! now colorindex has rgba codes (1,rrrr,gggg,bbbb,aaaa)
1441 //Con_Printf("^1colorindex:^7 %x\n", colorindex);
1442 DrawQ_GetTextColor(color, colorindex, basered, basegreen, baseblue, basealpha, shadow != 0);
1450 else if (ch == STRING_COLOR_TAG)
1459 // using a value of -1 for the oldstyle map because NULL means uninitialized...
1460 // this way we don't need to rebind fnt->tex for every old-style character
1461 // E000..E0FF: emulate old-font characters (to still have smileys and such available)
1464 x += 1.0/pix_x * r_textshadow.value;
1465 y += 1.0/pix_y * r_textshadow.value;
1467 if (!fontmap || (ch <= 0xFF && fontmap->glyphs[ch].image) || (ch >= 0xE000 && ch <= 0xE0FF))
1475 if (map != ft2_oldstyle_map)
1479 // switching from freetype to non-freetype rendering
1480 GL_LockArrays(0, batchcount * 4);
1481 R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, quadelement3s, 0, 0);
1482 GL_LockArrays(0, 0);
1488 R_SetupShader_Generic(fnt->tex, NULL, GL_MODULATE, 1);
1489 map = ft2_oldstyle_map;
1493 //num = (unsigned char) text[i];
1494 //thisw = fnt->width_of[num];
1495 thisw = fnt->width_of[ch];
1496 // FIXME make these smaller to just include the occupied part of the character for slightly faster rendering
1497 s = (ch & 15)*0.0625f + (0.5f / tw);
1498 t = (ch >> 4)*0.0625f + (0.5f / th);
1499 u = 0.0625f * thisw - (1.0f / tw);
1500 v = 0.0625f - (1.0f / th);
1501 ac[ 0] = color[0];ac[ 1] = color[1];ac[ 2] = color[2];ac[ 3] = color[3];
1502 ac[ 4] = color[0];ac[ 5] = color[1];ac[ 6] = color[2];ac[ 7] = color[3];
1503 ac[ 8] = color[0];ac[ 9] = color[1];ac[10] = color[2];ac[11] = color[3];
1504 ac[12] = color[0];ac[13] = color[1];ac[14] = color[2];ac[15] = color[3];
1505 at[ 0] = s ; at[ 1] = t ;
1506 at[ 2] = s+u ; at[ 3] = t ;
1507 at[ 4] = s+u ; at[ 5] = t+v ;
1508 at[ 6] = s ; at[ 7] = t+v ;
1509 av[ 0] = x ; av[ 1] = y ; av[ 2] = 10;
1510 av[ 3] = x+dw*thisw ; av[ 4] = y ; av[ 5] = 10;
1511 av[ 6] = x+dw*thisw ; av[ 7] = y+dh ; av[ 8] = 10;
1512 av[ 9] = x ; av[10] = y+dh ; av[11] = 10;
1517 if (batchcount >= QUADELEMENTS_MAXQUADS)
1519 GL_LockArrays(0, batchcount * 4);
1520 R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, quadelement3s, 0, 0);
1521 GL_LockArrays(0, 0);
1527 x += width_of[ch] * width_of_factor;
1529 if (!map || map == ft2_oldstyle_map || map->start < ch || map->start + FONT_CHARS_PER_MAP >= ch)
1531 // new charmap - need to render
1534 // we need a different character map, render what we currently have:
1535 GL_LockArrays(0, batchcount * 4);
1536 R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, quadelement3s, 0, 0);
1537 GL_LockArrays(0, 0);
1544 map = FontMap_FindForChar(fontmap, ch);
1547 if (!Font_LoadMapForIndex(ft2, map_index, ch, &map))
1554 // this shouldn't happen
1559 R_SetupShader_Generic(map->texture, NULL, GL_MODULATE, 1);
1562 mapch = ch - map->start;
1563 thisw = map->glyphs[mapch].advance_x;
1567 if (prevch && Font_GetKerningForMap(ft2, map_index, w, h, prevch, ch, &kx, &ky))
1574 ac[ 0] = color[0]; ac[ 1] = color[1]; ac[ 2] = color[2]; ac[ 3] = color[3];
1575 ac[ 4] = color[0]; ac[ 5] = color[1]; ac[ 6] = color[2]; ac[ 7] = color[3];
1576 ac[ 8] = color[0]; ac[ 9] = color[1]; ac[10] = color[2]; ac[11] = color[3];
1577 ac[12] = color[0]; ac[13] = color[1]; ac[14] = color[2]; ac[15] = color[3];
1578 at[0] = map->glyphs[mapch].txmin; at[1] = map->glyphs[mapch].tymin;
1579 at[2] = map->glyphs[mapch].txmax; at[3] = map->glyphs[mapch].tymin;
1580 at[4] = map->glyphs[mapch].txmax; at[5] = map->glyphs[mapch].tymax;
1581 at[6] = map->glyphs[mapch].txmin; at[7] = map->glyphs[mapch].tymax;
1582 av[ 0] = x + dw * map->glyphs[mapch].vxmin; av[ 1] = y + dh * map->glyphs[mapch].vymin; av[ 2] = 10;
1583 av[ 3] = x + dw * map->glyphs[mapch].vxmax; av[ 4] = y + dh * map->glyphs[mapch].vymin; av[ 5] = 10;
1584 av[ 6] = x + dw * map->glyphs[mapch].vxmax; av[ 7] = y + dh * map->glyphs[mapch].vymax; av[ 8] = 10;
1585 av[ 9] = x + dw * map->glyphs[mapch].vxmin; av[10] = y + dh * map->glyphs[mapch].vymax; av[11] = 10;
1594 if (batchcount >= QUADELEMENTS_MAXQUADS)
1596 GL_LockArrays(0, batchcount * 4);
1597 R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, quadelement3s, 0, 0);
1598 GL_LockArrays(0, 0);
1610 x -= 1.0/pix_x * r_textshadow.value;
1611 y -= 1.0/pix_y * r_textshadow.value;
1617 GL_LockArrays(0, batchcount * 4);
1618 R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, quadelement3s, 0, 0);
1619 GL_LockArrays(0, 0);
1623 *outcolor = colorindex;
1625 // note: this relies on the proper text (not shadow) being drawn last
1629 float DrawQ_String(float startx, float starty, const char *text, size_t maxlen, float w, float h, float basered, float basegreen, float baseblue, float basealpha, int flags, int *outcolor, qboolean ignorecolorcodes, const dp_font_t *fnt)
1631 return DrawQ_String_Scale(startx, starty, text, maxlen, w, h, 1, 1, basered, basegreen, baseblue, basealpha, flags, outcolor, ignorecolorcodes, fnt);
1634 float DrawQ_TextWidth_UntilWidth_TrackColors(const char *text, size_t *maxlen, float w, float h, int *outcolor, qboolean ignorecolorcodes, const dp_font_t *fnt, float maxwidth)
1636 return DrawQ_TextWidth_UntilWidth_TrackColors_Scale(text, maxlen, w, h, 1, 1, outcolor, ignorecolorcodes, fnt, maxwidth);
1639 float DrawQ_TextWidth(const char *text, size_t maxlen, float w, float h, qboolean ignorecolorcodes, const dp_font_t *fnt)
1641 return DrawQ_TextWidth_UntilWidth(text, &maxlen, w, h, ignorecolorcodes, fnt, 1000000000);
1644 float DrawQ_TextWidth_UntilWidth(const char *text, size_t *maxlen, float w, float h, qboolean ignorecolorcodes, const dp_font_t *fnt, float maxWidth)
1646 return DrawQ_TextWidth_UntilWidth_TrackColors(text, maxlen, w, h, NULL, ignorecolorcodes, fnt, maxWidth);
1651 // no ^xrgb management
1652 static int DrawQ_BuildColoredText(char *output2c, size_t maxoutchars, const char *text, int maxreadchars, qboolean ignorecolorcodes, int *outcolor)
1654 int color, numchars = 0;
1655 char *outputend2c = output2c + maxoutchars - 2;
1656 if (!outcolor || *outcolor == -1)
1657 color = STRING_COLOR_DEFAULT;
1661 maxreadchars = 1<<30;
1662 textend = text + maxreadchars;
1663 while (text != textend && *text)
1665 if (*text == STRING_COLOR_TAG && !ignorecolorcodes && text + 1 != textend)
1667 if (text[1] == STRING_COLOR_TAG)
1669 else if (text[1] >= '0' && text[1] <= '9')
1671 color = text[1] - '0';
1676 if (output2c >= outputend2c)
1678 *output2c++ = *text++;
1679 *output2c++ = color;
1682 output2c[0] = output2c[1] = 0;
1689 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)
1693 _DrawQ_ProcessDrawFlag(flags);
1695 R_Mesh_VertexPointer(floats, 0, 0);
1696 R_Mesh_ColorPointer(floats + 20, 0, 0);
1697 R_Mesh_ResetTextureState();
1703 height = pic->height;
1704 R_SetupShader_Generic(Draw_GetPicTexture(pic), NULL, GL_MODULATE, 1);
1705 R_Mesh_TexCoordPointer(0, 2, floats + 12, 0, 0);
1706 floats[12] = s1;floats[13] = t1;
1707 floats[14] = s2;floats[15] = t2;
1708 floats[16] = s4;floats[17] = t4;
1709 floats[18] = s3;floats[19] = t3;
1712 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
1714 floats[2] = floats[5] = floats[8] = floats[11] = 0;
1715 floats[0] = floats[9] = x;
1716 floats[1] = floats[4] = y;
1717 floats[3] = floats[6] = x + width;
1718 floats[7] = floats[10] = y + height;
1719 floats[20] = r1;floats[21] = g1;floats[22] = b1;floats[23] = a1;
1720 floats[24] = r2;floats[25] = g2;floats[26] = b2;floats[27] = a2;
1721 floats[28] = r4;floats[29] = g4;floats[30] = b4;floats[31] = a4;
1722 floats[32] = r3;floats[33] = g3;floats[34] = b3;floats[35] = a3;
1724 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
1727 void DrawQ_Mesh (drawqueuemesh_t *mesh, int flags)
1729 _DrawQ_ProcessDrawFlag(flags);
1731 R_Mesh_VertexPointer(mesh->data_vertex3f, 0, 0);
1732 R_Mesh_ColorPointer(mesh->data_color4f, 0, 0);
1733 R_Mesh_ResetTextureState();
1734 R_Mesh_TexCoordPointer(0, 2, mesh->data_texcoord2f, 0, 0);
1735 R_SetupShader_Generic(mesh->texture, NULL, GL_MODULATE, 1);
1737 GL_LockArrays(0, mesh->num_vertices);
1738 R_Mesh_Draw(0, mesh->num_vertices, 0, mesh->num_triangles, mesh->data_element3i, mesh->data_element3s, 0, 0);
1739 GL_LockArrays(0, 0);
1742 void DrawQ_LineLoop (drawqueuemesh_t *mesh, int flags)
1746 _DrawQ_ProcessDrawFlag(flags);
1750 qglBegin(GL_LINE_LOOP);
1751 for (num = 0;num < mesh->num_vertices;num++)
1753 if (mesh->data_color4f)
1754 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]);
1755 qglVertex2f(mesh->data_vertex3f[num*3+0], mesh->data_vertex3f[num*3+1]);
1761 //[515]: this is old, delete
1762 void DrawQ_Line (float width, float x1, float y1, float x2, float y2, float r, float g, float b, float alpha, int flags)
1764 _DrawQ_ProcessDrawFlag(flags);
1766 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
1769 //qglLineWidth(width);CHECKGLERROR
1771 GL_Color(r,g,b,alpha);
1774 qglVertex2f(x1, y1);
1775 qglVertex2f(x2, y2);
1780 void DrawQ_SetClipArea(float x, float y, float width, float height)
1785 // We have to convert the con coords into real coords
1786 // OGL uses top to bottom
1787 ix = (int)(0.5 + x * ((float)vid.width / vid_conwidth.integer));
1788 iy = (int)(0.5 + y * ((float) vid.height / vid_conheight.integer));
1789 iw = (int)(width * ((float)vid.width / vid_conwidth.integer));
1790 ih = (int)(height * ((float)vid.height / vid_conheight.integer));
1791 GL_Scissor(ix, vid.height - iy - ih, iw, ih);
1793 GL_ScissorTest(true);
1796 void DrawQ_ResetClipArea(void)
1799 GL_ScissorTest(false);
1802 void DrawQ_Finish(void)
1804 r_refdef.draw2dstage = false;
1807 static float blendvertex3f[9] = {-5000, -5000, 10, 10000, -5000, 10, -5000, 10000, 10};
1808 void R_DrawGamma(void)
1811 switch(vid.renderpath)
1813 case RENDERPATH_GL20:
1814 case RENDERPATH_CGGL:
1815 if (vid_usinghwgamma || v_glslgamma.integer)
1818 case RENDERPATH_GL13:
1819 case RENDERPATH_GL11:
1820 if (vid_usinghwgamma)
1824 // all the blends ignore depth
1825 R_Mesh_VertexPointer(blendvertex3f, 0, 0);
1826 R_Mesh_ColorPointer(NULL, 0, 0);
1827 R_Mesh_ResetTextureState();
1828 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
1830 GL_DepthRange(0, 1);
1831 GL_PolygonOffset(0, 0);
1832 GL_DepthTest(false);
1833 if (v_color_enable.integer)
1835 c[0] = v_color_white_r.value;
1836 c[1] = v_color_white_g.value;
1837 c[2] = v_color_white_b.value;
1840 c[0] = c[1] = c[2] = v_contrast.value;
1841 if (c[0] >= 1.01f || c[1] >= 1.01f || c[2] >= 1.01f)
1843 GL_BlendFunc(GL_DST_COLOR, GL_ONE);
1844 while (c[0] >= 1.01f || c[1] >= 1.01f || c[2] >= 1.01f)
1846 GL_Color(bound(0, c[0] - 1, 1), bound(0, c[1] - 1, 1), bound(0, c[2] - 1, 1), 1);
1847 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, polygonelement3s, 0, 0);
1848 VectorScale(c, 0.5, c);
1851 if (v_color_enable.integer)
1853 c[0] = v_color_black_r.value;
1854 c[1] = v_color_black_g.value;
1855 c[2] = v_color_black_b.value;
1858 c[0] = c[1] = c[2] = v_brightness.value;
1859 if (c[0] >= 0.01f || c[1] >= 0.01f || c[2] >= 0.01f)
1861 GL_BlendFunc(GL_ONE, GL_ONE);
1862 GL_Color(c[0], c[1], c[2], 1);
1863 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, polygonelement3s, 0, 0);