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+1), 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)
307 unsigned char *lmpdata;
308 char lmpname[MAX_QPATH];
310 if (!strncmp(CLVIDEOPREFIX, path, sizeof(CLVIDEOPREFIX) - 1))
314 video = CL_GetVideoByName(path);
319 crc = CRC_Block((unsigned char *)path, strlen(path));
320 hashkey = ((crc >> 8) ^ crc) % CACHEPICHASHSIZE;
321 for (pic = cachepichash[hashkey];pic;pic = pic->chain)
322 if (!strcmp (path, pic->name))
325 if (numcachepics == MAX_CACHED_PICS)
327 Con_Printf ("Draw_CachePic: numcachepics == MAX_CACHED_PICS\n");
328 // FIXME: support NULL in callers?
329 return cachepics; // return the first one
331 pic = cachepics + (numcachepics++);
332 strlcpy (pic->name, path, sizeof(pic->name));
334 pic->chain = cachepichash[hashkey];
335 cachepichash[hashkey] = pic;
339 flags |= TEXF_PRECACHE;
340 if (!strcmp(path, "gfx/colorcontrol/ditherpattern"))
343 // load a high quality image from disk if possible
344 pic->tex = loadtextureimage(drawtexturepool, path, 0, 0, false, flags);
345 if (pic->tex == NULL && !strncmp(path, "gfx/", 4))
347 // compatibility with older versions which did not require gfx/ prefix
348 pic->tex = loadtextureimage(drawtexturepool, path + 4, 0, 0, false, flags);
350 // if a high quality image was loaded, set the pic's size to match it, just
351 // in case there's no low quality version to get the size from
354 pic->width = R_TextureWidth(pic->tex);
355 pic->height = R_TextureHeight(pic->tex);
358 // now read the low quality version (wad or lmp file), and take the pic
359 // size from that even if we don't upload the texture, this way the pics
360 // show up the right size in the menu even if they were replaced with
361 // higher or lower resolution versions
362 dpsnprintf(lmpname, sizeof(lmpname), "%s.lmp", path);
363 if (!strncmp(path, "gfx/", 4) && (lmpdata = FS_LoadFile(lmpname, tempmempool, false, &lmpsize)))
367 pic->width = lmpdata[0] + lmpdata[1] * 256 + lmpdata[2] * 65536 + lmpdata[3] * 16777216;
368 pic->height = lmpdata[4] + lmpdata[5] * 256 + lmpdata[6] * 65536 + lmpdata[7] * 16777216;
369 // if no high quality replacement image was found, upload the original low quality texture
371 pic->tex = R_LoadTexture2D(drawtexturepool, path, pic->width, pic->height, lmpdata + 8, TEXTYPE_PALETTE, flags, palette_transparent);
375 else if ((lmpdata = W_GetLumpName (path + 4)))
377 if (!strcmp(path, "gfx/conchars"))
379 // conchars is a raw image and with color 0 as transparent instead of 255
382 // if no high quality replacement image was found, upload the original low quality texture
384 pic->tex = R_LoadTexture2D(drawtexturepool, path, 128, 128, lmpdata, TEXTYPE_PALETTE, flags, palette_font);
388 pic->width = lmpdata[0] + lmpdata[1] * 256 + lmpdata[2] * 65536 + lmpdata[3] * 16777216;
389 pic->height = lmpdata[4] + lmpdata[5] * 256 + lmpdata[6] * 65536 + lmpdata[7] * 16777216;
390 // if no high quality replacement image was found, upload the original low quality texture
392 pic->tex = R_LoadTexture2D(drawtexturepool, path, pic->width, pic->height, lmpdata + 8, TEXTYPE_PALETTE, flags, palette_transparent);
396 // if it's not found on disk, check if it's one of the builtin images
397 if (pic->tex == NULL)
399 if (pic->tex == NULL && !strcmp(path, "gfx/conchars"))
400 pic->tex = draw_generateconchars();
401 if (pic->tex == NULL && !strcmp(path, "ui/mousepointer"))
402 pic->tex = draw_generatemousepointer();
403 if (pic->tex == NULL && !strcmp(path, "gfx/prydoncursor001"))
404 pic->tex = draw_generatemousepointer();
405 if (pic->tex == NULL && !strcmp(path, "gfx/crosshair1"))
406 pic->tex = draw_generatecrosshair(0);
407 if (pic->tex == NULL && !strcmp(path, "gfx/crosshair2"))
408 pic->tex = draw_generatecrosshair(1);
409 if (pic->tex == NULL && !strcmp(path, "gfx/crosshair3"))
410 pic->tex = draw_generatecrosshair(2);
411 if (pic->tex == NULL && !strcmp(path, "gfx/crosshair4"))
412 pic->tex = draw_generatecrosshair(3);
413 if (pic->tex == NULL && !strcmp(path, "gfx/crosshair5"))
414 pic->tex = draw_generatecrosshair(4);
415 if (pic->tex == NULL && !strcmp(path, "gfx/crosshair6"))
416 pic->tex = draw_generatecrosshair(5);
417 if (pic->tex == NULL && !strcmp(path, "gfx/colorcontrol/ditherpattern"))
418 pic->tex = draw_generateditherpattern();
419 if (pic->tex == NULL)
421 // don't complain about missing gfx/crosshair images
422 if (strncmp(path, "gfx/crosshair", 13))
423 Con_Printf("Draw_CachePic: failed to load %s\n", path);
424 pic->tex = r_texture_notexture;
426 pic->width = R_TextureWidth(pic->tex);
427 pic->height = R_TextureHeight(pic->tex);
433 cachepic_t *Draw_NewPic(const char *picname, int width, int height, int alpha, unsigned char *pixels)
438 crc = CRC_Block((unsigned char *)picname, strlen(picname));
439 hashkey = ((crc >> 8) ^ crc) % CACHEPICHASHSIZE;
440 for (pic = cachepichash[hashkey];pic;pic = pic->chain)
441 if (!strcmp (picname, pic->name))
446 if (pic->tex && pic->width == width && pic->height == height)
448 R_UpdateTexture(pic->tex, pixels, 0, 0, width, height);
456 if (numcachepics == MAX_CACHED_PICS)
458 Con_Printf ("Draw_NewPic: numcachepics == MAX_CACHED_PICS\n");
459 // FIXME: support NULL in callers?
460 return cachepics; // return the first one
462 pic = cachepics + (numcachepics++);
463 strlcpy (pic->name, picname, sizeof(pic->name));
465 pic->chain = cachepichash[hashkey];
466 cachepichash[hashkey] = pic;
471 pic->height = height;
473 R_FreeTexture(pic->tex);
474 pic->tex = R_LoadTexture2D(drawtexturepool, picname, width, height, pixels, TEXTYPE_RGBA, alpha ? TEXF_ALPHA : 0, NULL);
478 void Draw_FreePic(const char *picname)
483 // this doesn't really free the pic, but does free it's texture
484 crc = CRC_Block((unsigned char *)picname, strlen(picname));
485 hashkey = ((crc >> 8) ^ crc) % CACHEPICHASHSIZE;
486 for (pic = cachepichash[hashkey];pic;pic = pic->chain)
488 if (!strcmp (picname, pic->name) && pic->tex)
490 R_FreeTexture(pic->tex);
503 static void gl_draw_start(void)
506 drawtexturepool = R_AllocTexturePool();
509 memset(cachepichash, 0, sizeof(cachepichash));
511 char_texture = Draw_CachePic("gfx/conchars", true)->tex;
512 for (i = 1;i <= NUMCROSSHAIRS;i++)
513 r_crosshairs[i] = Draw_CachePic(va("gfx/crosshair%i", i), true);
516 static void gl_draw_shutdown(void)
518 R_FreeTexturePool(&drawtexturepool);
521 memset(cachepichash, 0, sizeof(cachepichash));
524 static void gl_draw_newmap(void)
528 void GL_Draw_Init (void)
530 Cvar_RegisterVariable(&r_textshadow);
531 R_RegisterModule("GL_Draw", gl_draw_start, gl_draw_shutdown, gl_draw_newmap);
534 static void _DrawQ_Setup(void)
536 if (r_refdef.draw2dstage)
538 r_refdef.draw2dstage = true;
540 qglViewport(r_view.x, vid.height - (r_view.y + r_view.height), r_view.width, r_view.height);CHECKGLERROR
541 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
542 GL_SetupView_Mode_Ortho(0, 0, vid_conwidth.integer, vid_conheight.integer, -10, 100);
543 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
544 qglDisable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
545 R_Mesh_Matrix(&identitymatrix);
551 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
553 if (gl_support_fragment_shader)
555 qglUseProgramObjectARB(0);CHECKGLERROR
559 static void _DrawQ_ProcessDrawFlag(int flags)
563 if(flags == DRAWFLAG_ADDITIVE)
564 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
565 else if(flags == DRAWFLAG_MODULATE)
566 GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
567 else if(flags == DRAWFLAG_2XMODULATE)
568 GL_BlendFunc(GL_DST_COLOR,GL_SRC_COLOR);
570 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
573 void DrawQ_Pic(float x, float y, cachepic_t *pic, float width, float height, float red, float green, float blue, float alpha, int flags)
575 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);
578 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)
583 float vertex3f[QUADELEMENTS_MAXQUADS*4*3];
584 float texcoord2f[QUADELEMENTS_MAXQUADS*4*2];
586 if (alpha < (1.0f / 255.0f))
589 _DrawQ_ProcessDrawFlag(flags);
591 GL_Color(red, green, blue, alpha);
593 R_Mesh_VertexPointer(vertex3f);
594 R_Mesh_ColorPointer(NULL);
595 R_Mesh_ResetTextureState();
596 R_Mesh_TexBind(0, R_GetTexture(char_texture));
597 R_Mesh_TexCoordPointer(0, 2, texcoord2f);
605 for (i = 0;i < maxlen && x < vid_conwidth.integer && (num = string[i]);i++, x += w)
610 s = (num & 15)*0.0625f + (0.5f / 256.0f);
611 t = (num >> 4)*0.0625f + (0.5f / 256.0f);
612 u = 0.0625f - (1.0f / 256.0f);
613 v = 0.0625f - (1.0f / 256.0f);
614 at[ 0] = s ;at[ 1] = t ;
615 at[ 2] = s+u;at[ 3] = t ;
616 at[ 4] = s+u;at[ 5] = t+v;
617 at[ 6] = s ;at[ 7] = t+v;
618 av[ 0] = x ;av[ 1] = y ;av[ 2] = 10;
619 av[ 3] = x+w;av[ 4] = y ;av[ 5] = 10;
620 av[ 6] = x+w;av[ 7] = y+h;av[ 8] = 10;
621 av[ 9] = x ;av[10] = y+h;av[11] = 10;
625 if (batchcount >= QUADELEMENTS_MAXQUADS)
627 GL_LockArrays(0, batchcount * 4);
628 R_Mesh_Draw(0, batchcount * 4, batchcount * 2, quadelements);
637 GL_LockArrays(0, batchcount * 4);
638 R_Mesh_Draw(0, batchcount * 4, batchcount * 2, quadelements);
643 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)
645 if (r_textshadow.integer)
646 DrawQ_String_Real(x+scalex*0.25,y+scaley*0.25,string,maxlen,scalex,scaley,0,0,0,alpha*0.8,flags);
648 DrawQ_String_Real(x,y,string,maxlen,scalex,scaley,red,green,blue,alpha,flags);
651 // color tag printing
652 static vec4_t string_colors[] =
655 // LordHavoc: why on earth is cyan before magenta in Quake3?
656 // LordHavoc: note: Doom3 uses white for [0] and [7]
657 {0.0, 0.0, 0.0, 1.0}, // black
658 {1.0, 0.0, 0.0, 1.0}, // red
659 {0.0, 1.0, 0.0, 1.0}, // green
660 {1.0, 1.0, 0.0, 1.0}, // yellow
661 {0.0, 0.0, 1.0, 1.0}, // blue
662 {0.0, 1.0, 1.0, 1.0}, // cyan
663 {1.0, 0.0, 1.0, 1.0}, // magenta
664 {1.0, 1.0, 1.0, 1.0}, // white
665 // [515]'s BX_COLOREDTEXT extension
666 {1.0, 1.0, 1.0, 0.5}, // half transparent
667 {0.5, 0.5, 0.5, 1.0} // half brightness
668 // Black's color table
669 //{1.0, 1.0, 1.0, 1.0},
670 //{1.0, 0.0, 0.0, 1.0},
671 //{0.0, 1.0, 0.0, 1.0},
672 //{0.0, 0.0, 1.0, 1.0},
673 //{1.0, 1.0, 0.0, 1.0},
674 //{0.0, 1.0, 1.0, 1.0},
675 //{1.0, 0.0, 1.0, 1.0},
676 //{0.1, 0.1, 0.1, 1.0}
679 #define STRING_COLORS_COUNT (sizeof(string_colors) / sizeof(vec4_t))
681 // color is read and changed in the end
682 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 )
687 const char *start, *current;
689 if( !outcolor || *outcolor == -1 ) {
690 colorindex = STRING_COLOR_DEFAULT;
692 colorindex = *outcolor;
694 color = string_colors[colorindex];
697 len = (int)strlen( text );
699 len = min( maxlen, (int) strlen( text ) );
701 start = current = text;
703 // check for color control char
704 if( *current == STRING_COLOR_TAG ) {
711 // display the tag char?
712 if( *current == STRING_COLOR_TAG ) {
713 // only display one of the two
718 } else if( '0' <= *current && *current <= '9' ) {
721 colorindex = colorindex * 10 + (*current - '0');
722 // only read as long as it makes a valid index
723 if( colorindex >= (int)STRING_COLORS_COUNT ) {
724 // undo the last operation
730 } while( len > 0 && '0' <= *current && *current <= '9' );
732 color = string_colors[colorindex];
733 // we jump over the color tag
737 // go on and read normal text in until the next control char
738 while( len > 0 && *current != STRING_COLOR_TAG ) {
743 if( start != current ) {
745 DrawQ_String( x, y, start, current - start, scalex, scaley, basered * color[0], basegreen * color[1], baseblue * color[2], basealpha * color[3], flags );
746 // update x to be at the new start position
747 x += (current - start) * scalex;
748 // set start accordingly
753 // return the last colorindex
755 *outcolor = colorindex;
759 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)
763 _DrawQ_ProcessDrawFlag(flags);
765 R_Mesh_VertexPointer(floats);
766 R_Mesh_ColorPointer(floats + 20);
767 R_Mesh_ResetTextureState();
773 height = pic->height;
774 R_Mesh_TexBind(0, R_GetTexture(pic->tex));
775 R_Mesh_TexCoordPointer(0, 2, floats + 12);
776 floats[12] = s1;floats[13] = t1;
777 floats[14] = s2;floats[15] = t2;
778 floats[16] = s4;floats[17] = t4;
779 floats[18] = s3;floats[19] = t3;
782 floats[2] = floats[5] = floats[8] = floats[11] = 0;
783 floats[0] = floats[9] = x;
784 floats[1] = floats[4] = y;
785 floats[3] = floats[6] = x + width;
786 floats[7] = floats[10] = y + height;
787 floats[20] = r1;floats[21] = g1;floats[22] = b1;floats[23] = a1;
788 floats[24] = r2;floats[25] = g2;floats[26] = b2;floats[27] = a2;
789 floats[28] = r4;floats[29] = g4;floats[30] = b4;floats[31] = a4;
790 floats[32] = r3;floats[33] = g3;floats[34] = b3;floats[35] = a3;
792 R_Mesh_Draw(0, 4, 2, polygonelements);
795 void DrawQ_Mesh (drawqueuemesh_t *mesh, int flags)
797 _DrawQ_ProcessDrawFlag(flags);
799 R_Mesh_VertexPointer(mesh->data_vertex3f);
800 R_Mesh_ColorPointer(mesh->data_color4f);
801 R_Mesh_ResetTextureState();
802 R_Mesh_TexBind(0, R_GetTexture(mesh->texture));
803 R_Mesh_TexCoordPointer(0, 2, mesh->data_texcoord2f);
805 GL_LockArrays(0, mesh->num_vertices);
806 R_Mesh_Draw(0, mesh->num_vertices, mesh->num_triangles, mesh->data_element3i);
810 void DrawQ_LineLoop (drawqueuemesh_t *mesh, int flags)
814 _DrawQ_ProcessDrawFlag(flags);
818 qglBegin(GL_LINE_LOOP);
819 for (num = 0;num < mesh->num_vertices;num++)
821 if (mesh->data_color4f)
822 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]);
823 qglVertex2f(mesh->data_vertex3f[num*3+0], mesh->data_vertex3f[num*3+1]);
829 //[515]: this is old, delete
830 void DrawQ_Line (float width, float x1, float y1, float x2, float y2, float r, float g, float b, float alpha, int flags)
832 _DrawQ_ProcessDrawFlag(flags);
835 qglLineWidth(width);CHECKGLERROR
837 GL_Color(r,g,b,alpha);
846 void DrawQ_SetClipArea(float x, float y, float width, float height)
850 // We have to convert the con coords into real coords
851 // OGL uses top to bottom
852 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)));
854 GL_ScissorTest(true);
857 void DrawQ_ResetClipArea(void)
860 GL_ScissorTest(false);
863 void DrawQ_Finish(void)
865 r_refdef.draw2dstage = false;
868 static float blendvertex3f[9] = {-5000, -5000, 10, 10000, -5000, 10, -5000, 10000, 10};
869 void R_DrawGamma(void)
872 if (!vid_usinghwgamma)
874 // all the blends ignore depth
875 R_Mesh_VertexPointer(blendvertex3f);
876 R_Mesh_ColorPointer(NULL);
877 R_Mesh_ResetTextureState();
880 if (v_color_enable.integer)
882 c[0] = v_color_white_r.value;
883 c[1] = v_color_white_g.value;
884 c[2] = v_color_white_b.value;
887 c[0] = c[1] = c[2] = v_contrast.value;
888 if (c[0] >= 1.01f || c[1] >= 1.01f || c[2] >= 1.01f)
890 GL_BlendFunc(GL_DST_COLOR, GL_ONE);
891 while (c[0] >= 1.01f || c[1] >= 1.01f || c[2] >= 1.01f)
893 GL_Color(bound(0, c[0] - 1, 1), bound(0, c[1] - 1, 1), bound(0, c[2] - 1, 1), 1);
894 R_Mesh_Draw(0, 3, 1, polygonelements);
895 VectorScale(c, 0.5, c);
898 if (v_color_enable.integer)
900 c[0] = v_color_black_r.value;
901 c[1] = v_color_black_g.value;
902 c[2] = v_color_black_b.value;
905 c[0] = c[1] = c[2] = v_brightness.value;
906 if (c[0] >= 0.01f || c[1] >= 0.01f || c[2] >= 0.01f)
908 GL_BlendFunc(GL_ONE, GL_ONE);
909 GL_Color(c[0], c[1], c[2], 1);
910 R_Mesh_Draw(0, 3, 1, polygonelements);