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++);
865 void _DrawQ_Setup(void)
867 r_viewport_t viewport;
868 if (r_refdef.draw2dstage)
870 r_refdef.draw2dstage = true;
872 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);
873 R_SetViewport(&viewport);
874 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
875 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
876 qglDisable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
877 GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
878 R_EntityMatrix(&identitymatrix);
882 GL_PolygonOffset(0, 0);
886 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
889 static void _DrawQ_ProcessDrawFlag(int flags)
893 if(flags == DRAWFLAG_ADDITIVE)
894 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
895 else if(flags == DRAWFLAG_MODULATE)
896 GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
897 else if(flags == DRAWFLAG_2XMODULATE)
898 GL_BlendFunc(GL_DST_COLOR,GL_SRC_COLOR);
899 else if(flags == DRAWFLAG_SCREEN)
900 GL_BlendFunc(GL_ONE_MINUS_DST_COLOR,GL_ONE);
902 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
905 void DrawQ_Pic(float x, float y, cachepic_t *pic, float width, float height, float red, float green, float blue, float alpha, int flags)
909 _DrawQ_ProcessDrawFlag(flags);
910 GL_Color(red, green, blue, alpha);
912 R_Mesh_VertexPointer(floats, 0, 0);
913 R_Mesh_ColorPointer(NULL, 0, 0);
914 R_Mesh_ResetTextureState();
920 height = pic->height;
921 R_SetupShader_Generic(Draw_GetPicTexture(pic), NULL, GL_MODULATE, 1);
922 R_Mesh_TexCoordPointer(0, 2, floats + 12, 0, 0);
925 floats[12] = 0.0f;floats[13] = 0.0f;
926 floats[14] = 1.0f;floats[15] = 0.0f;
927 floats[16] = 1.0f;floats[17] = 1.0f;
928 floats[18] = 0.0f;floats[19] = 1.0f;
930 // AK07: lets be texel correct on the corners
932 float horz_offset = 0.5f / pic->width;
933 float vert_offset = 0.5f / pic->height;
935 floats[12] = 0.0f + horz_offset;floats[13] = 0.0f + vert_offset;
936 floats[14] = 1.0f - horz_offset;floats[15] = 0.0f + vert_offset;
937 floats[16] = 1.0f - horz_offset;floats[17] = 1.0f - vert_offset;
938 floats[18] = 0.0f + horz_offset;floats[19] = 1.0f - vert_offset;
943 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
945 floats[2] = floats[5] = floats[8] = floats[11] = 0;
946 floats[0] = floats[9] = x;
947 floats[1] = floats[4] = y;
948 floats[3] = floats[6] = x + width;
949 floats[7] = floats[10] = y + height;
951 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
954 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)
957 float af = DEG2RAD(-angle); // forward
958 float ar = DEG2RAD(-angle + 90); // right
959 float sinaf = sin(af);
960 float cosaf = cos(af);
961 float sinar = sin(ar);
962 float cosar = cos(ar);
964 _DrawQ_ProcessDrawFlag(flags);
965 GL_Color(red, green, blue, alpha);
967 R_Mesh_VertexPointer(floats, 0, 0);
968 R_Mesh_ColorPointer(NULL, 0, 0);
969 R_Mesh_ResetTextureState();
975 height = pic->height;
976 R_SetupShader_Generic(Draw_GetPicTexture(pic), NULL, GL_MODULATE, 1);
977 R_Mesh_TexCoordPointer(0, 2, floats + 12, 0, 0);
979 floats[12] = 0.0f;floats[13] = 0.0f;
980 floats[14] = 1.0f;floats[15] = 0.0f;
981 floats[16] = 1.0f;floats[17] = 1.0f;
982 floats[18] = 0.0f;floats[19] = 1.0f;
985 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
987 floats[2] = floats[5] = floats[8] = floats[11] = 0;
990 floats[0] = x - cosaf*org_x - cosar*org_y;
991 floats[1] = y - sinaf*org_x - sinar*org_y;
994 floats[3] = x + cosaf*(width-org_x) - cosar*org_y;
995 floats[4] = y + sinaf*(width-org_x) - sinar*org_y;
998 floats[6] = x + cosaf*(width-org_x) + cosar*(height-org_y);
999 floats[7] = y + sinaf*(width-org_x) + sinar*(height-org_y);
1002 floats[9] = x - cosaf*org_x + cosar*(height-org_y);
1003 floats[10] = y - sinaf*org_x + sinar*(height-org_y);
1005 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
1008 void DrawQ_Fill(float x, float y, float width, float height, float red, float green, float blue, float alpha, int flags)
1012 _DrawQ_ProcessDrawFlag(flags);
1013 GL_Color(red, green, blue, alpha);
1015 R_Mesh_VertexPointer(floats, 0, 0);
1016 R_Mesh_ColorPointer(NULL, 0, 0);
1017 R_Mesh_ResetTextureState();
1018 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
1020 floats[2] = floats[5] = floats[8] = floats[11] = 0;
1021 floats[0] = floats[9] = x;
1022 floats[1] = floats[4] = y;
1023 floats[3] = floats[6] = x + width;
1024 floats[7] = floats[10] = y + height;
1026 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
1029 /// color tag printing
1030 static const vec4_t string_colors[] =
1033 // LordHavoc: why on earth is cyan before magenta in Quake3?
1034 // LordHavoc: note: Doom3 uses white for [0] and [7]
1035 {0.0, 0.0, 0.0, 1.0}, // black
1036 {1.0, 0.0, 0.0, 1.0}, // red
1037 {0.0, 1.0, 0.0, 1.0}, // green
1038 {1.0, 1.0, 0.0, 1.0}, // yellow
1039 {0.0, 0.0, 1.0, 1.0}, // blue
1040 {0.0, 1.0, 1.0, 1.0}, // cyan
1041 {1.0, 0.0, 1.0, 1.0}, // magenta
1042 {1.0, 1.0, 1.0, 1.0}, // white
1043 // [515]'s BX_COLOREDTEXT extension
1044 {1.0, 1.0, 1.0, 0.5}, // half transparent
1045 {0.5, 0.5, 0.5, 1.0} // half brightness
1046 // Black's color table
1047 //{1.0, 1.0, 1.0, 1.0},
1048 //{1.0, 0.0, 0.0, 1.0},
1049 //{0.0, 1.0, 0.0, 1.0},
1050 //{0.0, 0.0, 1.0, 1.0},
1051 //{1.0, 1.0, 0.0, 1.0},
1052 //{0.0, 1.0, 1.0, 1.0},
1053 //{1.0, 0.0, 1.0, 1.0},
1054 //{0.1, 0.1, 0.1, 1.0}
1057 #define STRING_COLORS_COUNT (sizeof(string_colors) / sizeof(vec4_t))
1059 static void DrawQ_GetTextColor(float color[4], int colorindex, float r, float g, float b, float a, qboolean shadow)
1061 float C = r_textcontrast.value;
1062 float B = r_textbrightness.value;
1063 if (colorindex & 0x10000) // that bit means RGB color
1065 color[0] = ((colorindex >> 12) & 0xf) / 15.0;
1066 color[1] = ((colorindex >> 8) & 0xf) / 15.0;
1067 color[2] = ((colorindex >> 4) & 0xf) / 15.0;
1068 color[3] = (colorindex & 0xf) / 15.0;
1071 Vector4Copy(string_colors[colorindex], color);
1072 Vector4Set(color, color[0] * r * C + B, color[1] * g * C + B, color[2] * b * C + B, color[3] * a);
1075 float shadowalpha = (color[0]+color[1]+color[2]) * 0.8;
1076 Vector4Set(color, 0, 0, 0, color[3] * bound(0, shadowalpha, 1));
1080 // NOTE: this function always draws exactly one character if maxwidth <= 0
1081 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)
1083 const char *text_start = text;
1084 int colorindex = STRING_COLOR_DEFAULT;
1087 Uchar ch, mapch, nextch;
1088 Uchar prevch = 0; // used for kerning
1093 ft2_font_map_t *fontmap = NULL;
1094 ft2_font_map_t *map = NULL;
1095 ft2_font_map_t *prevmap = NULL;
1096 ft2_font_t *ft2 = fnt->ft2;
1098 qboolean snap = true;
1099 qboolean least_one = false;
1100 float dw, dh; // display w/h
1101 float width_of_factor;
1102 const float *width_of;
1109 // do this in the end
1113 // find the most fitting size:
1117 map_index = Font_IndexForSize(ft2, h, &w, &h);
1119 map_index = Font_IndexForSize(ft2, h, NULL, NULL);
1120 fontmap = Font_MapForIndex(ft2, map_index);
1129 if (!outcolor || *outcolor == -1)
1130 colorindex = STRING_COLOR_DEFAULT;
1132 colorindex = *outcolor;
1134 // maxwidth /= fnt->scale; // w and h are multiplied by it already
1135 // ftbase_x = snap_to_pixel_x(0);
1140 maxwidth = -maxwidth;
1144 // x = snap_to_pixel_x(x, 0.4); // haha, it's 0 anyway
1148 width_of_factor = 1;
1149 width_of = fontmap->width_of;
1153 width_of_factor = dw;
1154 width_of = fnt->width_of;
1157 for (i = 0;((bytes_left = *maxlen - (text - text_start)) > 0) && *text;)
1160 nextch = ch = u8_getnchar(text, &text, bytes_left);
1161 i = text - text_start;
1164 if (ch == ' ' && !fontmap)
1166 if(!least_one || i0) // never skip the first character
1167 if(x + width_of[(int) ' '] * width_of_factor > maxwidth)
1170 break; // oops, can't draw this
1172 x += width_of[(int) ' '] * width_of_factor;
1175 // i points to the char after ^
1176 if (ch == STRING_COLOR_TAG && !ignorecolorcodes && i < *maxlen)
1178 ch = *text; // colors are ascii, so no u8_ needed
1179 if (ch <= '9' && ch >= '0') // ^[0-9] found
1181 colorindex = ch - '0';
1186 // i points to the char after ^...
1187 // i+3 points to 3 in ^x123
1188 // i+3 == *maxlen would mean that char is missing
1189 else if (ch == STRING_COLOR_RGB_TAG_CHAR && i + 3 < *maxlen ) // ^x found
1191 // building colorindex...
1192 ch = tolower(text[1]);
1193 tempcolorindex = 0x10000; // binary: 1,0000,0000,0000,0000
1194 if (ch <= '9' && ch >= '0') tempcolorindex |= (ch - '0') << 12;
1195 else if (ch >= 'a' && ch <= 'f') tempcolorindex |= (ch - 87) << 12;
1196 else tempcolorindex = 0;
1199 ch = tolower(text[2]);
1200 if (ch <= '9' && ch >= '0') tempcolorindex |= (ch - '0') << 8;
1201 else if (ch >= 'a' && ch <= 'f') tempcolorindex |= (ch - 87) << 8;
1202 else tempcolorindex = 0;
1205 ch = tolower(text[3]);
1206 if (ch <= '9' && ch >= '0') tempcolorindex |= (ch - '0') << 4;
1207 else if (ch >= 'a' && ch <= 'f') tempcolorindex |= (ch - 87) << 4;
1208 else tempcolorindex = 0;
1211 colorindex = tempcolorindex | 0xf;
1212 // ...done! now colorindex has rgba codes (1,rrrr,gggg,bbbb,aaaa)
1220 else if (ch == STRING_COLOR_TAG) // ^^ found, ignore the first ^ and go to print the second
1229 if (!fontmap || (ch <= 0xFF && fontmap->glyphs[ch].image) || (ch >= 0xE000 && ch <= 0xE0FF))
1236 map = ft2_oldstyle_map;
1238 if(!least_one || i0) // never skip the first character
1239 if(x + width_of[ch] * width_of_factor > maxwidth)
1242 break; // oops, can't draw this
1244 x += width_of[ch] * width_of_factor;
1246 if (!map || map == ft2_oldstyle_map || map->start < ch || map->start + FONT_CHARS_PER_MAP >= ch)
1248 map = FontMap_FindForChar(fontmap, ch);
1251 if (!Font_LoadMapForIndex(ft2, map_index, ch, &map))
1257 mapch = ch - map->start;
1258 if (prevch && Font_GetKerningForMap(ft2, map_index, w, h, prevch, ch, &kx, NULL))
1260 x += map->glyphs[mapch].advance_x * dw;
1269 *outcolor = colorindex;
1274 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)
1276 int shadow, colorindex = STRING_COLOR_DEFAULT;
1278 float x = startx, y, s, t, u, v, thisw;
1279 float *av, *at, *ac;
1282 static float vertex3f[QUADELEMENTS_MAXQUADS*4*3];
1283 static float texcoord2f[QUADELEMENTS_MAXQUADS*4*2];
1284 static float color4f[QUADELEMENTS_MAXQUADS*4*4];
1285 Uchar ch, mapch, nextch;
1286 Uchar prevch = 0; // used for kerning
1289 ft2_font_map_t *prevmap = NULL; // the previous map
1290 ft2_font_map_t *map = NULL; // the currently used map
1291 ft2_font_map_t *fontmap = NULL; // the font map for the size
1293 const char *text_start = text;
1295 ft2_font_t *ft2 = fnt->ft2;
1296 qboolean snap = true;
1300 float width_of_factor;
1301 const float *width_of;
1304 tw = R_TextureWidth(fnt->tex);
1305 th = R_TextureHeight(fnt->tex);
1313 starty -= (fnt->scale - 1) * h * 0.5; // center
1320 map_index = Font_IndexForSize(ft2, h, &w, &h);
1322 map_index = Font_IndexForSize(ft2, h, NULL, NULL);
1323 fontmap = Font_MapForIndex(ft2, map_index);
1329 // draw the font at its baseline when using freetype
1331 ftbase_y = dh * (4.5/6.0);
1336 _DrawQ_ProcessDrawFlag(flags);
1338 R_Mesh_ColorPointer(color4f, 0, 0);
1339 R_Mesh_ResetTextureState();
1341 R_Mesh_TexBind(0, fnt->tex);
1342 R_Mesh_TexCoordPointer(0, 2, texcoord2f, 0, 0);
1343 R_Mesh_VertexPointer(vertex3f, 0, 0);
1344 R_SetupShader_Generic(fnt->tex, NULL, GL_MODULATE, 1);
1351 //ftbase_x = snap_to_pixel_x(ftbase_x);
1354 startx = snap_to_pixel_x(startx, 0.4);
1355 starty = snap_to_pixel_y(starty, 0.4);
1356 ftbase_y = snap_to_pixel_y(ftbase_y, 0.3);
1359 pix_x = vid.width / vid_conwidth.value;
1360 pix_y = vid.height / vid_conheight.value;
1364 width_of_factor = 1;
1365 width_of = fontmap->width_of;
1369 width_of_factor = dw;
1370 width_of = fnt->width_of;
1373 for (shadow = r_textshadow.value != 0 && basealpha > 0;shadow >= 0;shadow--)
1378 if (!outcolor || *outcolor == -1)
1379 colorindex = STRING_COLOR_DEFAULT;
1381 colorindex = *outcolor;
1383 DrawQ_GetTextColor(color, colorindex, basered, basegreen, baseblue, basealpha, shadow != 0);
1390 x += r_textshadow.value * vid.width / vid_conwidth.value;
1391 y += r_textshadow.value * vid.height / vid_conheight.value;
1394 for (i = 0;((bytes_left = maxlen - (text - text_start)) > 0) && *text;)
1396 nextch = ch = u8_getnchar(text, &text, bytes_left);
1397 i = text - text_start;
1400 if (ch == ' ' && !fontmap)
1402 x += width_of[(int) ' '] * width_of_factor;
1405 if (ch == STRING_COLOR_TAG && !ignorecolorcodes && i < maxlen)
1407 ch = *text; // colors are ascii, so no u8_ needed
1408 if (ch <= '9' && ch >= '0') // ^[0-9] found
1410 colorindex = ch - '0';
1411 DrawQ_GetTextColor(color, colorindex, basered, basegreen, baseblue, basealpha, shadow != 0);
1416 else if (ch == STRING_COLOR_RGB_TAG_CHAR && i+3 < maxlen ) // ^x found
1418 // building colorindex...
1419 ch = tolower(text[1]);
1420 tempcolorindex = 0x10000; // binary: 1,0000,0000,0000,0000
1421 if (ch <= '9' && ch >= '0') tempcolorindex |= (ch - '0') << 12;
1422 else if (ch >= 'a' && ch <= 'f') tempcolorindex |= (ch - 87) << 12;
1423 else tempcolorindex = 0;
1426 ch = tolower(text[2]);
1427 if (ch <= '9' && ch >= '0') tempcolorindex |= (ch - '0') << 8;
1428 else if (ch >= 'a' && ch <= 'f') tempcolorindex |= (ch - 87) << 8;
1429 else tempcolorindex = 0;
1432 ch = tolower(text[3]);
1433 if (ch <= '9' && ch >= '0') tempcolorindex |= (ch - '0') << 4;
1434 else if (ch >= 'a' && ch <= 'f') tempcolorindex |= (ch - 87) << 4;
1435 else tempcolorindex = 0;
1438 colorindex = tempcolorindex | 0xf;
1439 // ...done! now colorindex has rgba codes (1,rrrr,gggg,bbbb,aaaa)
1440 //Con_Printf("^1colorindex:^7 %x\n", colorindex);
1441 DrawQ_GetTextColor(color, colorindex, basered, basegreen, baseblue, basealpha, shadow != 0);
1449 else if (ch == STRING_COLOR_TAG)
1458 // using a value of -1 for the oldstyle map because NULL means uninitialized...
1459 // this way we don't need to rebind fnt->tex for every old-style character
1460 // E000..E0FF: emulate old-font characters (to still have smileys and such available)
1463 x += 1.0/pix_x * r_textshadow.value;
1464 y += 1.0/pix_y * r_textshadow.value;
1466 if (!fontmap || (ch <= 0xFF && fontmap->glyphs[ch].image) || (ch >= 0xE000 && ch <= 0xE0FF))
1474 if (map != ft2_oldstyle_map)
1478 // switching from freetype to non-freetype rendering
1479 GL_LockArrays(0, batchcount * 4);
1480 R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, quadelement3s, 0, 0);
1481 GL_LockArrays(0, 0);
1487 R_SetupShader_Generic(fnt->tex, NULL, GL_MODULATE, 1);
1488 map = ft2_oldstyle_map;
1492 //num = (unsigned char) text[i];
1493 //thisw = fnt->width_of[num];
1494 thisw = fnt->width_of[ch];
1495 // FIXME make these smaller to just include the occupied part of the character for slightly faster rendering
1496 s = (ch & 15)*0.0625f + (0.5f / tw);
1497 t = (ch >> 4)*0.0625f + (0.5f / th);
1498 u = 0.0625f * thisw - (1.0f / tw);
1499 v = 0.0625f - (1.0f / th);
1500 ac[ 0] = color[0];ac[ 1] = color[1];ac[ 2] = color[2];ac[ 3] = color[3];
1501 ac[ 4] = color[0];ac[ 5] = color[1];ac[ 6] = color[2];ac[ 7] = color[3];
1502 ac[ 8] = color[0];ac[ 9] = color[1];ac[10] = color[2];ac[11] = color[3];
1503 ac[12] = color[0];ac[13] = color[1];ac[14] = color[2];ac[15] = color[3];
1504 at[ 0] = s ; at[ 1] = t ;
1505 at[ 2] = s+u ; at[ 3] = t ;
1506 at[ 4] = s+u ; at[ 5] = t+v ;
1507 at[ 6] = s ; at[ 7] = t+v ;
1508 av[ 0] = x ; av[ 1] = y ; av[ 2] = 10;
1509 av[ 3] = x+dw*thisw ; av[ 4] = y ; av[ 5] = 10;
1510 av[ 6] = x+dw*thisw ; av[ 7] = y+dh ; av[ 8] = 10;
1511 av[ 9] = x ; av[10] = y+dh ; av[11] = 10;
1516 if (batchcount >= QUADELEMENTS_MAXQUADS)
1518 GL_LockArrays(0, batchcount * 4);
1519 R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, quadelement3s, 0, 0);
1520 GL_LockArrays(0, 0);
1526 x += width_of[ch] * width_of_factor;
1528 if (!map || map == ft2_oldstyle_map || map->start < ch || map->start + FONT_CHARS_PER_MAP >= ch)
1530 // new charmap - need to render
1533 // we need a different character map, render what we currently have:
1534 GL_LockArrays(0, batchcount * 4);
1535 R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, quadelement3s, 0, 0);
1536 GL_LockArrays(0, 0);
1543 map = FontMap_FindForChar(fontmap, ch);
1546 if (!Font_LoadMapForIndex(ft2, map_index, ch, &map))
1553 // this shouldn't happen
1558 R_SetupShader_Generic(map->texture, NULL, GL_MODULATE, 1);
1561 mapch = ch - map->start;
1562 thisw = map->glyphs[mapch].advance_x;
1566 if (prevch && Font_GetKerningForMap(ft2, map_index, w, h, prevch, ch, &kx, &ky))
1573 ac[ 0] = color[0]; ac[ 1] = color[1]; ac[ 2] = color[2]; ac[ 3] = color[3];
1574 ac[ 4] = color[0]; ac[ 5] = color[1]; ac[ 6] = color[2]; ac[ 7] = color[3];
1575 ac[ 8] = color[0]; ac[ 9] = color[1]; ac[10] = color[2]; ac[11] = color[3];
1576 ac[12] = color[0]; ac[13] = color[1]; ac[14] = color[2]; ac[15] = color[3];
1577 at[0] = map->glyphs[mapch].txmin; at[1] = map->glyphs[mapch].tymin;
1578 at[2] = map->glyphs[mapch].txmax; at[3] = map->glyphs[mapch].tymin;
1579 at[4] = map->glyphs[mapch].txmax; at[5] = map->glyphs[mapch].tymax;
1580 at[6] = map->glyphs[mapch].txmin; at[7] = map->glyphs[mapch].tymax;
1581 av[ 0] = x + dw * map->glyphs[mapch].vxmin; av[ 1] = y + dh * map->glyphs[mapch].vymin; av[ 2] = 10;
1582 av[ 3] = x + dw * map->glyphs[mapch].vxmax; av[ 4] = y + dh * map->glyphs[mapch].vymin; av[ 5] = 10;
1583 av[ 6] = x + dw * map->glyphs[mapch].vxmax; av[ 7] = y + dh * map->glyphs[mapch].vymax; av[ 8] = 10;
1584 av[ 9] = x + dw * map->glyphs[mapch].vxmin; av[10] = y + dh * map->glyphs[mapch].vymax; av[11] = 10;
1593 if (batchcount >= QUADELEMENTS_MAXQUADS)
1595 GL_LockArrays(0, batchcount * 4);
1596 R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, quadelement3s, 0, 0);
1597 GL_LockArrays(0, 0);
1609 x -= 1.0/pix_x * r_textshadow.value;
1610 y -= 1.0/pix_y * r_textshadow.value;
1616 GL_LockArrays(0, batchcount * 4);
1617 R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, quadelement3s, 0, 0);
1618 GL_LockArrays(0, 0);
1622 *outcolor = colorindex;
1624 // note: this relies on the proper text (not shadow) being drawn last
1628 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)
1630 return DrawQ_String_Scale(startx, starty, text, maxlen, w, h, 1, 1, basered, basegreen, baseblue, basealpha, flags, outcolor, ignorecolorcodes, fnt);
1633 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)
1635 return DrawQ_TextWidth_UntilWidth_TrackColors_Scale(text, maxlen, w, h, 1, 1, outcolor, ignorecolorcodes, fnt, maxwidth);
1638 float DrawQ_TextWidth(const char *text, size_t maxlen, float w, float h, qboolean ignorecolorcodes, const dp_font_t *fnt)
1640 return DrawQ_TextWidth_UntilWidth(text, &maxlen, w, h, ignorecolorcodes, fnt, 1000000000);
1643 float DrawQ_TextWidth_UntilWidth(const char *text, size_t *maxlen, float w, float h, qboolean ignorecolorcodes, const dp_font_t *fnt, float maxWidth)
1645 return DrawQ_TextWidth_UntilWidth_TrackColors(text, maxlen, w, h, NULL, ignorecolorcodes, fnt, maxWidth);
1650 // no ^xrgb management
1651 static int DrawQ_BuildColoredText(char *output2c, size_t maxoutchars, const char *text, int maxreadchars, qboolean ignorecolorcodes, int *outcolor)
1653 int color, numchars = 0;
1654 char *outputend2c = output2c + maxoutchars - 2;
1655 if (!outcolor || *outcolor == -1)
1656 color = STRING_COLOR_DEFAULT;
1660 maxreadchars = 1<<30;
1661 textend = text + maxreadchars;
1662 while (text != textend && *text)
1664 if (*text == STRING_COLOR_TAG && !ignorecolorcodes && text + 1 != textend)
1666 if (text[1] == STRING_COLOR_TAG)
1668 else if (text[1] >= '0' && text[1] <= '9')
1670 color = text[1] - '0';
1675 if (output2c >= outputend2c)
1677 *output2c++ = *text++;
1678 *output2c++ = color;
1681 output2c[0] = output2c[1] = 0;
1688 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)
1692 _DrawQ_ProcessDrawFlag(flags);
1694 R_Mesh_VertexPointer(floats, 0, 0);
1695 R_Mesh_ColorPointer(floats + 20, 0, 0);
1696 R_Mesh_ResetTextureState();
1702 height = pic->height;
1703 R_SetupShader_Generic(Draw_GetPicTexture(pic), NULL, GL_MODULATE, 1);
1704 R_Mesh_TexCoordPointer(0, 2, floats + 12, 0, 0);
1705 floats[12] = s1;floats[13] = t1;
1706 floats[14] = s2;floats[15] = t2;
1707 floats[16] = s4;floats[17] = t4;
1708 floats[18] = s3;floats[19] = t3;
1711 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
1713 floats[2] = floats[5] = floats[8] = floats[11] = 0;
1714 floats[0] = floats[9] = x;
1715 floats[1] = floats[4] = y;
1716 floats[3] = floats[6] = x + width;
1717 floats[7] = floats[10] = y + height;
1718 floats[20] = r1;floats[21] = g1;floats[22] = b1;floats[23] = a1;
1719 floats[24] = r2;floats[25] = g2;floats[26] = b2;floats[27] = a2;
1720 floats[28] = r4;floats[29] = g4;floats[30] = b4;floats[31] = a4;
1721 floats[32] = r3;floats[33] = g3;floats[34] = b3;floats[35] = a3;
1723 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
1726 void DrawQ_Mesh (drawqueuemesh_t *mesh, int flags)
1728 _DrawQ_ProcessDrawFlag(flags);
1730 R_Mesh_VertexPointer(mesh->data_vertex3f, 0, 0);
1731 R_Mesh_ColorPointer(mesh->data_color4f, 0, 0);
1732 R_Mesh_ResetTextureState();
1733 R_Mesh_TexCoordPointer(0, 2, mesh->data_texcoord2f, 0, 0);
1734 R_SetupShader_Generic(mesh->texture, NULL, GL_MODULATE, 1);
1736 GL_LockArrays(0, mesh->num_vertices);
1737 R_Mesh_Draw(0, mesh->num_vertices, 0, mesh->num_triangles, mesh->data_element3i, mesh->data_element3s, 0, 0);
1738 GL_LockArrays(0, 0);
1741 void DrawQ_LineLoop (drawqueuemesh_t *mesh, int flags)
1745 _DrawQ_ProcessDrawFlag(flags);
1749 qglBegin(GL_LINE_LOOP);
1750 for (num = 0;num < mesh->num_vertices;num++)
1752 if (mesh->data_color4f)
1753 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]);
1754 qglVertex2f(mesh->data_vertex3f[num*3+0], mesh->data_vertex3f[num*3+1]);
1760 //[515]: this is old, delete
1761 void DrawQ_Line (float width, float x1, float y1, float x2, float y2, float r, float g, float b, float alpha, int flags)
1763 _DrawQ_ProcessDrawFlag(flags);
1765 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
1768 //qglLineWidth(width);CHECKGLERROR
1770 GL_Color(r,g,b,alpha);
1773 qglVertex2f(x1, y1);
1774 qglVertex2f(x2, y2);
1779 void DrawQ_SetClipArea(float x, float y, float width, float height)
1784 // We have to convert the con coords into real coords
1785 // OGL uses top to bottom
1786 ix = (int)(0.5 + x * ((float)vid.width / vid_conwidth.integer));
1787 iy = (int)(0.5 + y * ((float) vid.height / vid_conheight.integer));
1788 iw = (int)(width * ((float)vid.width / vid_conwidth.integer));
1789 ih = (int)(height * ((float)vid.height / vid_conheight.integer));
1790 GL_Scissor(ix, vid.height - iy - ih, iw, ih);
1792 GL_ScissorTest(true);
1795 void DrawQ_ResetClipArea(void)
1798 GL_ScissorTest(false);
1801 void DrawQ_Finish(void)
1803 r_refdef.draw2dstage = false;
1806 static float blendvertex3f[9] = {-5000, -5000, 10, 10000, -5000, 10, -5000, 10000, 10};
1807 void R_DrawGamma(void)
1810 switch(vid.renderpath)
1812 case RENDERPATH_GL20:
1813 case RENDERPATH_CGGL:
1814 if (vid_usinghwgamma || v_glslgamma.integer)
1817 case RENDERPATH_GL13:
1818 case RENDERPATH_GL11:
1819 if (vid_usinghwgamma)
1823 // all the blends ignore depth
1824 R_Mesh_VertexPointer(blendvertex3f, 0, 0);
1825 R_Mesh_ColorPointer(NULL, 0, 0);
1826 R_Mesh_ResetTextureState();
1827 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
1829 GL_DepthRange(0, 1);
1830 GL_PolygonOffset(0, 0);
1831 GL_DepthTest(false);
1832 if (v_color_enable.integer)
1834 c[0] = v_color_white_r.value;
1835 c[1] = v_color_white_g.value;
1836 c[2] = v_color_white_b.value;
1839 c[0] = c[1] = c[2] = v_contrast.value;
1840 if (c[0] >= 1.01f || c[1] >= 1.01f || c[2] >= 1.01f)
1842 GL_BlendFunc(GL_DST_COLOR, GL_ONE);
1843 while (c[0] >= 1.01f || c[1] >= 1.01f || c[2] >= 1.01f)
1845 GL_Color(bound(0, c[0] - 1, 1), bound(0, c[1] - 1, 1), bound(0, c[2] - 1, 1), 1);
1846 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, polygonelement3s, 0, 0);
1847 VectorScale(c, 0.5, c);
1850 if (v_color_enable.integer)
1852 c[0] = v_color_black_r.value;
1853 c[1] = v_color_black_g.value;
1854 c[2] = v_color_black_b.value;
1857 c[0] = c[1] = c[2] = v_brightness.value;
1858 if (c[0] >= 0.01f || c[1] >= 0.01f || c[2] >= 0.01f)
1860 GL_BlendFunc(GL_ONE, GL_ONE);
1861 GL_Color(c[0], c[1], c[2], 1);
1862 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, polygonelement3s, 0, 0);