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)"};
33 //=============================================================================
34 /* Support Routines */
36 #define FONT_FILESIZE 13468
37 #define MAX_CACHED_PICS 1024
38 #define CACHEPICHASHSIZE 256
39 static cachepic_t *cachepichash[CACHEPICHASHSIZE];
40 static cachepic_t cachepics[MAX_CACHED_PICS];
41 static int numcachepics;
43 static rtexturepool_t *drawtexturepool;
45 static unsigned char concharimage[FONT_FILESIZE] =
50 static rtexture_t *draw_generateconchars(void)
53 unsigned char buffer[65536][4], *data = NULL;
56 data = LoadTGA_BGRA (concharimage, FONT_FILESIZE);
58 for (i = 0;i < 8192;i++)
60 random = lhrandom (0.0,1.0);
61 buffer[i][2] = 83 + (unsigned char)(random * 64);
62 buffer[i][1] = 71 + (unsigned char)(random * 32);
63 buffer[i][0] = 23 + (unsigned char)(random * 16);
64 buffer[i][3] = data[i*4+0];
67 for (i = 8192;i < 32768;i++)
69 random = lhrandom (0.0,1.0);
70 buffer[i][2] = 95 + (unsigned char)(random * 64);
71 buffer[i][1] = 95 + (unsigned char)(random * 64);
72 buffer[i][0] = 95 + (unsigned char)(random * 64);
73 buffer[i][3] = data[i*4+0];
76 for (i = 32768;i < 40960;i++)
78 random = lhrandom (0.0,1.0);
79 buffer[i][2] = 83 + (unsigned char)(random * 64);
80 buffer[i][1] = 71 + (unsigned char)(random * 32);
81 buffer[i][0] = 23 + (unsigned char)(random * 16);
82 buffer[i][3] = data[i*4+0];
85 for (i = 40960;i < 65536;i++)
87 random = lhrandom (0.0,1.0);
88 buffer[i][2] = 96 + (unsigned char)(random * 64);
89 buffer[i][1] = 43 + (unsigned char)(random * 32);
90 buffer[i][0] = 27 + (unsigned char)(random * 32);
91 buffer[i][3] = data[i*4+0];
95 Image_WriteTGABGRA ("gfx/generated_conchars.tga", 256, 256, &buffer[0][0]);
99 return R_LoadTexture2D(drawtexturepool, "conchars", 256, 256, &buffer[0][0], TEXTYPE_BGRA, TEXF_ALPHA | TEXF_PRECACHE, NULL);
102 static rtexture_t *draw_generateditherpattern(void)
105 unsigned char pixels[8][8];
106 for (y = 0;y < 8;y++)
107 for (x = 0;x < 8;x++)
108 pixels[y][x] = ((x^y) & 4) ? 254 : 0;
109 return R_LoadTexture2D(drawtexturepool, "ditherpattern", 8, 8, pixels[0], TEXTYPE_PALETTE, TEXF_FORCENEAREST | TEXF_PRECACHE, NULL);
112 typedef struct embeddedpic_s
121 static embeddedpic_t embeddedpics[] =
124 "gfx/prydoncursor001", 16, 16,
143 "ui/mousepointer", 16, 16,
162 "gfx/crosshair1", 16, 16,
181 "gfx/crosshair2", 16, 16,
200 "gfx/crosshair3", 16, 16,
219 "gfx/crosshair4", 16, 16,
238 "gfx/crosshair5", 8, 8,
249 "gfx/crosshair6", 2, 2,
254 "gfx/crosshair7", 16, 16,
273 "gfx/editlights/cursor", 16, 16,
292 "gfx/editlights/light", 16, 16,
311 "gfx/editlights/noshadow", 16, 16,
330 "gfx/editlights/selection", 16, 16,
349 "gfx/editlights/cubemaplight", 16, 16,
368 "gfx/editlights/cubemapnoshadowlight", 16, 16,
389 static rtexture_t *draw_generatepic(const char *name)
392 for (p = embeddedpics;p->name;p++)
393 if (!strcmp(name, p->name))
394 return R_LoadTexture2D(drawtexturepool, p->name, p->width, p->height, (const unsigned char *)p->pixels, TEXTYPE_PALETTE, TEXF_ALPHA | TEXF_PRECACHE, palette_bgra_embeddedpic);
395 if (!strcmp(name, "gfx/conchars"))
396 return draw_generateconchars();
397 if (!strcmp(name, "gfx/colorcontrol/ditherpattern"))
398 return draw_generateditherpattern();
399 Con_Printf("Draw_CachePic: failed to load %s\n", name);
400 return r_texture_notexture;
409 // FIXME: move this to client somehow
410 static cachepic_t *Draw_CachePic_Compression (const char *path, qboolean persistent, qboolean allow_compression)
416 unsigned char *lmpdata;
417 char lmpname[MAX_QPATH];
419 // check whether the picture has already been cached
420 crc = CRC_Block((unsigned char *)path, strlen(path));
421 hashkey = ((crc >> 8) ^ crc) % CACHEPICHASHSIZE;
422 for (pic = cachepichash[hashkey];pic;pic = pic->chain)
423 if (!strcmp (path, pic->name))
426 if (numcachepics == MAX_CACHED_PICS)
428 Con_Printf ("Draw_CachePic: numcachepics == MAX_CACHED_PICS\n");
429 // FIXME: support NULL in callers?
430 return cachepics; // return the first one
432 pic = cachepics + (numcachepics++);
433 strlcpy (pic->name, path, sizeof(pic->name));
435 pic->chain = cachepichash[hashkey];
436 cachepichash[hashkey] = pic;
438 // check whether it is an dynamic texture (if so, we can directly use its texture handler)
439 pic->tex = CL_GetDynTexture( path );
440 // if so, set the width/height, too
442 pic->width = R_TextureWidth(pic->tex);
443 pic->height = R_TextureHeight(pic->tex);
444 // we're done now (early-out)
450 flags |= TEXF_PRECACHE;
451 if (strcmp(path, "gfx/colorcontrol/ditherpattern"))
453 if(allow_compression && gl_texturecompression_2d.integer)
454 flags |= TEXF_COMPRESS;
456 // load a high quality image from disk if possible
457 pic->tex = loadtextureimage(drawtexturepool, path, false, flags, true);
458 if (pic->tex == NULL && !strncmp(path, "gfx/", 4))
460 // compatibility with older versions which did not require gfx/ prefix
461 pic->tex = loadtextureimage(drawtexturepool, path + 4, false, flags, true);
463 // if a high quality image was loaded, set the pic's size to match it, just
464 // in case there's no low quality version to get the size from
467 pic->width = R_TextureWidth(pic->tex);
468 pic->height = R_TextureHeight(pic->tex);
471 // now read the low quality version (wad or lmp file), and take the pic
472 // size from that even if we don't upload the texture, this way the pics
473 // show up the right size in the menu even if they were replaced with
474 // higher or lower resolution versions
475 dpsnprintf(lmpname, sizeof(lmpname), "%s.lmp", path);
476 if (!strncmp(path, "gfx/", 4) && (lmpdata = FS_LoadFile(lmpname, tempmempool, false, &lmpsize)))
480 pic->width = lmpdata[0] + lmpdata[1] * 256 + lmpdata[2] * 65536 + lmpdata[3] * 16777216;
481 pic->height = lmpdata[4] + lmpdata[5] * 256 + lmpdata[6] * 65536 + lmpdata[7] * 16777216;
482 // if no high quality replacement image was found, upload the original low quality texture
484 pic->tex = R_LoadTexture2D(drawtexturepool, path, pic->width, pic->height, lmpdata + 8, TEXTYPE_PALETTE, flags & ~TEXF_COMPRESS, palette_bgra_transparent);
488 else if ((lmpdata = W_GetLumpName (path + 4)))
490 if (!strcmp(path, "gfx/conchars"))
492 // conchars is a raw image and with color 0 as transparent instead of 255
495 // if no high quality replacement image was found, upload the original low quality texture
497 pic->tex = R_LoadTexture2D(drawtexturepool, path, 128, 128, lmpdata, TEXTYPE_PALETTE, flags & ~TEXF_COMPRESS, palette_bgra_font);
501 pic->width = lmpdata[0] + lmpdata[1] * 256 + lmpdata[2] * 65536 + lmpdata[3] * 16777216;
502 pic->height = lmpdata[4] + lmpdata[5] * 256 + lmpdata[6] * 65536 + lmpdata[7] * 16777216;
503 // if no high quality replacement image was found, upload the original low quality texture
505 pic->tex = R_LoadTexture2D(drawtexturepool, path, pic->width, pic->height, lmpdata + 8, TEXTYPE_PALETTE, flags & ~TEXF_COMPRESS, palette_bgra_transparent);
509 // if it's not found on disk, generate an image
510 if (pic->tex == NULL)
512 pic->tex = draw_generatepic(path);
513 pic->width = R_TextureWidth(pic->tex);
514 pic->height = R_TextureHeight(pic->tex);
519 cachepic_t *Draw_CachePic (const char *path, qboolean persistent)
521 return Draw_CachePic_Compression(path, persistent, true);
524 cachepic_t *Draw_NewPic(const char *picname, int width, int height, int alpha, unsigned char *pixels_bgra)
529 crc = CRC_Block((unsigned char *)picname, strlen(picname));
530 hashkey = ((crc >> 8) ^ crc) % CACHEPICHASHSIZE;
531 for (pic = cachepichash[hashkey];pic;pic = pic->chain)
532 if (!strcmp (picname, pic->name))
537 if (pic->tex && pic->width == width && pic->height == height)
539 R_UpdateTexture(pic->tex, pixels_bgra, 0, 0, width, height);
547 if (numcachepics == MAX_CACHED_PICS)
549 Con_Printf ("Draw_NewPic: numcachepics == MAX_CACHED_PICS\n");
550 // FIXME: support NULL in callers?
551 return cachepics; // return the first one
553 pic = cachepics + (numcachepics++);
554 strlcpy (pic->name, picname, sizeof(pic->name));
556 pic->chain = cachepichash[hashkey];
557 cachepichash[hashkey] = pic;
562 pic->height = height;
564 R_FreeTexture(pic->tex);
565 pic->tex = R_LoadTexture2D(drawtexturepool, picname, width, height, pixels_bgra, TEXTYPE_BGRA, alpha ? TEXF_ALPHA : 0, NULL);
569 void Draw_FreePic(const char *picname)
574 // this doesn't really free the pic, but does free it's texture
575 crc = CRC_Block((unsigned char *)picname, strlen(picname));
576 hashkey = ((crc >> 8) ^ crc) % CACHEPICHASHSIZE;
577 for (pic = cachepichash[hashkey];pic;pic = pic->chain)
579 if (!strcmp (picname, pic->name) && pic->tex)
581 R_FreeTexture(pic->tex);
589 extern int con_linewidth; // to force rewrapping
590 static void LoadFont(qboolean override, const char *name, dp_font_t *fnt)
594 char widthfile[MAX_QPATH];
596 fs_offset_t widthbufsize;
598 if(override || !fnt->texpath[0])
599 strlcpy(fnt->texpath, name, sizeof(fnt->texpath));
601 if(drawtexturepool == NULL)
602 return; // before gl_draw_start, so will be loaded later
604 fnt->tex = Draw_CachePic_Compression(fnt->texpath, true, false)->tex;
605 if(fnt->tex == r_texture_notexture)
607 fnt->tex = Draw_CachePic_Compression("gfx/conchars", true, false)->tex;
608 strlcpy(widthfile, "gfx/conchars.width", sizeof(widthfile));
611 dpsnprintf(widthfile, sizeof(widthfile), "%s.width", fnt->texpath);
613 // unspecified width == 1 (base width)
614 for(i = 1; i < 256; ++i)
615 fnt->width_of[i] = 1;
617 // FIXME load "name.width", if it fails, fill all with 1
618 if((widthbuf = (char *) FS_LoadFile(widthfile, tempmempool, true, &widthbufsize)))
620 float extraspacing = 0;
621 const char *p = widthbuf;
626 if(!COM_ParseToken_Simple(&p, false, false))
629 if(!strcmp(com_token, "extraspacing"))
631 if(!COM_ParseToken_Simple(&p, false, false))
633 extraspacing = atof(com_token);
636 fnt->width_of[ch++] = atof(com_token) + extraspacing;
642 maxwidth = fnt->width_of[1];
643 for(i = 2; i < 256; ++i)
644 maxwidth = max(maxwidth, fnt->width_of[i]);
645 fnt->width_of[0] = maxwidth;
647 if(fnt == FONT_CONSOLE)
648 con_linewidth = -1; // rewrap console in next frame
651 static dp_font_t *FindFont(const char *title)
654 for(i = 0; i < MAX_FONTS; ++i)
655 if(!strcmp(dp_fonts[i].title, title))
660 static void LoadFont_f(void)
666 Con_Printf("Available font commands:\n");
667 for(i = 0; i < MAX_FONTS; ++i)
668 Con_Printf(" loadfont %s gfx/tgafile\n", dp_fonts[i].title);
671 f = FindFont(Cmd_Argv(1));
674 Con_Printf("font function not found\n");
677 LoadFont(true, (Cmd_Argc() < 3) ? "gfx/conchars" : Cmd_Argv(2), f);
685 static void gl_draw_start(void)
688 drawtexturepool = R_AllocTexturePool();
691 memset(cachepichash, 0, sizeof(cachepichash));
693 for(i = 0; i < MAX_FONTS; ++i)
694 LoadFont(false, va("gfx/font_%s", dp_fonts[i].title), &dp_fonts[i]);
696 // draw the loading screen so people have something to see in the newly opened window
697 SCR_UpdateLoadingScreen(true);
700 static void gl_draw_shutdown(void)
702 R_FreeTexturePool(&drawtexturepool);
705 memset(cachepichash, 0, sizeof(cachepichash));
708 static void gl_draw_newmap(void)
712 void GL_Draw_Init (void)
715 Cvar_RegisterVariable(&r_textshadow);
716 Cvar_RegisterVariable(&r_textbrightness);
717 Cmd_AddCommand ("loadfont",LoadFont_f, "loadfont function tganame loads a font; example: loadfont console gfx/veramono; loadfont without arguments lists the available functions");
718 R_RegisterModule("GL_Draw", gl_draw_start, gl_draw_shutdown, gl_draw_newmap);
720 strlcpy(FONT_DEFAULT->title, "default", sizeof(FONT_DEFAULT->title));
721 strlcpy(FONT_DEFAULT->texpath, "gfx/conchars", sizeof(FONT_DEFAULT->texpath));
722 strlcpy(FONT_CONSOLE->title, "console", sizeof(FONT_CONSOLE->title));
723 strlcpy(FONT_SBAR->title, "sbar", sizeof(FONT_SBAR->title));
724 strlcpy(FONT_NOTIFY->title, "notify", sizeof(FONT_NOTIFY->title));
725 strlcpy(FONT_CHAT->title, "chat", sizeof(FONT_CHAT->title));
726 strlcpy(FONT_CENTERPRINT->title, "centerprint", sizeof(FONT_CENTERPRINT->title));
727 strlcpy(FONT_INFOBAR->title, "infobar", sizeof(FONT_INFOBAR->title));
728 strlcpy(FONT_MENU->title, "menu", sizeof(FONT_MENU->title));
729 for(i = 0, j = 0; i < MAX_FONTS; ++i)
730 if(!FONT_USER[i].title[0])
731 dpsnprintf(FONT_USER[i].title, sizeof(FONT_USER[i].title), "user%d", j++);
734 static void _DrawQ_Setup(void)
736 if (r_refdef.draw2dstage)
738 r_refdef.draw2dstage = true;
740 qglViewport(r_view.x, vid.height - (r_view.y + r_view.height), r_view.width, r_view.height);CHECKGLERROR
741 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
742 GL_SetupView_Mode_Ortho(0, 0, vid_conwidth.integer, vid_conheight.integer, -10, 100);
743 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
744 qglDisable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
745 GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
746 R_Mesh_Matrix(&identitymatrix);
750 GL_PolygonOffset(0, 0);
754 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
756 if (gl_support_fragment_shader)
758 qglUseProgramObjectARB(0);CHECKGLERROR
762 static void _DrawQ_ProcessDrawFlag(int flags)
766 if(flags == DRAWFLAG_ADDITIVE)
767 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
768 else if(flags == DRAWFLAG_MODULATE)
769 GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
770 else if(flags == DRAWFLAG_2XMODULATE)
771 GL_BlendFunc(GL_DST_COLOR,GL_SRC_COLOR);
773 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
776 void DrawQ_Pic(float x, float y, cachepic_t *pic, float width, float height, float red, float green, float blue, float alpha, int flags)
780 _DrawQ_ProcessDrawFlag(flags);
781 GL_Color(red, green, blue, alpha);
783 R_Mesh_VertexPointer(floats, 0, 0);
784 R_Mesh_ColorPointer(NULL, 0, 0);
785 R_Mesh_ResetTextureState();
791 height = pic->height;
792 R_Mesh_TexBind(0, R_GetTexture(pic->tex));
793 R_Mesh_TexCoordPointer(0, 2, floats + 12, 0, 0);
795 // AK07: lets be texel correct on the corners
797 float horz_offset = 0.5f / pic->width;
798 float vert_offset = 0.5f / pic->height;
800 floats[12] = 0.0f + horz_offset;floats[13] = 0.0f + vert_offset;
801 floats[14] = 1.0f - horz_offset;floats[15] = 0.0f + vert_offset;
802 floats[16] = 1.0f - horz_offset;floats[17] = 1.0f - vert_offset;
803 floats[18] = 0.0f + horz_offset;floats[19] = 1.0f - vert_offset;
807 floats[2] = floats[5] = floats[8] = floats[11] = 0;
808 floats[0] = floats[9] = x;
809 floats[1] = floats[4] = y;
810 floats[3] = floats[6] = x + width;
811 floats[7] = floats[10] = y + height;
813 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
816 void DrawQ_Fill(float x, float y, float width, float height, float red, float green, float blue, float alpha, int flags)
820 _DrawQ_ProcessDrawFlag(flags);
821 GL_Color(red, green, blue, alpha);
823 R_Mesh_VertexPointer(floats, 0, 0);
824 R_Mesh_ColorPointer(NULL, 0, 0);
825 R_Mesh_ResetTextureState();
827 floats[2] = floats[5] = floats[8] = floats[11] = 0;
828 floats[0] = floats[9] = x;
829 floats[1] = floats[4] = y;
830 floats[3] = floats[6] = x + width;
831 floats[7] = floats[10] = y + height;
833 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
836 // color tag printing
837 static vec4_t string_colors[] =
840 // LordHavoc: why on earth is cyan before magenta in Quake3?
841 // LordHavoc: note: Doom3 uses white for [0] and [7]
842 {0.0, 0.0, 0.0, 1.0}, // black
843 {1.0, 0.0, 0.0, 1.0}, // red
844 {0.0, 1.0, 0.0, 1.0}, // green
845 {1.0, 1.0, 0.0, 1.0}, // yellow
846 {0.0, 0.0, 1.0, 1.0}, // blue
847 {0.0, 1.0, 1.0, 1.0}, // cyan
848 {1.0, 0.0, 1.0, 1.0}, // magenta
849 {1.0, 1.0, 1.0, 1.0}, // white
850 // [515]'s BX_COLOREDTEXT extension
851 {1.0, 1.0, 1.0, 0.5}, // half transparent
852 {0.5, 0.5, 0.5, 1.0} // half brightness
853 // Black's color table
854 //{1.0, 1.0, 1.0, 1.0},
855 //{1.0, 0.0, 0.0, 1.0},
856 //{0.0, 1.0, 0.0, 1.0},
857 //{0.0, 0.0, 1.0, 1.0},
858 //{1.0, 1.0, 0.0, 1.0},
859 //{0.0, 1.0, 1.0, 1.0},
860 //{1.0, 0.0, 1.0, 1.0},
861 //{0.1, 0.1, 0.1, 1.0}
864 #define STRING_COLORS_COUNT (sizeof(string_colors) / sizeof(vec4_t))
866 static void DrawQ_GetTextColor(float color[4], int colorindex, float r, float g, float b, float a, qboolean shadow)
868 float v = r_textbrightness.value;
869 Vector4Copy(string_colors[colorindex], color);
870 Vector4Set(color, (color[0] * (1-v) + v) * r, (color[1] * (1-v) + v) * g, (color[2] * (1-v) + v) * b, color[3] * a);
873 float shadowalpha = color[0]+color[1]+color[2] * 0.8;
874 Vector4Set(color, 0, 0, 0, color[3] * bound(0, shadowalpha, 1));
878 static float DrawQ_String_Font_UntilX(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, float maxx)
880 int num, shadow, colorindex = STRING_COLOR_DEFAULT;
882 float x = startx, y, s, t, u, v;
886 float vertex3f[QUADELEMENTS_MAXQUADS*4*3];
887 float texcoord2f[QUADELEMENTS_MAXQUADS*4*2];
888 float color4f[QUADELEMENTS_MAXQUADS*4*4];
894 // when basealpha == 0, skip as much as possible (just return width)
897 _DrawQ_ProcessDrawFlag(flags);
899 R_Mesh_ColorPointer(color4f, 0, 0);
900 R_Mesh_ResetTextureState();
901 R_Mesh_TexBind(0, R_GetTexture(fnt->tex));
902 R_Mesh_TexCoordPointer(0, 2, texcoord2f, 0, 0);
903 R_Mesh_VertexPointer(vertex3f, 0, 0);
910 checkwidth = (maxx >= startx);
912 for (shadow = r_textshadow.value != 0 && basealpha > 0;shadow >= 0;shadow--)
914 if (!outcolor || *outcolor == -1)
915 colorindex = STRING_COLOR_DEFAULT;
917 colorindex = *outcolor;
919 DrawQ_GetTextColor(color, colorindex, basered, basegreen, baseblue, basealpha, shadow);
925 x += r_textshadow.value;
926 y += r_textshadow.value;
928 for (i = 0;i < *maxlen && text[i];i++)
933 if(x + fnt->width_of[' '] * w > maxx)
934 break; // oops, can't draw this
935 x += fnt->width_of[' '] * w;
938 if (text[i] == STRING_COLOR_TAG && !ignorecolorcodes && i + 1 < *maxlen)
940 if (text[i+1] == STRING_COLOR_TAG)
944 else if (text[i+1] >= '0' && text[i+1] <= '9')
946 colorindex = text[i+1] - '0';
947 DrawQ_GetTextColor(color, colorindex, basered, basegreen, baseblue, basealpha, shadow);
952 num = (unsigned char) text[i];
954 if(x + fnt->width_of[num] * w > maxx)
955 break; // oops, can't draw this
958 // FIXME make these smaller to just include the occupied part of the character for slightly faster rendering
959 s = (num & 15)*0.0625f + (0.5f / 256.0f);
960 t = (num >> 4)*0.0625f + (0.5f / 256.0f);
961 u = 0.0625f - (1.0f / 256.0f);
962 v = 0.0625f - (1.0f / 256.0f);
963 ac[ 0] = color[0];ac[ 1] = color[1];ac[ 2] = color[2];ac[ 3] = color[3];
964 ac[ 4] = color[0];ac[ 5] = color[1];ac[ 6] = color[2];ac[ 7] = color[3];
965 ac[ 8] = color[0];ac[ 9] = color[1];ac[10] = color[2];ac[11] = color[3];
966 ac[12] = color[0];ac[13] = color[1];ac[14] = color[2];ac[15] = color[3];
967 at[ 0] = s ;at[ 1] = t ;
968 at[ 2] = s+u;at[ 3] = t ;
969 at[ 4] = s+u;at[ 5] = t+v;
970 at[ 6] = s ;at[ 7] = t+v;
971 av[ 0] = x ;av[ 1] = y ;av[ 2] = 10;
972 av[ 3] = x+w;av[ 4] = y ;av[ 5] = 10;
973 av[ 6] = x+w;av[ 7] = y+h;av[ 8] = 10;
974 av[ 9] = x ;av[10] = y+h;av[11] = 10;
979 if (batchcount >= QUADELEMENTS_MAXQUADS)
981 if (basealpha >= (1.0f / 255.0f))
983 GL_LockArrays(0, batchcount * 4);
984 R_Mesh_Draw(0, batchcount * 4, batchcount * 2, quadelements, 0, 0);
993 x += fnt->width_of[num] * w;
997 checkwidth = 0; // we've done all we had to
1003 GL_LockArrays(0, batchcount * 4);
1004 R_Mesh_Draw(0, batchcount * 4, batchcount * 2, quadelements, 0, 0);
1005 GL_LockArrays(0, 0);
1010 *outcolor = colorindex;
1012 // note: this relies on the proper text (not shadow) being drawn last
1016 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)
1018 return DrawQ_String_Font_UntilX(startx, starty, text, &maxlen, w, h, basered, basegreen, baseblue, basealpha, flags, outcolor, ignorecolorcodes, fnt, startx-1);
1021 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)
1023 return DrawQ_String_Font(startx, starty, text, maxlen, w, h, basered, basegreen, baseblue, basealpha, flags, outcolor, ignorecolorcodes, &dp_fonts[0]);
1026 float DrawQ_TextWidth_Font_UntilWidth(const char *text, size_t *maxlen, float scalex, float scaley, qboolean ignorecolorcodes, const dp_font_t *fnt, float maxWidth)
1028 return DrawQ_String_Font_UntilX(0, 0, text, maxlen, scalex, scaley, 1, 1, 1, 0, 0, NULL, ignorecolorcodes, fnt, maxWidth);
1031 float DrawQ_TextWidth_Font(const char *text, size_t maxlen, float scalex, float scaley, qboolean ignorecolorcodes, const dp_font_t *fnt)
1033 return DrawQ_TextWidth_Font_UntilWidth(text, &maxlen, scalex, scaley, ignorecolorcodes, fnt, -1);
1038 static int DrawQ_BuildColoredText(char *output2c, size_t maxoutchars, const char *text, int maxreadchars, qboolean ignorecolorcodes, int *outcolor)
1040 int color, numchars = 0;
1041 char *outputend2c = output2c + maxoutchars - 2;
1042 if (!outcolor || *outcolor == -1)
1043 color = STRING_COLOR_DEFAULT;
1047 maxreadchars = 1<<30;
1048 textend = text + maxreadchars;
1049 while (text != textend && *text)
1051 if (*text == STRING_COLOR_TAG && !ignorecolorcodes && text + 1 != textend)
1053 if (text[1] == STRING_COLOR_TAG)
1055 else if (text[1] >= '0' && text[1] <= '9')
1057 color = text[1] - '0';
1062 if (output2c >= outputend2c)
1064 *output2c++ = *text++;
1065 *output2c++ = color;
1068 output2c[0] = output2c[1] = 0;
1075 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)
1079 _DrawQ_ProcessDrawFlag(flags);
1081 R_Mesh_VertexPointer(floats, 0, 0);
1082 R_Mesh_ColorPointer(floats + 20, 0, 0);
1083 R_Mesh_ResetTextureState();
1089 height = pic->height;
1090 R_Mesh_TexBind(0, R_GetTexture(pic->tex));
1091 R_Mesh_TexCoordPointer(0, 2, floats + 12, 0, 0);
1092 floats[12] = s1;floats[13] = t1;
1093 floats[14] = s2;floats[15] = t2;
1094 floats[16] = s4;floats[17] = t4;
1095 floats[18] = s3;floats[19] = t3;
1098 floats[2] = floats[5] = floats[8] = floats[11] = 0;
1099 floats[0] = floats[9] = x;
1100 floats[1] = floats[4] = y;
1101 floats[3] = floats[6] = x + width;
1102 floats[7] = floats[10] = y + height;
1103 floats[20] = r1;floats[21] = g1;floats[22] = b1;floats[23] = a1;
1104 floats[24] = r2;floats[25] = g2;floats[26] = b2;floats[27] = a2;
1105 floats[28] = r4;floats[29] = g4;floats[30] = b4;floats[31] = a4;
1106 floats[32] = r3;floats[33] = g3;floats[34] = b3;floats[35] = a3;
1108 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
1111 void DrawQ_Mesh (drawqueuemesh_t *mesh, int flags)
1113 _DrawQ_ProcessDrawFlag(flags);
1115 R_Mesh_VertexPointer(mesh->data_vertex3f, 0, 0);
1116 R_Mesh_ColorPointer(mesh->data_color4f, 0, 0);
1117 R_Mesh_ResetTextureState();
1118 R_Mesh_TexBind(0, R_GetTexture(mesh->texture));
1119 R_Mesh_TexCoordPointer(0, 2, mesh->data_texcoord2f, 0, 0);
1121 GL_LockArrays(0, mesh->num_vertices);
1122 R_Mesh_Draw(0, mesh->num_vertices, mesh->num_triangles, mesh->data_element3i, 0, 0);
1123 GL_LockArrays(0, 0);
1126 void DrawQ_LineLoop (drawqueuemesh_t *mesh, int flags)
1130 _DrawQ_ProcessDrawFlag(flags);
1134 qglBegin(GL_LINE_LOOP);
1135 for (num = 0;num < mesh->num_vertices;num++)
1137 if (mesh->data_color4f)
1138 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]);
1139 qglVertex2f(mesh->data_vertex3f[num*3+0], mesh->data_vertex3f[num*3+1]);
1145 //[515]: this is old, delete
1146 void DrawQ_Line (float width, float x1, float y1, float x2, float y2, float r, float g, float b, float alpha, int flags)
1148 _DrawQ_ProcessDrawFlag(flags);
1151 qglLineWidth(width);CHECKGLERROR
1153 GL_Color(r,g,b,alpha);
1156 qglVertex2f(x1, y1);
1157 qglVertex2f(x2, y2);
1162 void DrawQ_SetClipArea(float x, float y, float width, float height)
1166 // We have to convert the con coords into real coords
1167 // OGL uses top to bottom
1168 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)));
1170 GL_ScissorTest(true);
1173 void DrawQ_ResetClipArea(void)
1176 GL_ScissorTest(false);
1179 void DrawQ_Finish(void)
1181 r_refdef.draw2dstage = false;
1184 static float blendvertex3f[9] = {-5000, -5000, 10, 10000, -5000, 10, -5000, 10000, 10};
1185 void R_DrawGamma(void)
1188 if (!vid_usinghwgamma)
1190 // all the blends ignore depth
1191 R_Mesh_VertexPointer(blendvertex3f, 0, 0);
1192 R_Mesh_ColorPointer(NULL, 0, 0);
1193 R_Mesh_ResetTextureState();
1195 GL_DepthRange(0, 1);
1196 GL_PolygonOffset(0, 0);
1197 GL_DepthTest(false);
1198 if (v_color_enable.integer)
1200 c[0] = v_color_white_r.value;
1201 c[1] = v_color_white_g.value;
1202 c[2] = v_color_white_b.value;
1205 c[0] = c[1] = c[2] = v_contrast.value;
1206 if (c[0] >= 1.01f || c[1] >= 1.01f || c[2] >= 1.01f)
1208 GL_BlendFunc(GL_DST_COLOR, GL_ONE);
1209 while (c[0] >= 1.01f || c[1] >= 1.01f || c[2] >= 1.01f)
1211 GL_Color(bound(0, c[0] - 1, 1), bound(0, c[1] - 1, 1), bound(0, c[2] - 1, 1), 1);
1212 R_Mesh_Draw(0, 3, 1, polygonelements, 0, 0);
1213 VectorScale(c, 0.5, c);
1216 if (v_color_enable.integer)
1218 c[0] = v_color_black_r.value;
1219 c[1] = v_color_black_g.value;
1220 c[2] = v_color_black_b.value;
1223 c[0] = c[1] = c[2] = v_brightness.value;
1224 if (c[0] >= 0.01f || c[1] >= 0.01f || c[2] >= 0.01f)
1226 GL_BlendFunc(GL_ONE, GL_ONE);
1227 GL_Color(c[0], c[1], c[2], 1);
1228 R_Mesh_Draw(0, 3, 1, polygonelements, 0, 0);