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_Printf("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 extern int con_linewidth; // to force rewrapping
536 static void LoadFont(qboolean override, const char *name, dp_font_t *fnt)
539 float maxwidth, scale;
540 char widthfile[MAX_QPATH];
542 fs_offset_t widthbufsize;
544 if(override || !fnt->texpath[0])
545 strlcpy(fnt->texpath, name, sizeof(fnt->texpath));
547 if(drawtexturepool == NULL)
548 return; // before gl_draw_start, so will be loaded later
552 // clear freetype font
553 Font_UnloadFont(fnt->ft2);
558 if(fnt->req_face != -1)
560 if(!Font_LoadFont(fnt->texpath, fnt))
561 Con_Printf("Failed to load font-file for '%s', it will not support as many characters.\n", fnt->texpath);
564 fnt->tex = Draw_CachePic_Flags(fnt->texpath, CACHEPICFLAG_QUIET | CACHEPICFLAG_NOCOMPRESSION)->tex;
565 if(fnt->tex == r_texture_notexture)
567 fnt->tex = Draw_CachePic_Flags("gfx/conchars", CACHEPICFLAG_NOCOMPRESSION)->tex;
568 strlcpy(widthfile, "gfx/conchars.width", sizeof(widthfile));
571 dpsnprintf(widthfile, sizeof(widthfile), "%s.width", fnt->texpath);
573 // unspecified width == 1 (base width)
574 for(i = 1; i < 256; ++i)
575 fnt->width_of[i] = 1;
578 // FIXME load "name.width", if it fails, fill all with 1
579 if((widthbuf = (char *) FS_LoadFile(widthfile, tempmempool, true, &widthbufsize)))
581 float extraspacing = 0;
582 const char *p = widthbuf;
587 if(!COM_ParseToken_Simple(&p, false, false))
605 fnt->width_of[ch++] = atof(com_token) + extraspacing;
608 if(!strcmp(com_token, "extraspacing"))
610 if(!COM_ParseToken_Simple(&p, false, false))
612 extraspacing = atof(com_token);
614 else if(!strcmp(com_token, "scale"))
616 if(!COM_ParseToken_Simple(&p, false, false))
618 scale = atof(com_token);
622 Con_Printf("Warning: skipped unknown font property %s\n", com_token);
623 if(!COM_ParseToken_Simple(&p, false, false))
633 maxwidth = fnt->width_of[1];
634 for(i = 2; i < 256; ++i)
635 maxwidth = max(maxwidth, fnt->width_of[i]);
636 fnt->maxwidth = maxwidth;
638 // fix up maxwidth for overlap
639 fnt->maxwidth *= scale;
642 if(fnt == FONT_CONSOLE)
643 con_linewidth = -1; // rewrap console in next frame
646 static dp_font_t *FindFont(const char *title)
649 for(i = 0; i < MAX_FONTS; ++i)
650 if(!strcmp(dp_fonts[i].title, title))
655 static float snap_to_pixel_x(float x, float roundUpAt)
657 float pixelpos = x * vid.width / vid_conwidth.value;
658 int snap = (int) pixelpos;
659 if (pixelpos - snap >= roundUpAt) ++snap;
660 return ((float)snap * vid_conwidth.value / vid.width);
662 x = (int)(x * vid.width / vid_conwidth.value);
663 x = (x * vid_conwidth.value / vid.width);
668 static float snap_to_pixel_y(float y, float roundUpAt)
670 float pixelpos = y * vid.height / vid_conheight.value;
671 int snap = (int) pixelpos;
672 if (pixelpos - snap > roundUpAt) ++snap;
673 return ((float)snap * vid_conheight.value / vid.height);
675 y = (int)(y * vid.height / vid_conheight.value);
676 y = (y * vid_conheight.value / vid.height);
681 static void LoadFont_f(void)
686 const char *filelist, *c, *cm;
687 char mainfont[MAX_QPATH];
691 Con_Printf("Available font commands:\n");
692 for(i = 0; i < MAX_FONTS; ++i)
693 Con_Printf(" loadfont %s gfx/tgafile[...] [sizes...]\n", dp_fonts[i].title);
694 Con_Printf("A font can simply be gfx/tgafile, or alternatively you\n"
695 "can specify multiple fonts and faces\n"
696 "Like this: gfx/vera-sans:2,gfx/fallback:1\n"
697 "to load face 2 of the font gfx/vera-sans and use face 1\n"
698 "of gfx/fallback as fallback font.\n"
699 "You can also specify a list of font sizes to load, like this:\n"
700 "loadfont console gfx/conchars,gfx/fallback 8 12 16 24 32\n"
701 "In many cases, 8 12 16 24 32 should be a good choice.\n"
705 f = FindFont(Cmd_Argv(1));
708 Con_Printf("font function not found\n");
713 filelist = "gfx/conchars";
715 filelist = Cmd_Argv(2);
717 memset(f->fallbacks, 0, sizeof(f->fallbacks));
718 memset(f->fallback_faces, 0, sizeof(f->fallback_faces));
720 // first font is handled "normally"
721 c = strchr(filelist, ':');
722 cm = strchr(filelist, ',');
723 if(c && (!cm || c < cm))
724 f->req_face = atoi(c+1);
731 if(!c || (c - filelist) > MAX_QPATH)
732 strlcpy(mainfont, filelist, sizeof(mainfont));
735 memcpy(mainfont, filelist, c - filelist);
736 mainfont[c - filelist] = 0;
739 for(i = 0; i < MAX_FONT_FALLBACKS; ++i)
741 c = strchr(filelist, ',');
747 c = strchr(filelist, ':');
748 cm = strchr(filelist, ',');
749 if(c && (!cm || c < cm))
750 f->fallback_faces[i] = atoi(c+1);
753 f->fallback_faces[i] = 0; // f->req_face; could make it stick to the default-font's face index
756 if(!c || (c-filelist) > MAX_QPATH)
758 strlcpy(f->fallbacks[i], filelist, sizeof(mainfont));
762 memcpy(f->fallbacks[i], filelist, c - filelist);
763 f->fallbacks[i][c - filelist] = 0;
767 // for now: by default load only one size: the default size
769 for(i = 1; i < MAX_FONT_SIZES; ++i)
770 f->req_sizes[i] = -1;
772 // for some reason this argc is 3 even when using 2 arguments here, maybe nexuiz screws up
775 for(i = 0; i < Cmd_Argc()-3; ++i)
777 sz = atof(Cmd_Argv(i+3));
778 if (IS_NAN(sz)) // do not use crap sizes
780 // now try to scale to our actual size:
782 sn = snap_to_pixel_y(sz, 0.5);
785 sn = sz * vid_height.value / vid_conheight.value;
787 if ( sn - (float)si >= 0.5 )
789 sn = si * vid_conheight.value / vid_height.value;
792 f->req_sizes[i] = sn;
794 f->req_sizes[i] = sz;
797 LoadFont(true, mainfont, f);
805 static void gl_draw_start(void)
808 drawtexturepool = R_AllocTexturePool();
811 memset(cachepichash, 0, sizeof(cachepichash));
815 for(i = 0; i < MAX_FONTS; ++i)
816 LoadFont(false, va("gfx/font_%s", dp_fonts[i].title), &dp_fonts[i]);
818 // draw the loading screen so people have something to see in the newly opened window
819 SCR_UpdateLoadingScreen(true);
822 static void gl_draw_shutdown(void)
826 R_FreeTexturePool(&drawtexturepool);
829 memset(cachepichash, 0, sizeof(cachepichash));
832 static void gl_draw_newmap(void)
837 void GL_Draw_Init (void)
840 Cvar_RegisterVariable(&r_textshadow);
841 Cvar_RegisterVariable(&r_textbrightness);
842 Cvar_RegisterVariable(&r_textcontrast);
843 Cmd_AddCommand ("loadfont",LoadFont_f, "loadfont function tganame loads a font; example: loadfont console gfx/veramono; loadfont without arguments lists the available functions");
844 R_RegisterModule("GL_Draw", gl_draw_start, gl_draw_shutdown, gl_draw_newmap);
846 strlcpy(FONT_DEFAULT->title, "default", sizeof(FONT_DEFAULT->title));
847 strlcpy(FONT_DEFAULT->texpath, "gfx/conchars", sizeof(FONT_DEFAULT->texpath));
848 strlcpy(FONT_CONSOLE->title, "console", sizeof(FONT_CONSOLE->title));
849 strlcpy(FONT_SBAR->title, "sbar", sizeof(FONT_SBAR->title));
850 strlcpy(FONT_NOTIFY->title, "notify", sizeof(FONT_NOTIFY->title));
851 strlcpy(FONT_CHAT->title, "chat", sizeof(FONT_CHAT->title));
852 strlcpy(FONT_CENTERPRINT->title, "centerprint", sizeof(FONT_CENTERPRINT->title));
853 strlcpy(FONT_INFOBAR->title, "infobar", sizeof(FONT_INFOBAR->title));
854 strlcpy(FONT_MENU->title, "menu", sizeof(FONT_MENU->title));
855 for(i = 0, j = 0; i < MAX_USERFONTS; ++i)
856 if(!FONT_USER[i].title[0])
857 dpsnprintf(FONT_USER[i].title, sizeof(FONT_USER[i].title), "user%d", j++);
861 void _DrawQ_Setup(void)
863 r_viewport_t viewport;
864 if (r_refdef.draw2dstage)
866 r_refdef.draw2dstage = true;
868 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);
869 R_SetViewport(&viewport);
870 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
871 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
872 qglDisable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
873 GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
874 R_EntityMatrix(&identitymatrix);
878 GL_PolygonOffset(0, 0);
882 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
885 static void _DrawQ_ProcessDrawFlag(int flags)
889 if(flags == DRAWFLAG_ADDITIVE)
890 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
891 else if(flags == DRAWFLAG_MODULATE)
892 GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
893 else if(flags == DRAWFLAG_2XMODULATE)
894 GL_BlendFunc(GL_DST_COLOR,GL_SRC_COLOR);
895 else if(flags == DRAWFLAG_SCREEN)
896 GL_BlendFunc(GL_ONE_MINUS_DST_COLOR,GL_ONE);
898 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
901 void DrawQ_Pic(float x, float y, cachepic_t *pic, float width, float height, float red, float green, float blue, float alpha, int flags)
905 _DrawQ_ProcessDrawFlag(flags);
906 GL_Color(red, green, blue, alpha);
908 R_Mesh_VertexPointer(floats, 0, 0);
909 R_Mesh_ColorPointer(NULL, 0, 0);
910 R_Mesh_ResetTextureState();
916 height = pic->height;
917 R_SetupShader_Generic(Draw_GetPicTexture(pic), NULL, GL_MODULATE, 1);
918 R_Mesh_TexCoordPointer(0, 2, floats + 12, 0, 0);
921 floats[12] = 0.0f;floats[13] = 0.0f;
922 floats[14] = 1.0f;floats[15] = 0.0f;
923 floats[16] = 1.0f;floats[17] = 1.0f;
924 floats[18] = 0.0f;floats[19] = 1.0f;
926 // AK07: lets be texel correct on the corners
928 float horz_offset = 0.5f / pic->width;
929 float vert_offset = 0.5f / pic->height;
931 floats[12] = 0.0f + horz_offset;floats[13] = 0.0f + vert_offset;
932 floats[14] = 1.0f - horz_offset;floats[15] = 0.0f + vert_offset;
933 floats[16] = 1.0f - horz_offset;floats[17] = 1.0f - vert_offset;
934 floats[18] = 0.0f + horz_offset;floats[19] = 1.0f - vert_offset;
939 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
941 floats[2] = floats[5] = floats[8] = floats[11] = 0;
942 floats[0] = floats[9] = x;
943 floats[1] = floats[4] = y;
944 floats[3] = floats[6] = x + width;
945 floats[7] = floats[10] = y + height;
947 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
950 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)
953 float af = DEG2RAD(-angle); // forward
954 float ar = DEG2RAD(-angle + 90); // right
955 float sinaf = sin(af);
956 float cosaf = cos(af);
957 float sinar = sin(ar);
958 float cosar = cos(ar);
960 _DrawQ_ProcessDrawFlag(flags);
961 GL_Color(red, green, blue, alpha);
963 R_Mesh_VertexPointer(floats, 0, 0);
964 R_Mesh_ColorPointer(NULL, 0, 0);
965 R_Mesh_ResetTextureState();
971 height = pic->height;
972 R_SetupShader_Generic(Draw_GetPicTexture(pic), NULL, GL_MODULATE, 1);
973 R_Mesh_TexCoordPointer(0, 2, floats + 12, 0, 0);
975 floats[12] = 0.0f;floats[13] = 0.0f;
976 floats[14] = 1.0f;floats[15] = 0.0f;
977 floats[16] = 1.0f;floats[17] = 1.0f;
978 floats[18] = 0.0f;floats[19] = 1.0f;
981 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
983 floats[2] = floats[5] = floats[8] = floats[11] = 0;
986 floats[0] = x - cosaf*org_x - cosar*org_y;
987 floats[1] = y - sinaf*org_x - sinar*org_y;
990 floats[3] = x + cosaf*(width-org_x) - cosar*org_y;
991 floats[4] = y + sinaf*(width-org_x) - sinar*org_y;
994 floats[6] = x + cosaf*(width-org_x) + cosar*(height-org_y);
995 floats[7] = y + sinaf*(width-org_x) + sinar*(height-org_y);
998 floats[9] = x - cosaf*org_x + cosar*(height-org_y);
999 floats[10] = y - sinaf*org_x + sinar*(height-org_y);
1001 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
1004 void DrawQ_Fill(float x, float y, float width, float height, float red, float green, float blue, float alpha, int flags)
1008 _DrawQ_ProcessDrawFlag(flags);
1009 GL_Color(red, green, blue, alpha);
1011 R_Mesh_VertexPointer(floats, 0, 0);
1012 R_Mesh_ColorPointer(NULL, 0, 0);
1013 R_Mesh_ResetTextureState();
1014 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
1016 floats[2] = floats[5] = floats[8] = floats[11] = 0;
1017 floats[0] = floats[9] = x;
1018 floats[1] = floats[4] = y;
1019 floats[3] = floats[6] = x + width;
1020 floats[7] = floats[10] = y + height;
1022 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
1025 /// color tag printing
1026 static const vec4_t string_colors[] =
1029 // LordHavoc: why on earth is cyan before magenta in Quake3?
1030 // LordHavoc: note: Doom3 uses white for [0] and [7]
1031 {0.0, 0.0, 0.0, 1.0}, // black
1032 {1.0, 0.0, 0.0, 1.0}, // red
1033 {0.0, 1.0, 0.0, 1.0}, // green
1034 {1.0, 1.0, 0.0, 1.0}, // yellow
1035 {0.0, 0.0, 1.0, 1.0}, // blue
1036 {0.0, 1.0, 1.0, 1.0}, // cyan
1037 {1.0, 0.0, 1.0, 1.0}, // magenta
1038 {1.0, 1.0, 1.0, 1.0}, // white
1039 // [515]'s BX_COLOREDTEXT extension
1040 {1.0, 1.0, 1.0, 0.5}, // half transparent
1041 {0.5, 0.5, 0.5, 1.0} // half brightness
1042 // Black's color table
1043 //{1.0, 1.0, 1.0, 1.0},
1044 //{1.0, 0.0, 0.0, 1.0},
1045 //{0.0, 1.0, 0.0, 1.0},
1046 //{0.0, 0.0, 1.0, 1.0},
1047 //{1.0, 1.0, 0.0, 1.0},
1048 //{0.0, 1.0, 1.0, 1.0},
1049 //{1.0, 0.0, 1.0, 1.0},
1050 //{0.1, 0.1, 0.1, 1.0}
1053 #define STRING_COLORS_COUNT (sizeof(string_colors) / sizeof(vec4_t))
1055 static void DrawQ_GetTextColor(float color[4], int colorindex, float r, float g, float b, float a, qboolean shadow)
1057 float C = r_textcontrast.value;
1058 float B = r_textbrightness.value;
1059 if (colorindex & 0x10000) // that bit means RGB color
1061 color[0] = ((colorindex >> 12) & 0xf) / 15.0;
1062 color[1] = ((colorindex >> 8) & 0xf) / 15.0;
1063 color[2] = ((colorindex >> 4) & 0xf) / 15.0;
1064 color[3] = (colorindex & 0xf) / 15.0;
1067 Vector4Copy(string_colors[colorindex], color);
1068 Vector4Set(color, color[0] * r * C + B, color[1] * g * C + B, color[2] * b * C + B, color[3] * a);
1071 float shadowalpha = (color[0]+color[1]+color[2]) * 0.8;
1072 Vector4Set(color, 0, 0, 0, color[3] * bound(0, shadowalpha, 1));
1076 // NOTE: this function always draws exactly one character if maxwidth <= 0
1077 float DrawQ_TextWidth_Font_UntilWidth_TrackColors_Size_Scale(const char *text, float w, float h, float sw, float sh, size_t *maxlen, int *outcolor, qboolean ignorecolorcodes, const dp_font_t *fnt, float maxwidth)
1079 const char *text_start = text;
1080 int colorindex = STRING_COLOR_DEFAULT;
1083 Uchar ch, mapch, nextch;
1084 Uchar prevch = 0; // used for kerning
1089 ft2_font_map_t *fontmap = NULL;
1090 ft2_font_map_t *map = NULL;
1091 ft2_font_map_t *prevmap = NULL;
1092 ft2_font_t *ft2 = fnt->ft2;
1094 qboolean snap = true;
1095 qboolean least_one = false;
1096 float dw, dh; // display w/h
1103 // do this in the end
1107 // find the most fitting size:
1111 map_index = Font_IndexForSize(ft2, h, &w, &h);
1113 map_index = Font_IndexForSize(ft2, h, NULL, NULL);
1114 fontmap = Font_MapForIndex(ft2, map_index);
1118 if(fabs(sw - 1) > 0.001 || fabs(sh - 1) > 0.001)
1119 snap = false; // turn off pixel snapping for better animation
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;
1144 for (i = 0;((bytes_left = *maxlen - (text - text_start)) > 0) && *text;)
1147 nextch = ch = u8_getnchar(text, &text, bytes_left);
1148 i = text - text_start;
1152 x = snap_to_pixel_x(x, 0.4);
1153 if (ch == ' ' && !fontmap)
1155 if(!least_one || i0) // never skip the first character
1156 if(x + fnt->width_of[(int) ' '] * dw > maxwidth)
1159 break; // oops, can't draw this
1161 x += fnt->width_of[(int) ' '] * dw;
1164 // i points to the char after ^
1165 if (ch == STRING_COLOR_TAG && !ignorecolorcodes && i < *maxlen)
1167 ch = *text; // colors are ascii, so no u8_ needed
1168 if (ch <= '9' && ch >= '0') // ^[0-9] found
1170 colorindex = ch - '0';
1175 // i points to the char after ^...
1176 // i+3 points to 3 in ^x123
1177 // i+3 == *maxlen would mean that char is missing
1178 else if (ch == STRING_COLOR_RGB_TAG_CHAR && i + 3 < *maxlen ) // ^x found
1180 // building colorindex...
1181 ch = tolower(text[1]);
1182 tempcolorindex = 0x10000; // binary: 1,0000,0000,0000,0000
1183 if (ch <= '9' && ch >= '0') tempcolorindex |= (ch - '0') << 12;
1184 else if (ch >= 'a' && ch <= 'f') tempcolorindex |= (ch - 87) << 12;
1185 else tempcolorindex = 0;
1188 ch = tolower(text[2]);
1189 if (ch <= '9' && ch >= '0') tempcolorindex |= (ch - '0') << 8;
1190 else if (ch >= 'a' && ch <= 'f') tempcolorindex |= (ch - 87) << 8;
1191 else tempcolorindex = 0;
1194 ch = tolower(text[3]);
1195 if (ch <= '9' && ch >= '0') tempcolorindex |= (ch - '0') << 4;
1196 else if (ch >= 'a' && ch <= 'f') tempcolorindex |= (ch - 87) << 4;
1197 else tempcolorindex = 0;
1200 colorindex = tempcolorindex | 0xf;
1201 // ...done! now colorindex has rgba codes (1,rrrr,gggg,bbbb,aaaa)
1209 else if (ch == STRING_COLOR_TAG) // ^^ found, ignore the first ^ and go to print the second
1218 if (!fontmap || (ch <= 0xFF && fontmap->glyphs[ch].image) || (ch >= 0xE000 && ch <= 0xE0FF))
1225 map = ft2_oldstyle_map;
1227 if(!least_one || i0) // never skip the first character
1228 if(x + fnt->width_of[ch] * dw > maxwidth)
1231 break; // oops, can't draw this
1233 x += fnt->width_of[ch] * dw;
1235 if (!map || map == ft2_oldstyle_map || map->start < ch || map->start + FONT_CHARS_PER_MAP >= ch)
1237 map = FontMap_FindForChar(fontmap, ch);
1240 if (!Font_LoadMapForIndex(ft2, map_index, ch, &map))
1246 mapch = ch - map->start;
1247 if (prevch && Font_GetKerningForMap(ft2, map_index, w, h, prevch, ch, &kx, NULL))
1249 x += map->glyphs[mapch].advance_x * dw;
1258 *outcolor = colorindex;
1263 float DrawQ_String_Font_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)
1265 int shadow, colorindex = STRING_COLOR_DEFAULT;
1267 float x = startx, y, s, t, u, v, thisw;
1268 float *av, *at, *ac;
1271 static float vertex3f[QUADELEMENTS_MAXQUADS*4*3];
1272 static float texcoord2f[QUADELEMENTS_MAXQUADS*4*2];
1273 static float color4f[QUADELEMENTS_MAXQUADS*4*4];
1274 Uchar ch, mapch, nextch;
1275 Uchar prevch = 0; // used for kerning
1278 ft2_font_map_t *prevmap = NULL; // the previous map
1279 ft2_font_map_t *map = NULL; // the currently used map
1280 ft2_font_map_t *fontmap = NULL; // the font map for the size
1282 const char *text_start = text;
1284 ft2_font_t *ft2 = fnt->ft2;
1285 qboolean snap = true;
1291 tw = R_TextureWidth(fnt->tex);
1292 th = R_TextureHeight(fnt->tex);
1300 starty -= (fnt->scale - 1) * h * 0.5; // center
1307 map_index = Font_IndexForSize(ft2, h, &w, &h);
1309 map_index = Font_IndexForSize(ft2, h, NULL, NULL);
1310 fontmap = Font_MapForIndex(ft2, map_index);
1314 if(fabs(sw - 1) > 0.001 || fabs(sh - 1) > 0.001)
1315 snap = false; // turn off pixel snapping for better animation
1323 // draw the font at its baseline when using freetype
1325 ftbase_y = dh * (4.5/6.0);
1330 _DrawQ_ProcessDrawFlag(flags);
1332 R_Mesh_ColorPointer(color4f, 0, 0);
1333 R_Mesh_ResetTextureState();
1335 R_Mesh_TexBind(0, R_GetTexture(fnt->tex));
1336 R_Mesh_TexCoordPointer(0, 2, texcoord2f, 0, 0);
1337 R_Mesh_VertexPointer(vertex3f, 0, 0);
1338 R_SetupShader_Generic(fnt->tex, NULL, GL_MODULATE, 1);
1345 //ftbase_x = snap_to_pixel_x(ftbase_x);
1347 ftbase_y = snap_to_pixel_y(ftbase_y, 0.3);
1349 pix_x = vid.width / vid_conwidth.value;
1350 pix_y = vid.height / vid_conheight.value;
1351 for (shadow = r_textshadow.value != 0 && basealpha > 0;shadow >= 0;shadow--)
1355 if (!outcolor || *outcolor == -1)
1356 colorindex = STRING_COLOR_DEFAULT;
1358 colorindex = *outcolor;
1360 DrawQ_GetTextColor(color, colorindex, basered, basegreen, baseblue, basealpha, shadow != 0);
1367 x += r_textshadow.value * vid.width / vid_conwidth.value;
1368 y += r_textshadow.value * vid.height / vid_conheight.value;
1371 for (i = 0;((bytes_left = maxlen - (text - text_start)) > 0) && *text;)
1373 nextch = ch = u8_getnchar(text, &text, bytes_left);
1374 i = text - text_start;
1379 x = snap_to_pixel_x(x, 0.4);
1380 y = snap_to_pixel_y(y, 0.4);
1382 if (ch == ' ' && !fontmap)
1384 x += fnt->width_of[(int) ' '] * dw;
1387 if (ch == STRING_COLOR_TAG && !ignorecolorcodes && i < maxlen)
1389 ch = *text; // colors are ascii, so no u8_ needed
1390 if (ch <= '9' && ch >= '0') // ^[0-9] found
1392 colorindex = ch - '0';
1393 DrawQ_GetTextColor(color, colorindex, basered, basegreen, baseblue, basealpha, shadow != 0);
1398 else if (ch == STRING_COLOR_RGB_TAG_CHAR && i+3 < maxlen ) // ^x found
1400 // building colorindex...
1401 ch = tolower(text[1]);
1402 tempcolorindex = 0x10000; // binary: 1,0000,0000,0000,0000
1403 if (ch <= '9' && ch >= '0') tempcolorindex |= (ch - '0') << 12;
1404 else if (ch >= 'a' && ch <= 'f') tempcolorindex |= (ch - 87) << 12;
1405 else tempcolorindex = 0;
1408 ch = tolower(text[2]);
1409 if (ch <= '9' && ch >= '0') tempcolorindex |= (ch - '0') << 8;
1410 else if (ch >= 'a' && ch <= 'f') tempcolorindex |= (ch - 87) << 8;
1411 else tempcolorindex = 0;
1414 ch = tolower(text[3]);
1415 if (ch <= '9' && ch >= '0') tempcolorindex |= (ch - '0') << 4;
1416 else if (ch >= 'a' && ch <= 'f') tempcolorindex |= (ch - 87) << 4;
1417 else tempcolorindex = 0;
1420 colorindex = tempcolorindex | 0xf;
1421 // ...done! now colorindex has rgba codes (1,rrrr,gggg,bbbb,aaaa)
1422 //Con_Printf("^1colorindex:^7 %x\n", colorindex);
1423 DrawQ_GetTextColor(color, colorindex, basered, basegreen, baseblue, basealpha, shadow != 0);
1431 else if (ch == STRING_COLOR_TAG)
1440 // using a value of -1 for the oldstyle map because NULL means uninitialized...
1441 // this way we don't need to rebind fnt->tex for every old-style character
1442 // E000..E0FF: emulate old-font characters (to still have smileys and such available)
1445 x += pix_x * r_textshadow.value;
1446 y += pix_y * r_textshadow.value;
1448 if (!fontmap || (ch <= 0xFF && fontmap->glyphs[ch].image) || (ch >= 0xE000 && ch <= 0xE0FF))
1456 if (map != ft2_oldstyle_map)
1460 // switching from freetype to non-freetype rendering
1461 GL_LockArrays(0, batchcount * 4);
1462 R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, quadelement3s, 0, 0);
1463 GL_LockArrays(0, 0);
1469 R_SetupShader_Generic(fnt->tex, NULL, GL_MODULATE, 1);
1470 map = ft2_oldstyle_map;
1474 //num = (unsigned char) text[i];
1475 //thisw = fnt->width_of[num];
1476 thisw = fnt->width_of[ch];
1477 // FIXME make these smaller to just include the occupied part of the character for slightly faster rendering
1478 s = (ch & 15)*0.0625f + (0.5f / tw);
1479 t = (ch >> 4)*0.0625f + (0.5f / th);
1480 u = 0.0625f * thisw - (1.0f / tw);
1481 v = 0.0625f - (1.0f / th);
1482 ac[ 0] = color[0];ac[ 1] = color[1];ac[ 2] = color[2];ac[ 3] = color[3];
1483 ac[ 4] = color[0];ac[ 5] = color[1];ac[ 6] = color[2];ac[ 7] = color[3];
1484 ac[ 8] = color[0];ac[ 9] = color[1];ac[10] = color[2];ac[11] = color[3];
1485 ac[12] = color[0];ac[13] = color[1];ac[14] = color[2];ac[15] = color[3];
1486 at[ 0] = s ; at[ 1] = t ;
1487 at[ 2] = s+u ; at[ 3] = t ;
1488 at[ 4] = s+u ; at[ 5] = t+v ;
1489 at[ 6] = s ; at[ 7] = t+v ;
1490 av[ 0] = x ; av[ 1] = y ; av[ 2] = 10;
1491 av[ 3] = x+dw*thisw ; av[ 4] = y ; av[ 5] = 10;
1492 av[ 6] = x+dw*thisw ; av[ 7] = y+dh ; av[ 8] = 10;
1493 av[ 9] = x ; av[10] = y+dh ; av[11] = 10;
1498 if (batchcount >= QUADELEMENTS_MAXQUADS)
1500 GL_LockArrays(0, batchcount * 4);
1501 R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, quadelement3s, 0, 0);
1502 GL_LockArrays(0, 0);
1510 if (!map || map == ft2_oldstyle_map || map->start < ch || map->start + FONT_CHARS_PER_MAP >= ch)
1512 // new charmap - need to render
1515 // we need a different character map, render what we currently have:
1516 GL_LockArrays(0, batchcount * 4);
1517 R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, quadelement3s, 0, 0);
1518 GL_LockArrays(0, 0);
1525 map = FontMap_FindForChar(fontmap, ch);
1528 if (!Font_LoadMapForIndex(ft2, map_index, ch, &map))
1535 // this shouldn't happen
1540 R_SetupShader_Generic(map->texture, NULL, GL_MODULATE, 1);
1543 mapch = ch - map->start;
1544 thisw = map->glyphs[mapch].advance_x;
1548 if (prevch && Font_GetKerningForMap(ft2, map_index, w, h, prevch, ch, &kx, &ky))
1555 ac[ 0] = color[0]; ac[ 1] = color[1]; ac[ 2] = color[2]; ac[ 3] = color[3];
1556 ac[ 4] = color[0]; ac[ 5] = color[1]; ac[ 6] = color[2]; ac[ 7] = color[3];
1557 ac[ 8] = color[0]; ac[ 9] = color[1]; ac[10] = color[2]; ac[11] = color[3];
1558 ac[12] = color[0]; ac[13] = color[1]; ac[14] = color[2]; ac[15] = color[3];
1559 at[0] = map->glyphs[mapch].txmin; at[1] = map->glyphs[mapch].tymin;
1560 at[2] = map->glyphs[mapch].txmax; at[3] = map->glyphs[mapch].tymin;
1561 at[4] = map->glyphs[mapch].txmax; at[5] = map->glyphs[mapch].tymax;
1562 at[6] = map->glyphs[mapch].txmin; at[7] = map->glyphs[mapch].tymax;
1563 av[ 0] = x + dw * map->glyphs[mapch].vxmin; av[ 1] = y + dh * map->glyphs[mapch].vymin; av[ 2] = 10;
1564 av[ 3] = x + dw * map->glyphs[mapch].vxmax; av[ 4] = y + dh * map->glyphs[mapch].vymin; av[ 5] = 10;
1565 av[ 6] = x + dw * map->glyphs[mapch].vxmax; av[ 7] = y + dh * map->glyphs[mapch].vymax; av[ 8] = 10;
1566 av[ 9] = x + dw * map->glyphs[mapch].vxmin; av[10] = y + dh * map->glyphs[mapch].vymax; av[11] = 10;
1575 if (batchcount >= QUADELEMENTS_MAXQUADS)
1577 GL_LockArrays(0, batchcount * 4);
1578 R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, quadelement3s, 0, 0);
1579 GL_LockArrays(0, 0);
1591 x -= pix_x * r_textshadow.value;
1592 y -= pix_y * r_textshadow.value;
1598 GL_LockArrays(0, batchcount * 4);
1599 R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, quadelement3s, 0, 0);
1600 GL_LockArrays(0, 0);
1604 *outcolor = colorindex;
1606 // note: this relies on the proper text (not shadow) being drawn last
1610 float DrawQ_String_Font(float startx, float starty, const char *text, size_t maxlen, float w, float h, float basered, float basegreen, float baseblue, float basealpha, int flags, int *outcolor, qboolean ignorecolorcodes, const dp_font_t *fnt)
1612 return DrawQ_String_Font_Scale(startx, starty, text, maxlen, w, h, 1, 1, basered, basegreen, baseblue, basealpha, flags, outcolor, ignorecolorcodes, fnt);
1615 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)
1617 return DrawQ_String_Font(startx, starty, text, maxlen, w, h, basered, basegreen, baseblue, basealpha, flags, outcolor, ignorecolorcodes, &dp_fonts[0]);
1620 float DrawQ_TextWidth_Font_UntilWidth_TrackColors_Size(const char *text, float w, float h, size_t *maxlen, int *outcolor, qboolean ignorecolorcodes, const dp_font_t *fnt, float maxwidth)
1622 return DrawQ_TextWidth_Font_UntilWidth_TrackColors_Size_Scale(text, w, h, 1, 1, maxlen, outcolor, ignorecolorcodes, fnt, maxwidth);
1625 float DrawQ_TextWidth_Font(const char *text, size_t maxlen, qboolean ignorecolorcodes, const dp_font_t *fnt)
1627 return DrawQ_TextWidth_Font_UntilWidth(text, &maxlen, ignorecolorcodes, fnt, 1000000000);
1630 float DrawQ_TextWidth_Font_Size(const char *text, float w, float h, size_t maxlen, qboolean ignorecolorcodes, const dp_font_t *fnt)
1632 return DrawQ_TextWidth_Font_UntilWidth_Size(text, w, h, &maxlen, ignorecolorcodes, fnt, 1000000000);
1635 float DrawQ_TextWidth_Font_UntilWidth(const char *text, size_t *maxlen, qboolean ignorecolorcodes, const dp_font_t *fnt, float maxWidth)
1637 return DrawQ_TextWidth_Font_UntilWidth_TrackColors(text, maxlen, NULL, ignorecolorcodes, fnt, maxWidth);
1640 float DrawQ_TextWidth_Font_UntilWidth_Size(const char *text, float w, float h, size_t *maxlen, qboolean ignorecolorcodes, const dp_font_t *fnt, float maxWidth)
1642 return DrawQ_TextWidth_Font_UntilWidth_TrackColors_Size(text, w, h, maxlen, NULL, ignorecolorcodes, fnt, maxWidth);
1645 float DrawQ_TextWidth_Font_UntilWidth_TrackColors(const char *text, size_t *maxlen, int *outcolor, qboolean ignorecolorcodes, const dp_font_t *fnt, float maxwidth)
1647 return DrawQ_TextWidth_Font_UntilWidth_TrackColors_Size(text, 0, 0, maxlen, outcolor, ignorecolorcodes, fnt, maxwidth);
1652 // no ^xrgb management
1653 static int DrawQ_BuildColoredText(char *output2c, size_t maxoutchars, const char *text, int maxreadchars, qboolean ignorecolorcodes, int *outcolor)
1655 int color, numchars = 0;
1656 char *outputend2c = output2c + maxoutchars - 2;
1657 if (!outcolor || *outcolor == -1)
1658 color = STRING_COLOR_DEFAULT;
1662 maxreadchars = 1<<30;
1663 textend = text + maxreadchars;
1664 while (text != textend && *text)
1666 if (*text == STRING_COLOR_TAG && !ignorecolorcodes && text + 1 != textend)
1668 if (text[1] == STRING_COLOR_TAG)
1670 else if (text[1] >= '0' && text[1] <= '9')
1672 color = text[1] - '0';
1677 if (output2c >= outputend2c)
1679 *output2c++ = *text++;
1680 *output2c++ = color;
1683 output2c[0] = output2c[1] = 0;
1690 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)
1694 _DrawQ_ProcessDrawFlag(flags);
1696 R_Mesh_VertexPointer(floats, 0, 0);
1697 R_Mesh_ColorPointer(floats + 20, 0, 0);
1698 R_Mesh_ResetTextureState();
1704 height = pic->height;
1705 R_SetupShader_Generic(Draw_GetPicTexture(pic), NULL, GL_MODULATE, 1);
1706 R_Mesh_TexCoordPointer(0, 2, floats + 12, 0, 0);
1707 floats[12] = s1;floats[13] = t1;
1708 floats[14] = s2;floats[15] = t2;
1709 floats[16] = s4;floats[17] = t4;
1710 floats[18] = s3;floats[19] = t3;
1713 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
1715 floats[2] = floats[5] = floats[8] = floats[11] = 0;
1716 floats[0] = floats[9] = x;
1717 floats[1] = floats[4] = y;
1718 floats[3] = floats[6] = x + width;
1719 floats[7] = floats[10] = y + height;
1720 floats[20] = r1;floats[21] = g1;floats[22] = b1;floats[23] = a1;
1721 floats[24] = r2;floats[25] = g2;floats[26] = b2;floats[27] = a2;
1722 floats[28] = r4;floats[29] = g4;floats[30] = b4;floats[31] = a4;
1723 floats[32] = r3;floats[33] = g3;floats[34] = b3;floats[35] = a3;
1725 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
1728 void DrawQ_Mesh (drawqueuemesh_t *mesh, int flags)
1730 _DrawQ_ProcessDrawFlag(flags);
1732 R_Mesh_VertexPointer(mesh->data_vertex3f, 0, 0);
1733 R_Mesh_ColorPointer(mesh->data_color4f, 0, 0);
1734 R_Mesh_ResetTextureState();
1735 R_Mesh_TexCoordPointer(0, 2, mesh->data_texcoord2f, 0, 0);
1736 R_SetupShader_Generic(mesh->texture, NULL, GL_MODULATE, 1);
1738 GL_LockArrays(0, mesh->num_vertices);
1739 R_Mesh_Draw(0, mesh->num_vertices, 0, mesh->num_triangles, mesh->data_element3i, mesh->data_element3s, 0, 0);
1740 GL_LockArrays(0, 0);
1743 void DrawQ_LineLoop (drawqueuemesh_t *mesh, int flags)
1747 _DrawQ_ProcessDrawFlag(flags);
1751 qglBegin(GL_LINE_LOOP);
1752 for (num = 0;num < mesh->num_vertices;num++)
1754 if (mesh->data_color4f)
1755 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]);
1756 qglVertex2f(mesh->data_vertex3f[num*3+0], mesh->data_vertex3f[num*3+1]);
1762 //[515]: this is old, delete
1763 void DrawQ_Line (float width, float x1, float y1, float x2, float y2, float r, float g, float b, float alpha, int flags)
1765 _DrawQ_ProcessDrawFlag(flags);
1767 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
1770 //qglLineWidth(width);CHECKGLERROR
1772 GL_Color(r,g,b,alpha);
1775 qglVertex2f(x1, y1);
1776 qglVertex2f(x2, y2);
1781 void DrawQ_SetClipArea(float x, float y, float width, float height)
1786 // We have to convert the con coords into real coords
1787 // OGL uses top to bottom
1788 ix = (int)(0.5 + x * ((float)vid.width / vid_conwidth.integer));
1789 iy = (int)(0.5 + y * ((float) vid.height / vid_conheight.integer));
1790 iw = (int)(width * ((float)vid.width / vid_conwidth.integer));
1791 ih = (int)(height * ((float)vid.height / vid_conheight.integer));
1792 GL_Scissor(ix, vid.height - iy - ih, iw, ih);
1794 GL_ScissorTest(true);
1797 void DrawQ_ResetClipArea(void)
1800 GL_ScissorTest(false);
1803 void DrawQ_Finish(void)
1805 r_refdef.draw2dstage = false;
1808 static float blendvertex3f[9] = {-5000, -5000, 10, 10000, -5000, 10, -5000, 10000, 10};
1809 void R_DrawGamma(void)
1812 switch(vid.renderpath)
1814 case RENDERPATH_GL20:
1815 case RENDERPATH_CGGL:
1816 if (vid_usinghwgamma || v_glslgamma.integer)
1819 case RENDERPATH_GL13:
1820 case RENDERPATH_GL11:
1821 if (vid_usinghwgamma)
1825 // all the blends ignore depth
1826 R_Mesh_VertexPointer(blendvertex3f, 0, 0);
1827 R_Mesh_ColorPointer(NULL, 0, 0);
1828 R_Mesh_ResetTextureState();
1829 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
1831 GL_DepthRange(0, 1);
1832 GL_PolygonOffset(0, 0);
1833 GL_DepthTest(false);
1834 if (v_color_enable.integer)
1836 c[0] = v_color_white_r.value;
1837 c[1] = v_color_white_g.value;
1838 c[2] = v_color_white_b.value;
1841 c[0] = c[1] = c[2] = v_contrast.value;
1842 if (c[0] >= 1.01f || c[1] >= 1.01f || c[2] >= 1.01f)
1844 GL_BlendFunc(GL_DST_COLOR, GL_ONE);
1845 while (c[0] >= 1.01f || c[1] >= 1.01f || c[2] >= 1.01f)
1847 GL_Color(bound(0, c[0] - 1, 1), bound(0, c[1] - 1, 1), bound(0, c[2] - 1, 1), 1);
1848 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, polygonelement3s, 0, 0);
1849 VectorScale(c, 0.5, c);
1852 if (v_color_enable.integer)
1854 c[0] = v_color_black_r.value;
1855 c[1] = v_color_black_g.value;
1856 c[2] = v_color_black_b.value;
1859 c[0] = c[1] = c[2] = v_brightness.value;
1860 if (c[0] >= 0.01f || c[1] >= 0.01f || c[2] >= 0.01f)
1862 GL_BlendFunc(GL_ONE, GL_ONE);
1863 GL_Color(c[0], c[1], c[2], 1);
1864 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, polygonelement3s, 0, 0);