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