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.
27 cvar_t r_textshadow = {0, "r_textshadow", "0", "draws a shadow on all text to improve readability"};
29 static rtexture_t *char_texture;
30 cachepic_t *r_crosshairs[NUMCROSSHAIRS+1];
32 //=============================================================================
33 /* Support Routines */
35 #define FONT_FILESIZE 13468
36 #define MAX_CACHED_PICS 1024
37 #define CACHEPICHASHSIZE 256
38 static cachepic_t *cachepichash[CACHEPICHASHSIZE];
39 static cachepic_t cachepics[MAX_CACHED_PICS];
40 static int numcachepics;
42 static rtexturepool_t *drawtexturepool;
44 static unsigned char concharimage[FONT_FILESIZE] =
49 static rtexture_t *draw_generateconchars(void)
52 unsigned char buffer[65536][4], *data = NULL;
55 data = LoadTGA (concharimage, FONT_FILESIZE, 256, 256);
57 for (i = 0;i < 8192;i++)
59 random = lhrandom (0.0,1.0);
60 buffer[i][0] = 83 + (unsigned char)(random * 64);
61 buffer[i][1] = 71 + (unsigned char)(random * 32);
62 buffer[i][2] = 23 + (unsigned char)(random * 16);
63 buffer[i][3] = data[i*4+0];
66 for (i = 8192;i < 32768;i++)
68 random = lhrandom (0.0,1.0);
69 buffer[i][0] = 95 + (unsigned char)(random * 64);
70 buffer[i][1] = 95 + (unsigned char)(random * 64);
71 buffer[i][2] = 95 + (unsigned char)(random * 64);
72 buffer[i][3] = data[i*4+0];
75 for (i = 32768;i < 40960;i++)
77 random = lhrandom (0.0,1.0);
78 buffer[i][0] = 83 + (unsigned char)(random * 64);
79 buffer[i][1] = 71 + (unsigned char)(random * 32);
80 buffer[i][2] = 23 + (unsigned char)(random * 16);
81 buffer[i][3] = data[i*4+0];
84 for (i = 40960;i < 65536;i++)
86 random = lhrandom (0.0,1.0);
87 buffer[i][0] = 96 + (unsigned char)(random * 64);
88 buffer[i][1] = 43 + (unsigned char)(random * 32);
89 buffer[i][2] = 27 + (unsigned char)(random * 32);
90 buffer[i][3] = data[i*4+0];
94 Image_WriteTGARGBA ("gfx/generated_conchars.tga", 256, 256, &buffer[0][0]);
98 return R_LoadTexture2D(drawtexturepool, "conchars", 256, 256, &buffer[0][0], TEXTYPE_RGBA, TEXF_ALPHA | TEXF_PRECACHE, NULL);
101 static char *pointerimage =
120 static rtexture_t *draw_generatemousepointer(void)
123 unsigned char buffer[256][4];
124 for (i = 0;i < 256;i++)
126 if (pointerimage[i] == '.')
135 buffer[i][0] = (pointerimage[i] - '0') * 16;
136 buffer[i][1] = (pointerimage[i] - '0') * 16;
137 buffer[i][2] = (pointerimage[i] - '0') * 16;
141 return R_LoadTexture2D(drawtexturepool, "mousepointer", 16, 16, &buffer[0][0], TEXTYPE_RGBA, TEXF_ALPHA | TEXF_PRECACHE, NULL);
144 static char *crosshairtexdata[NUMCROSSHAIRS] =
249 static rtexture_t *draw_generatecrosshair(int num)
253 unsigned char data[16*16][4];
254 in = crosshairtexdata[num];
255 for (i = 0;i < 16*16;i++)
266 data[i][0] = data[i][1] = data[i][2] = (unsigned char) ((int) (in[i] - '0') * 127 / 7 + 128);
270 return R_LoadTexture2D(drawtexturepool, va("crosshair%i", num), 16, 16, &data[0][0], TEXTYPE_RGBA, TEXF_ALPHA | TEXF_PRECACHE, NULL);
273 static rtexture_t *draw_generateditherpattern(void)
277 unsigned char data[8*8*4];
278 for (y = 0;y < 8;y++)
280 for (x = 0;x < 8;x++)
282 data[(y*8+x)*4+0] = data[(y*8+x)*4+1] = data[(y*8+x)*4+2] = ((x^y) & 4) ? 255 : 0;
283 data[(y*8+x)*4+3] = 255;
286 return R_LoadTexture2D(drawtexturepool, "ditherpattern", 8, 8, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_PRECACHE, NULL);
288 unsigned char data[16];
289 memset(data, 255, sizeof(data));
290 data[0] = data[1] = data[2] = data[12] = data[13] = data[14] = 0;
291 return R_LoadTexture2D(drawtexturepool, "ditherpattern", 2, 2, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_PRECACHE, NULL);
300 // FIXME: move this to client somehow
301 cachepic_t *Draw_CachePic (const char *path, qboolean persistent)
308 if (!strncmp(CLVIDEOPREFIX, path, sizeof(CLVIDEOPREFIX) - 1))
312 video = CL_GetVideoByName(path);
317 crc = CRC_Block((unsigned char *)path, strlen(path));
318 hashkey = ((crc >> 8) ^ crc) % CACHEPICHASHSIZE;
319 for (pic = cachepichash[hashkey];pic;pic = pic->chain)
320 if (!strcmp (path, pic->name))
323 if (numcachepics == MAX_CACHED_PICS)
325 Con_Printf ("Draw_CachePic: numcachepics == MAX_CACHED_PICS\n");
326 // FIXME: support NULL in callers?
327 return cachepics; // return the first one
329 pic = cachepics + (numcachepics++);
330 strlcpy (pic->name, path, sizeof(pic->name));
332 pic->chain = cachepichash[hashkey];
333 cachepichash[hashkey] = pic;
337 flags |= TEXF_PRECACHE;
338 if (!strcmp(path, "gfx/colorcontrol/ditherpattern"))
341 // load the pic from disk
342 pic->tex = loadtextureimage(drawtexturepool, path, 0, 0, false, flags);
343 if (pic->tex == NULL && !strncmp(path, "gfx/", 4))
345 // compatibility with older versions
346 pic->tex = loadtextureimage(drawtexturepool, path + 4, 0, 0, false, flags);
347 // failed to find gfx/whatever.tga or similar, try the wad
348 if (pic->tex == NULL && (p = (qpic_t *)W_GetLumpName (path + 4)))
350 if (!strcmp(path, "gfx/conchars"))
352 // conchars is a raw image and with color 0 as transparent instead of 255
353 pic->tex = R_LoadTexture2D(drawtexturepool, path, 128, 128, (unsigned char *)p, TEXTYPE_PALETTE, flags, palette_font);
356 pic->tex = R_LoadTexture2D(drawtexturepool, path, p->width, p->height, p->data, TEXTYPE_PALETTE, flags, palette_transparent);
360 if (pic->tex == NULL && !strcmp(path, "gfx/conchars"))
361 pic->tex = draw_generateconchars();
362 if (pic->tex == NULL && !strcmp(path, "ui/mousepointer"))
363 pic->tex = draw_generatemousepointer();
364 if (pic->tex == NULL && !strcmp(path, "gfx/prydoncursor001"))
365 pic->tex = draw_generatemousepointer();
366 if (pic->tex == NULL && !strcmp(path, "gfx/crosshair1"))
367 pic->tex = draw_generatecrosshair(0);
368 if (pic->tex == NULL && !strcmp(path, "gfx/crosshair2"))
369 pic->tex = draw_generatecrosshair(1);
370 if (pic->tex == NULL && !strcmp(path, "gfx/crosshair3"))
371 pic->tex = draw_generatecrosshair(2);
372 if (pic->tex == NULL && !strcmp(path, "gfx/crosshair4"))
373 pic->tex = draw_generatecrosshair(3);
374 if (pic->tex == NULL && !strcmp(path, "gfx/crosshair5"))
375 pic->tex = draw_generatecrosshair(4);
376 if (pic->tex == NULL && !strcmp(path, "gfx/crosshair6"))
377 pic->tex = draw_generatecrosshair(5);
378 if (pic->tex == NULL && !strcmp(path, "gfx/colorcontrol/ditherpattern"))
379 pic->tex = draw_generateditherpattern();
380 if (pic->tex == NULL)
382 Con_Printf("Draw_CachePic: failed to load %s\n", path);
383 pic->tex = r_texture_notexture;
386 pic->width = R_TextureWidth(pic->tex);
387 pic->height = R_TextureHeight(pic->tex);
391 cachepic_t *Draw_NewPic(const char *picname, int width, int height, int alpha, unsigned char *pixels)
396 crc = CRC_Block((unsigned char *)picname, strlen(picname));
397 hashkey = ((crc >> 8) ^ crc) % CACHEPICHASHSIZE;
398 for (pic = cachepichash[hashkey];pic;pic = pic->chain)
399 if (!strcmp (picname, pic->name))
404 if (pic->tex && pic->width == width && pic->height == height)
406 R_UpdateTexture(pic->tex, pixels, 0, 0, width, height);
414 if (numcachepics == MAX_CACHED_PICS)
416 Con_Printf ("Draw_NewPic: numcachepics == MAX_CACHED_PICS\n");
417 // FIXME: support NULL in callers?
418 return cachepics; // return the first one
420 pic = cachepics + (numcachepics++);
421 strcpy (pic->name, picname);
423 pic->chain = cachepichash[hashkey];
424 cachepichash[hashkey] = pic;
429 pic->height = height;
431 R_FreeTexture(pic->tex);
432 pic->tex = R_LoadTexture2D(drawtexturepool, picname, width, height, pixels, TEXTYPE_RGBA, alpha ? TEXF_ALPHA : 0, NULL);
436 void Draw_FreePic(const char *picname)
441 // this doesn't really free the pic, but does free it's texture
442 crc = CRC_Block((unsigned char *)picname, strlen(picname));
443 hashkey = ((crc >> 8) ^ crc) % CACHEPICHASHSIZE;
444 for (pic = cachepichash[hashkey];pic;pic = pic->chain)
446 if (!strcmp (picname, pic->name) && pic->tex)
448 R_FreeTexture(pic->tex);
461 static void gl_draw_start(void)
464 drawtexturepool = R_AllocTexturePool();
467 memset(cachepichash, 0, sizeof(cachepichash));
469 char_texture = Draw_CachePic("gfx/conchars", true)->tex;
470 for (i = 1;i <= NUMCROSSHAIRS;i++)
471 r_crosshairs[i] = Draw_CachePic(va("gfx/crosshair%i", i), true);
474 static void gl_draw_shutdown(void)
476 R_FreeTexturePool(&drawtexturepool);
479 memset(cachepichash, 0, sizeof(cachepichash));
482 static void gl_draw_newmap(void)
486 void GL_Draw_Init (void)
488 Cvar_RegisterVariable(&r_textshadow);
489 R_RegisterModule("GL_Draw", gl_draw_start, gl_draw_shutdown, gl_draw_newmap);
492 void DrawQ_Begin(void)
494 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
497 qglViewport(r_view.x, vid.height - (r_view.y + r_view.height), r_view.width, r_view.height);CHECKGLERROR
498 GL_SetupView_Mode_Ortho(0, 0, vid_conwidth.integer, vid_conheight.integer, -10, 100);
499 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
500 R_Mesh_Matrix(&identitymatrix);
506 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
508 r_refdef.draw2dstage = true;
511 static void _DrawQ_ProcessDrawFlag(int flags)
514 if(flags == DRAWFLAG_ADDITIVE)
515 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
516 else if(flags == DRAWFLAG_MODULATE)
517 GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
518 else if(flags == DRAWFLAG_2XMODULATE)
519 GL_BlendFunc(GL_DST_COLOR,GL_SRC_COLOR);
521 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
524 void DrawQ_Pic(float x, float y, cachepic_t *pic, float width, float height, float red, float green, float blue, float alpha, int flags)
526 if (!r_refdef.draw2dstage)
528 Con_Printf("DrawQ_Pic: not in 2d rendering stage!\n");
531 DrawQ_SuperPic(x,y,pic,width,height,0,0,red,green,blue,alpha,1,0,red,green,blue,alpha,0,1,red,green,blue,alpha,1,1,red,green,blue,alpha,flags);
534 void DrawQ_String_Real(float x, float y, const char *string, int maxlen, float w, float h, float red, float green, float blue, float alpha, int flags)
539 float vertex3f[QUADELEMENTS_MAXQUADS*4*3];
540 float texcoord2f[QUADELEMENTS_MAXQUADS*4*2];
542 if (!r_refdef.draw2dstage)
544 Con_Printf("DrawQ_String: not in 2d rendering stage!\n");
548 if (alpha < (1.0f / 255.0f))
551 _DrawQ_ProcessDrawFlag(flags);
553 GL_Color(red, green, blue, alpha);
555 R_Mesh_VertexPointer(vertex3f);
556 R_Mesh_ColorPointer(NULL);
557 R_Mesh_ResetTextureState();
558 R_Mesh_TexBind(0, R_GetTexture(char_texture));
559 R_Mesh_TexCoordPointer(0, 2, texcoord2f);
567 for (i = 0;i < maxlen && x < vid_conwidth.integer && (num = string[i]);i++, x += w)
572 s = (num & 15)*0.0625f + (0.5f / 256.0f);
573 t = (num >> 4)*0.0625f + (0.5f / 256.0f);
574 u = 0.0625f - (1.0f / 256.0f);
575 v = 0.0625f - (1.0f / 256.0f);
576 at[ 0] = s ;at[ 1] = t ;
577 at[ 2] = s+u;at[ 3] = t ;
578 at[ 4] = s+u;at[ 5] = t+v;
579 at[ 6] = s ;at[ 7] = t+v;
580 av[ 0] = x ;av[ 1] = y ;av[ 2] = 10;
581 av[ 3] = x+w;av[ 4] = y ;av[ 5] = 10;
582 av[ 6] = x+w;av[ 7] = y+h;av[ 8] = 10;
583 av[ 9] = x ;av[10] = y+h;av[11] = 10;
587 if (batchcount >= QUADELEMENTS_MAXQUADS)
589 GL_LockArrays(0, batchcount * 4);
590 R_Mesh_Draw(0, batchcount * 4, batchcount * 2, quadelements);
599 GL_LockArrays(0, batchcount * 4);
600 R_Mesh_Draw(0, batchcount * 4, batchcount * 2, quadelements);
605 void DrawQ_String(float x, float y, const char *string, int maxlen, float scalex, float scaley, float red, float green, float blue, float alpha, int flags)
607 if (!r_refdef.draw2dstage)
609 Con_Printf("DrawQ_String: not in 2d rendering stage!\n");
613 if (r_textshadow.integer)
614 DrawQ_String_Real(x+scalex*0.25,y+scaley*0.25,string,maxlen,scalex,scaley,0,0,0,alpha*0.8,flags);
616 DrawQ_String_Real(x,y,string,maxlen,scalex,scaley,red,green,blue,alpha,flags);
619 // color tag printing
620 static vec4_t string_colors[] =
623 // LordHavoc: why on earth is cyan before magenta in Quake3?
624 // LordHavoc: note: Doom3 uses white for [0] and [7]
625 {0.0, 0.0, 0.0, 1.0}, // black
626 {1.0, 0.0, 0.0, 1.0}, // red
627 {0.0, 1.0, 0.0, 1.0}, // green
628 {1.0, 1.0, 0.0, 1.0}, // yellow
629 {0.0, 0.0, 1.0, 1.0}, // blue
630 {0.0, 1.0, 1.0, 1.0}, // cyan
631 {1.0, 0.0, 1.0, 1.0}, // magenta
632 {1.0, 1.0, 1.0, 1.0}, // white
633 // [515]'s BX_COLOREDTEXT extension
634 {1.0, 1.0, 1.0, 0.5}, // half transparent
635 {0.5, 0.5, 0.5, 1.0} // half brightness
636 // Black's color table
637 //{1.0, 1.0, 1.0, 1.0},
638 //{1.0, 0.0, 0.0, 1.0},
639 //{0.0, 1.0, 0.0, 1.0},
640 //{0.0, 0.0, 1.0, 1.0},
641 //{1.0, 1.0, 0.0, 1.0},
642 //{0.0, 1.0, 1.0, 1.0},
643 //{1.0, 0.0, 1.0, 1.0},
644 //{0.1, 0.1, 0.1, 1.0}
647 #define STRING_COLORS_COUNT (sizeof(string_colors) / sizeof(vec4_t))
649 // color is read and changed in the end
650 void DrawQ_ColoredString( float x, float y, const char *text, int maxlen, float scalex, float scaley, float basered, float basegreen, float baseblue, float basealpha, int flags, int *outcolor )
655 const char *start, *current;
657 if (!r_refdef.draw2dstage)
659 Con_Printf("DrawQ_ColoredString: not in 2d rendering stage!\n");
662 if( !outcolor || *outcolor == -1 ) {
663 colorindex = STRING_COLOR_DEFAULT;
665 colorindex = *outcolor;
667 color = string_colors[colorindex];
670 len = (int)strlen( text );
672 len = min( maxlen, (int) strlen( text ) );
674 start = current = text;
676 // check for color control char
677 if( *current == STRING_COLOR_TAG ) {
684 // display the tag char?
685 if( *current == STRING_COLOR_TAG ) {
686 // only display one of the two
691 } else if( '0' <= *current && *current <= '9' ) {
694 colorindex = colorindex * 10 + (*current - '0');
695 // only read as long as it makes a valid index
696 if( colorindex >= (int)STRING_COLORS_COUNT ) {
697 // undo the last operation
703 } while( len > 0 && '0' <= *current && *current <= '9' );
705 color = string_colors[colorindex];
706 // we jump over the color tag
710 // go on and read normal text in until the next control char
711 while( len > 0 && *current != STRING_COLOR_TAG ) {
716 if( start != current ) {
718 DrawQ_String( x, y, start, current - start, scalex, scaley, basered * color[0], basegreen * color[1], baseblue * color[2], basealpha * color[3], flags );
719 // update x to be at the new start position
720 x += (current - start) * scalex;
721 // set start accordingly
726 // return the last colorindex
728 *outcolor = colorindex;
732 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)
736 if (!r_refdef.draw2dstage)
738 Con_Printf("DrawQ_SuperPic: not in 2d rendering stage!\n");
742 _DrawQ_ProcessDrawFlag(flags);
744 R_Mesh_VertexPointer(floats);
745 R_Mesh_ColorPointer(floats + 20);
746 R_Mesh_ResetTextureState();
752 height = pic->height;
753 R_Mesh_TexBind(0, R_GetTexture(pic->tex));
754 R_Mesh_TexCoordPointer(0, 2, floats + 12);
755 floats[12] = s1;floats[13] = t1;
756 floats[14] = s2;floats[15] = t2;
757 floats[16] = s4;floats[17] = t4;
758 floats[18] = s3;floats[19] = t3;
761 floats[2] = floats[5] = floats[8] = floats[11] = 0;
762 floats[0] = floats[9] = x;
763 floats[1] = floats[4] = y;
764 floats[3] = floats[6] = x + width;
765 floats[7] = floats[10] = y + height;
766 floats[20] = r1;floats[21] = g1;floats[22] = b1;floats[23] = a1;
767 floats[24] = r2;floats[25] = g2;floats[26] = b2;floats[27] = a2;
768 floats[28] = r4;floats[29] = g4;floats[30] = b4;floats[31] = a4;
769 floats[32] = r3;floats[33] = g3;floats[34] = b3;floats[35] = a3;
771 R_Mesh_Draw(0, 4, 2, polygonelements);
774 void DrawQ_Mesh (drawqueuemesh_t *mesh, int flags)
776 if (!r_refdef.draw2dstage)
778 Con_Printf("DrawQ_Mesh: not in 2d rendering stage!\n");
782 _DrawQ_ProcessDrawFlag(flags);
784 R_Mesh_VertexPointer(mesh->data_vertex3f);
785 R_Mesh_ColorPointer(mesh->data_color4f);
786 R_Mesh_ResetTextureState();
787 R_Mesh_TexBind(0, R_GetTexture(mesh->texture));
788 R_Mesh_TexCoordPointer(0, 2, mesh->data_texcoord2f);
790 GL_LockArrays(0, mesh->num_vertices);
791 R_Mesh_Draw(0, mesh->num_vertices, mesh->num_triangles, mesh->data_element3i);
795 void DrawQ_LineLoop (drawqueuemesh_t *mesh, int flags)
799 if (!r_refdef.draw2dstage)
801 Con_Printf("DrawQ_LineLoop: not in 2d rendering stage!\n");
805 _DrawQ_ProcessDrawFlag(flags);
809 qglBegin(GL_LINE_LOOP);
810 for (num = 0;num < mesh->num_vertices;num++)
812 if (mesh->data_color4f)
813 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]);
814 qglVertex2f(mesh->data_vertex3f[num*3+0], mesh->data_vertex3f[num*3+1]);
820 //LordHavoc: FIXME: this is nasty!
821 void DrawQ_LineWidth (float width)
823 if (!r_refdef.draw2dstage)
825 Con_Printf("DrawQ_LineWidth: not in 2d rendering stage!\n");
829 qglLineWidth(width);CHECKGLERROR
832 //[515]: this is old, delete
833 void DrawQ_Line (float width, float x1, float y1, float x2, float y2, float r, float g, float b, float alpha, int flags)
835 if (!r_refdef.draw2dstage)
837 Con_Printf("DrawQ_Line: not in 2d rendering stage!\n");
843 DrawQ_LineWidth(width);
845 _DrawQ_ProcessDrawFlag(flags);
847 GL_Color(r,g,b,alpha);
856 void DrawQ_SetClipArea(float x, float y, float width, float height)
858 if (!r_refdef.draw2dstage)
860 Con_Printf("DrawQ_SetClipArea: not in 2d rendering stage!\n");
864 // We have to convert the con coords into real coords
865 // OGL uses top to bottom
866 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)));
868 GL_ScissorTest(true);
871 void DrawQ_ResetClipArea(void)
873 if (!r_refdef.draw2dstage)
875 Con_Printf("DrawQ_ResetClipArea: not in 2d rendering stage!\n");
878 GL_ScissorTest(false);
881 void DrawQ_Finish(void)
883 if (!r_refdef.draw2dstage)
885 Con_Printf("R_DrawQueue: not in 2d rendering stage!\n");
889 r_refdef.draw2dstage = false;
892 static float blendvertex3f[9] = {-5000, -5000, 10, 10000, -5000, 10, -5000, 10000, 10};
893 void R_DrawGamma(void)
896 if (!vid_usinghwgamma)
898 // all the blends ignore depth
899 R_Mesh_VertexPointer(blendvertex3f);
900 R_Mesh_ColorPointer(NULL);
901 R_Mesh_ResetTextureState();
904 if (v_color_enable.integer)
906 c[0] = v_color_white_r.value;
907 c[1] = v_color_white_g.value;
908 c[2] = v_color_white_b.value;
911 c[0] = c[1] = c[2] = v_contrast.value;
912 if (c[0] >= 1.01f || c[1] >= 1.01f || c[2] >= 1.01f)
914 GL_BlendFunc(GL_DST_COLOR, GL_ONE);
915 while (c[0] >= 1.01f || c[1] >= 1.01f || c[2] >= 1.01f)
917 GL_Color(bound(0, c[0] - 1, 1), bound(0, c[1] - 1, 1), bound(0, c[2] - 1, 1), 1);
918 R_Mesh_Draw(0, 3, 1, polygonelements);
919 VectorScale(c, 0.5, c);
922 if (v_color_enable.integer)
924 c[0] = v_color_black_r.value;
925 c[1] = v_color_black_g.value;
926 c[2] = v_color_black_b.value;
929 c[0] = c[1] = c[2] = v_brightness.value;
930 if (c[0] >= 0.01f || c[1] >= 0.01f || c[2] >= 0.01f)
932 GL_BlendFunc(GL_ONE, GL_ONE);
933 GL_Color(c[0], c[1], c[2], 1);
934 R_Mesh_Draw(0, 3, 1, polygonelements);