]> icculus.org git repositories - divverent/darkplaces.git/blob - gl_draw.c
nexuiz team scoreboard patch from esteel
[divverent/darkplaces.git] / gl_draw.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
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.
8
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.
12
13 See the GNU General Public License for more details.
14
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.
18
19 */
20
21 #include "quakedef.h"
22 #include "image.h"
23 #include "wad.h"
24
25 #include "cl_video.h"
26
27
28 static rtexture_t *char_texture;
29
30 //=============================================================================
31 /* Support Routines */
32
33 #define FONT_FILESIZE 13468
34 #define MAX_CACHED_PICS 1024
35 #define CACHEPICHASHSIZE 256
36 static cachepic_t *cachepichash[CACHEPICHASHSIZE];
37 static cachepic_t cachepics[MAX_CACHED_PICS];
38 static int numcachepics;
39
40 static rtexturepool_t *drawtexturepool;
41
42 static unsigned char concharimage[FONT_FILESIZE] =
43 {
44 #include "lhfont.h"
45 };
46
47 static rtexture_t *draw_generateconchars(void)
48 {
49         int i;
50         unsigned char buffer[65536][4], *data = NULL;
51         double random;
52
53         data = LoadTGA (concharimage, FONT_FILESIZE, 256, 256);
54 // Gold numbers
55         for (i = 0;i < 8192;i++)
56         {
57                 random = lhrandom (0.0,1.0);
58                 buffer[i][0] = 83 + (unsigned char)(random * 64);
59                 buffer[i][1] = 71 + (unsigned char)(random * 32);
60                 buffer[i][2] = 23 + (unsigned char)(random * 16);
61                 buffer[i][3] = data[i*4+0];
62         }
63 // White chars
64         for (i = 8192;i < 32768;i++)
65         {
66                 random = lhrandom (0.0,1.0);
67                 buffer[i][0] = 95 + (unsigned char)(random * 64);
68                 buffer[i][1] = 95 + (unsigned char)(random * 64);
69                 buffer[i][2] = 95 + (unsigned char)(random * 64);
70                 buffer[i][3] = data[i*4+0];
71         }
72 // Gold numbers
73         for (i = 32768;i < 40960;i++)
74         {
75                 random = lhrandom (0.0,1.0);
76                 buffer[i][0] = 83 + (unsigned char)(random * 64);
77                 buffer[i][1] = 71 + (unsigned char)(random * 32);
78                 buffer[i][2] = 23 + (unsigned char)(random * 16);
79                 buffer[i][3] = data[i*4+0];
80         }
81 // Red chars
82         for (i = 40960;i < 65536;i++)
83         {
84                 random = lhrandom (0.0,1.0);
85                 buffer[i][0] = 96 + (unsigned char)(random * 64);
86                 buffer[i][1] = 43 + (unsigned char)(random * 32);
87                 buffer[i][2] = 27 + (unsigned char)(random * 32);
88                 buffer[i][3] = data[i*4+0];
89         }
90
91 #if 0
92         Image_WriteTGARGBA ("gfx/generated_conchars.tga", 256, 256, &buffer[0][0]);
93 #endif
94
95         Mem_Free(data);
96         return R_LoadTexture2D(drawtexturepool, "conchars", 256, 256, &buffer[0][0], TEXTYPE_RGBA, TEXF_ALPHA | TEXF_PRECACHE, NULL);
97 }
98
99 static char *pointerimage =
100         "333333332......."
101         "26777761........"
102         "2655541........."
103         "265541.........."
104         "2654561........."
105         "26414561........"
106         "251.14561......."
107         "21...14561......"
108         "1.....141......."
109         ".......1........"
110         "................"
111         "................"
112         "................"
113         "................"
114         "................"
115         "................"
116 ;
117
118 static rtexture_t *draw_generatemousepointer(void)
119 {
120         int i;
121         unsigned char buffer[256][4];
122         for (i = 0;i < 256;i++)
123         {
124                 if (pointerimage[i] == '.')
125                 {
126                         buffer[i][0] = 0;
127                         buffer[i][1] = 0;
128                         buffer[i][2] = 0;
129                         buffer[i][3] = 0;
130                 }
131                 else
132                 {
133                         buffer[i][0] = (pointerimage[i] - '0') * 16;
134                         buffer[i][1] = (pointerimage[i] - '0') * 16;
135                         buffer[i][2] = (pointerimage[i] - '0') * 16;
136                         buffer[i][3] = 255;
137                 }
138         }
139         return R_LoadTexture2D(drawtexturepool, "mousepointer", 16, 16, &buffer[0][0], TEXTYPE_RGBA, TEXF_ALPHA | TEXF_PRECACHE, NULL);
140 }
141
142 // must match NUMCROSSHAIRS in r_crosshairs.c
143 #define NUMCROSSHAIRS 6
144
145 static char *crosshairtexdata[NUMCROSSHAIRS] =
146 {
147         "................"
148         "................"
149         "................"
150         "...33......33..."
151         "...355....553..."
152         "....577..775...."
153         ".....77..77....."
154         "................"
155         "................"
156         ".....77..77....."
157         "....577..775...."
158         "...355....553..."
159         "...33......33..."
160         "................"
161         "................"
162         "................"
163         ,
164         "................"
165         "................"
166         "................"
167         "...3........3..."
168         "....5......5...."
169         ".....7....7....."
170         "......7..7......"
171         "................"
172         "................"
173         "......7..7......"
174         ".....7....7....."
175         "....5......5...."
176         "...3........3..."
177         "................"
178         "................"
179         "................"
180         ,
181         "................"
182         ".......77......."
183         ".......77......."
184         "................"
185         "................"
186         ".......44......."
187         ".......44......."
188         ".77..44..44..77."
189         ".77..44..44..77."
190         ".......44......."
191         ".......44......."
192         "................"
193         "................"
194         ".......77......."
195         ".......77......."
196         "................"
197         ,
198         "................"
199         "................"
200         "................"
201         "................"
202         "................"
203         "................"
204         "................"
205         "................"
206         "........7777777."
207         "........752....."
208         "........72......"
209         "........7......."
210         "........7......."
211         "........7......."
212         "........7......."
213         "................"
214         ,
215         "................"
216         "................"
217         "................"
218         "................"
219         "................"
220         "........7......."
221         "................"
222         "........4......."
223         ".....7.4.4.7...."
224         "........4......."
225         "................"
226         "........7......."
227         "................"
228         "................"
229         "................"
230         "................"
231         ,
232         "................"
233         "................"
234         "................"
235         "................"
236         "................"
237         "................"
238         "................"
239         ".......55......."
240         ".......55......."
241         "................"
242         "................"
243         "................"
244         "................"
245         "................"
246         "................"
247         "................"
248 };
249
250 static rtexture_t *draw_generatecrosshair(int num)
251 {
252         int i;
253         char *in;
254         unsigned char data[16*16][4];
255         in = crosshairtexdata[num];
256         for (i = 0;i < 16*16;i++)
257         {
258                 if (in[i] == '.')
259                 {
260                         data[i][0] = 255;
261                         data[i][1] = 255;
262                         data[i][2] = 255;
263                         data[i][3] = 0;
264                 }
265                 else
266                 {
267                         data[i][0] = 255;
268                         data[i][1] = 255;
269                         data[i][2] = 255;
270                         data[i][3] = (unsigned char) ((int) (in[i] - '0') * 255 / 7);
271                 }
272         }
273         return R_LoadTexture2D(drawtexturepool, va("crosshair%i", num), 16, 16, &data[0][0], TEXTYPE_RGBA, TEXF_ALPHA | TEXF_PRECACHE, NULL);
274 }
275
276 static rtexture_t *draw_generateditherpattern(void)
277 {
278 #if 1
279         int x, y;
280         unsigned char data[8*8*4];
281         for (y = 0;y < 8;y++)
282         {
283                 for (x = 0;x < 8;x++)
284                 {
285                         data[(y*8+x)*4+0] = data[(y*8+x)*4+1] = data[(y*8+x)*4+2] = ((x^y) & 4) ? 255 : 0;
286                         data[(y*8+x)*4+3] = 255;
287                 }
288         }
289         return R_LoadTexture2D(drawtexturepool, "ditherpattern", 8, 8, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_PRECACHE, NULL);
290 #else
291         unsigned char data[16];
292         memset(data, 255, sizeof(data));
293         data[0] = data[1] = data[2] = data[12] = data[13] = data[14] = 0;
294         return R_LoadTexture2D(drawtexturepool, "ditherpattern", 2, 2, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_PRECACHE, NULL);
295 #endif
296 }
297
298 /*
299 ================
300 Draw_CachePic
301 ================
302 */
303 // FIXME: move this to client somehow
304 cachepic_t      *Draw_CachePic (const char *path, qboolean persistent)
305 {
306         int i, crc, hashkey;
307         cachepic_t *pic;
308         qpic_t *p;
309         int flags;
310
311         if (!strncmp(CLVIDEOPREFIX, path, sizeof(CLVIDEOPREFIX) - 1))
312
313         {
314                 clvideo_t *video;
315
316                 video = CL_GetVideo(path);
317                 if( video )
318                         return &video->cpif;
319         }
320
321         crc = CRC_Block((unsigned char *)path, strlen(path));
322         hashkey = ((crc >> 8) ^ crc) % CACHEPICHASHSIZE;
323         for (pic = cachepichash[hashkey];pic;pic = pic->chain)
324                 if (!strcmp (path, pic->name))
325                         return pic;
326
327         if (numcachepics == MAX_CACHED_PICS)
328         {
329                 Con_Printf ("Draw_CachePic: numcachepics == MAX_CACHED_PICS\n");
330                 // FIXME: support NULL in callers?
331                 return cachepics; // return the first one
332         }
333         pic = cachepics + (numcachepics++);
334         strlcpy (pic->name, path, sizeof(pic->name));
335         // link into list
336         pic->chain = cachepichash[hashkey];
337         cachepichash[hashkey] = pic;
338
339         flags = TEXF_ALPHA;
340         if (persistent)
341                 flags |= TEXF_PRECACHE;
342         if (!strcmp(path, "gfx/colorcontrol/ditherpattern"))
343                 flags |= TEXF_CLAMP;
344
345         // load the pic from disk
346         pic->tex = loadtextureimage(drawtexturepool, path, 0, 0, false, flags);
347         if (pic->tex == NULL && !strncmp(path, "gfx/", 4))
348         {
349                 // compatibility with older versions
350                 pic->tex = loadtextureimage(drawtexturepool, path + 4, 0, 0, false, flags);
351                 // failed to find gfx/whatever.tga or similar, try the wad
352                 if (pic->tex == NULL && (p = (qpic_t *)W_GetLumpName (path + 4)))
353                 {
354                         if (!strcmp(path, "gfx/conchars"))
355                         {
356                                 unsigned char *pix;
357                                 // conchars is a raw image and with the wrong transparent color
358                                 pix = (unsigned char *)p;
359                                 for (i = 0;i < 128 * 128;i++)
360                                         if (pix[i] == 0)
361                                                 pix[i] = 255;
362                                 pic->tex = R_LoadTexture2D(drawtexturepool, path, 128, 128, pix, TEXTYPE_PALETTE, flags, palette_complete);
363                         }
364                         else
365                                 pic->tex = R_LoadTexture2D(drawtexturepool, path, p->width, p->height, p->data, TEXTYPE_PALETTE, flags, palette_complete);
366                 }
367         }
368
369         if (pic->tex == NULL && !strcmp(path, "gfx/conchars"))
370                 pic->tex = draw_generateconchars();
371         if (pic->tex == NULL && !strcmp(path, "ui/mousepointer"))
372                 pic->tex = draw_generatemousepointer();
373         if (pic->tex == NULL && !strcmp(path, "gfx/prydoncursor001"))
374                 pic->tex = draw_generatemousepointer();
375         if (pic->tex == NULL && !strcmp(path, "gfx/crosshair1"))
376                 pic->tex = draw_generatecrosshair(0);
377         if (pic->tex == NULL && !strcmp(path, "gfx/crosshair2"))
378                 pic->tex = draw_generatecrosshair(1);
379         if (pic->tex == NULL && !strcmp(path, "gfx/crosshair3"))
380                 pic->tex = draw_generatecrosshair(2);
381         if (pic->tex == NULL && !strcmp(path, "gfx/crosshair4"))
382                 pic->tex = draw_generatecrosshair(3);
383         if (pic->tex == NULL && !strcmp(path, "gfx/crosshair5"))
384                 pic->tex = draw_generatecrosshair(4);
385         if (pic->tex == NULL && !strcmp(path, "gfx/crosshair6"))
386                 pic->tex = draw_generatecrosshair(5);
387         if (pic->tex == NULL && !strcmp(path, "gfx/colorcontrol/ditherpattern"))
388                 pic->tex = draw_generateditherpattern();
389         if (pic->tex == NULL)
390         {
391                 Con_Printf("Draw_CachePic: failed to load %s\n", path);
392                 pic->tex = r_texture_notexture;
393         }
394
395         pic->width = R_TextureWidth(pic->tex);
396         pic->height = R_TextureHeight(pic->tex);
397         return pic;
398 }
399
400 cachepic_t *Draw_NewPic(const char *picname, int width, int height, int alpha, unsigned char *pixels)
401 {
402         int crc, hashkey;
403         cachepic_t *pic;
404
405         crc = CRC_Block((unsigned char *)picname, strlen(picname));
406         hashkey = ((crc >> 8) ^ crc) % CACHEPICHASHSIZE;
407         for (pic = cachepichash[hashkey];pic;pic = pic->chain)
408                 if (!strcmp (picname, pic->name))
409                         break;
410
411         if (pic)
412         {
413                 if (pic->tex && pic->width == width && pic->height == height)
414                 {
415                         R_UpdateTexture(pic->tex, pixels);
416                         return pic;
417                 }
418         }
419         else
420         {
421                 if (pic == NULL)
422                 {
423                         if (numcachepics == MAX_CACHED_PICS)
424                         {
425                                 Con_Printf ("Draw_NewPic: numcachepics == MAX_CACHED_PICS\n");
426                                 // FIXME: support NULL in callers?
427                                 return cachepics; // return the first one
428                         }
429                         pic = cachepics + (numcachepics++);
430                         strcpy (pic->name, picname);
431                         // link into list
432                         pic->chain = cachepichash[hashkey];
433                         cachepichash[hashkey] = pic;
434                 }
435         }
436
437         pic->width = width;
438         pic->height = height;
439         if (pic->tex)
440                 R_FreeTexture(pic->tex);
441         pic->tex = R_LoadTexture2D(drawtexturepool, picname, width, height, pixels, TEXTYPE_RGBA, alpha ? TEXF_ALPHA : 0, NULL);
442         return pic;
443 }
444
445 void Draw_FreePic(const char *picname)
446 {
447         int crc;
448         int hashkey;
449         cachepic_t *pic;
450         // this doesn't really free the pic, but does free it's texture
451         crc = CRC_Block((unsigned char *)picname, strlen(picname));
452         hashkey = ((crc >> 8) ^ crc) % CACHEPICHASHSIZE;
453         for (pic = cachepichash[hashkey];pic;pic = pic->chain)
454         {
455                 if (!strcmp (picname, pic->name) && pic->tex)
456                 {
457                         R_FreeTexture(pic->tex);
458                         pic->width = 0;
459                         pic->height = 0;
460                         return;
461                 }
462         }
463 }
464
465 /*
466 ===============
467 Draw_Init
468 ===============
469 */
470 static void gl_draw_start(void)
471 {
472         drawtexturepool = R_AllocTexturePool();
473
474         numcachepics = 0;
475         memset(cachepichash, 0, sizeof(cachepichash));
476
477         char_texture = Draw_CachePic("gfx/conchars", true)->tex;
478 }
479
480 static void gl_draw_shutdown(void)
481 {
482         R_FreeTexturePool(&drawtexturepool);
483
484         numcachepics = 0;
485         memset(cachepichash, 0, sizeof(cachepichash));
486 }
487
488 static void gl_draw_newmap(void)
489 {
490 }
491
492 void GL_Draw_Init (void)
493 {
494         numcachepics = 0;
495         memset(cachepichash, 0, sizeof(cachepichash));
496
497         R_RegisterModule("GL_Draw", gl_draw_start, gl_draw_shutdown, gl_draw_newmap);
498 }
499
500 float blendvertex3f[9] = {-5000, -5000, 10, 10000, -5000, 10, -5000, 10000, 10};
501
502 int quadelements[768];
503 void R_DrawQueue(void)
504 {
505         int pos, num, chartexnum, texnum, batch;
506         float x, y, w, h, s, t, u, v, *av, *at, c[4];
507         cachepic_t *pic;
508         drawqueue_t *dq;
509         char *str;
510         int batchcount;
511         unsigned int color;
512         drawqueuemesh_t *mesh;
513         rmeshstate_t m;
514
515         if (!r_render.integer)
516                 return;
517
518         if (!quadelements[1])
519         {
520                 // elements for rendering a series of quads as triangles
521                 for (batch = 0, pos = 0, num = 0;batch < 128;batch++, num += 4)
522                 {
523                         quadelements[pos++] = num;
524                         quadelements[pos++] = num + 1;
525                         quadelements[pos++] = num + 2;
526                         quadelements[pos++] = num;
527                         quadelements[pos++] = num + 2;
528                         quadelements[pos++] = num + 3;
529                 }
530         }
531
532         r_view_width = bound(0, r_refdef.width, vid.width);
533         r_view_height = bound(0, r_refdef.height, vid.height);
534         r_view_depth = 1;
535         r_view_x = bound(0, r_refdef.x, vid.width - r_refdef.width);
536         r_view_y = bound(0, r_refdef.y, vid.height - r_refdef.height);
537         r_view_z = 0;
538         r_view_matrix = r_refdef.viewentitymatrix;
539         GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
540
541         qglViewport(r_view_x, vid.height - (r_view_y + r_view_height), r_view_width, r_view_height);
542         GL_SetupView_Mode_Ortho(0, 0, vid_conwidth.integer, vid_conheight.integer, -10, 100);
543         qglDepthFunc(GL_LEQUAL);
544         R_Mesh_Matrix(&r_identitymatrix);
545
546         chartexnum = R_GetTexture(char_texture);
547
548         memset(&m, 0, sizeof(m));
549
550         pic = NULL;
551         texnum = 0;
552         color = 0;
553         GL_Color(1,1,1,1);
554
555         batch = false;
556         batchcount = 0;
557         for (pos = 0;pos < r_refdef.drawqueuesize;pos += ((drawqueue_t *)(r_refdef.drawqueue + pos))->size)
558         {
559                 dq = (drawqueue_t *)(r_refdef.drawqueue + pos);
560                 color = dq->color;
561
562                 if(dq->flags == DRAWFLAG_ADDITIVE)
563                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
564                 else if(dq->flags == DRAWFLAG_MODULATE)
565                         GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
566                 else if(dq->flags == DRAWFLAG_2XMODULATE)
567                         GL_BlendFunc(GL_DST_COLOR,GL_SRC_COLOR);
568                 else
569                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
570
571                 GL_DepthMask(true);
572                 GL_DepthTest(false);
573
574                 c[0] = (float) ((color >> 24) & 0xFF) * (1.0f / 255.0f);
575                 c[1] = (float) ((color >> 16) & 0xFF) * (1.0f / 255.0f);
576                 c[2] = (float) ((color >>  8) & 0xFF) * (1.0f / 255.0f);
577                 c[3] = (float) ( color        & 0xFF) * (1.0f / 255.0f);
578                 x = dq->x;
579                 y = dq->y;
580                 w = dq->scalex;
581                 h = dq->scaley;
582
583                 switch(dq->command)
584                 {
585                 case DRAWQUEUE_STRING:
586                         GL_Color(c[0], c[1], c[2], c[3]);
587                         str = (char *)(dq + 1);
588                         batchcount = 0;
589                         m.pointer_vertex = varray_vertex3f;
590                         m.pointer_color = NULL;
591                         m.pointer_texcoord[0] = varray_texcoord2f[0];
592                         m.tex[0] = chartexnum;
593                         R_Mesh_State(&m);
594                         at = varray_texcoord2f[0];
595                         av = varray_vertex3f;
596                         while ((num = *str++) && x < vid_conwidth.integer)
597                         {
598                                 if (num != ' ')
599                                 {
600                                         s = (num & 15)*0.0625f + (0.5f / 256.0f);
601                                         t = (num >> 4)*0.0625f + (0.5f / 256.0f);
602                                         u = 0.0625f - (1.0f / 256.0f);
603                                         v = 0.0625f - (1.0f / 256.0f);
604                                         at[ 0] = s  ;at[ 1] = t  ;
605                                         at[ 2] = s+u;at[ 3] = t  ;
606                                         at[ 4] = s+u;at[ 5] = t+v;
607                                         at[ 6] = s  ;at[ 7] = t+v;
608                                         av[ 0] = x  ;av[ 1] = y  ;av[ 2] = 10;
609                                         av[ 3] = x+w;av[ 4] = y  ;av[ 5] = 10;
610                                         av[ 6] = x+w;av[ 7] = y+h;av[ 8] = 10;
611                                         av[ 9] = x  ;av[10] = y+h;av[11] = 10;
612                                         at += 8;
613                                         av += 12;
614                                         batchcount++;
615                                         if (batchcount >= 128)
616                                         {
617                                                 GL_LockArrays(0, batchcount * 4);
618                                                 R_Mesh_Draw(0, batchcount * 4, batchcount * 2, quadelements);
619                                                 GL_LockArrays(0, 0);
620                                                 batchcount = 0;
621                                                 at = varray_texcoord2f[0];
622                                                 av = varray_vertex3f;
623                                         }
624                                 }
625                                 x += w;
626                         }
627                         if (batchcount > 0)
628                         {
629                                 GL_LockArrays(0, batchcount * 4);
630                                 R_Mesh_Draw(0, batchcount * 4, batchcount * 2, quadelements);
631                                 GL_LockArrays(0, 0);
632                         }
633                         break;
634                 case DRAWQUEUE_MESH:
635                         mesh = (drawqueuemesh_t *)(dq + 1);
636                         m.pointer_vertex = mesh->data_vertex3f;
637                         m.pointer_color = mesh->data_color4f;
638                         m.pointer_texcoord[0] = mesh->data_texcoord2f;
639                         m.tex[0] = R_GetTexture(mesh->texture);
640                         if (!m.tex[0])
641                                 m.pointer_texcoord[0] = NULL;
642                         R_Mesh_State(&m);
643                         GL_LockArrays(0, mesh->num_vertices);
644                         R_Mesh_Draw(0, mesh->num_vertices, mesh->num_triangles, mesh->data_element3i);
645                         GL_LockArrays(0, 0);
646                         break;
647                 case DRAWQUEUE_SETCLIP:
648                         {
649                                 // We have to convert the con coords into real coords
650                                 int x , y, width, height;
651                                 x = dq->x * ((float)vid.width / vid_conwidth.integer);
652                                 // OGL uses top to bottom
653                                 y = dq->y * ((float) vid.height / vid_conheight.integer);
654                                 width = dq->scalex * ((float)vid.width / vid_conwidth.integer);
655                                 height = dq->scaley * ((float)vid.height / vid_conheight.integer);
656
657                                 GL_Scissor(x, y, width, height);
658
659                                 GL_ScissorTest(true);
660                         }
661                         break;
662                 case DRAWQUEUE_RESETCLIP:
663                         GL_ScissorTest(false);
664                         break;
665                 }
666         }
667
668         if (!vid_usinghwgamma)
669         {
670                 // all the blends ignore depth
671                 memset(&m, 0, sizeof(m));
672                 m.pointer_vertex = blendvertex3f;
673                 R_Mesh_State(&m);
674                 GL_DepthMask(true);
675                 GL_DepthTest(false);
676                 if (v_color_enable.integer)
677                 {
678                         c[0] = v_color_white_r.value;
679                         c[1] = v_color_white_g.value;
680                         c[2] = v_color_white_b.value;
681                 }
682                 else
683                         c[0] = c[1] = c[2] = v_contrast.value;
684                 if (c[0] >= 1.01f || c[1] >= 1.01f || c[2] >= 1.01f)
685                 {
686                         GL_BlendFunc(GL_DST_COLOR, GL_ONE);
687                         while (c[0] >= 1.01f || c[1] >= 1.01f || c[2] >= 1.01f)
688                         {
689                                 GL_Color(bound(0, c[0] - 1, 1), bound(0, c[1] - 1, 1), bound(0, c[2] - 1, 1), 1);
690                                 R_Mesh_Draw(0, 3, 1, polygonelements);
691                                 VectorScale(c, 0.5, c);
692                         }
693                 }
694                 if (v_color_enable.integer)
695                 {
696                         c[0] = v_color_black_r.value;
697                         c[1] = v_color_black_g.value;
698                         c[2] = v_color_black_b.value;
699                 }
700                 else
701                         c[0] = c[1] = c[2] = v_brightness.value;
702                 if (c[0] >= 0.01f || c[1] >= 0.01f || c[2] >= 0.01f)
703                 {
704                         GL_BlendFunc(GL_ONE, GL_ONE);
705                         GL_Color(c[0], c[1], c[2], 1);
706                         R_Mesh_Draw(0, 3, 1, polygonelements);
707                 }
708         }
709 }
710