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 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)"};
29 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)"};
31 static rtexture_t *char_texture;
32 cachepic_t *r_crosshairs[NUMCROSSHAIRS+1];
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 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 char *pointerimage =
122 static rtexture_t *draw_generatemousepointer(void)
125 unsigned char buffer[256][4];
126 for (i = 0;i < 256;i++)
128 if (pointerimage[i] == '.')
137 buffer[i][0] = (pointerimage[i] - '0') * 16;
138 buffer[i][1] = (pointerimage[i] - '0') * 16;
139 buffer[i][2] = (pointerimage[i] - '0') * 16;
143 return R_LoadTexture2D(drawtexturepool, "mousepointer", 16, 16, &buffer[0][0], TEXTYPE_BGRA, TEXF_ALPHA | TEXF_PRECACHE, NULL);
146 static char *crosshairtexdata[NUMCROSSHAIRS] =
251 static rtexture_t *draw_generatecrosshair(int num)
255 unsigned char data[16*16][4];
256 in = crosshairtexdata[num];
257 for (i = 0;i < 16*16;i++)
268 data[i][0] = data[i][1] = data[i][2] = (unsigned char) ((int) (in[i] - '0') * 127 / 7 + 128);
272 return R_LoadTexture2D(drawtexturepool, va("crosshair%i", num+1), 16, 16, &data[0][0], TEXTYPE_BGRA, TEXF_ALPHA | TEXF_PRECACHE, NULL);
275 static rtexture_t *draw_generateditherpattern(void)
279 unsigned char data[8*8*4];
280 for (y = 0;y < 8;y++)
282 for (x = 0;x < 8;x++)
284 data[(y*8+x)*4+0] = data[(y*8+x)*4+1] = data[(y*8+x)*4+2] = ((x^y) & 4) ? 255 : 0;
285 data[(y*8+x)*4+3] = 255;
288 return R_LoadTexture2D(drawtexturepool, "ditherpattern", 8, 8, data, TEXTYPE_BGRA, TEXF_FORCENEAREST | TEXF_PRECACHE, NULL);
290 unsigned char data[16];
291 memset(data, 255, sizeof(data));
292 data[0] = data[1] = data[2] = data[12] = data[13] = data[14] = 0;
293 return R_LoadTexture2D(drawtexturepool, "ditherpattern", 2, 2, data, TEXTYPE_BGRA, TEXF_FORCENEAREST | TEXF_PRECACHE, NULL);
302 // FIXME: move this to client somehow
303 cachepic_t *Draw_CachePic (const char *path, qboolean persistent)
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)
343 flags |= TEXF_PRECACHE;
344 if (!strcmp(path, "gfx/colorcontrol/ditherpattern"))
347 // load a high quality image from disk if possible
348 pic->tex = loadtextureimage(drawtexturepool, path, false, flags | (gl_texturecompression_2d.integer ? TEXF_COMPRESS : 0), true);
349 if (pic->tex == NULL && !strncmp(path, "gfx/", 4))
351 // compatibility with older versions which did not require gfx/ prefix
352 pic->tex = loadtextureimage(drawtexturepool, path + 4, false, flags | (gl_texturecompression_2d.integer ? TEXF_COMPRESS : 0), true);
354 // if a high quality image was loaded, set the pic's size to match it, just
355 // in case there's no low quality version to get the size from
358 pic->width = R_TextureWidth(pic->tex);
359 pic->height = R_TextureHeight(pic->tex);
362 // now read the low quality version (wad or lmp file), and take the pic
363 // size from that even if we don't upload the texture, this way the pics
364 // show up the right size in the menu even if they were replaced with
365 // higher or lower resolution versions
366 dpsnprintf(lmpname, sizeof(lmpname), "%s.lmp", path);
367 if (!strncmp(path, "gfx/", 4) && (lmpdata = FS_LoadFile(lmpname, tempmempool, false, &lmpsize)))
371 pic->width = lmpdata[0] + lmpdata[1] * 256 + lmpdata[2] * 65536 + lmpdata[3] * 16777216;
372 pic->height = lmpdata[4] + lmpdata[5] * 256 + lmpdata[6] * 65536 + lmpdata[7] * 16777216;
373 // if no high quality replacement image was found, upload the original low quality texture
375 pic->tex = R_LoadTexture2D(drawtexturepool, path, pic->width, pic->height, lmpdata + 8, TEXTYPE_PALETTE, flags, palette_bgra_transparent);
379 else if ((lmpdata = W_GetLumpName (path + 4)))
381 if (!strcmp(path, "gfx/conchars"))
383 // conchars is a raw image and with color 0 as transparent instead of 255
386 // if no high quality replacement image was found, upload the original low quality texture
388 pic->tex = R_LoadTexture2D(drawtexturepool, path, 128, 128, lmpdata, TEXTYPE_PALETTE, flags, palette_bgra_font);
392 pic->width = lmpdata[0] + lmpdata[1] * 256 + lmpdata[2] * 65536 + lmpdata[3] * 16777216;
393 pic->height = lmpdata[4] + lmpdata[5] * 256 + lmpdata[6] * 65536 + lmpdata[7] * 16777216;
394 // if no high quality replacement image was found, upload the original low quality texture
396 pic->tex = R_LoadTexture2D(drawtexturepool, path, pic->width, pic->height, lmpdata + 8, TEXTYPE_PALETTE, flags, palette_bgra_transparent);
400 // if it's not found on disk, check if it's one of the builtin images
401 if (pic->tex == NULL)
403 if (pic->tex == NULL && !strcmp(path, "gfx/conchars"))
404 pic->tex = draw_generateconchars();
405 if (pic->tex == NULL && !strcmp(path, "ui/mousepointer"))
406 pic->tex = draw_generatemousepointer();
407 if (pic->tex == NULL && !strcmp(path, "gfx/prydoncursor001"))
408 pic->tex = draw_generatemousepointer();
409 if (pic->tex == NULL && !strcmp(path, "gfx/crosshair1"))
410 pic->tex = draw_generatecrosshair(0);
411 if (pic->tex == NULL && !strcmp(path, "gfx/crosshair2"))
412 pic->tex = draw_generatecrosshair(1);
413 if (pic->tex == NULL && !strcmp(path, "gfx/crosshair3"))
414 pic->tex = draw_generatecrosshair(2);
415 if (pic->tex == NULL && !strcmp(path, "gfx/crosshair4"))
416 pic->tex = draw_generatecrosshair(3);
417 if (pic->tex == NULL && !strcmp(path, "gfx/crosshair5"))
418 pic->tex = draw_generatecrosshair(4);
419 if (pic->tex == NULL && !strcmp(path, "gfx/crosshair6"))
420 pic->tex = draw_generatecrosshair(5);
421 if (pic->tex == NULL && !strcmp(path, "gfx/colorcontrol/ditherpattern"))
422 pic->tex = draw_generateditherpattern();
423 // default textures for light sprites
424 // todo: improve them
425 if (pic->tex == NULL && !strcmp(path, "gfx/editlights/cursor"))
426 pic->tex = draw_generatecrosshair(0);
427 if (pic->tex == NULL && !strcmp(path, "gfx/editlights/light"))
428 pic->tex = draw_generatecrosshair(0);
429 if (pic->tex == NULL && !strcmp(path, "gfx/editlights/noshadow"))
430 pic->tex = draw_generatecrosshair(0);
431 if (pic->tex == NULL && !strcmp(path, "gfx/editlights/cubemap"))
432 pic->tex = draw_generatecrosshair(0);
433 if (pic->tex == NULL && !strcmp(path, "gfx/editlights/selection"))
434 pic->tex = draw_generatecrosshair(0);
435 if (pic->tex == NULL)
437 // don't complain about missing gfx/crosshair images
438 if (strncmp(path, "gfx/crosshair", 13))
439 Con_Printf("Draw_CachePic: failed to load %s\n", path);
440 pic->tex = r_texture_notexture;
442 pic->width = R_TextureWidth(pic->tex);
443 pic->height = R_TextureHeight(pic->tex);
449 cachepic_t *Draw_NewPic(const char *picname, int width, int height, int alpha, unsigned char *pixels_bgra)
454 crc = CRC_Block((unsigned char *)picname, strlen(picname));
455 hashkey = ((crc >> 8) ^ crc) % CACHEPICHASHSIZE;
456 for (pic = cachepichash[hashkey];pic;pic = pic->chain)
457 if (!strcmp (picname, pic->name))
462 if (pic->tex && pic->width == width && pic->height == height)
464 R_UpdateTexture(pic->tex, pixels_bgra, 0, 0, width, height);
472 if (numcachepics == MAX_CACHED_PICS)
474 Con_Printf ("Draw_NewPic: numcachepics == MAX_CACHED_PICS\n");
475 // FIXME: support NULL in callers?
476 return cachepics; // return the first one
478 pic = cachepics + (numcachepics++);
479 strlcpy (pic->name, picname, sizeof(pic->name));
481 pic->chain = cachepichash[hashkey];
482 cachepichash[hashkey] = pic;
487 pic->height = height;
489 R_FreeTexture(pic->tex);
490 pic->tex = R_LoadTexture2D(drawtexturepool, picname, width, height, pixels_bgra, TEXTYPE_BGRA, alpha ? TEXF_ALPHA : 0, NULL);
494 void Draw_FreePic(const char *picname)
499 // this doesn't really free the pic, but does free it's texture
500 crc = CRC_Block((unsigned char *)picname, strlen(picname));
501 hashkey = ((crc >> 8) ^ crc) % CACHEPICHASHSIZE;
502 for (pic = cachepichash[hashkey];pic;pic = pic->chain)
504 if (!strcmp (picname, pic->name) && pic->tex)
506 R_FreeTexture(pic->tex);
519 static void gl_draw_start(void)
522 drawtexturepool = R_AllocTexturePool();
525 memset(cachepichash, 0, sizeof(cachepichash));
527 char_texture = Draw_CachePic("gfx/conchars", true)->tex;
528 for (i = 1;i <= NUMCROSSHAIRS;i++)
529 r_crosshairs[i] = Draw_CachePic(va("gfx/crosshair%i", i), true);
531 // draw the loading screen so people have something to see in the newly opened window
532 SCR_UpdateLoadingScreen(true);
535 static void gl_draw_shutdown(void)
537 R_FreeTexturePool(&drawtexturepool);
540 memset(cachepichash, 0, sizeof(cachepichash));
543 static void gl_draw_newmap(void)
547 void GL_Draw_Init (void)
549 Cvar_RegisterVariable(&r_textshadow);
550 Cvar_RegisterVariable(&r_textbrightness);
551 R_RegisterModule("GL_Draw", gl_draw_start, gl_draw_shutdown, gl_draw_newmap);
554 static void _DrawQ_Setup(void)
556 if (r_refdef.draw2dstage)
558 r_refdef.draw2dstage = true;
560 qglViewport(r_view.x, vid.height - (r_view.y + r_view.height), r_view.width, r_view.height);CHECKGLERROR
561 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
562 GL_SetupView_Mode_Ortho(0, 0, vid_conwidth.integer, vid_conheight.integer, -10, 100);
563 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
564 qglDisable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
565 GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
566 R_Mesh_Matrix(&identitymatrix);
570 GL_PolygonOffset(0, 0);
574 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
576 if (gl_support_fragment_shader)
578 qglUseProgramObjectARB(0);CHECKGLERROR
582 static void _DrawQ_ProcessDrawFlag(int flags)
586 if(flags == DRAWFLAG_ADDITIVE)
587 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
588 else if(flags == DRAWFLAG_MODULATE)
589 GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
590 else if(flags == DRAWFLAG_2XMODULATE)
591 GL_BlendFunc(GL_DST_COLOR,GL_SRC_COLOR);
593 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
596 void DrawQ_Pic(float x, float y, cachepic_t *pic, float width, float height, float red, float green, float blue, float alpha, int flags)
600 _DrawQ_ProcessDrawFlag(flags);
601 GL_Color(red, green, blue, alpha);
603 R_Mesh_VertexPointer(floats, 0, 0);
604 R_Mesh_ColorPointer(NULL, 0, 0);
605 R_Mesh_ResetTextureState();
611 height = pic->height;
612 R_Mesh_TexBind(0, R_GetTexture(pic->tex));
613 R_Mesh_TexCoordPointer(0, 2, floats + 12, 0, 0);
615 // AK07: lets be texel correct on the corners
617 float horz_offset = 0.5f / pic->width;
618 float vert_offset = 0.5f / pic->height;
620 floats[12] = 0.0f + horz_offset;floats[13] = 0.0f + vert_offset;
621 floats[14] = 1.0f - horz_offset;floats[15] = 0.0f + vert_offset;
622 floats[16] = 1.0f - horz_offset;floats[17] = 1.0f - vert_offset;
623 floats[18] = 0.0f + horz_offset;floats[19] = 1.0f - vert_offset;
627 floats[2] = floats[5] = floats[8] = floats[11] = 0;
628 floats[0] = floats[9] = x;
629 floats[1] = floats[4] = y;
630 floats[3] = floats[6] = x + width;
631 floats[7] = floats[10] = y + height;
633 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
636 void DrawQ_Fill(float x, float y, float width, float height, float red, float green, float blue, float alpha, int flags)
640 _DrawQ_ProcessDrawFlag(flags);
641 GL_Color(red, green, blue, alpha);
643 R_Mesh_VertexPointer(floats, 0, 0);
644 R_Mesh_ColorPointer(NULL, 0, 0);
645 R_Mesh_ResetTextureState();
647 floats[2] = floats[5] = floats[8] = floats[11] = 0;
648 floats[0] = floats[9] = x;
649 floats[1] = floats[4] = y;
650 floats[3] = floats[6] = x + width;
651 floats[7] = floats[10] = y + height;
653 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
656 // color tag printing
657 static vec4_t string_colors[] =
660 // LordHavoc: why on earth is cyan before magenta in Quake3?
661 // LordHavoc: note: Doom3 uses white for [0] and [7]
662 {0.0, 0.0, 0.0, 1.0}, // black
663 {1.0, 0.0, 0.0, 1.0}, // red
664 {0.0, 1.0, 0.0, 1.0}, // green
665 {1.0, 1.0, 0.0, 1.0}, // yellow
666 {0.0, 0.0, 1.0, 1.0}, // blue
667 {0.0, 1.0, 1.0, 1.0}, // cyan
668 {1.0, 0.0, 1.0, 1.0}, // magenta
669 {1.0, 1.0, 1.0, 1.0}, // white
670 // [515]'s BX_COLOREDTEXT extension
671 {1.0, 1.0, 1.0, 0.5}, // half transparent
672 {0.5, 0.5, 0.5, 1.0} // half brightness
673 // Black's color table
674 //{1.0, 1.0, 1.0, 1.0},
675 //{1.0, 0.0, 0.0, 1.0},
676 //{0.0, 1.0, 0.0, 1.0},
677 //{0.0, 0.0, 1.0, 1.0},
678 //{1.0, 1.0, 0.0, 1.0},
679 //{0.0, 1.0, 1.0, 1.0},
680 //{1.0, 0.0, 1.0, 1.0},
681 //{0.1, 0.1, 0.1, 1.0}
684 #define STRING_COLORS_COUNT (sizeof(string_colors) / sizeof(vec4_t))
686 static void DrawQ_GetTextColor(float color[4], int colorindex, float r, float g, float b, float a, qboolean shadow)
688 float v = r_textbrightness.value;
689 Vector4Copy(string_colors[colorindex], color);
690 Vector4Set(color, (color[0] * (1-v) + v) * r, (color[1] * (1-v) + v) * g, (color[2] * (1-v) + v) * b, color[3] * a);
693 float shadowalpha = color[0]+color[1]+color[2] * 0.8;
694 Vector4Set(color, 0, 0, 0, color[3] * bound(0, shadowalpha, 1));
698 float DrawQ_String(float startx, float starty, const char *text, int maxlen, float w, float h, float basered, float basegreen, float baseblue, float basealpha, int flags, int *outcolor, qboolean ignorecolorcodes)
700 int i, num, shadow, colorindex = STRING_COLOR_DEFAULT;
701 float x = startx, y, s, t, u, v;
705 float vertex3f[QUADELEMENTS_MAXQUADS*4*3];
706 float texcoord2f[QUADELEMENTS_MAXQUADS*4*2];
707 float color4f[QUADELEMENTS_MAXQUADS*4*4];
712 _DrawQ_ProcessDrawFlag(flags);
714 R_Mesh_ColorPointer(color4f, 0, 0);
715 R_Mesh_ResetTextureState();
716 R_Mesh_TexBind(0, R_GetTexture(char_texture));
717 R_Mesh_TexCoordPointer(0, 2, texcoord2f, 0, 0);
718 R_Mesh_VertexPointer(vertex3f, 0, 0);
725 for (shadow = r_textshadow.value != 0;shadow >= 0;shadow--)
727 if (!outcolor || *outcolor == -1)
728 colorindex = STRING_COLOR_DEFAULT;
730 colorindex = *outcolor;
731 DrawQ_GetTextColor(color, colorindex, basered, basegreen, baseblue, basealpha, shadow);
737 x += r_textshadow.value;
738 y += r_textshadow.value;
740 for (i = 0;i < maxlen && text[i];i++, x += w)
744 if (text[i] == STRING_COLOR_TAG && !ignorecolorcodes && i + 1 < maxlen)
746 if (text[i+1] == STRING_COLOR_TAG)
752 else if (text[i+1] >= '0' && text[i+1] <= '9')
754 colorindex = text[i+1] - '0';
755 DrawQ_GetTextColor(color, colorindex, basered, basegreen, baseblue, basealpha, shadow);
762 s = (num & 15)*0.0625f + (0.5f / 256.0f);
763 t = (num >> 4)*0.0625f + (0.5f / 256.0f);
764 u = 0.0625f - (1.0f / 256.0f);
765 v = 0.0625f - (1.0f / 256.0f);
766 ac[ 0] = color[0];ac[ 1] = color[1];ac[ 2] = color[2];ac[ 3] = color[3];
767 ac[ 4] = color[0];ac[ 5] = color[1];ac[ 6] = color[2];ac[ 7] = color[3];
768 ac[ 8] = color[0];ac[ 9] = color[1];ac[10] = color[2];ac[11] = color[3];
769 ac[12] = color[0];ac[13] = color[1];ac[14] = color[2];ac[15] = color[3];
770 at[ 0] = s ;at[ 1] = t ;
771 at[ 2] = s+u;at[ 3] = t ;
772 at[ 4] = s+u;at[ 5] = t+v;
773 at[ 6] = s ;at[ 7] = t+v;
774 av[ 0] = x ;av[ 1] = y ;av[ 2] = 10;
775 av[ 3] = x+w;av[ 4] = y ;av[ 5] = 10;
776 av[ 6] = x+w;av[ 7] = y+h;av[ 8] = 10;
777 av[ 9] = x ;av[10] = y+h;av[11] = 10;
782 if (batchcount >= QUADELEMENTS_MAXQUADS)
784 if (basealpha >= (1.0f / 255.0f))
786 GL_LockArrays(0, batchcount * 4);
787 R_Mesh_Draw(0, batchcount * 4, batchcount * 2, quadelements, 0, 0);
799 if (basealpha >= (1.0f / 255.0f))
801 GL_LockArrays(0, batchcount * 4);
802 R_Mesh_Draw(0, batchcount * 4, batchcount * 2, quadelements, 0, 0);
808 *outcolor = colorindex;
810 // note: this relies on the proper text (not shadow) being drawn last
816 static int DrawQ_BuildColoredText(char *output2c, size_t maxoutchars, const char *text, int maxreadchars, qboolean ignorecolorcodes, int *outcolor)
818 int color, numchars = 0;
819 char *outputend2c = output2c + maxoutchars - 2;
820 if (!outcolor || *outcolor == -1)
821 color = STRING_COLOR_DEFAULT;
825 maxreadchars = 1<<30;
826 textend = text + maxreadchars;
827 while (text != textend && *text)
829 if (*text == STRING_COLOR_TAG && !ignorecolorcodes && text + 1 != textend)
831 if (text[1] == STRING_COLOR_TAG)
833 else if (text[1] >= '0' && text[1] <= '9')
835 color = text[1] - '0';
840 if (output2c >= outputend2c)
842 *output2c++ = *text++;
846 output2c[0] = output2c[1] = 0;
853 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)
857 _DrawQ_ProcessDrawFlag(flags);
859 R_Mesh_VertexPointer(floats, 0, 0);
860 R_Mesh_ColorPointer(floats + 20, 0, 0);
861 R_Mesh_ResetTextureState();
867 height = pic->height;
868 R_Mesh_TexBind(0, R_GetTexture(pic->tex));
869 R_Mesh_TexCoordPointer(0, 2, floats + 12, 0, 0);
870 floats[12] = s1;floats[13] = t1;
871 floats[14] = s2;floats[15] = t2;
872 floats[16] = s4;floats[17] = t4;
873 floats[18] = s3;floats[19] = t3;
876 floats[2] = floats[5] = floats[8] = floats[11] = 0;
877 floats[0] = floats[9] = x;
878 floats[1] = floats[4] = y;
879 floats[3] = floats[6] = x + width;
880 floats[7] = floats[10] = y + height;
881 floats[20] = r1;floats[21] = g1;floats[22] = b1;floats[23] = a1;
882 floats[24] = r2;floats[25] = g2;floats[26] = b2;floats[27] = a2;
883 floats[28] = r4;floats[29] = g4;floats[30] = b4;floats[31] = a4;
884 floats[32] = r3;floats[33] = g3;floats[34] = b3;floats[35] = a3;
886 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
889 void DrawQ_Mesh (drawqueuemesh_t *mesh, int flags)
891 _DrawQ_ProcessDrawFlag(flags);
893 R_Mesh_VertexPointer(mesh->data_vertex3f, 0, 0);
894 R_Mesh_ColorPointer(mesh->data_color4f, 0, 0);
895 R_Mesh_ResetTextureState();
896 R_Mesh_TexBind(0, R_GetTexture(mesh->texture));
897 R_Mesh_TexCoordPointer(0, 2, mesh->data_texcoord2f, 0, 0);
899 GL_LockArrays(0, mesh->num_vertices);
900 R_Mesh_Draw(0, mesh->num_vertices, mesh->num_triangles, mesh->data_element3i, 0, 0);
904 void DrawQ_LineLoop (drawqueuemesh_t *mesh, int flags)
908 _DrawQ_ProcessDrawFlag(flags);
912 qglBegin(GL_LINE_LOOP);
913 for (num = 0;num < mesh->num_vertices;num++)
915 if (mesh->data_color4f)
916 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]);
917 qglVertex2f(mesh->data_vertex3f[num*3+0], mesh->data_vertex3f[num*3+1]);
923 //[515]: this is old, delete
924 void DrawQ_Line (float width, float x1, float y1, float x2, float y2, float r, float g, float b, float alpha, int flags)
926 _DrawQ_ProcessDrawFlag(flags);
929 qglLineWidth(width);CHECKGLERROR
931 GL_Color(r,g,b,alpha);
940 void DrawQ_SetClipArea(float x, float y, float width, float height)
944 // We have to convert the con coords into real coords
945 // OGL uses top to bottom
946 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)));
948 GL_ScissorTest(true);
951 void DrawQ_ResetClipArea(void)
954 GL_ScissorTest(false);
957 void DrawQ_Finish(void)
959 r_refdef.draw2dstage = false;
962 static float blendvertex3f[9] = {-5000, -5000, 10, 10000, -5000, 10, -5000, 10000, 10};
963 void R_DrawGamma(void)
966 if (!vid_usinghwgamma)
968 // all the blends ignore depth
969 R_Mesh_VertexPointer(blendvertex3f, 0, 0);
970 R_Mesh_ColorPointer(NULL, 0, 0);
971 R_Mesh_ResetTextureState();
974 GL_PolygonOffset(0, 0);
976 if (v_color_enable.integer)
978 c[0] = v_color_white_r.value;
979 c[1] = v_color_white_g.value;
980 c[2] = v_color_white_b.value;
983 c[0] = c[1] = c[2] = v_contrast.value;
984 if (c[0] >= 1.01f || c[1] >= 1.01f || c[2] >= 1.01f)
986 GL_BlendFunc(GL_DST_COLOR, GL_ONE);
987 while (c[0] >= 1.01f || c[1] >= 1.01f || c[2] >= 1.01f)
989 GL_Color(bound(0, c[0] - 1, 1), bound(0, c[1] - 1, 1), bound(0, c[2] - 1, 1), 1);
990 R_Mesh_Draw(0, 3, 1, polygonelements, 0, 0);
991 VectorScale(c, 0.5, c);
994 if (v_color_enable.integer)
996 c[0] = v_color_black_r.value;
997 c[1] = v_color_black_g.value;
998 c[2] = v_color_black_b.value;
1001 c[0] = c[1] = c[2] = v_brightness.value;
1002 if (c[0] >= 0.01f || c[1] >= 0.01f || c[2] >= 0.01f)
1004 GL_BlendFunc(GL_ONE, GL_ONE);
1005 GL_Color(c[0], c[1], c[2], 1);
1006 R_Mesh_Draw(0, 3, 1, polygonelements, 0, 0);