2 Copyright (C) 1996-1997 Id Software, Inc.
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 See the GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26 #include "cl_dyntexture.h"
29 #include "ft2_fontdefs.h"
31 dp_font_t dp_fonts[MAX_FONTS] = {{0}};
33 cvar_t r_textshadow = {CVAR_SAVE, "r_textshadow", "0", "draws a shadow on all text to improve readability (note: value controls offset, 1 = 1 pixel, 1.5 = 1.5 pixels, etc)"};
34 cvar_t r_textbrightness = {CVAR_SAVE, "r_textbrightness", "0", "additional brightness for text color codes (0 keeps colors as is, 1 makes them all white)"};
35 cvar_t r_textcontrast = {CVAR_SAVE, "r_textcontrast", "1", "additional contrast for text color codes (1 keeps colors as is, 0 makes them all black)"};
37 extern cvar_t v_glslgamma;
39 //=============================================================================
40 /* Support Routines */
42 #define FONT_FILESIZE 13468
43 static cachepic_t *cachepichash[CACHEPICHASHSIZE];
44 static cachepic_t cachepics[MAX_CACHED_PICS];
45 static int numcachepics;
47 static rtexturepool_t *drawtexturepool;
49 static const unsigned char concharimage[FONT_FILESIZE] =
54 static rtexture_t *draw_generateconchars(void)
61 data = LoadTGA_BGRA (concharimage, FONT_FILESIZE);
63 for (i = 0;i < 8192;i++)
65 random = lhrandom (0.0,1.0);
66 data[i*4+3] = data[i*4+0];
67 data[i*4+2] = 83 + (unsigned char)(random * 64);
68 data[i*4+1] = 71 + (unsigned char)(random * 32);
69 data[i*4+0] = 23 + (unsigned char)(random * 16);
72 for (i = 8192;i < 32768;i++)
74 random = lhrandom (0.0,1.0);
75 data[i*4+3] = data[i*4+0];
76 data[i*4+2] = 95 + (unsigned char)(random * 64);
77 data[i*4+1] = 95 + (unsigned char)(random * 64);
78 data[i*4+0] = 95 + (unsigned char)(random * 64);
81 for (i = 32768;i < 40960;i++)
83 random = lhrandom (0.0,1.0);
84 data[i*4+3] = data[i*4+0];
85 data[i*4+2] = 83 + (unsigned char)(random * 64);
86 data[i*4+1] = 71 + (unsigned char)(random * 32);
87 data[i*4+0] = 23 + (unsigned char)(random * 16);
90 for (i = 40960;i < 65536;i++)
92 random = lhrandom (0.0,1.0);
93 data[i*4+3] = data[i*4+0];
94 data[i*4+2] = 96 + (unsigned char)(random * 64);
95 data[i*4+1] = 43 + (unsigned char)(random * 32);
96 data[i*4+0] = 27 + (unsigned char)(random * 32);
100 Image_WriteTGABGRA ("gfx/generated_conchars.tga", 256, 256, data);
103 tex = R_LoadTexture2D(drawtexturepool, "conchars", 256, 256, data, TEXTYPE_BGRA, TEXF_ALPHA, NULL);
108 static rtexture_t *draw_generateditherpattern(void)
111 unsigned char pixels[8][8];
112 for (y = 0;y < 8;y++)
113 for (x = 0;x < 8;x++)
114 pixels[y][x] = ((x^y) & 4) ? 254 : 0;
115 return R_LoadTexture2D(drawtexturepool, "ditherpattern", 8, 8, pixels[0], TEXTYPE_PALETTE, TEXF_FORCENEAREST, palette_bgra_transparent);
118 typedef struct embeddedpic_s
127 static const embeddedpic_t embeddedpics[] =
130 "gfx/prydoncursor001", 16, 16,
149 "ui/mousepointer", 16, 16,
168 "gfx/crosshair1", 16, 16,
187 "gfx/crosshair2", 16, 16,
206 "gfx/crosshair3", 16, 16,
225 "gfx/crosshair4", 16, 16,
244 "gfx/crosshair5", 8, 8,
255 "gfx/crosshair6", 2, 2,
260 "gfx/crosshair7", 16, 16,
281 static rtexture_t *draw_generatepic(const char *name, qboolean quiet)
283 const embeddedpic_t *p;
284 for (p = embeddedpics;p->name;p++)
285 if (!strcmp(name, p->name))
286 return R_LoadTexture2D(drawtexturepool, p->name, p->width, p->height, (const unsigned char *)p->pixels, TEXTYPE_PALETTE, TEXF_ALPHA, palette_bgra_embeddedpic);
287 if (!strcmp(name, "gfx/conchars"))
288 return draw_generateconchars();
289 if (!strcmp(name, "gfx/colorcontrol/ditherpattern"))
290 return draw_generateditherpattern();
292 Con_DPrintf("Draw_CachePic: failed to load %s\n", name);
293 return r_texture_notexture;
302 // FIXME: move this to client somehow
303 cachepic_t *Draw_CachePic_Flags(const char *path, unsigned int cachepicflags)
306 unsigned char *pixels;
309 unsigned char *lmpdata;
310 char lmpname[MAX_QPATH];
312 // check whether the picture has already been cached
313 crc = CRC_Block((unsigned char *)path, strlen(path));
314 hashkey = ((crc >> 8) ^ crc) % CACHEPICHASHSIZE;
315 for (pic = cachepichash[hashkey];pic;pic = pic->chain)
316 if (!strcmp (path, pic->name))
319 if (numcachepics == MAX_CACHED_PICS)
321 Con_Printf ("Draw_CachePic: numcachepics == MAX_CACHED_PICS\n");
322 // FIXME: support NULL in callers?
323 return cachepics; // return the first one
325 pic = cachepics + (numcachepics++);
326 strlcpy (pic->name, path, sizeof(pic->name));
328 pic->chain = cachepichash[hashkey];
329 cachepichash[hashkey] = pic;
331 // check whether it is an dynamic texture (if so, we can directly use its texture handler)
332 pic->tex = CL_GetDynTexture( path );
333 // if so, set the width/height, too
335 pic->width = R_TextureWidth(pic->tex);
336 pic->height = R_TextureHeight(pic->tex);
337 // we're done now (early-out)
341 pic->texflags = TEXF_ALPHA;
342 if (!(cachepicflags & CACHEPICFLAG_NOCLAMP))
343 pic->texflags |= TEXF_CLAMP;
344 if (!(cachepicflags & CACHEPICFLAG_NOCOMPRESSION) && gl_texturecompression_2d.integer)
345 pic->texflags |= TEXF_COMPRESS;
347 pic->autoload = (cachepicflags & CACHEPICFLAG_NOTPERSISTENT);
349 // load a high quality image from disk if possible
350 pixels = loadimagepixelsbgra(path, false, true);
351 if (pixels == NULL && !strncmp(path, "gfx/", 4))
352 pixels = loadimagepixelsbgra(path+4, false, true);
355 pic->width = image_width;
356 pic->height = image_height;
358 pic->tex = R_LoadTexture2D(drawtexturepool, path, image_width, image_height, pixels, TEXTYPE_BGRA, pic->texflags, NULL);
362 pic->autoload = false;
363 // never compress the fallback images
364 pic->texflags &= ~TEXF_COMPRESS;
367 // now read the low quality version (wad or lmp file), and take the pic
368 // size from that even if we don't upload the texture, this way the pics
369 // show up the right size in the menu even if they were replaced with
370 // higher or lower resolution versions
371 dpsnprintf(lmpname, sizeof(lmpname), "%s.lmp", path);
372 if (!strncmp(path, "gfx/", 4) && (lmpdata = FS_LoadFile(lmpname, tempmempool, false, &lmpsize)))
374 if (developer_loading.integer)
375 Con_Printf("loading lump \"%s\"\n", path);
379 pic->width = lmpdata[0] + lmpdata[1] * 256 + lmpdata[2] * 65536 + lmpdata[3] * 16777216;
380 pic->height = lmpdata[4] + lmpdata[5] * 256 + lmpdata[6] * 65536 + lmpdata[7] * 16777216;
381 // if no high quality replacement image was found, upload the original low quality texture
383 pic->tex = R_LoadTexture2D(drawtexturepool, path, pic->width, pic->height, lmpdata + 8, TEXTYPE_PALETTE, pic->texflags, palette_bgra_transparent);
387 else if ((lmpdata = W_GetLumpName (path + 4)))
389 if (developer_loading.integer)
390 Con_Printf("loading gfx.wad lump \"%s\"\n", path + 4);
392 if (!strcmp(path, "gfx/conchars"))
394 // conchars is a raw image and with color 0 as transparent instead of 255
397 // if no high quality replacement image was found, upload the original low quality texture
399 pic->tex = R_LoadTexture2D(drawtexturepool, path, 128, 128, lmpdata, TEXTYPE_PALETTE, pic->texflags, palette_bgra_font);
403 pic->width = lmpdata[0] + lmpdata[1] * 256 + lmpdata[2] * 65536 + lmpdata[3] * 16777216;
404 pic->height = lmpdata[4] + lmpdata[5] * 256 + lmpdata[6] * 65536 + lmpdata[7] * 16777216;
405 // if no high quality replacement image was found, upload the original low quality texture
407 pic->tex = R_LoadTexture2D(drawtexturepool, path, pic->width, pic->height, lmpdata + 8, TEXTYPE_PALETTE, pic->texflags, palette_bgra_transparent);
416 else if (pic->tex == NULL)
418 // if it's not found on disk, generate an image
419 pic->tex = draw_generatepic(path, (cachepicflags & CACHEPICFLAG_QUIET) != 0);
420 pic->width = R_TextureWidth(pic->tex);
421 pic->height = R_TextureHeight(pic->tex);
427 cachepic_t *Draw_CachePic (const char *path)
429 return Draw_CachePic_Flags (path, 0);
434 rtexture_t *Draw_GetPicTexture(cachepic_t *pic)
436 if (pic->autoload && !pic->tex)
438 pic->tex = loadtextureimage(drawtexturepool, pic->name, false, pic->texflags, true);
439 if (pic->tex == NULL && !strncmp(pic->name, "gfx/", 4))
440 pic->tex = loadtextureimage(drawtexturepool, pic->name+4, false, pic->texflags, true);
441 if (pic->tex == NULL)
442 pic->tex = draw_generatepic(pic->name, true);
444 pic->lastusedframe = draw_frame;
448 void Draw_Frame(void)
452 static double nextpurgetime;
454 if (nextpurgetime > realtime)
456 nextpurgetime = realtime + 0.05;
457 purgeframe = draw_frame - 1;
458 for (i = 0, pic = cachepics;i < numcachepics;i++, pic++)
460 if (pic->autoload && pic->tex && pic->lastusedframe < draw_frame)
462 R_FreeTexture(pic->tex);
469 cachepic_t *Draw_NewPic(const char *picname, int width, int height, int alpha, unsigned char *pixels_bgra)
474 crc = CRC_Block((unsigned char *)picname, strlen(picname));
475 hashkey = ((crc >> 8) ^ crc) % CACHEPICHASHSIZE;
476 for (pic = cachepichash[hashkey];pic;pic = pic->chain)
477 if (!strcmp (picname, pic->name))
482 if (pic->tex && pic->width == width && pic->height == height)
484 R_UpdateTexture(pic->tex, pixels_bgra, 0, 0, width, height);
492 if (numcachepics == MAX_CACHED_PICS)
494 Con_Printf ("Draw_NewPic: numcachepics == MAX_CACHED_PICS\n");
495 // FIXME: support NULL in callers?
496 return cachepics; // return the first one
498 pic = cachepics + (numcachepics++);
499 strlcpy (pic->name, picname, sizeof(pic->name));
501 pic->chain = cachepichash[hashkey];
502 cachepichash[hashkey] = pic;
507 pic->height = height;
509 R_FreeTexture(pic->tex);
510 pic->tex = R_LoadTexture2D(drawtexturepool, picname, width, height, pixels_bgra, TEXTYPE_BGRA, (alpha ? TEXF_ALPHA : 0) | TEXF_ALLOWUPDATES, NULL);
514 void Draw_FreePic(const char *picname)
519 // this doesn't really free the pic, but does free it's texture
520 crc = CRC_Block((unsigned char *)picname, strlen(picname));
521 hashkey = ((crc >> 8) ^ crc) % CACHEPICHASHSIZE;
522 for (pic = cachepichash[hashkey];pic;pic = pic->chain)
524 if (!strcmp (picname, pic->name) && pic->tex)
526 R_FreeTexture(pic->tex);
535 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_DPrintf("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 for (i = 0; i < MAX_FONT_FALLBACKS; ++i)
569 if (!fnt->fallbacks[i][0])
571 fnt->tex = Draw_CachePic_Flags(fnt->fallbacks[i], CACHEPICFLAG_QUIET | CACHEPICFLAG_NOCOMPRESSION)->tex;
572 if(fnt->tex != r_texture_notexture)
575 if(fnt->tex == r_texture_notexture)
577 fnt->tex = Draw_CachePic_Flags("gfx/conchars", CACHEPICFLAG_NOCOMPRESSION)->tex;
578 strlcpy(widthfile, "gfx/conchars.width", sizeof(widthfile));
581 dpsnprintf(widthfile, sizeof(widthfile), "%s.width", fnt->fallbacks[i]);
584 dpsnprintf(widthfile, sizeof(widthfile), "%s.width", fnt->texpath);
586 // unspecified width == 1 (base width)
587 for(i = 1; i < 256; ++i)
588 fnt->width_of[i] = 1;
591 // FIXME load "name.width", if it fails, fill all with 1
592 if((widthbuf = (char *) FS_LoadFile(widthfile, tempmempool, true, &widthbufsize)))
594 float extraspacing = 0;
595 const char *p = widthbuf;
600 if(!COM_ParseToken_Simple(&p, false, false))
618 fnt->width_of[ch++] = atof(com_token) + extraspacing;
621 if(!strcmp(com_token, "extraspacing"))
623 if(!COM_ParseToken_Simple(&p, false, false))
625 extraspacing = atof(com_token);
627 else if(!strcmp(com_token, "scale"))
629 if(!COM_ParseToken_Simple(&p, false, false))
631 scale = atof(com_token);
635 Con_Printf("Warning: skipped unknown font property %s\n", com_token);
636 if(!COM_ParseToken_Simple(&p, false, false))
646 maxwidth = fnt->width_of[1];
647 for(i = 2; i < 256; ++i)
648 maxwidth = max(maxwidth, fnt->width_of[i]);
649 fnt->maxwidth = maxwidth;
651 // fix up maxwidth for overlap
652 fnt->maxwidth *= scale;
655 if(fnt == FONT_CONSOLE)
656 con_linewidth = -1; // rewrap console in next frame
659 static dp_font_t *FindFont(const char *title)
662 for(i = 0; i < MAX_FONTS; ++i)
663 if(!strcmp(dp_fonts[i].title, title))
668 static float snap_to_pixel_x(float x, float roundUpAt)
670 float pixelpos = x * vid.width / vid_conwidth.value;
671 int snap = (int) pixelpos;
672 if (pixelpos - snap >= roundUpAt) ++snap;
673 return ((float)snap * vid_conwidth.value / vid.width);
675 x = (int)(x * vid.width / vid_conwidth.value);
676 x = (x * vid_conwidth.value / vid.width);
681 static float snap_to_pixel_y(float y, float roundUpAt)
683 float pixelpos = y * vid.height / vid_conheight.value;
684 int snap = (int) pixelpos;
685 if (pixelpos - snap > roundUpAt) ++snap;
686 return ((float)snap * vid_conheight.value / vid.height);
688 y = (int)(y * vid.height / vid_conheight.value);
689 y = (y * vid_conheight.value / vid.height);
694 static void LoadFont_f(void)
698 const char *filelist, *c, *cm;
700 char mainfont[MAX_QPATH];
704 Con_Printf("Available font commands:\n");
705 for(i = 0; i < MAX_FONTS; ++i)
706 Con_Printf(" loadfont %s gfx/tgafile[...] [sizes...]\n", dp_fonts[i].title);
707 Con_Printf("A font can simply be gfx/tgafile, or alternatively you\n"
708 "can specify multiple fonts and faces\n"
709 "Like this: gfx/vera-sans:2,gfx/fallback:1\n"
710 "to load face 2 of the font gfx/vera-sans and use face 1\n"
711 "of gfx/fallback as fallback font.\n"
712 "You can also specify a list of font sizes to load, like this:\n"
713 "loadfont console gfx/conchars,gfx/fallback 8 12 16 24 32\n"
714 "In many cases, 8 12 16 24 32 should be a good choice.\n"
718 f = FindFont(Cmd_Argv(1));
721 Con_Printf("font function not found\n");
726 filelist = "gfx/conchars";
728 filelist = Cmd_Argv(2);
730 memset(f->fallbacks, 0, sizeof(f->fallbacks));
731 memset(f->fallback_faces, 0, sizeof(f->fallback_faces));
733 // first font is handled "normally"
734 c = strchr(filelist, ':');
735 cm = strchr(filelist, ',');
736 if(c && (!cm || c < cm))
737 f->req_face = atoi(c+1);
744 if(!c || (c - filelist) > MAX_QPATH)
745 strlcpy(mainfont, filelist, sizeof(mainfont));
748 memcpy(mainfont, filelist, c - filelist);
749 mainfont[c - filelist] = 0;
752 for(i = 0; i < MAX_FONT_FALLBACKS; ++i)
754 c = strchr(filelist, ',');
760 c = strchr(filelist, ':');
761 cm = strchr(filelist, ',');
762 if(c && (!cm || c < cm))
763 f->fallback_faces[i] = atoi(c+1);
766 f->fallback_faces[i] = 0; // f->req_face; could make it stick to the default-font's face index
769 if(!c || (c-filelist) > MAX_QPATH)
771 strlcpy(f->fallbacks[i], filelist, sizeof(mainfont));
775 memcpy(f->fallbacks[i], filelist, c - filelist);
776 f->fallbacks[i][c - filelist] = 0;
780 // for now: by default load only one size: the default size
782 for(i = 1; i < MAX_FONT_SIZES; ++i)
783 f->req_sizes[i] = -1;
785 // for some reason this argc is 3 even when using 2 arguments here, maybe nexuiz screws up
788 for(i = 0; i < Cmd_Argc()-3; ++i)
790 sz = atof(Cmd_Argv(i+3));
791 if (sz > 0.001f && sz < 1000.0f) // do not use crap sizes
792 f->req_sizes[i] = sz;
795 LoadFont(true, mainfont, f);
803 static void gl_draw_start(void)
806 drawtexturepool = R_AllocTexturePool();
809 memset(cachepichash, 0, sizeof(cachepichash));
813 for(i = 0; i < MAX_FONTS; ++i)
814 LoadFont(false, va("gfx/font_%s", dp_fonts[i].title), &dp_fonts[i]);
816 // draw the loading screen so people have something to see in the newly opened window
817 SCR_UpdateLoadingScreen(true);
820 static void gl_draw_shutdown(void)
824 R_FreeTexturePool(&drawtexturepool);
827 memset(cachepichash, 0, sizeof(cachepichash));
830 static void gl_draw_newmap(void)
835 void GL_Draw_Init (void)
838 Cvar_RegisterVariable(&r_textshadow);
839 Cvar_RegisterVariable(&r_textbrightness);
840 Cvar_RegisterVariable(&r_textcontrast);
841 Cmd_AddCommand ("loadfont",LoadFont_f, "loadfont function tganame loads a font; example: loadfont console gfx/veramono; loadfont without arguments lists the available functions");
842 R_RegisterModule("GL_Draw", gl_draw_start, gl_draw_shutdown, gl_draw_newmap);
844 strlcpy(FONT_DEFAULT->title, "default", sizeof(FONT_DEFAULT->title));
845 strlcpy(FONT_DEFAULT->texpath, "gfx/conchars", sizeof(FONT_DEFAULT->texpath));
846 strlcpy(FONT_CONSOLE->title, "console", sizeof(FONT_CONSOLE->title));
847 strlcpy(FONT_SBAR->title, "sbar", sizeof(FONT_SBAR->title));
848 strlcpy(FONT_NOTIFY->title, "notify", sizeof(FONT_NOTIFY->title));
849 strlcpy(FONT_CHAT->title, "chat", sizeof(FONT_CHAT->title));
850 strlcpy(FONT_CENTERPRINT->title, "centerprint", sizeof(FONT_CENTERPRINT->title));
851 strlcpy(FONT_INFOBAR->title, "infobar", sizeof(FONT_INFOBAR->title));
852 strlcpy(FONT_MENU->title, "menu", sizeof(FONT_MENU->title));
853 for(i = 0, j = 0; i < MAX_USERFONTS; ++i)
854 if(!FONT_USER[i].title[0])
855 dpsnprintf(FONT_USER[i].title, sizeof(FONT_USER[i].title), "user%d", j++);
859 void _DrawQ_Setup(void)
861 r_viewport_t viewport;
862 if (r_refdef.draw2dstage)
864 r_refdef.draw2dstage = true;
866 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);
867 R_SetViewport(&viewport);
868 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
869 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
870 qglDisable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
871 GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
872 R_EntityMatrix(&identitymatrix);
876 GL_PolygonOffset(0, 0);
880 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
883 static void _DrawQ_ProcessDrawFlag(int flags)
887 if(flags == DRAWFLAG_ADDITIVE)
888 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
889 else if(flags == DRAWFLAG_MODULATE)
890 GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
891 else if(flags == DRAWFLAG_2XMODULATE)
892 GL_BlendFunc(GL_DST_COLOR,GL_SRC_COLOR);
893 else if(flags == DRAWFLAG_SCREEN)
894 GL_BlendFunc(GL_ONE_MINUS_DST_COLOR,GL_ONE);
896 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
899 void DrawQ_Pic(float x, float y, cachepic_t *pic, float width, float height, float red, float green, float blue, float alpha, int flags)
903 _DrawQ_ProcessDrawFlag(flags);
904 GL_Color(red, green, blue, alpha);
906 R_Mesh_VertexPointer(floats, 0, 0);
907 R_Mesh_ColorPointer(NULL, 0, 0);
908 R_Mesh_ResetTextureState();
914 height = pic->height;
915 R_SetupShader_Generic(Draw_GetPicTexture(pic), NULL, GL_MODULATE, 1);
916 R_Mesh_TexCoordPointer(0, 2, floats + 12, 0, 0);
919 floats[12] = 0.0f;floats[13] = 0.0f;
920 floats[14] = 1.0f;floats[15] = 0.0f;
921 floats[16] = 1.0f;floats[17] = 1.0f;
922 floats[18] = 0.0f;floats[19] = 1.0f;
924 // AK07: lets be texel correct on the corners
926 float horz_offset = 0.5f / pic->width;
927 float vert_offset = 0.5f / pic->height;
929 floats[12] = 0.0f + horz_offset;floats[13] = 0.0f + vert_offset;
930 floats[14] = 1.0f - horz_offset;floats[15] = 0.0f + vert_offset;
931 floats[16] = 1.0f - horz_offset;floats[17] = 1.0f - vert_offset;
932 floats[18] = 0.0f + horz_offset;floats[19] = 1.0f - vert_offset;
937 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
939 floats[2] = floats[5] = floats[8] = floats[11] = 0;
940 floats[0] = floats[9] = x;
941 floats[1] = floats[4] = y;
942 floats[3] = floats[6] = x + width;
943 floats[7] = floats[10] = y + height;
945 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
948 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)
951 float af = DEG2RAD(-angle); // forward
952 float ar = DEG2RAD(-angle + 90); // right
953 float sinaf = sin(af);
954 float cosaf = cos(af);
955 float sinar = sin(ar);
956 float cosar = cos(ar);
958 _DrawQ_ProcessDrawFlag(flags);
959 GL_Color(red, green, blue, alpha);
961 R_Mesh_VertexPointer(floats, 0, 0);
962 R_Mesh_ColorPointer(NULL, 0, 0);
963 R_Mesh_ResetTextureState();
969 height = pic->height;
970 R_SetupShader_Generic(Draw_GetPicTexture(pic), NULL, GL_MODULATE, 1);
971 R_Mesh_TexCoordPointer(0, 2, floats + 12, 0, 0);
973 floats[12] = 0.0f;floats[13] = 0.0f;
974 floats[14] = 1.0f;floats[15] = 0.0f;
975 floats[16] = 1.0f;floats[17] = 1.0f;
976 floats[18] = 0.0f;floats[19] = 1.0f;
979 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
981 floats[2] = floats[5] = floats[8] = floats[11] = 0;
984 floats[0] = x - cosaf*org_x - cosar*org_y;
985 floats[1] = y - sinaf*org_x - sinar*org_y;
988 floats[3] = x + cosaf*(width-org_x) - cosar*org_y;
989 floats[4] = y + sinaf*(width-org_x) - sinar*org_y;
992 floats[6] = x + cosaf*(width-org_x) + cosar*(height-org_y);
993 floats[7] = y + sinaf*(width-org_x) + sinar*(height-org_y);
996 floats[9] = x - cosaf*org_x + cosar*(height-org_y);
997 floats[10] = y - sinaf*org_x + sinar*(height-org_y);
999 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
1002 void DrawQ_Fill(float x, float y, float width, float height, float red, float green, float blue, float alpha, int flags)
1006 _DrawQ_ProcessDrawFlag(flags);
1007 GL_Color(red, green, blue, alpha);
1009 R_Mesh_VertexPointer(floats, 0, 0);
1010 R_Mesh_ColorPointer(NULL, 0, 0);
1011 R_Mesh_ResetTextureState();
1012 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
1014 floats[2] = floats[5] = floats[8] = floats[11] = 0;
1015 floats[0] = floats[9] = x;
1016 floats[1] = floats[4] = y;
1017 floats[3] = floats[6] = x + width;
1018 floats[7] = floats[10] = y + height;
1020 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
1023 /// color tag printing
1024 static const vec4_t string_colors[] =
1027 // LordHavoc: why on earth is cyan before magenta in Quake3?
1028 // LordHavoc: note: Doom3 uses white for [0] and [7]
1029 {0.0, 0.0, 0.0, 1.0}, // black
1030 {1.0, 0.0, 0.0, 1.0}, // red
1031 {0.0, 1.0, 0.0, 1.0}, // green
1032 {1.0, 1.0, 0.0, 1.0}, // yellow
1033 {0.0, 0.0, 1.0, 1.0}, // blue
1034 {0.0, 1.0, 1.0, 1.0}, // cyan
1035 {1.0, 0.0, 1.0, 1.0}, // magenta
1036 {1.0, 1.0, 1.0, 1.0}, // white
1037 // [515]'s BX_COLOREDTEXT extension
1038 {1.0, 1.0, 1.0, 0.5}, // half transparent
1039 {0.5, 0.5, 0.5, 1.0} // half brightness
1040 // Black's color table
1041 //{1.0, 1.0, 1.0, 1.0},
1042 //{1.0, 0.0, 0.0, 1.0},
1043 //{0.0, 1.0, 0.0, 1.0},
1044 //{0.0, 0.0, 1.0, 1.0},
1045 //{1.0, 1.0, 0.0, 1.0},
1046 //{0.0, 1.0, 1.0, 1.0},
1047 //{1.0, 0.0, 1.0, 1.0},
1048 //{0.1, 0.1, 0.1, 1.0}
1051 #define STRING_COLORS_COUNT (sizeof(string_colors) / sizeof(vec4_t))
1053 static void DrawQ_GetTextColor(float color[4], int colorindex, float r, float g, float b, float a, qboolean shadow)
1055 float C = r_textcontrast.value;
1056 float B = r_textbrightness.value;
1057 if (colorindex & 0x10000) // that bit means RGB color
1059 color[0] = ((colorindex >> 12) & 0xf) / 15.0;
1060 color[1] = ((colorindex >> 8) & 0xf) / 15.0;
1061 color[2] = ((colorindex >> 4) & 0xf) / 15.0;
1062 color[3] = (colorindex & 0xf) / 15.0;
1065 Vector4Copy(string_colors[colorindex], color);
1066 Vector4Set(color, color[0] * r * C + B, color[1] * g * C + B, color[2] * b * C + B, color[3] * a);
1069 float shadowalpha = (color[0]+color[1]+color[2]) * 0.8;
1070 Vector4Set(color, 0, 0, 0, color[3] * bound(0, shadowalpha, 1));
1074 // NOTE: this function always draws exactly one character if maxwidth <= 0
1075 float DrawQ_TextWidth_UntilWidth_TrackColors_Scale(const char *text, size_t *maxlen, float w, float h, float sw, float sh, int *outcolor, qboolean ignorecolorcodes, const dp_font_t *fnt, float maxwidth)
1077 const char *text_start = text;
1078 int colorindex = STRING_COLOR_DEFAULT;
1081 Uchar ch, mapch, nextch;
1082 Uchar prevch = 0; // used for kerning
1087 ft2_font_map_t *fontmap = NULL;
1088 ft2_font_map_t *map = NULL;
1089 ft2_font_map_t *prevmap = NULL;
1090 ft2_font_t *ft2 = fnt->ft2;
1092 qboolean snap = true;
1093 qboolean least_one = false;
1094 float dw, dh; // display w/h
1101 // do this in the end
1105 // find the most fitting size:
1109 map_index = Font_IndexForSize(ft2, h, &w, &h);
1111 map_index = Font_IndexForSize(ft2, h, NULL, NULL);
1112 fontmap = Font_MapForIndex(ft2, map_index);
1116 if(fabs(sw - 1) > 0.001 || fabs(sh - 1) > 0.001)
1117 snap = false; // turn off pixel snapping for better animation
1128 if (!outcolor || *outcolor == -1)
1129 colorindex = STRING_COLOR_DEFAULT;
1131 colorindex = *outcolor;
1133 // maxwidth /= fnt->scale; // w and h are multiplied by it already
1134 // ftbase_x = snap_to_pixel_x(0);
1139 maxwidth = -maxwidth;
1142 for (i = 0;((bytes_left = *maxlen - (text - text_start)) > 0) && *text;)
1145 nextch = ch = u8_getnchar(text, &text, bytes_left);
1146 i = text - text_start;
1150 x = snap_to_pixel_x(x, 0.4);
1151 if (ch == ' ' && !fontmap)
1153 if(!least_one || i0) // never skip the first character
1154 if(x + fnt->width_of[(int) ' '] * dw > maxwidth)
1157 break; // oops, can't draw this
1159 x += fnt->width_of[(int) ' '] * dw;
1162 // i points to the char after ^
1163 if (ch == STRING_COLOR_TAG && !ignorecolorcodes && i < *maxlen)
1165 ch = *text; // colors are ascii, so no u8_ needed
1166 if (ch <= '9' && ch >= '0') // ^[0-9] found
1168 colorindex = ch - '0';
1173 // i points to the char after ^...
1174 // i+3 points to 3 in ^x123
1175 // i+3 == *maxlen would mean that char is missing
1176 else if (ch == STRING_COLOR_RGB_TAG_CHAR && i + 3 < *maxlen ) // ^x found
1178 // building colorindex...
1179 ch = tolower(text[1]);
1180 tempcolorindex = 0x10000; // binary: 1,0000,0000,0000,0000
1181 if (ch <= '9' && ch >= '0') tempcolorindex |= (ch - '0') << 12;
1182 else if (ch >= 'a' && ch <= 'f') tempcolorindex |= (ch - 87) << 12;
1183 else tempcolorindex = 0;
1186 ch = tolower(text[2]);
1187 if (ch <= '9' && ch >= '0') tempcolorindex |= (ch - '0') << 8;
1188 else if (ch >= 'a' && ch <= 'f') tempcolorindex |= (ch - 87) << 8;
1189 else tempcolorindex = 0;
1192 ch = tolower(text[3]);
1193 if (ch <= '9' && ch >= '0') tempcolorindex |= (ch - '0') << 4;
1194 else if (ch >= 'a' && ch <= 'f') tempcolorindex |= (ch - 87) << 4;
1195 else tempcolorindex = 0;
1198 colorindex = tempcolorindex | 0xf;
1199 // ...done! now colorindex has rgba codes (1,rrrr,gggg,bbbb,aaaa)
1207 else if (ch == STRING_COLOR_TAG) // ^^ found, ignore the first ^ and go to print the second
1216 if (!fontmap || (ch <= 0xFF && fontmap->glyphs[ch].image) || (ch >= 0xE000 && ch <= 0xE0FF))
1223 map = ft2_oldstyle_map;
1225 if(!least_one || i0) // never skip the first character
1226 if(x + fnt->width_of[ch] * dw > maxwidth)
1229 break; // oops, can't draw this
1231 x += fnt->width_of[ch] * dw;
1233 if (!map || map == ft2_oldstyle_map || map->start < ch || map->start + FONT_CHARS_PER_MAP >= ch)
1235 map = FontMap_FindForChar(fontmap, ch);
1238 if (!Font_LoadMapForIndex(ft2, map_index, ch, &map))
1244 mapch = ch - map->start;
1245 if (prevch && Font_GetKerningForMap(ft2, map_index, w, h, prevch, ch, &kx, NULL))
1247 x += map->glyphs[mapch].advance_x * dw;
1256 *outcolor = colorindex;
1261 float DrawQ_String_Scale(float startx, float starty, const char *text, size_t maxlen, float w, float h, float sw, float sh, float basered, float basegreen, float baseblue, float basealpha, int flags, int *outcolor, qboolean ignorecolorcodes, const dp_font_t *fnt)
1263 int shadow, colorindex = STRING_COLOR_DEFAULT;
1265 float x = startx, y, s, t, u, v, thisw;
1266 float *av, *at, *ac;
1269 static float vertex3f[QUADELEMENTS_MAXQUADS*4*3];
1270 static float texcoord2f[QUADELEMENTS_MAXQUADS*4*2];
1271 static float color4f[QUADELEMENTS_MAXQUADS*4*4];
1272 Uchar ch, mapch, nextch;
1273 Uchar prevch = 0; // used for kerning
1276 ft2_font_map_t *prevmap = NULL; // the previous map
1277 ft2_font_map_t *map = NULL; // the currently used map
1278 ft2_font_map_t *fontmap = NULL; // the font map for the size
1280 const char *text_start = text;
1282 ft2_font_t *ft2 = fnt->ft2;
1283 qboolean snap = true;
1289 tw = R_TextureWidth(fnt->tex);
1290 th = R_TextureHeight(fnt->tex);
1298 starty -= (fnt->scale - 1) * h * 0.5; // center
1305 map_index = Font_IndexForSize(ft2, h, &w, &h);
1307 map_index = Font_IndexForSize(ft2, h, NULL, NULL);
1308 fontmap = Font_MapForIndex(ft2, map_index);
1312 if(fabs(sw - 1) > 0.001 || fabs(sh - 1) > 0.001)
1313 snap = false; // turn off pixel snapping for better animation
1321 // draw the font at its baseline when using freetype
1323 ftbase_y = dh * (4.5/6.0);
1328 _DrawQ_ProcessDrawFlag(flags);
1330 R_Mesh_ColorPointer(color4f, 0, 0);
1331 R_Mesh_ResetTextureState();
1333 R_Mesh_TexBind(0, fnt->tex);
1334 R_Mesh_TexCoordPointer(0, 2, texcoord2f, 0, 0);
1335 R_Mesh_VertexPointer(vertex3f, 0, 0);
1336 R_SetupShader_Generic(fnt->tex, NULL, GL_MODULATE, 1);
1343 //ftbase_x = snap_to_pixel_x(ftbase_x);
1345 ftbase_y = snap_to_pixel_y(ftbase_y, 0.3);
1347 pix_x = vid.width / vid_conwidth.value;
1348 pix_y = vid.height / vid_conheight.value;
1349 for (shadow = r_textshadow.value != 0 && basealpha > 0;shadow >= 0;shadow--)
1353 if (!outcolor || *outcolor == -1)
1354 colorindex = STRING_COLOR_DEFAULT;
1356 colorindex = *outcolor;
1358 DrawQ_GetTextColor(color, colorindex, basered, basegreen, baseblue, basealpha, shadow != 0);
1365 x += r_textshadow.value * vid.width / vid_conwidth.value;
1366 y += r_textshadow.value * vid.height / vid_conheight.value;
1369 for (i = 0;((bytes_left = maxlen - (text - text_start)) > 0) && *text;)
1371 nextch = ch = u8_getnchar(text, &text, bytes_left);
1372 i = text - text_start;
1377 x = snap_to_pixel_x(x, 0.4);
1378 y = snap_to_pixel_y(y, 0.4);
1380 if (ch == ' ' && !fontmap)
1382 x += fnt->width_of[(int) ' '] * dw;
1385 if (ch == STRING_COLOR_TAG && !ignorecolorcodes && i < maxlen)
1387 ch = *text; // colors are ascii, so no u8_ needed
1388 if (ch <= '9' && ch >= '0') // ^[0-9] found
1390 colorindex = ch - '0';
1391 DrawQ_GetTextColor(color, colorindex, basered, basegreen, baseblue, basealpha, shadow != 0);
1396 else if (ch == STRING_COLOR_RGB_TAG_CHAR && i+3 < maxlen ) // ^x found
1398 // building colorindex...
1399 ch = tolower(text[1]);
1400 tempcolorindex = 0x10000; // binary: 1,0000,0000,0000,0000
1401 if (ch <= '9' && ch >= '0') tempcolorindex |= (ch - '0') << 12;
1402 else if (ch >= 'a' && ch <= 'f') tempcolorindex |= (ch - 87) << 12;
1403 else tempcolorindex = 0;
1406 ch = tolower(text[2]);
1407 if (ch <= '9' && ch >= '0') tempcolorindex |= (ch - '0') << 8;
1408 else if (ch >= 'a' && ch <= 'f') tempcolorindex |= (ch - 87) << 8;
1409 else tempcolorindex = 0;
1412 ch = tolower(text[3]);
1413 if (ch <= '9' && ch >= '0') tempcolorindex |= (ch - '0') << 4;
1414 else if (ch >= 'a' && ch <= 'f') tempcolorindex |= (ch - 87) << 4;
1415 else tempcolorindex = 0;
1418 colorindex = tempcolorindex | 0xf;
1419 // ...done! now colorindex has rgba codes (1,rrrr,gggg,bbbb,aaaa)
1420 //Con_Printf("^1colorindex:^7 %x\n", colorindex);
1421 DrawQ_GetTextColor(color, colorindex, basered, basegreen, baseblue, basealpha, shadow != 0);
1429 else if (ch == STRING_COLOR_TAG)
1438 // using a value of -1 for the oldstyle map because NULL means uninitialized...
1439 // this way we don't need to rebind fnt->tex for every old-style character
1440 // E000..E0FF: emulate old-font characters (to still have smileys and such available)
1443 x += 1.0/pix_x * r_textshadow.value;
1444 y += 1.0/pix_y * r_textshadow.value;
1446 if (!fontmap || (ch <= 0xFF && fontmap->glyphs[ch].image) || (ch >= 0xE000 && ch <= 0xE0FF))
1454 if (map != ft2_oldstyle_map)
1458 // switching from freetype to non-freetype rendering
1459 GL_LockArrays(0, batchcount * 4);
1460 R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, quadelement3s, 0, 0);
1461 GL_LockArrays(0, 0);
1467 R_SetupShader_Generic(fnt->tex, NULL, GL_MODULATE, 1);
1468 map = ft2_oldstyle_map;
1472 //num = (unsigned char) text[i];
1473 //thisw = fnt->width_of[num];
1474 thisw = fnt->width_of[ch];
1475 // FIXME make these smaller to just include the occupied part of the character for slightly faster rendering
1476 s = (ch & 15)*0.0625f + (0.5f / tw);
1477 t = (ch >> 4)*0.0625f + (0.5f / th);
1478 u = 0.0625f * thisw - (1.0f / tw);
1479 v = 0.0625f - (1.0f / th);
1480 ac[ 0] = color[0];ac[ 1] = color[1];ac[ 2] = color[2];ac[ 3] = color[3];
1481 ac[ 4] = color[0];ac[ 5] = color[1];ac[ 6] = color[2];ac[ 7] = color[3];
1482 ac[ 8] = color[0];ac[ 9] = color[1];ac[10] = color[2];ac[11] = color[3];
1483 ac[12] = color[0];ac[13] = color[1];ac[14] = color[2];ac[15] = color[3];
1484 at[ 0] = s ; at[ 1] = t ;
1485 at[ 2] = s+u ; at[ 3] = t ;
1486 at[ 4] = s+u ; at[ 5] = t+v ;
1487 at[ 6] = s ; at[ 7] = t+v ;
1488 av[ 0] = x ; av[ 1] = y ; av[ 2] = 10;
1489 av[ 3] = x+dw*thisw ; av[ 4] = y ; av[ 5] = 10;
1490 av[ 6] = x+dw*thisw ; av[ 7] = y+dh ; av[ 8] = 10;
1491 av[ 9] = x ; av[10] = y+dh ; av[11] = 10;
1496 if (batchcount >= QUADELEMENTS_MAXQUADS)
1498 GL_LockArrays(0, batchcount * 4);
1499 R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, quadelement3s, 0, 0);
1500 GL_LockArrays(0, 0);
1508 if (!map || map == ft2_oldstyle_map || map->start < ch || map->start + FONT_CHARS_PER_MAP >= ch)
1510 // new charmap - need to render
1513 // we need a different character map, render what we currently have:
1514 GL_LockArrays(0, batchcount * 4);
1515 R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, quadelement3s, 0, 0);
1516 GL_LockArrays(0, 0);
1523 map = FontMap_FindForChar(fontmap, ch);
1526 if (!Font_LoadMapForIndex(ft2, map_index, ch, &map))
1533 // this shouldn't happen
1538 R_SetupShader_Generic(map->texture, NULL, GL_MODULATE, 1);
1541 mapch = ch - map->start;
1542 thisw = map->glyphs[mapch].advance_x;
1546 if (prevch && Font_GetKerningForMap(ft2, map_index, w, h, prevch, ch, &kx, &ky))
1553 ac[ 0] = color[0]; ac[ 1] = color[1]; ac[ 2] = color[2]; ac[ 3] = color[3];
1554 ac[ 4] = color[0]; ac[ 5] = color[1]; ac[ 6] = color[2]; ac[ 7] = color[3];
1555 ac[ 8] = color[0]; ac[ 9] = color[1]; ac[10] = color[2]; ac[11] = color[3];
1556 ac[12] = color[0]; ac[13] = color[1]; ac[14] = color[2]; ac[15] = color[3];
1557 at[0] = map->glyphs[mapch].txmin; at[1] = map->glyphs[mapch].tymin;
1558 at[2] = map->glyphs[mapch].txmax; at[3] = map->glyphs[mapch].tymin;
1559 at[4] = map->glyphs[mapch].txmax; at[5] = map->glyphs[mapch].tymax;
1560 at[6] = map->glyphs[mapch].txmin; at[7] = map->glyphs[mapch].tymax;
1561 av[ 0] = x + dw * map->glyphs[mapch].vxmin; av[ 1] = y + dh * map->glyphs[mapch].vymin; av[ 2] = 10;
1562 av[ 3] = x + dw * map->glyphs[mapch].vxmax; av[ 4] = y + dh * map->glyphs[mapch].vymin; av[ 5] = 10;
1563 av[ 6] = x + dw * map->glyphs[mapch].vxmax; av[ 7] = y + dh * map->glyphs[mapch].vymax; av[ 8] = 10;
1564 av[ 9] = x + dw * map->glyphs[mapch].vxmin; av[10] = y + dh * map->glyphs[mapch].vymax; av[11] = 10;
1573 if (batchcount >= QUADELEMENTS_MAXQUADS)
1575 GL_LockArrays(0, batchcount * 4);
1576 R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, quadelement3s, 0, 0);
1577 GL_LockArrays(0, 0);
1589 x -= 1.0/pix_x * r_textshadow.value;
1590 y -= 1.0/pix_y * r_textshadow.value;
1596 GL_LockArrays(0, batchcount * 4);
1597 R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, quadelement3s, 0, 0);
1598 GL_LockArrays(0, 0);
1602 *outcolor = colorindex;
1604 // note: this relies on the proper text (not shadow) being drawn last
1608 float DrawQ_String(float startx, float starty, const char *text, size_t maxlen, float w, float h, float basered, float basegreen, float baseblue, float basealpha, int flags, int *outcolor, qboolean ignorecolorcodes, const dp_font_t *fnt)
1610 return DrawQ_String_Scale(startx, starty, text, maxlen, w, h, 1, 1, basered, basegreen, baseblue, basealpha, flags, outcolor, ignorecolorcodes, fnt);
1613 float DrawQ_TextWidth_UntilWidth_TrackColors(const char *text, size_t *maxlen, float w, float h, int *outcolor, qboolean ignorecolorcodes, const dp_font_t *fnt, float maxwidth)
1615 return DrawQ_TextWidth_UntilWidth_TrackColors_Scale(text, maxlen, w, h, 1, 1, outcolor, ignorecolorcodes, fnt, maxwidth);
1618 float DrawQ_TextWidth(const char *text, size_t maxlen, float w, float h, qboolean ignorecolorcodes, const dp_font_t *fnt)
1620 return DrawQ_TextWidth_UntilWidth(text, &maxlen, w, h, ignorecolorcodes, fnt, 1000000000);
1623 float DrawQ_TextWidth_UntilWidth(const char *text, size_t *maxlen, float w, float h, qboolean ignorecolorcodes, const dp_font_t *fnt, float maxWidth)
1625 return DrawQ_TextWidth_UntilWidth_TrackColors(text, maxlen, w, h, NULL, ignorecolorcodes, fnt, maxWidth);
1630 // no ^xrgb management
1631 static int DrawQ_BuildColoredText(char *output2c, size_t maxoutchars, const char *text, int maxreadchars, qboolean ignorecolorcodes, int *outcolor)
1633 int color, numchars = 0;
1634 char *outputend2c = output2c + maxoutchars - 2;
1635 if (!outcolor || *outcolor == -1)
1636 color = STRING_COLOR_DEFAULT;
1640 maxreadchars = 1<<30;
1641 textend = text + maxreadchars;
1642 while (text != textend && *text)
1644 if (*text == STRING_COLOR_TAG && !ignorecolorcodes && text + 1 != textend)
1646 if (text[1] == STRING_COLOR_TAG)
1648 else if (text[1] >= '0' && text[1] <= '9')
1650 color = text[1] - '0';
1655 if (output2c >= outputend2c)
1657 *output2c++ = *text++;
1658 *output2c++ = color;
1661 output2c[0] = output2c[1] = 0;
1668 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)
1672 _DrawQ_ProcessDrawFlag(flags);
1674 R_Mesh_VertexPointer(floats, 0, 0);
1675 R_Mesh_ColorPointer(floats + 20, 0, 0);
1676 R_Mesh_ResetTextureState();
1682 height = pic->height;
1683 R_SetupShader_Generic(Draw_GetPicTexture(pic), NULL, GL_MODULATE, 1);
1684 R_Mesh_TexCoordPointer(0, 2, floats + 12, 0, 0);
1685 floats[12] = s1;floats[13] = t1;
1686 floats[14] = s2;floats[15] = t2;
1687 floats[16] = s4;floats[17] = t4;
1688 floats[18] = s3;floats[19] = t3;
1691 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
1693 floats[2] = floats[5] = floats[8] = floats[11] = 0;
1694 floats[0] = floats[9] = x;
1695 floats[1] = floats[4] = y;
1696 floats[3] = floats[6] = x + width;
1697 floats[7] = floats[10] = y + height;
1698 floats[20] = r1;floats[21] = g1;floats[22] = b1;floats[23] = a1;
1699 floats[24] = r2;floats[25] = g2;floats[26] = b2;floats[27] = a2;
1700 floats[28] = r4;floats[29] = g4;floats[30] = b4;floats[31] = a4;
1701 floats[32] = r3;floats[33] = g3;floats[34] = b3;floats[35] = a3;
1703 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
1706 void DrawQ_Mesh (drawqueuemesh_t *mesh, int flags)
1708 _DrawQ_ProcessDrawFlag(flags);
1710 R_Mesh_VertexPointer(mesh->data_vertex3f, 0, 0);
1711 R_Mesh_ColorPointer(mesh->data_color4f, 0, 0);
1712 R_Mesh_ResetTextureState();
1713 R_Mesh_TexCoordPointer(0, 2, mesh->data_texcoord2f, 0, 0);
1714 R_SetupShader_Generic(mesh->texture, NULL, GL_MODULATE, 1);
1716 GL_LockArrays(0, mesh->num_vertices);
1717 R_Mesh_Draw(0, mesh->num_vertices, 0, mesh->num_triangles, mesh->data_element3i, mesh->data_element3s, 0, 0);
1718 GL_LockArrays(0, 0);
1721 void DrawQ_LineLoop (drawqueuemesh_t *mesh, int flags)
1725 _DrawQ_ProcessDrawFlag(flags);
1729 qglBegin(GL_LINE_LOOP);
1730 for (num = 0;num < mesh->num_vertices;num++)
1732 if (mesh->data_color4f)
1733 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]);
1734 qglVertex2f(mesh->data_vertex3f[num*3+0], mesh->data_vertex3f[num*3+1]);
1740 //[515]: this is old, delete
1741 void DrawQ_Line (float width, float x1, float y1, float x2, float y2, float r, float g, float b, float alpha, int flags)
1743 _DrawQ_ProcessDrawFlag(flags);
1745 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
1748 //qglLineWidth(width);CHECKGLERROR
1750 GL_Color(r,g,b,alpha);
1753 qglVertex2f(x1, y1);
1754 qglVertex2f(x2, y2);
1759 void DrawQ_SetClipArea(float x, float y, float width, float height)
1764 // We have to convert the con coords into real coords
1765 // OGL uses top to bottom
1766 ix = (int)(0.5 + x * ((float)vid.width / vid_conwidth.integer));
1767 iy = (int)(0.5 + y * ((float) vid.height / vid_conheight.integer));
1768 iw = (int)(width * ((float)vid.width / vid_conwidth.integer));
1769 ih = (int)(height * ((float)vid.height / vid_conheight.integer));
1770 GL_Scissor(ix, vid.height - iy - ih, iw, ih);
1772 GL_ScissorTest(true);
1775 void DrawQ_ResetClipArea(void)
1778 GL_ScissorTest(false);
1781 void DrawQ_Finish(void)
1783 r_refdef.draw2dstage = false;
1786 static float blendvertex3f[9] = {-5000, -5000, 10, 10000, -5000, 10, -5000, 10000, 10};
1787 void R_DrawGamma(void)
1790 switch(vid.renderpath)
1792 case RENDERPATH_GL20:
1793 case RENDERPATH_CGGL:
1794 if (vid_usinghwgamma || v_glslgamma.integer)
1797 case RENDERPATH_GL13:
1798 case RENDERPATH_GL11:
1799 if (vid_usinghwgamma)
1803 // all the blends ignore depth
1804 R_Mesh_VertexPointer(blendvertex3f, 0, 0);
1805 R_Mesh_ColorPointer(NULL, 0, 0);
1806 R_Mesh_ResetTextureState();
1807 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
1809 GL_DepthRange(0, 1);
1810 GL_PolygonOffset(0, 0);
1811 GL_DepthTest(false);
1812 if (v_color_enable.integer)
1814 c[0] = v_color_white_r.value;
1815 c[1] = v_color_white_g.value;
1816 c[2] = v_color_white_b.value;
1819 c[0] = c[1] = c[2] = v_contrast.value;
1820 if (c[0] >= 1.01f || c[1] >= 1.01f || c[2] >= 1.01f)
1822 GL_BlendFunc(GL_DST_COLOR, GL_ONE);
1823 while (c[0] >= 1.01f || c[1] >= 1.01f || c[2] >= 1.01f)
1825 GL_Color(bound(0, c[0] - 1, 1), bound(0, c[1] - 1, 1), bound(0, c[2] - 1, 1), 1);
1826 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, polygonelement3s, 0, 0);
1827 VectorScale(c, 0.5, c);
1830 if (v_color_enable.integer)
1832 c[0] = v_color_black_r.value;
1833 c[1] = v_color_black_g.value;
1834 c[2] = v_color_black_b.value;
1837 c[0] = c[1] = c[2] = v_brightness.value;
1838 if (c[0] >= 0.01f || c[1] >= 0.01f || c[2] >= 0.01f)
1840 GL_BlendFunc(GL_ONE, GL_ONE);
1841 GL_Color(c[0], c[1], c[2], 1);
1842 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, polygonelement3s, 0, 0);