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; ++i)
624 //Font_MapForIndex(fnt->ft2, i)->width_of[ch] = snap_to_pixel_x(fnt->width_of[ch] * fnt->req_sizes[i], 0.4);
625 ft2_font_map_t *map = Font_MapForIndex(fnt->ft2, i);
628 map->width_of[ch] = Font_SnapTo(fnt->width_of[ch], 1/map->size);
634 if(!strcmp(com_token, "extraspacing"))
636 if(!COM_ParseToken_Simple(&p, false, false))
638 extraspacing = atof(com_token);
640 else if(!strcmp(com_token, "scale"))
642 if(!COM_ParseToken_Simple(&p, false, false))
644 scale = atof(com_token);
648 Con_Printf("Warning: skipped unknown font property %s\n", com_token);
649 if(!COM_ParseToken_Simple(&p, false, false))
659 maxwidth = fnt->width_of[1];
660 for(i = 2; i < 256; ++i)
661 maxwidth = max(maxwidth, fnt->width_of[i]);
662 fnt->maxwidth = maxwidth;
664 // fix up maxwidth for overlap
665 fnt->maxwidth *= scale;
668 if(fnt == FONT_CONSOLE)
669 con_linewidth = -1; // rewrap console in next frame
672 static dp_font_t *FindFont(const char *title)
675 for(i = 0; i < MAX_FONTS; ++i)
676 if(!strcmp(dp_fonts[i].title, title))
681 static float snap_to_pixel_x(float x, float roundUpAt)
683 float pixelpos = x * vid.width / vid_conwidth.value;
684 int snap = (int) pixelpos;
685 if (pixelpos - snap >= roundUpAt) ++snap;
686 return ((float)snap * vid_conwidth.value / vid.width);
688 x = (int)(x * vid.width / vid_conwidth.value);
689 x = (x * vid_conwidth.value / vid.width);
694 static float snap_to_pixel_y(float y, float roundUpAt)
696 float pixelpos = y * vid.height / vid_conheight.value;
697 int snap = (int) pixelpos;
698 if (pixelpos - snap > roundUpAt) ++snap;
699 return ((float)snap * vid_conheight.value / vid.height);
701 y = (int)(y * vid.height / vid_conheight.value);
702 y = (y * vid_conheight.value / vid.height);
707 static void LoadFont_f(void)
711 const char *filelist, *c, *cm;
713 char mainfont[MAX_QPATH];
717 Con_Printf("Available font commands:\n");
718 for(i = 0; i < MAX_FONTS; ++i)
719 Con_Printf(" loadfont %s gfx/tgafile[...] [sizes...]\n", dp_fonts[i].title);
720 Con_Printf("A font can simply be gfx/tgafile, or alternatively you\n"
721 "can specify multiple fonts and faces\n"
722 "Like this: gfx/vera-sans:2,gfx/fallback:1\n"
723 "to load face 2 of the font gfx/vera-sans and use face 1\n"
724 "of gfx/fallback as fallback font.\n"
725 "You can also specify a list of font sizes to load, like this:\n"
726 "loadfont console gfx/conchars,gfx/fallback 8 12 16 24 32\n"
727 "In many cases, 8 12 16 24 32 should be a good choice.\n"
731 f = FindFont(Cmd_Argv(1));
734 Con_Printf("font function not found\n");
739 filelist = "gfx/conchars";
741 filelist = Cmd_Argv(2);
743 memset(f->fallbacks, 0, sizeof(f->fallbacks));
744 memset(f->fallback_faces, 0, sizeof(f->fallback_faces));
746 // first font is handled "normally"
747 c = strchr(filelist, ':');
748 cm = strchr(filelist, ',');
749 if(c && (!cm || c < cm))
750 f->req_face = atoi(c+1);
757 if(!c || (c - filelist) > MAX_QPATH)
758 strlcpy(mainfont, filelist, sizeof(mainfont));
761 memcpy(mainfont, filelist, c - filelist);
762 mainfont[c - filelist] = 0;
765 for(i = 0; i < MAX_FONT_FALLBACKS; ++i)
767 c = strchr(filelist, ',');
773 c = strchr(filelist, ':');
774 cm = strchr(filelist, ',');
775 if(c && (!cm || c < cm))
776 f->fallback_faces[i] = atoi(c+1);
779 f->fallback_faces[i] = 0; // f->req_face; could make it stick to the default-font's face index
782 if(!c || (c-filelist) > MAX_QPATH)
784 strlcpy(f->fallbacks[i], filelist, sizeof(mainfont));
788 memcpy(f->fallbacks[i], filelist, c - filelist);
789 f->fallbacks[i][c - filelist] = 0;
793 // for now: by default load only one size: the default size
795 for(i = 1; i < MAX_FONT_SIZES; ++i)
796 f->req_sizes[i] = -1;
800 for(i = 0; i < Cmd_Argc()-3; ++i)
802 sz = atof(Cmd_Argv(i+3));
803 if (sz > 0.001f && sz < 1000.0f) // do not use crap sizes
804 f->req_sizes[i] = sz;
807 LoadFont(true, mainfont, f);
815 static void gl_draw_start(void)
818 drawtexturepool = R_AllocTexturePool();
821 memset(cachepichash, 0, sizeof(cachepichash));
825 for(i = 0; i < MAX_FONTS; ++i)
826 LoadFont(false, va("gfx/font_%s", dp_fonts[i].title), &dp_fonts[i]);
828 // draw the loading screen so people have something to see in the newly opened window
829 SCR_UpdateLoadingScreen(true);
832 static void gl_draw_shutdown(void)
836 R_FreeTexturePool(&drawtexturepool);
839 memset(cachepichash, 0, sizeof(cachepichash));
842 static void gl_draw_newmap(void)
847 void GL_Draw_Init (void)
850 Cvar_RegisterVariable(&r_textshadow);
851 Cvar_RegisterVariable(&r_textbrightness);
852 Cvar_RegisterVariable(&r_textcontrast);
853 Cmd_AddCommand ("loadfont",LoadFont_f, "loadfont function tganame loads a font; example: loadfont console gfx/veramono; loadfont without arguments lists the available functions");
854 R_RegisterModule("GL_Draw", gl_draw_start, gl_draw_shutdown, gl_draw_newmap);
856 strlcpy(FONT_DEFAULT->title, "default", sizeof(FONT_DEFAULT->title));
857 strlcpy(FONT_DEFAULT->texpath, "gfx/conchars", sizeof(FONT_DEFAULT->texpath));
858 strlcpy(FONT_CONSOLE->title, "console", sizeof(FONT_CONSOLE->title));
859 strlcpy(FONT_SBAR->title, "sbar", sizeof(FONT_SBAR->title));
860 strlcpy(FONT_NOTIFY->title, "notify", sizeof(FONT_NOTIFY->title));
861 strlcpy(FONT_CHAT->title, "chat", sizeof(FONT_CHAT->title));
862 strlcpy(FONT_CENTERPRINT->title, "centerprint", sizeof(FONT_CENTERPRINT->title));
863 strlcpy(FONT_INFOBAR->title, "infobar", sizeof(FONT_INFOBAR->title));
864 strlcpy(FONT_MENU->title, "menu", sizeof(FONT_MENU->title));
865 for(i = 0, j = 0; i < MAX_USERFONTS; ++i)
866 if(!FONT_USER[i].title[0])
867 dpsnprintf(FONT_USER[i].title, sizeof(FONT_USER[i].title), "user%d", j++);
870 void _DrawQ_Setup(void)
872 r_viewport_t viewport;
873 if (r_refdef.draw2dstage)
875 r_refdef.draw2dstage = true;
877 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);
878 R_SetViewport(&viewport);
879 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
880 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
881 qglDisable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
882 GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
883 R_EntityMatrix(&identitymatrix);
887 GL_PolygonOffset(0, 0);
891 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
894 static void _DrawQ_ProcessDrawFlag(int flags)
898 if(flags == DRAWFLAG_ADDITIVE)
899 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
900 else if(flags == DRAWFLAG_MODULATE)
901 GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
902 else if(flags == DRAWFLAG_2XMODULATE)
903 GL_BlendFunc(GL_DST_COLOR,GL_SRC_COLOR);
904 else if(flags == DRAWFLAG_SCREEN)
905 GL_BlendFunc(GL_ONE_MINUS_DST_COLOR,GL_ONE);
907 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
910 void DrawQ_Pic(float x, float y, cachepic_t *pic, float width, float height, float red, float green, float blue, float alpha, int flags)
914 _DrawQ_ProcessDrawFlag(flags);
915 GL_Color(red, green, blue, alpha);
917 R_Mesh_VertexPointer(floats, 0, 0);
918 R_Mesh_ColorPointer(NULL, 0, 0);
919 R_Mesh_ResetTextureState();
925 height = pic->height;
926 R_SetupShader_Generic(Draw_GetPicTexture(pic), NULL, GL_MODULATE, 1);
927 R_Mesh_TexCoordPointer(0, 2, floats + 12, 0, 0);
930 floats[12] = 0.0f;floats[13] = 0.0f;
931 floats[14] = 1.0f;floats[15] = 0.0f;
932 floats[16] = 1.0f;floats[17] = 1.0f;
933 floats[18] = 0.0f;floats[19] = 1.0f;
935 // AK07: lets be texel correct on the corners
937 float horz_offset = 0.5f / pic->width;
938 float vert_offset = 0.5f / pic->height;
940 floats[12] = 0.0f + horz_offset;floats[13] = 0.0f + vert_offset;
941 floats[14] = 1.0f - horz_offset;floats[15] = 0.0f + vert_offset;
942 floats[16] = 1.0f - horz_offset;floats[17] = 1.0f - vert_offset;
943 floats[18] = 0.0f + horz_offset;floats[19] = 1.0f - vert_offset;
948 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
950 floats[2] = floats[5] = floats[8] = floats[11] = 0;
951 floats[0] = floats[9] = x;
952 floats[1] = floats[4] = y;
953 floats[3] = floats[6] = x + width;
954 floats[7] = floats[10] = y + height;
956 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
959 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)
962 float af = DEG2RAD(-angle); // forward
963 float ar = DEG2RAD(-angle + 90); // right
964 float sinaf = sin(af);
965 float cosaf = cos(af);
966 float sinar = sin(ar);
967 float cosar = cos(ar);
969 _DrawQ_ProcessDrawFlag(flags);
970 GL_Color(red, green, blue, alpha);
972 R_Mesh_VertexPointer(floats, 0, 0);
973 R_Mesh_ColorPointer(NULL, 0, 0);
974 R_Mesh_ResetTextureState();
980 height = pic->height;
981 R_SetupShader_Generic(Draw_GetPicTexture(pic), NULL, GL_MODULATE, 1);
982 R_Mesh_TexCoordPointer(0, 2, floats + 12, 0, 0);
984 floats[12] = 0.0f;floats[13] = 0.0f;
985 floats[14] = 1.0f;floats[15] = 0.0f;
986 floats[16] = 1.0f;floats[17] = 1.0f;
987 floats[18] = 0.0f;floats[19] = 1.0f;
990 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
992 floats[2] = floats[5] = floats[8] = floats[11] = 0;
995 floats[0] = x - cosaf*org_x - cosar*org_y;
996 floats[1] = y - sinaf*org_x - sinar*org_y;
999 floats[3] = x + cosaf*(width-org_x) - cosar*org_y;
1000 floats[4] = y + sinaf*(width-org_x) - sinar*org_y;
1003 floats[6] = x + cosaf*(width-org_x) + cosar*(height-org_y);
1004 floats[7] = y + sinaf*(width-org_x) + sinar*(height-org_y);
1007 floats[9] = x - cosaf*org_x + cosar*(height-org_y);
1008 floats[10] = y - sinaf*org_x + sinar*(height-org_y);
1010 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
1013 void DrawQ_Fill(float x, float y, float width, float height, float red, float green, float blue, float alpha, int flags)
1017 _DrawQ_ProcessDrawFlag(flags);
1018 GL_Color(red, green, blue, alpha);
1020 R_Mesh_VertexPointer(floats, 0, 0);
1021 R_Mesh_ColorPointer(NULL, 0, 0);
1022 R_Mesh_ResetTextureState();
1023 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
1025 floats[2] = floats[5] = floats[8] = floats[11] = 0;
1026 floats[0] = floats[9] = x;
1027 floats[1] = floats[4] = y;
1028 floats[3] = floats[6] = x + width;
1029 floats[7] = floats[10] = y + height;
1031 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
1034 /// color tag printing
1035 static const vec4_t string_colors[] =
1038 // LordHavoc: why on earth is cyan before magenta in Quake3?
1039 // LordHavoc: note: Doom3 uses white for [0] and [7]
1040 {0.0, 0.0, 0.0, 1.0}, // black
1041 {1.0, 0.0, 0.0, 1.0}, // red
1042 {0.0, 1.0, 0.0, 1.0}, // green
1043 {1.0, 1.0, 0.0, 1.0}, // yellow
1044 {0.0, 0.0, 1.0, 1.0}, // blue
1045 {0.0, 1.0, 1.0, 1.0}, // cyan
1046 {1.0, 0.0, 1.0, 1.0}, // magenta
1047 {1.0, 1.0, 1.0, 1.0}, // white
1048 // [515]'s BX_COLOREDTEXT extension
1049 {1.0, 1.0, 1.0, 0.5}, // half transparent
1050 {0.5, 0.5, 0.5, 1.0} // half brightness
1051 // Black's color table
1052 //{1.0, 1.0, 1.0, 1.0},
1053 //{1.0, 0.0, 0.0, 1.0},
1054 //{0.0, 1.0, 0.0, 1.0},
1055 //{0.0, 0.0, 1.0, 1.0},
1056 //{1.0, 1.0, 0.0, 1.0},
1057 //{0.0, 1.0, 1.0, 1.0},
1058 //{1.0, 0.0, 1.0, 1.0},
1059 //{0.1, 0.1, 0.1, 1.0}
1062 #define STRING_COLORS_COUNT (sizeof(string_colors) / sizeof(vec4_t))
1064 static void DrawQ_GetTextColor(float color[4], int colorindex, float r, float g, float b, float a, qboolean shadow)
1066 float C = r_textcontrast.value;
1067 float B = r_textbrightness.value;
1068 if (colorindex & 0x10000) // that bit means RGB color
1070 color[0] = ((colorindex >> 12) & 0xf) / 15.0;
1071 color[1] = ((colorindex >> 8) & 0xf) / 15.0;
1072 color[2] = ((colorindex >> 4) & 0xf) / 15.0;
1073 color[3] = (colorindex & 0xf) / 15.0;
1076 Vector4Copy(string_colors[colorindex], color);
1077 Vector4Set(color, color[0] * r * C + B, color[1] * g * C + B, color[2] * b * C + B, color[3] * a);
1080 float shadowalpha = (color[0]+color[1]+color[2]) * 0.8;
1081 Vector4Set(color, 0, 0, 0, color[3] * bound(0, shadowalpha, 1));
1085 // NOTE: this function always draws exactly one character if maxwidth <= 0
1086 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)
1088 const char *text_start = text;
1089 int colorindex = STRING_COLOR_DEFAULT;
1092 Uchar ch, mapch, nextch;
1093 Uchar prevch = 0; // used for kerning
1098 ft2_font_map_t *fontmap = NULL;
1099 ft2_font_map_t *map = NULL;
1100 ft2_font_map_t *prevmap = NULL;
1101 ft2_font_t *ft2 = fnt->ft2;
1103 qboolean snap = true;
1104 qboolean least_one = false;
1105 float dw, dh; // display w/h
1106 float width_of_factor;
1107 const float *width_of;
1114 // do this in the end
1118 // find the most fitting size:
1122 map_index = Font_IndexForSize(ft2, h, &w, &h);
1124 map_index = Font_IndexForSize(ft2, h, NULL, NULL);
1125 fontmap = Font_MapForIndex(ft2, map_index);
1134 if (!outcolor || *outcolor == -1)
1135 colorindex = STRING_COLOR_DEFAULT;
1137 colorindex = *outcolor;
1139 // maxwidth /= fnt->scale; // w and h are multiplied by it already
1140 // ftbase_x = snap_to_pixel_x(0);
1145 maxwidth = -maxwidth;
1149 // x = snap_to_pixel_x(x, 0.4); // haha, it's 0 anyway
1153 width_of_factor = dw;
1154 width_of = fontmap->width_of;
1158 width_of_factor = dw;
1159 width_of = fnt->width_of;
1162 for (i = 0;((bytes_left = *maxlen - (text - text_start)) > 0) && *text;)
1165 nextch = ch = u8_getnchar(text, &text, bytes_left);
1166 i = text - text_start;
1169 if (ch == ' ' && !fontmap)
1171 if(!least_one || i0) // never skip the first character
1172 if(x + width_of[(int) ' '] * width_of_factor > maxwidth)
1175 break; // oops, can't draw this
1177 x += width_of[(int) ' '] * width_of_factor;
1180 // i points to the char after ^
1181 if (ch == STRING_COLOR_TAG && !ignorecolorcodes && i < *maxlen)
1183 ch = *text; // colors are ascii, so no u8_ needed
1184 if (ch <= '9' && ch >= '0') // ^[0-9] found
1186 colorindex = ch - '0';
1191 // i points to the char after ^...
1192 // i+3 points to 3 in ^x123
1193 // i+3 == *maxlen would mean that char is missing
1194 else if (ch == STRING_COLOR_RGB_TAG_CHAR && i + 3 < *maxlen ) // ^x found
1196 // building colorindex...
1197 ch = tolower(text[1]);
1198 tempcolorindex = 0x10000; // binary: 1,0000,0000,0000,0000
1199 if (ch <= '9' && ch >= '0') tempcolorindex |= (ch - '0') << 12;
1200 else if (ch >= 'a' && ch <= 'f') tempcolorindex |= (ch - 87) << 12;
1201 else tempcolorindex = 0;
1204 ch = tolower(text[2]);
1205 if (ch <= '9' && ch >= '0') tempcolorindex |= (ch - '0') << 8;
1206 else if (ch >= 'a' && ch <= 'f') tempcolorindex |= (ch - 87) << 8;
1207 else tempcolorindex = 0;
1210 ch = tolower(text[3]);
1211 if (ch <= '9' && ch >= '0') tempcolorindex |= (ch - '0') << 4;
1212 else if (ch >= 'a' && ch <= 'f') tempcolorindex |= (ch - 87) << 4;
1213 else tempcolorindex = 0;
1216 colorindex = tempcolorindex | 0xf;
1217 // ...done! now colorindex has rgba codes (1,rrrr,gggg,bbbb,aaaa)
1225 else if (ch == STRING_COLOR_TAG) // ^^ found, ignore the first ^ and go to print the second
1234 if (!fontmap || (ch <= 0xFF && fontmap->glyphs[ch].image) || (ch >= 0xE000 && ch <= 0xE0FF))
1241 map = ft2_oldstyle_map;
1243 if(!least_one || i0) // never skip the first character
1244 if(x + width_of[ch] * width_of_factor > maxwidth)
1247 break; // oops, can't draw this
1249 x += width_of[ch] * width_of_factor;
1251 if (!map || map == ft2_oldstyle_map || map->start < ch || map->start + FONT_CHARS_PER_MAP >= ch)
1253 map = FontMap_FindForChar(fontmap, ch);
1256 if (!Font_LoadMapForIndex(ft2, map_index, ch, &map))
1262 mapch = ch - map->start;
1263 if (prevch && Font_GetKerningForMap(ft2, map_index, w, h, prevch, ch, &kx, NULL))
1265 x += map->glyphs[mapch].advance_x * dw;
1274 *outcolor = colorindex;
1279 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)
1281 int shadow, colorindex = STRING_COLOR_DEFAULT;
1283 float x = startx, y, s, t, u, v, thisw;
1284 float *av, *at, *ac;
1287 static float vertex3f[QUADELEMENTS_MAXQUADS*4*3];
1288 static float texcoord2f[QUADELEMENTS_MAXQUADS*4*2];
1289 static float color4f[QUADELEMENTS_MAXQUADS*4*4];
1290 Uchar ch, mapch, nextch;
1291 Uchar prevch = 0; // used for kerning
1294 ft2_font_map_t *prevmap = NULL; // the previous map
1295 ft2_font_map_t *map = NULL; // the currently used map
1296 ft2_font_map_t *fontmap = NULL; // the font map for the size
1298 const char *text_start = text;
1300 ft2_font_t *ft2 = fnt->ft2;
1301 qboolean snap = true;
1305 float width_of_factor;
1306 const float *width_of;
1309 tw = R_TextureWidth(fnt->tex);
1310 th = R_TextureHeight(fnt->tex);
1318 starty -= (fnt->scale - 1) * h * 0.5; // center
1325 map_index = Font_IndexForSize(ft2, h, &w, &h);
1327 map_index = Font_IndexForSize(ft2, h, NULL, NULL);
1328 fontmap = Font_MapForIndex(ft2, map_index);
1334 // draw the font at its baseline when using freetype
1336 ftbase_y = dh * (4.5/6.0);
1341 _DrawQ_ProcessDrawFlag(flags);
1343 R_Mesh_ColorPointer(color4f, 0, 0);
1344 R_Mesh_ResetTextureState();
1346 R_Mesh_TexBind(0, fnt->tex);
1347 R_Mesh_TexCoordPointer(0, 2, texcoord2f, 0, 0);
1348 R_Mesh_VertexPointer(vertex3f, 0, 0);
1349 R_SetupShader_Generic(fnt->tex, NULL, GL_MODULATE, 1);
1356 //ftbase_x = snap_to_pixel_x(ftbase_x);
1359 startx = snap_to_pixel_x(startx, 0.4);
1360 starty = snap_to_pixel_y(starty, 0.4);
1361 ftbase_y = snap_to_pixel_y(ftbase_y, 0.3);
1364 pix_x = vid.width / vid_conwidth.value;
1365 pix_y = vid.height / vid_conheight.value;
1369 width_of_factor = dw;
1370 width_of = fontmap->width_of;
1374 width_of_factor = dw;
1375 width_of = fnt->width_of;
1378 for (shadow = r_textshadow.value != 0 && basealpha > 0;shadow >= 0;shadow--)
1383 if (!outcolor || *outcolor == -1)
1384 colorindex = STRING_COLOR_DEFAULT;
1386 colorindex = *outcolor;
1388 DrawQ_GetTextColor(color, colorindex, basered, basegreen, baseblue, basealpha, shadow != 0);
1395 x += r_textshadow.value * vid.width / vid_conwidth.value;
1396 y += r_textshadow.value * vid.height / vid_conheight.value;
1399 for (i = 0;((bytes_left = maxlen - (text - text_start)) > 0) && *text;)
1401 nextch = ch = u8_getnchar(text, &text, bytes_left);
1402 i = text - text_start;
1405 if (ch == ' ' && !fontmap)
1407 x += width_of[(int) ' '] * width_of_factor;
1410 if (ch == STRING_COLOR_TAG && !ignorecolorcodes && i < maxlen)
1412 ch = *text; // colors are ascii, so no u8_ needed
1413 if (ch <= '9' && ch >= '0') // ^[0-9] found
1415 colorindex = ch - '0';
1416 DrawQ_GetTextColor(color, colorindex, basered, basegreen, baseblue, basealpha, shadow != 0);
1421 else if (ch == STRING_COLOR_RGB_TAG_CHAR && i+3 < maxlen ) // ^x found
1423 // building colorindex...
1424 ch = tolower(text[1]);
1425 tempcolorindex = 0x10000; // binary: 1,0000,0000,0000,0000
1426 if (ch <= '9' && ch >= '0') tempcolorindex |= (ch - '0') << 12;
1427 else if (ch >= 'a' && ch <= 'f') tempcolorindex |= (ch - 87) << 12;
1428 else tempcolorindex = 0;
1431 ch = tolower(text[2]);
1432 if (ch <= '9' && ch >= '0') tempcolorindex |= (ch - '0') << 8;
1433 else if (ch >= 'a' && ch <= 'f') tempcolorindex |= (ch - 87) << 8;
1434 else tempcolorindex = 0;
1437 ch = tolower(text[3]);
1438 if (ch <= '9' && ch >= '0') tempcolorindex |= (ch - '0') << 4;
1439 else if (ch >= 'a' && ch <= 'f') tempcolorindex |= (ch - 87) << 4;
1440 else tempcolorindex = 0;
1443 colorindex = tempcolorindex | 0xf;
1444 // ...done! now colorindex has rgba codes (1,rrrr,gggg,bbbb,aaaa)
1445 //Con_Printf("^1colorindex:^7 %x\n", colorindex);
1446 DrawQ_GetTextColor(color, colorindex, basered, basegreen, baseblue, basealpha, shadow != 0);
1454 else if (ch == STRING_COLOR_TAG)
1463 // using a value of -1 for the oldstyle map because NULL means uninitialized...
1464 // this way we don't need to rebind fnt->tex for every old-style character
1465 // E000..E0FF: emulate old-font characters (to still have smileys and such available)
1468 x += 1.0/pix_x * r_textshadow.value;
1469 y += 1.0/pix_y * r_textshadow.value;
1471 if (!fontmap || (ch <= 0xFF && fontmap->glyphs[ch].image) || (ch >= 0xE000 && ch <= 0xE0FF))
1479 if (map != ft2_oldstyle_map)
1483 // switching from freetype to non-freetype rendering
1484 GL_LockArrays(0, batchcount * 4);
1485 R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, quadelement3s, 0, 0);
1486 GL_LockArrays(0, 0);
1492 R_SetupShader_Generic(fnt->tex, NULL, GL_MODULATE, 1);
1493 map = ft2_oldstyle_map;
1497 //num = (unsigned char) text[i];
1498 //thisw = fnt->width_of[num];
1499 thisw = fnt->width_of[ch];
1500 // FIXME make these smaller to just include the occupied part of the character for slightly faster rendering
1501 s = (ch & 15)*0.0625f + (0.5f / tw);
1502 t = (ch >> 4)*0.0625f + (0.5f / th);
1503 u = 0.0625f * thisw - (1.0f / tw);
1504 v = 0.0625f - (1.0f / th);
1505 ac[ 0] = color[0];ac[ 1] = color[1];ac[ 2] = color[2];ac[ 3] = color[3];
1506 ac[ 4] = color[0];ac[ 5] = color[1];ac[ 6] = color[2];ac[ 7] = color[3];
1507 ac[ 8] = color[0];ac[ 9] = color[1];ac[10] = color[2];ac[11] = color[3];
1508 ac[12] = color[0];ac[13] = color[1];ac[14] = color[2];ac[15] = color[3];
1509 at[ 0] = s ; at[ 1] = t ;
1510 at[ 2] = s+u ; at[ 3] = t ;
1511 at[ 4] = s+u ; at[ 5] = t+v ;
1512 at[ 6] = s ; at[ 7] = t+v ;
1513 av[ 0] = x ; av[ 1] = y ; av[ 2] = 10;
1514 av[ 3] = x+dw*thisw ; av[ 4] = y ; av[ 5] = 10;
1515 av[ 6] = x+dw*thisw ; av[ 7] = y+dh ; av[ 8] = 10;
1516 av[ 9] = x ; av[10] = y+dh ; av[11] = 10;
1521 if (batchcount >= QUADELEMENTS_MAXQUADS)
1523 GL_LockArrays(0, batchcount * 4);
1524 R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, quadelement3s, 0, 0);
1525 GL_LockArrays(0, 0);
1531 x += width_of[ch] * width_of_factor;
1533 if (!map || map == ft2_oldstyle_map || map->start < ch || map->start + FONT_CHARS_PER_MAP >= ch)
1535 // new charmap - need to render
1538 // we need a different character map, render what we currently have:
1539 GL_LockArrays(0, batchcount * 4);
1540 R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, quadelement3s, 0, 0);
1541 GL_LockArrays(0, 0);
1548 map = FontMap_FindForChar(fontmap, ch);
1551 if (!Font_LoadMapForIndex(ft2, map_index, ch, &map))
1558 // this shouldn't happen
1563 R_SetupShader_Generic(map->texture, NULL, GL_MODULATE, 1);
1566 mapch = ch - map->start;
1567 thisw = map->glyphs[mapch].advance_x;
1571 if (prevch && Font_GetKerningForMap(ft2, map_index, w, h, prevch, ch, &kx, &ky))
1578 ac[ 0] = color[0]; ac[ 1] = color[1]; ac[ 2] = color[2]; ac[ 3] = color[3];
1579 ac[ 4] = color[0]; ac[ 5] = color[1]; ac[ 6] = color[2]; ac[ 7] = color[3];
1580 ac[ 8] = color[0]; ac[ 9] = color[1]; ac[10] = color[2]; ac[11] = color[3];
1581 ac[12] = color[0]; ac[13] = color[1]; ac[14] = color[2]; ac[15] = color[3];
1582 at[0] = map->glyphs[mapch].txmin; at[1] = map->glyphs[mapch].tymin;
1583 at[2] = map->glyphs[mapch].txmax; at[3] = map->glyphs[mapch].tymin;
1584 at[4] = map->glyphs[mapch].txmax; at[5] = map->glyphs[mapch].tymax;
1585 at[6] = map->glyphs[mapch].txmin; at[7] = map->glyphs[mapch].tymax;
1586 av[ 0] = x + dw * map->glyphs[mapch].vxmin; av[ 1] = y + dh * map->glyphs[mapch].vymin; av[ 2] = 10;
1587 av[ 3] = x + dw * map->glyphs[mapch].vxmax; av[ 4] = y + dh * map->glyphs[mapch].vymin; av[ 5] = 10;
1588 av[ 6] = x + dw * map->glyphs[mapch].vxmax; av[ 7] = y + dh * map->glyphs[mapch].vymax; av[ 8] = 10;
1589 av[ 9] = x + dw * map->glyphs[mapch].vxmin; av[10] = y + dh * map->glyphs[mapch].vymax; av[11] = 10;
1598 if (batchcount >= QUADELEMENTS_MAXQUADS)
1600 GL_LockArrays(0, batchcount * 4);
1601 R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, quadelement3s, 0, 0);
1602 GL_LockArrays(0, 0);
1614 x -= 1.0/pix_x * r_textshadow.value;
1615 y -= 1.0/pix_y * r_textshadow.value;
1621 GL_LockArrays(0, batchcount * 4);
1622 R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, quadelement3s, 0, 0);
1623 GL_LockArrays(0, 0);
1627 *outcolor = colorindex;
1629 // note: this relies on the proper text (not shadow) being drawn last
1633 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)
1635 return DrawQ_String_Scale(startx, starty, text, maxlen, w, h, 1, 1, basered, basegreen, baseblue, basealpha, flags, outcolor, ignorecolorcodes, fnt);
1638 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)
1640 return DrawQ_TextWidth_UntilWidth_TrackColors_Scale(text, maxlen, w, h, 1, 1, outcolor, ignorecolorcodes, fnt, maxwidth);
1643 float DrawQ_TextWidth(const char *text, size_t maxlen, float w, float h, qboolean ignorecolorcodes, const dp_font_t *fnt)
1645 return DrawQ_TextWidth_UntilWidth(text, &maxlen, w, h, ignorecolorcodes, fnt, 1000000000);
1648 float DrawQ_TextWidth_UntilWidth(const char *text, size_t *maxlen, float w, float h, qboolean ignorecolorcodes, const dp_font_t *fnt, float maxWidth)
1650 return DrawQ_TextWidth_UntilWidth_TrackColors(text, maxlen, w, h, NULL, ignorecolorcodes, fnt, maxWidth);
1655 // no ^xrgb management
1656 static int DrawQ_BuildColoredText(char *output2c, size_t maxoutchars, const char *text, int maxreadchars, qboolean ignorecolorcodes, int *outcolor)
1658 int color, numchars = 0;
1659 char *outputend2c = output2c + maxoutchars - 2;
1660 if (!outcolor || *outcolor == -1)
1661 color = STRING_COLOR_DEFAULT;
1665 maxreadchars = 1<<30;
1666 textend = text + maxreadchars;
1667 while (text != textend && *text)
1669 if (*text == STRING_COLOR_TAG && !ignorecolorcodes && text + 1 != textend)
1671 if (text[1] == STRING_COLOR_TAG)
1673 else if (text[1] >= '0' && text[1] <= '9')
1675 color = text[1] - '0';
1680 if (output2c >= outputend2c)
1682 *output2c++ = *text++;
1683 *output2c++ = color;
1686 output2c[0] = output2c[1] = 0;
1693 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)
1697 _DrawQ_ProcessDrawFlag(flags);
1699 R_Mesh_VertexPointer(floats, 0, 0);
1700 R_Mesh_ColorPointer(floats + 20, 0, 0);
1701 R_Mesh_ResetTextureState();
1707 height = pic->height;
1708 R_SetupShader_Generic(Draw_GetPicTexture(pic), NULL, GL_MODULATE, 1);
1709 R_Mesh_TexCoordPointer(0, 2, floats + 12, 0, 0);
1710 floats[12] = s1;floats[13] = t1;
1711 floats[14] = s2;floats[15] = t2;
1712 floats[16] = s4;floats[17] = t4;
1713 floats[18] = s3;floats[19] = t3;
1716 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
1718 floats[2] = floats[5] = floats[8] = floats[11] = 0;
1719 floats[0] = floats[9] = x;
1720 floats[1] = floats[4] = y;
1721 floats[3] = floats[6] = x + width;
1722 floats[7] = floats[10] = y + height;
1723 floats[20] = r1;floats[21] = g1;floats[22] = b1;floats[23] = a1;
1724 floats[24] = r2;floats[25] = g2;floats[26] = b2;floats[27] = a2;
1725 floats[28] = r4;floats[29] = g4;floats[30] = b4;floats[31] = a4;
1726 floats[32] = r3;floats[33] = g3;floats[34] = b3;floats[35] = a3;
1728 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
1731 void DrawQ_Mesh (drawqueuemesh_t *mesh, int flags)
1733 _DrawQ_ProcessDrawFlag(flags);
1735 R_Mesh_VertexPointer(mesh->data_vertex3f, 0, 0);
1736 R_Mesh_ColorPointer(mesh->data_color4f, 0, 0);
1737 R_Mesh_ResetTextureState();
1738 R_Mesh_TexCoordPointer(0, 2, mesh->data_texcoord2f, 0, 0);
1739 R_SetupShader_Generic(mesh->texture, NULL, GL_MODULATE, 1);
1741 GL_LockArrays(0, mesh->num_vertices);
1742 R_Mesh_Draw(0, mesh->num_vertices, 0, mesh->num_triangles, mesh->data_element3i, mesh->data_element3s, 0, 0);
1743 GL_LockArrays(0, 0);
1746 void DrawQ_LineLoop (drawqueuemesh_t *mesh, int flags)
1750 _DrawQ_ProcessDrawFlag(flags);
1754 qglBegin(GL_LINE_LOOP);
1755 for (num = 0;num < mesh->num_vertices;num++)
1757 if (mesh->data_color4f)
1758 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]);
1759 qglVertex2f(mesh->data_vertex3f[num*3+0], mesh->data_vertex3f[num*3+1]);
1765 //[515]: this is old, delete
1766 void DrawQ_Line (float width, float x1, float y1, float x2, float y2, float r, float g, float b, float alpha, int flags)
1768 _DrawQ_ProcessDrawFlag(flags);
1770 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
1773 //qglLineWidth(width);CHECKGLERROR
1775 GL_Color(r,g,b,alpha);
1778 qglVertex2f(x1, y1);
1779 qglVertex2f(x2, y2);
1784 void DrawQ_SetClipArea(float x, float y, float width, float height)
1789 // We have to convert the con coords into real coords
1790 // OGL uses top to bottom
1791 ix = (int)(0.5 + x * ((float)vid.width / vid_conwidth.integer));
1792 iy = (int)(0.5 + y * ((float) vid.height / vid_conheight.integer));
1793 iw = (int)(width * ((float)vid.width / vid_conwidth.integer));
1794 ih = (int)(height * ((float)vid.height / vid_conheight.integer));
1795 GL_Scissor(ix, vid.height - iy - ih, iw, ih);
1797 GL_ScissorTest(true);
1800 void DrawQ_ResetClipArea(void)
1803 GL_ScissorTest(false);
1806 void DrawQ_Finish(void)
1808 r_refdef.draw2dstage = false;
1811 static float blendvertex3f[9] = {-5000, -5000, 10, 10000, -5000, 10, -5000, 10000, 10};
1812 void R_DrawGamma(void)
1815 switch(vid.renderpath)
1817 case RENDERPATH_GL20:
1818 case RENDERPATH_CGGL:
1819 if (vid_usinghwgamma || v_glslgamma.integer)
1822 case RENDERPATH_GL13:
1823 case RENDERPATH_GL11:
1824 if (vid_usinghwgamma)
1828 // all the blends ignore depth
1829 R_Mesh_VertexPointer(blendvertex3f, 0, 0);
1830 R_Mesh_ColorPointer(NULL, 0, 0);
1831 R_Mesh_ResetTextureState();
1832 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
1834 GL_DepthRange(0, 1);
1835 GL_PolygonOffset(0, 0);
1836 GL_DepthTest(false);
1837 if (v_color_enable.integer)
1839 c[0] = v_color_white_r.value;
1840 c[1] = v_color_white_g.value;
1841 c[2] = v_color_white_b.value;
1844 c[0] = c[1] = c[2] = v_contrast.value;
1845 if (c[0] >= 1.01f || c[1] >= 1.01f || c[2] >= 1.01f)
1847 GL_BlendFunc(GL_DST_COLOR, GL_ONE);
1848 while (c[0] >= 1.01f || c[1] >= 1.01f || c[2] >= 1.01f)
1850 GL_Color(bound(0, c[0] - 1, 1), bound(0, c[1] - 1, 1), bound(0, c[2] - 1, 1), 1);
1851 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, polygonelement3s, 0, 0);
1852 VectorScale(c, 0.5, c);
1855 if (v_color_enable.integer)
1857 c[0] = v_color_black_r.value;
1858 c[1] = v_color_black_g.value;
1859 c[2] = v_color_black_b.value;
1862 c[0] = c[1] = c[2] = v_brightness.value;
1863 if (c[0] >= 0.01f || c[1] >= 0.01f || c[2] >= 0.01f)
1865 GL_BlendFunc(GL_ONE, GL_ONE);
1866 GL_Color(c[0], c[1], c[2], 1);
1867 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, polygonelement3s, 0, 0);