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"
28 dp_font_t dp_fonts[MAX_FONTS] = {{0}};
30 cvar_t r_textshadow = {CVAR_SAVE, "r_textshadow", "0", "draws a shadow on all text to improve readability (note: value controls offset, 1 = 1 pixel, 1.5 = 1.5 pixels, etc)"};
31 cvar_t r_textbrightness = {CVAR_SAVE, "r_textbrightness", "0", "additional brightness for text color codes (0 keeps colors as is, 1 makes them all white)"};
32 cvar_t r_textcontrast = {CVAR_SAVE, "r_textcontrast", "1", "additional contrast for text color codes (1 keeps colors as is, 1 makes them all black)"};
34 //=============================================================================
35 /* Support Routines */
37 #define FONT_FILESIZE 13468
38 #define MAX_CACHED_PICS 1024
39 #define CACHEPICHASHSIZE 256
40 static cachepic_t *cachepichash[CACHEPICHASHSIZE];
41 static cachepic_t cachepics[MAX_CACHED_PICS];
42 static int numcachepics;
44 static rtexturepool_t *drawtexturepool;
46 static const unsigned char concharimage[FONT_FILESIZE] =
51 static rtexture_t *draw_generateconchars(void)
54 unsigned char buffer[65536][4], *data = NULL;
57 data = LoadTGA_BGRA (concharimage, FONT_FILESIZE);
59 for (i = 0;i < 8192;i++)
61 random = lhrandom (0.0,1.0);
62 buffer[i][2] = 83 + (unsigned char)(random * 64);
63 buffer[i][1] = 71 + (unsigned char)(random * 32);
64 buffer[i][0] = 23 + (unsigned char)(random * 16);
65 buffer[i][3] = data[i*4+0];
68 for (i = 8192;i < 32768;i++)
70 random = lhrandom (0.0,1.0);
71 buffer[i][2] = 95 + (unsigned char)(random * 64);
72 buffer[i][1] = 95 + (unsigned char)(random * 64);
73 buffer[i][0] = 95 + (unsigned char)(random * 64);
74 buffer[i][3] = data[i*4+0];
77 for (i = 32768;i < 40960;i++)
79 random = lhrandom (0.0,1.0);
80 buffer[i][2] = 83 + (unsigned char)(random * 64);
81 buffer[i][1] = 71 + (unsigned char)(random * 32);
82 buffer[i][0] = 23 + (unsigned char)(random * 16);
83 buffer[i][3] = data[i*4+0];
86 for (i = 40960;i < 65536;i++)
88 random = lhrandom (0.0,1.0);
89 buffer[i][2] = 96 + (unsigned char)(random * 64);
90 buffer[i][1] = 43 + (unsigned char)(random * 32);
91 buffer[i][0] = 27 + (unsigned char)(random * 32);
92 buffer[i][3] = data[i*4+0];
96 Image_WriteTGABGRA ("gfx/generated_conchars.tga", 256, 256, &buffer[0][0]);
100 return R_LoadTexture2D(drawtexturepool, "conchars", 256, 256, &buffer[0][0], TEXTYPE_BGRA, TEXF_ALPHA | TEXF_PRECACHE, NULL);
103 static rtexture_t *draw_generateditherpattern(void)
106 unsigned char pixels[8][8];
107 for (y = 0;y < 8;y++)
108 for (x = 0;x < 8;x++)
109 pixels[y][x] = ((x^y) & 4) ? 254 : 0;
110 return R_LoadTexture2D(drawtexturepool, "ditherpattern", 8, 8, pixels[0], TEXTYPE_PALETTE, TEXF_FORCENEAREST | TEXF_PRECACHE, palette_bgra_transparent);
113 typedef struct embeddedpic_s
122 static const embeddedpic_t embeddedpics[] =
125 "gfx/prydoncursor001", 16, 16,
144 "ui/mousepointer", 16, 16,
163 "gfx/crosshair1", 16, 16,
182 "gfx/crosshair2", 16, 16,
201 "gfx/crosshair3", 16, 16,
220 "gfx/crosshair4", 16, 16,
239 "gfx/crosshair5", 8, 8,
250 "gfx/crosshair6", 2, 2,
255 "gfx/crosshair7", 16, 16,
274 "gfx/editlights/cursor", 16, 16,
293 "gfx/editlights/light", 16, 16,
312 "gfx/editlights/noshadow", 16, 16,
331 "gfx/editlights/selection", 16, 16,
350 "gfx/editlights/cubemaplight", 16, 16,
369 "gfx/editlights/cubemapnoshadowlight", 16, 16,
390 static rtexture_t *draw_generatepic(const char *name)
392 const embeddedpic_t *p;
393 for (p = embeddedpics;p->name;p++)
394 if (!strcmp(name, p->name))
395 return R_LoadTexture2D(drawtexturepool, p->name, p->width, p->height, (const unsigned char *)p->pixels, TEXTYPE_PALETTE, TEXF_ALPHA | TEXF_PRECACHE, palette_bgra_embeddedpic);
396 if (!strcmp(name, "gfx/conchars"))
397 return draw_generateconchars();
398 if (!strcmp(name, "gfx/colorcontrol/ditherpattern"))
399 return draw_generateditherpattern();
400 Con_Printf("Draw_CachePic: failed to load %s\n", name);
401 return r_texture_notexture;
410 // FIXME: move this to client somehow
411 static cachepic_t *Draw_CachePic_Compression (const char *path, qboolean persistent, qboolean allow_compression)
417 unsigned char *lmpdata;
418 char lmpname[MAX_QPATH];
420 // check whether the picture has already been cached
421 crc = CRC_Block((unsigned char *)path, strlen(path));
422 hashkey = ((crc >> 8) ^ crc) % CACHEPICHASHSIZE;
423 for (pic = cachepichash[hashkey];pic;pic = pic->chain)
424 if (!strcmp (path, pic->name))
427 if (numcachepics == MAX_CACHED_PICS)
429 Con_Printf ("Draw_CachePic: numcachepics == MAX_CACHED_PICS\n");
430 // FIXME: support NULL in callers?
431 return cachepics; // return the first one
433 pic = cachepics + (numcachepics++);
434 strlcpy (pic->name, path, sizeof(pic->name));
436 pic->chain = cachepichash[hashkey];
437 cachepichash[hashkey] = pic;
439 // check whether it is an dynamic texture (if so, we can directly use its texture handler)
440 pic->tex = CL_GetDynTexture( path );
441 // if so, set the width/height, too
443 pic->width = R_TextureWidth(pic->tex);
444 pic->height = R_TextureHeight(pic->tex);
445 // we're done now (early-out)
451 flags |= TEXF_PRECACHE;
452 if (strcmp(path, "gfx/colorcontrol/ditherpattern"))
454 if(allow_compression && gl_texturecompression_2d.integer)
455 flags |= TEXF_COMPRESS;
457 // load a high quality image from disk if possible
458 pic->tex = loadtextureimage(drawtexturepool, path, false, flags, true);
459 if (pic->tex == NULL && !strncmp(path, "gfx/", 4))
461 // compatibility with older versions which did not require gfx/ prefix
462 pic->tex = loadtextureimage(drawtexturepool, path + 4, false, flags, true);
464 // if a high quality image was loaded, set the pic's size to match it, just
465 // in case there's no low quality version to get the size from
468 pic->width = R_TextureWidth(pic->tex);
469 pic->height = R_TextureHeight(pic->tex);
472 // now read the low quality version (wad or lmp file), and take the pic
473 // size from that even if we don't upload the texture, this way the pics
474 // show up the right size in the menu even if they were replaced with
475 // higher or lower resolution versions
476 dpsnprintf(lmpname, sizeof(lmpname), "%s.lmp", path);
477 if (!strncmp(path, "gfx/", 4) && (lmpdata = FS_LoadFile(lmpname, tempmempool, false, &lmpsize)))
481 pic->width = lmpdata[0] + lmpdata[1] * 256 + lmpdata[2] * 65536 + lmpdata[3] * 16777216;
482 pic->height = lmpdata[4] + lmpdata[5] * 256 + lmpdata[6] * 65536 + lmpdata[7] * 16777216;
483 // if no high quality replacement image was found, upload the original low quality texture
485 pic->tex = R_LoadTexture2D(drawtexturepool, path, pic->width, pic->height, lmpdata + 8, TEXTYPE_PALETTE, flags & ~TEXF_COMPRESS, palette_bgra_transparent);
489 else if ((lmpdata = W_GetLumpName (path + 4)))
491 if (!strcmp(path, "gfx/conchars"))
493 // conchars is a raw image and with color 0 as transparent instead of 255
496 // if no high quality replacement image was found, upload the original low quality texture
498 pic->tex = R_LoadTexture2D(drawtexturepool, path, 128, 128, lmpdata, TEXTYPE_PALETTE, flags & ~TEXF_COMPRESS, palette_bgra_font);
502 pic->width = lmpdata[0] + lmpdata[1] * 256 + lmpdata[2] * 65536 + lmpdata[3] * 16777216;
503 pic->height = lmpdata[4] + lmpdata[5] * 256 + lmpdata[6] * 65536 + lmpdata[7] * 16777216;
504 // if no high quality replacement image was found, upload the original low quality texture
506 pic->tex = R_LoadTexture2D(drawtexturepool, path, pic->width, pic->height, lmpdata + 8, TEXTYPE_PALETTE, flags & ~TEXF_COMPRESS, palette_bgra_transparent);
510 // if it's not found on disk, generate an image
511 if (pic->tex == NULL)
513 pic->tex = draw_generatepic(path);
514 pic->width = R_TextureWidth(pic->tex);
515 pic->height = R_TextureHeight(pic->tex);
520 cachepic_t *Draw_CachePic (const char *path, qboolean persistent)
522 return Draw_CachePic_Compression(path, persistent, true);
525 cachepic_t *Draw_NewPic(const char *picname, int width, int height, int alpha, unsigned char *pixels_bgra)
530 crc = CRC_Block((unsigned char *)picname, strlen(picname));
531 hashkey = ((crc >> 8) ^ crc) % CACHEPICHASHSIZE;
532 for (pic = cachepichash[hashkey];pic;pic = pic->chain)
533 if (!strcmp (picname, pic->name))
538 if (pic->tex && pic->width == width && pic->height == height)
540 R_UpdateTexture(pic->tex, pixels_bgra, 0, 0, width, height);
548 if (numcachepics == MAX_CACHED_PICS)
550 Con_Printf ("Draw_NewPic: numcachepics == MAX_CACHED_PICS\n");
551 // FIXME: support NULL in callers?
552 return cachepics; // return the first one
554 pic = cachepics + (numcachepics++);
555 strlcpy (pic->name, picname, sizeof(pic->name));
557 pic->chain = cachepichash[hashkey];
558 cachepichash[hashkey] = pic;
563 pic->height = height;
565 R_FreeTexture(pic->tex);
566 pic->tex = R_LoadTexture2D(drawtexturepool, picname, width, height, pixels_bgra, TEXTYPE_BGRA, alpha ? TEXF_ALPHA : 0, NULL);
570 void Draw_FreePic(const char *picname)
575 // this doesn't really free the pic, but does free it's texture
576 crc = CRC_Block((unsigned char *)picname, strlen(picname));
577 hashkey = ((crc >> 8) ^ crc) % CACHEPICHASHSIZE;
578 for (pic = cachepichash[hashkey];pic;pic = pic->chain)
580 if (!strcmp (picname, pic->name) && pic->tex)
582 R_FreeTexture(pic->tex);
590 extern int con_linewidth; // to force rewrapping
591 static void LoadFont(qboolean override, const char *name, dp_font_t *fnt)
595 char widthfile[MAX_QPATH];
597 fs_offset_t widthbufsize;
599 if(override || !fnt->texpath[0])
600 strlcpy(fnt->texpath, name, sizeof(fnt->texpath));
602 if(drawtexturepool == NULL)
603 return; // before gl_draw_start, so will be loaded later
605 fnt->tex = Draw_CachePic_Compression(fnt->texpath, true, false)->tex;
606 if(fnt->tex == r_texture_notexture)
608 fnt->tex = Draw_CachePic_Compression("gfx/conchars", true, false)->tex;
609 strlcpy(widthfile, "gfx/conchars.width", sizeof(widthfile));
612 dpsnprintf(widthfile, sizeof(widthfile), "%s.width", fnt->texpath);
614 // unspecified width == 1 (base width)
615 for(i = 1; i < 256; ++i)
616 fnt->width_of[i] = 1;
618 // FIXME load "name.width", if it fails, fill all with 1
619 if((widthbuf = (char *) FS_LoadFile(widthfile, tempmempool, true, &widthbufsize)))
621 float extraspacing = 0;
622 const char *p = widthbuf;
627 if(!COM_ParseToken_Simple(&p, false, false))
630 if(!strcmp(com_token, "extraspacing"))
632 if(!COM_ParseToken_Simple(&p, false, false))
634 extraspacing = atof(com_token);
637 fnt->width_of[ch++] = atof(com_token) + extraspacing;
643 maxwidth = fnt->width_of[1];
644 for(i = 2; i < 256; ++i)
645 maxwidth = max(maxwidth, fnt->width_of[i]);
646 fnt->width_of[0] = maxwidth;
648 if(fnt == FONT_CONSOLE)
649 con_linewidth = -1; // rewrap console in next frame
652 static dp_font_t *FindFont(const char *title)
655 for(i = 0; i < MAX_FONTS; ++i)
656 if(!strcmp(dp_fonts[i].title, title))
661 static void LoadFont_f(void)
667 Con_Printf("Available font commands:\n");
668 for(i = 0; i < MAX_FONTS; ++i)
669 Con_Printf(" loadfont %s gfx/tgafile\n", dp_fonts[i].title);
672 f = FindFont(Cmd_Argv(1));
675 Con_Printf("font function not found\n");
678 LoadFont(true, (Cmd_Argc() < 3) ? "gfx/conchars" : Cmd_Argv(2), f);
686 static void gl_draw_start(void)
689 drawtexturepool = R_AllocTexturePool();
692 memset(cachepichash, 0, sizeof(cachepichash));
694 for(i = 0; i < MAX_FONTS; ++i)
695 LoadFont(false, va("gfx/font_%s", dp_fonts[i].title), &dp_fonts[i]);
697 // draw the loading screen so people have something to see in the newly opened window
698 SCR_UpdateLoadingScreen(true);
701 static void gl_draw_shutdown(void)
703 R_FreeTexturePool(&drawtexturepool);
706 memset(cachepichash, 0, sizeof(cachepichash));
709 static void gl_draw_newmap(void)
713 void GL_Draw_Init (void)
716 Cvar_RegisterVariable(&r_textshadow);
717 Cvar_RegisterVariable(&r_textbrightness);
718 Cvar_RegisterVariable(&r_textcontrast);
719 Cmd_AddCommand ("loadfont",LoadFont_f, "loadfont function tganame loads a font; example: loadfont console gfx/veramono; loadfont without arguments lists the available functions");
720 R_RegisterModule("GL_Draw", gl_draw_start, gl_draw_shutdown, gl_draw_newmap);
722 strlcpy(FONT_DEFAULT->title, "default", sizeof(FONT_DEFAULT->title));
723 strlcpy(FONT_DEFAULT->texpath, "gfx/conchars", sizeof(FONT_DEFAULT->texpath));
724 strlcpy(FONT_CONSOLE->title, "console", sizeof(FONT_CONSOLE->title));
725 strlcpy(FONT_SBAR->title, "sbar", sizeof(FONT_SBAR->title));
726 strlcpy(FONT_NOTIFY->title, "notify", sizeof(FONT_NOTIFY->title));
727 strlcpy(FONT_CHAT->title, "chat", sizeof(FONT_CHAT->title));
728 strlcpy(FONT_CENTERPRINT->title, "centerprint", sizeof(FONT_CENTERPRINT->title));
729 strlcpy(FONT_INFOBAR->title, "infobar", sizeof(FONT_INFOBAR->title));
730 strlcpy(FONT_MENU->title, "menu", sizeof(FONT_MENU->title));
731 for(i = 0, j = 0; i < MAX_USERFONTS; ++i)
732 if(!FONT_USER[i].title[0])
733 dpsnprintf(FONT_USER[i].title, sizeof(FONT_USER[i].title), "user%d", j++);
736 void _DrawQ_Setup(void)
738 if (r_refdef.draw2dstage)
740 r_refdef.draw2dstage = true;
742 qglViewport(r_refdef.view.x, vid.height - (r_refdef.view.y + r_refdef.view.height), r_refdef.view.width, r_refdef.view.height);CHECKGLERROR
743 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
744 GL_SetupView_Mode_Ortho(0, 0, vid_conwidth.integer, vid_conheight.integer, -10, 100);
745 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
746 qglDisable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
747 GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
748 R_Mesh_Matrix(&identitymatrix);
752 GL_PolygonOffset(0, 0);
756 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
758 if (gl_support_fragment_shader)
760 qglUseProgramObjectARB(0);CHECKGLERROR
764 static void _DrawQ_ProcessDrawFlag(int flags)
768 if(flags == DRAWFLAG_ADDITIVE)
769 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
770 else if(flags == DRAWFLAG_MODULATE)
771 GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
772 else if(flags == DRAWFLAG_2XMODULATE)
773 GL_BlendFunc(GL_DST_COLOR,GL_SRC_COLOR);
775 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
778 void DrawQ_Pic(float x, float y, cachepic_t *pic, float width, float height, float red, float green, float blue, float alpha, int flags)
782 _DrawQ_ProcessDrawFlag(flags);
783 GL_Color(red, green, blue, alpha);
785 R_Mesh_VertexPointer(floats, 0, 0);
786 R_Mesh_ColorPointer(NULL, 0, 0);
787 R_Mesh_ResetTextureState();
793 height = pic->height;
794 R_Mesh_TexBind(0, R_GetTexture(pic->tex));
795 R_Mesh_TexCoordPointer(0, 2, floats + 12, 0, 0);
798 floats[12] = 0.0f;floats[13] = 0.0f;
799 floats[14] = 1.0f;floats[15] = 0.0f;
800 floats[16] = 1.0f;floats[17] = 1.0f;
801 floats[18] = 0.0f;floats[19] = 1.0f;
803 // AK07: lets be texel correct on the corners
805 float horz_offset = 0.5f / pic->width;
806 float vert_offset = 0.5f / pic->height;
808 floats[12] = 0.0f + horz_offset;floats[13] = 0.0f + vert_offset;
809 floats[14] = 1.0f - horz_offset;floats[15] = 0.0f + vert_offset;
810 floats[16] = 1.0f - horz_offset;floats[17] = 1.0f - vert_offset;
811 floats[18] = 0.0f + horz_offset;floats[19] = 1.0f - vert_offset;
816 floats[2] = floats[5] = floats[8] = floats[11] = 0;
817 floats[0] = floats[9] = x;
818 floats[1] = floats[4] = y;
819 floats[3] = floats[6] = x + width;
820 floats[7] = floats[10] = y + height;
822 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
825 void DrawQ_Fill(float x, float y, float width, float height, float red, float green, float blue, float alpha, int flags)
829 _DrawQ_ProcessDrawFlag(flags);
830 GL_Color(red, green, blue, alpha);
832 R_Mesh_VertexPointer(floats, 0, 0);
833 R_Mesh_ColorPointer(NULL, 0, 0);
834 R_Mesh_ResetTextureState();
836 floats[2] = floats[5] = floats[8] = floats[11] = 0;
837 floats[0] = floats[9] = x;
838 floats[1] = floats[4] = y;
839 floats[3] = floats[6] = x + width;
840 floats[7] = floats[10] = y + height;
842 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
845 // color tag printing
846 static const vec4_t string_colors[] =
849 // LordHavoc: why on earth is cyan before magenta in Quake3?
850 // LordHavoc: note: Doom3 uses white for [0] and [7]
851 {0.0, 0.0, 0.0, 1.0}, // black
852 {1.0, 0.0, 0.0, 1.0}, // red
853 {0.0, 1.0, 0.0, 1.0}, // green
854 {1.0, 1.0, 0.0, 1.0}, // yellow
855 {0.0, 0.0, 1.0, 1.0}, // blue
856 {0.0, 1.0, 1.0, 1.0}, // cyan
857 {1.0, 0.0, 1.0, 1.0}, // magenta
858 {1.0, 1.0, 1.0, 1.0}, // white
859 // [515]'s BX_COLOREDTEXT extension
860 {1.0, 1.0, 1.0, 0.5}, // half transparent
861 {0.5, 0.5, 0.5, 1.0} // half brightness
862 // Black's color table
863 //{1.0, 1.0, 1.0, 1.0},
864 //{1.0, 0.0, 0.0, 1.0},
865 //{0.0, 1.0, 0.0, 1.0},
866 //{0.0, 0.0, 1.0, 1.0},
867 //{1.0, 1.0, 0.0, 1.0},
868 //{0.0, 1.0, 1.0, 1.0},
869 //{1.0, 0.0, 1.0, 1.0},
870 //{0.1, 0.1, 0.1, 1.0}
873 #define STRING_COLORS_COUNT (sizeof(string_colors) / sizeof(vec4_t))
875 static void DrawQ_GetTextColor(float color[4], int colorindex, float r, float g, float b, float a, qboolean shadow)
877 float C = r_textcontrast.value;
878 float B = r_textbrightness.value;
879 Vector4Copy(string_colors[colorindex], color);
880 Vector4Set(color, (color[0] * C + B) * r, (color[1] * C + B) * g, (color[2] * C + B) * b, color[3] * a);
883 float shadowalpha = color[0]+color[1]+color[2] * 0.8;
884 Vector4Set(color, 0, 0, 0, color[3] * bound(0, shadowalpha, 1));
888 float DrawQ_TextWidth_Font_UntilWidth_TrackColors(const char *text, size_t *maxlen, int *outcolor, qboolean ignorecolorcodes, const dp_font_t *fnt, float maxwidth)
890 int num, colorindex = STRING_COLOR_DEFAULT;
897 if (!outcolor || *outcolor == -1)
898 colorindex = STRING_COLOR_DEFAULT;
900 colorindex = *outcolor;
902 for (i = 0;i < *maxlen && text[i];i++)
906 if(x + fnt->width_of[' '] > maxwidth)
907 break; // oops, can't draw this
908 x += fnt->width_of[' '];
911 if (text[i] == STRING_COLOR_TAG && !ignorecolorcodes && i + 1 < *maxlen)
913 if (text[i+1] == STRING_COLOR_TAG)
917 else if (text[i+1] >= '0' && text[i+1] <= '9')
919 colorindex = text[i+1] - '0';
924 num = (unsigned char) text[i];
925 if(x + fnt->width_of[num] > maxwidth)
926 break; // oops, can't draw this
927 x += fnt->width_of[num];
933 *outcolor = colorindex;
938 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)
940 int num, shadow, colorindex = STRING_COLOR_DEFAULT;
942 float x = startx, y, s, t, u, v;
946 float vertex3f[QUADELEMENTS_MAXQUADS*4*3];
947 float texcoord2f[QUADELEMENTS_MAXQUADS*4*2];
948 float color4f[QUADELEMENTS_MAXQUADS*4*4];
953 _DrawQ_ProcessDrawFlag(flags);
955 R_Mesh_ColorPointer(color4f, 0, 0);
956 R_Mesh_ResetTextureState();
957 R_Mesh_TexBind(0, R_GetTexture(fnt->tex));
958 R_Mesh_TexCoordPointer(0, 2, texcoord2f, 0, 0);
959 R_Mesh_VertexPointer(vertex3f, 0, 0);
966 for (shadow = r_textshadow.value != 0 && basealpha > 0;shadow >= 0;shadow--)
968 if (!outcolor || *outcolor == -1)
969 colorindex = STRING_COLOR_DEFAULT;
971 colorindex = *outcolor;
972 DrawQ_GetTextColor(color, colorindex, basered, basegreen, baseblue, basealpha, shadow);
978 x += r_textshadow.value;
979 y += r_textshadow.value;
981 for (i = 0;i < maxlen && text[i];i++)
985 x += fnt->width_of[' '] * w;
988 if (text[i] == STRING_COLOR_TAG && !ignorecolorcodes && i + 1 < maxlen)
990 if (text[i+1] == STRING_COLOR_TAG)
994 else if (text[i+1] >= '0' && text[i+1] <= '9')
996 colorindex = text[i+1] - '0';
997 DrawQ_GetTextColor(color, colorindex, basered, basegreen, baseblue, basealpha, shadow);
1002 num = (unsigned char) text[i];
1003 // FIXME make these smaller to just include the occupied part of the character for slightly faster rendering
1004 s = (num & 15)*0.0625f + (0.5f / 256.0f);
1005 t = (num >> 4)*0.0625f + (0.5f / 256.0f);
1006 u = 0.0625f - (1.0f / 256.0f);
1007 v = 0.0625f - (1.0f / 256.0f);
1008 ac[ 0] = color[0];ac[ 1] = color[1];ac[ 2] = color[2];ac[ 3] = color[3];
1009 ac[ 4] = color[0];ac[ 5] = color[1];ac[ 6] = color[2];ac[ 7] = color[3];
1010 ac[ 8] = color[0];ac[ 9] = color[1];ac[10] = color[2];ac[11] = color[3];
1011 ac[12] = color[0];ac[13] = color[1];ac[14] = color[2];ac[15] = color[3];
1012 at[ 0] = s ;at[ 1] = t ;
1013 at[ 2] = s+u;at[ 3] = t ;
1014 at[ 4] = s+u;at[ 5] = t+v;
1015 at[ 6] = s ;at[ 7] = t+v;
1016 av[ 0] = x ;av[ 1] = y ;av[ 2] = 10;
1017 av[ 3] = x+w;av[ 4] = y ;av[ 5] = 10;
1018 av[ 6] = x+w;av[ 7] = y+h;av[ 8] = 10;
1019 av[ 9] = x ;av[10] = y+h;av[11] = 10;
1024 if (batchcount >= QUADELEMENTS_MAXQUADS)
1026 GL_LockArrays(0, batchcount * 4);
1027 R_Mesh_Draw(0, batchcount * 4, batchcount * 2, quadelements, 0, 0);
1028 GL_LockArrays(0, 0);
1034 x += fnt->width_of[num] * w;
1039 GL_LockArrays(0, batchcount * 4);
1040 R_Mesh_Draw(0, batchcount * 4, batchcount * 2, quadelements, 0, 0);
1041 GL_LockArrays(0, 0);
1045 *outcolor = colorindex;
1047 // note: this relies on the proper text (not shadow) being drawn last
1051 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)
1053 return DrawQ_String_Font(startx, starty, text, maxlen, w, h, basered, basegreen, baseblue, basealpha, flags, outcolor, ignorecolorcodes, &dp_fonts[0]);
1056 float DrawQ_TextWidth_Font_UntilWidth(const char *text, size_t *maxlen, qboolean ignorecolorcodes, const dp_font_t *fnt, float maxWidth)
1058 return DrawQ_TextWidth_Font_UntilWidth_TrackColors(text, maxlen, NULL, ignorecolorcodes, fnt, maxWidth);
1061 float DrawQ_TextWidth_Font(const char *text, size_t maxlen, qboolean ignorecolorcodes, const dp_font_t *fnt)
1063 return DrawQ_TextWidth_Font_UntilWidth(text, &maxlen, ignorecolorcodes, fnt, 1000000000);
1068 static int DrawQ_BuildColoredText(char *output2c, size_t maxoutchars, const char *text, int maxreadchars, qboolean ignorecolorcodes, int *outcolor)
1070 int color, numchars = 0;
1071 char *outputend2c = output2c + maxoutchars - 2;
1072 if (!outcolor || *outcolor == -1)
1073 color = STRING_COLOR_DEFAULT;
1077 maxreadchars = 1<<30;
1078 textend = text + maxreadchars;
1079 while (text != textend && *text)
1081 if (*text == STRING_COLOR_TAG && !ignorecolorcodes && text + 1 != textend)
1083 if (text[1] == STRING_COLOR_TAG)
1085 else if (text[1] >= '0' && text[1] <= '9')
1087 color = text[1] - '0';
1092 if (output2c >= outputend2c)
1094 *output2c++ = *text++;
1095 *output2c++ = color;
1098 output2c[0] = output2c[1] = 0;
1105 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)
1109 _DrawQ_ProcessDrawFlag(flags);
1111 R_Mesh_VertexPointer(floats, 0, 0);
1112 R_Mesh_ColorPointer(floats + 20, 0, 0);
1113 R_Mesh_ResetTextureState();
1119 height = pic->height;
1120 R_Mesh_TexBind(0, R_GetTexture(pic->tex));
1121 R_Mesh_TexCoordPointer(0, 2, floats + 12, 0, 0);
1122 floats[12] = s1;floats[13] = t1;
1123 floats[14] = s2;floats[15] = t2;
1124 floats[16] = s4;floats[17] = t4;
1125 floats[18] = s3;floats[19] = t3;
1128 floats[2] = floats[5] = floats[8] = floats[11] = 0;
1129 floats[0] = floats[9] = x;
1130 floats[1] = floats[4] = y;
1131 floats[3] = floats[6] = x + width;
1132 floats[7] = floats[10] = y + height;
1133 floats[20] = r1;floats[21] = g1;floats[22] = b1;floats[23] = a1;
1134 floats[24] = r2;floats[25] = g2;floats[26] = b2;floats[27] = a2;
1135 floats[28] = r4;floats[29] = g4;floats[30] = b4;floats[31] = a4;
1136 floats[32] = r3;floats[33] = g3;floats[34] = b3;floats[35] = a3;
1138 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
1141 void DrawQ_Mesh (drawqueuemesh_t *mesh, int flags)
1143 _DrawQ_ProcessDrawFlag(flags);
1145 R_Mesh_VertexPointer(mesh->data_vertex3f, 0, 0);
1146 R_Mesh_ColorPointer(mesh->data_color4f, 0, 0);
1147 R_Mesh_ResetTextureState();
1148 R_Mesh_TexBind(0, R_GetTexture(mesh->texture));
1149 R_Mesh_TexCoordPointer(0, 2, mesh->data_texcoord2f, 0, 0);
1151 GL_LockArrays(0, mesh->num_vertices);
1152 R_Mesh_Draw(0, mesh->num_vertices, mesh->num_triangles, mesh->data_element3i, 0, 0);
1153 GL_LockArrays(0, 0);
1156 void DrawQ_LineLoop (drawqueuemesh_t *mesh, int flags)
1160 _DrawQ_ProcessDrawFlag(flags);
1164 qglBegin(GL_LINE_LOOP);
1165 for (num = 0;num < mesh->num_vertices;num++)
1167 if (mesh->data_color4f)
1168 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]);
1169 qglVertex2f(mesh->data_vertex3f[num*3+0], mesh->data_vertex3f[num*3+1]);
1175 //[515]: this is old, delete
1176 void DrawQ_Line (float width, float x1, float y1, float x2, float y2, float r, float g, float b, float alpha, int flags)
1178 _DrawQ_ProcessDrawFlag(flags);
1181 qglLineWidth(width);CHECKGLERROR
1183 GL_Color(r,g,b,alpha);
1186 qglVertex2f(x1, y1);
1187 qglVertex2f(x2, y2);
1192 void DrawQ_SetClipArea(float x, float y, float width, float height)
1196 // We have to convert the con coords into real coords
1197 // OGL uses top to bottom
1198 GL_Scissor((int)(x * ((float)vid.width / vid_conwidth.integer)), (int)(y * ((float) vid.height / vid_conheight.integer)), (int)(width * ((float)vid.width / vid_conwidth.integer)), (int)(height * ((float)vid.height / vid_conheight.integer)));
1200 GL_ScissorTest(true);
1203 void DrawQ_ResetClipArea(void)
1206 GL_ScissorTest(false);
1209 void DrawQ_Finish(void)
1211 r_refdef.draw2dstage = false;
1214 static float blendvertex3f[9] = {-5000, -5000, 10, 10000, -5000, 10, -5000, 10000, 10};
1215 void R_DrawGamma(void)
1218 if (!vid_usinghwgamma)
1220 // all the blends ignore depth
1221 R_Mesh_VertexPointer(blendvertex3f, 0, 0);
1222 R_Mesh_ColorPointer(NULL, 0, 0);
1223 R_Mesh_ResetTextureState();
1225 GL_DepthRange(0, 1);
1226 GL_PolygonOffset(0, 0);
1227 GL_DepthTest(false);
1228 if (v_color_enable.integer)
1230 c[0] = v_color_white_r.value;
1231 c[1] = v_color_white_g.value;
1232 c[2] = v_color_white_b.value;
1235 c[0] = c[1] = c[2] = v_contrast.value;
1236 if (c[0] >= 1.01f || c[1] >= 1.01f || c[2] >= 1.01f)
1238 GL_BlendFunc(GL_DST_COLOR, GL_ONE);
1239 while (c[0] >= 1.01f || c[1] >= 1.01f || c[2] >= 1.01f)
1241 GL_Color(bound(0, c[0] - 1, 1), bound(0, c[1] - 1, 1), bound(0, c[2] - 1, 1), 1);
1242 R_Mesh_Draw(0, 3, 1, polygonelements, 0, 0);
1243 VectorScale(c, 0.5, c);
1246 if (v_color_enable.integer)
1248 c[0] = v_color_black_r.value;
1249 c[1] = v_color_black_g.value;
1250 c[2] = v_color_black_b.value;
1253 c[0] = c[1] = c[2] = v_brightness.value;
1254 if (c[0] >= 0.01f || c[1] >= 0.01f || c[2] >= 0.01f)
1256 GL_BlendFunc(GL_ONE, GL_ONE);
1257 GL_Color(c[0], c[1], c[2], 1);
1258 R_Mesh_Draw(0, 3, 1, polygonelements, 0, 0);