Added dot crosshair (crosshair 6)
[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 6
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         "................"
199         ".......77......."
200         ".......77......."
201         "................"
202         ,
203         "................"
204         "................"
205         "................"
206         "................"
207         "................"
208         "................"
209         "................"
210         "................"
211         "........7777777."
212         "........752....."
213         "........72......"
214         "........7......."
215         "........7......."
216         "........7......."
217         "........7......."
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         "................"
239         "................"
240         "................"
241         "................"
242         "................"
243         "................"
244         "................"
245         "........7......."
246         "................"
247         "................"
248         "................"
249         "................"
250         "................"
251         "................"
252         "................"
253 };
254
255 static rtexture_t *draw_generatecrosshair(int num)
256 {
257         int i;
258         char *in;
259         qbyte data[16*16][4];
260         in = crosshairtexdata[num];
261         for (i = 0;i < 16*16;i++)
262         {
263                 if (in[i] == '.')
264                 {
265                         data[i][0] = 255;
266                         data[i][1] = 255;
267                         data[i][2] = 255;
268                         data[i][3] = 0;
269                 }
270                 else
271                 {
272                         data[i][0] = 255;
273                         data[i][1] = 255;
274                         data[i][2] = 255;
275                         data[i][3] = (qbyte) ((int) (in[i] - '0') * 255 / 7);
276                 }
277         }
278         return R_LoadTexture2D(drawtexturepool, va("crosshair%i", num), 16, 16, &data[0][0], TEXTYPE_RGBA, TEXF_ALPHA | TEXF_PRECACHE, NULL);
279 }
280
281 static rtexture_t *draw_generateditherpattern(void)
282 {
283 #if 1
284         int x, y;
285         qbyte data[8*8*4];
286         for (y = 0;y < 8;y++)
287         {
288                 for (x = 0;x < 8;x++)
289                 {
290                         data[(y*8+x)*4+0] = data[(y*8+x)*4+1] = data[(y*8+x)*4+2] = ((x^y) & 4) ? 255 : 0;
291                         data[(y*8+x)*4+3] = 255;
292                 }
293         }
294         return R_LoadTexture2D(drawtexturepool, "ditherpattern", 8, 8, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_PRECACHE, NULL);
295 #else
296         qbyte data[16];
297         memset(data, 255, sizeof(data));
298         data[0] = data[1] = data[2] = data[12] = data[13] = data[14] = 0;
299         return R_LoadTexture2D(drawtexturepool, "ditherpattern", 2, 2, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_PRECACHE, NULL);
300 #endif
301 }
302
303 /*
304 ================
305 Draw_CachePic
306 ================
307 */
308 // FIXME: move this to client somehow
309 cachepic_t      *Draw_CachePic (const char *path, qboolean persistent)
310 {
311         int i, crc, hashkey;
312         cachepic_t *pic;
313         qpic_t *p;
314         int flags;
315
316         if (!strncmp(CLVIDEOPREFIX, path, sizeof(CLVIDEOPREFIX) - 1)) {
317                 clvideo_t *video;
318
319                 video = CL_GetVideo(path);
320                 if( video )
321                         return &video->cpif;
322         }
323
324         crc = CRC_Block(path, strlen(path));
325         hashkey = ((crc >> 8) ^ crc) % CACHEPICHASHSIZE;
326         for (pic = cachepichash[hashkey];pic;pic = pic->chain)
327                 if (!strcmp (path, pic->name))
328                         return pic;
329
330         if (numcachepics == MAX_CACHED_PICS)
331         {
332                 Con_Printf ("Draw_CachePic: numcachepics == MAX_CACHED_PICS");
333                 // FIXME: support NULL in callers?
334                 return cachepics; // return the first one
335         }
336         pic = cachepics + (numcachepics++);
337         strlcpy (pic->name, path, sizeof(pic->name));
338         // link into list
339         pic->chain = cachepichash[hashkey];
340         cachepichash[hashkey] = pic;
341
342         flags = TEXF_ALPHA;
343         if (persistent)
344                 flags |= TEXF_PRECACHE;
345         if (!strcmp(path, "gfx/colorcontrol/ditherpattern.tga"))
346                 flags |= TEXF_CLAMP;
347
348         // load the pic from disk
349         pic->tex = loadtextureimage(drawtexturepool, path, 0, 0, false, flags);
350         if (pic->tex == NULL && !strncmp(path, "gfx/", 4))
351         {
352                 // compatibility with older versions
353                 pic->tex = loadtextureimage(drawtexturepool, path + 4, 0, 0, false, flags);
354                 // failed to find gfx/whatever.tga or similar, try the wad
355                 if (pic->tex == NULL && (p = W_GetLumpName (path + 4)))
356                 {
357                         if (!strcmp(path, "gfx/conchars"))
358                         {
359                                 qbyte *pix;
360                                 // conchars is a raw image and with the wrong transparent color
361                                 pix = (qbyte *)p;
362                                 for (i = 0;i < 128 * 128;i++)
363                                         if (pix[i] == 0)
364                                                 pix[i] = 255;
365                                 pic->tex = R_LoadTexture2D(drawtexturepool, path, 128, 128, pix, TEXTYPE_PALETTE, flags, palette_complete);
366                         }
367                         else
368                                 pic->tex = R_LoadTexture2D(drawtexturepool, path, p->width, p->height, p->data, TEXTYPE_PALETTE, flags, palette_complete);
369                 }
370         }
371
372         if (pic->tex == NULL && !strcmp(path, "gfx/conchars"))
373                 pic->tex = draw_generateconchars();
374         if (pic->tex == NULL && !strcmp(path, "ui/mousepointer.tga"))
375                 pic->tex = draw_generatemousepointer();
376         if (pic->tex == NULL && !strcmp(path, "gfx/prydoncursor001.tga"))
377                 pic->tex = draw_generatemousepointer();
378         if (pic->tex == NULL && !strcmp(path, "gfx/crosshair1.tga"))
379                 pic->tex = draw_generatecrosshair(0);
380         if (pic->tex == NULL && !strcmp(path, "gfx/crosshair2.tga"))
381                 pic->tex = draw_generatecrosshair(1);
382         if (pic->tex == NULL && !strcmp(path, "gfx/crosshair3.tga"))
383                 pic->tex = draw_generatecrosshair(2);
384         if (pic->tex == NULL && !strcmp(path, "gfx/crosshair4.tga"))
385                 pic->tex = draw_generatecrosshair(3);
386         if (pic->tex == NULL && !strcmp(path, "gfx/crosshair5.tga"))
387                 pic->tex = draw_generatecrosshair(4);
388         if (pic->tex == NULL && !strcmp(path, "gfx/crosshair6.tga"))
389                 pic->tex = draw_generatecrosshair(5);
390         if (pic->tex == NULL && !strcmp(path, "gfx/colorcontrol/ditherpattern.tga"))
391                 pic->tex = draw_generateditherpattern();
392         if (pic->tex == NULL)
393         {
394                 Con_Printf("Draw_CachePic: failed to load %s\n", path);
395                 pic->tex = r_texture_notexture;
396         }
397
398         pic->width = R_TextureWidth(pic->tex);
399         pic->height = R_TextureHeight(pic->tex);
400         return pic;
401 }
402
403 cachepic_t *Draw_NewPic(const char *picname, int width, int height, int alpha, qbyte *pixels)
404 {
405         int crc, hashkey;
406         cachepic_t *pic;
407
408         crc = CRC_Block(picname, strlen(picname));
409         hashkey = ((crc >> 8) ^ crc) % CACHEPICHASHSIZE;
410         for (pic = cachepichash[hashkey];pic;pic = pic->chain)
411                 if (!strcmp (picname, pic->name))
412                         break;
413
414         if (pic)
415         {
416                 if (pic->tex && pic->width == width && pic->height == height)
417                 {
418                         R_UpdateTexture(pic->tex, pixels);
419                         return pic;
420                 }
421         }
422         else
423         {
424                 if (pic == NULL)
425                 {
426                         if (numcachepics == MAX_CACHED_PICS)
427                         {
428                                 Con_Printf ("Draw_NewPic: numcachepics == MAX_CACHED_PICS");
429                                 // FIXME: support NULL in callers?
430                                 return cachepics; // return the first one
431                         }
432                         pic = cachepics + (numcachepics++);
433                         strcpy (pic->name, picname);
434                         // link into list
435                         pic->chain = cachepichash[hashkey];
436                         cachepichash[hashkey] = pic;
437                 }
438         }
439
440         pic->width = width;
441         pic->height = height;
442         if (pic->tex)
443                 R_FreeTexture(pic->tex);
444         pic->tex = R_LoadTexture2D(drawtexturepool, picname, width, height, pixels, TEXTYPE_RGBA, alpha ? TEXF_ALPHA : 0, NULL);
445         return pic;
446 }
447
448 void Draw_FreePic(const char *picname)
449 {
450         int crc;
451         int hashkey;
452         cachepic_t *pic;
453         // this doesn't really free the pic, but does free it's texture
454         crc = CRC_Block(picname, strlen(picname));
455         hashkey = ((crc >> 8) ^ crc) % CACHEPICHASHSIZE;
456         for (pic = cachepichash[hashkey];pic;pic = pic->chain)
457         {
458                 if (!strcmp (picname, pic->name) && pic->tex)
459                 {
460                         R_FreeTexture(pic->tex);
461                         pic->width = 0;
462                         pic->height = 0;
463                         return;
464                 }
465         }
466 }
467
468 /*
469 ===============
470 Draw_Init
471 ===============
472 */
473 static void gl_draw_start(void)
474 {
475         drawtexturepool = R_AllocTexturePool();
476
477         numcachepics = 0;
478         memset(cachepichash, 0, sizeof(cachepichash));
479
480         char_texture = Draw_CachePic("gfx/conchars", true)->tex;
481 }
482
483 static void gl_draw_shutdown(void)
484 {
485         R_FreeTexturePool(&drawtexturepool);
486
487         numcachepics = 0;
488         memset(cachepichash, 0, sizeof(cachepichash));
489 }
490
491 static void gl_draw_newmap(void)
492 {
493 }
494
495 void GL_Draw_Init (void)
496 {
497         numcachepics = 0;
498         memset(cachepichash, 0, sizeof(cachepichash));
499
500         R_RegisterModule("GL_Draw", gl_draw_start, gl_draw_shutdown, gl_draw_newmap);
501 }
502
503 float blendvertex3f[9] = {-5000, -5000, 10, 10000, -5000, 10, -5000, 10000, 10};
504
505 int quadelements[768];
506 void R_DrawQueue(void)
507 {
508         int pos, num, chartexnum, texnum, batch;
509         float x, y, w, h, s, t, u, v, *av, *at, c[4];
510         cachepic_t *pic;
511         drawqueue_t *dq;
512         char *str;
513         int batchcount;
514         unsigned int color;
515         drawqueuemesh_t *mesh;
516         rmeshstate_t m;
517
518         if (!r_render.integer)
519                 return;
520
521         if (!quadelements[1])
522         {
523                 // elements for rendering a series of quads as triangles
524                 for (batch = 0, pos = 0, num = 0;batch < 128;batch++, num += 4)
525                 {
526                         quadelements[pos++] = num;
527                         quadelements[pos++] = num + 1;
528                         quadelements[pos++] = num + 2;
529                         quadelements[pos++] = num;
530                         quadelements[pos++] = num + 2;
531                         quadelements[pos++] = num + 3;
532                 }
533         }
534
535         r_view_width = bound(0, r_refdef.width, vid.width);
536         r_view_height = bound(0, r_refdef.height, vid.height);
537         r_view_depth = 1;
538         r_view_x = bound(0, r_refdef.x, vid.width - r_refdef.width);
539         r_view_y = bound(0, r_refdef.y, vid.height - r_refdef.height);
540         r_view_z = 0;
541         r_view_fov_x = bound(0.1, r_refdef.fov_x, 170);
542         r_view_fov_y = bound(0.1, r_refdef.fov_y, 170);
543         r_view_matrix = r_refdef.viewentitymatrix;
544         GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
545
546         qglViewport(r_view_x, vid.height - (r_view_y + r_view_height), r_view_width, r_view_height);
547         GL_SetupView_Mode_Ortho(0, 0, vid_conwidth.integer, vid_conheight.integer, -10, 100);
548         qglDepthFunc(GL_LEQUAL);
549         R_Mesh_Matrix(&r_identitymatrix);
550
551         chartexnum = R_GetTexture(char_texture);
552
553         memset(&m, 0, sizeof(m));
554
555         pic = NULL;
556         texnum = 0;
557         color = 0;
558         GL_Color(1,1,1,1);
559
560         batch = false;
561         batchcount = 0;
562         for (pos = 0;pos < r_refdef.drawqueuesize;pos += ((drawqueue_t *)(r_refdef.drawqueue + pos))->size)
563         {
564                 dq = (drawqueue_t *)(r_refdef.drawqueue + pos);
565                 color = dq->color;
566
567                 if(dq->flags == DRAWFLAG_ADDITIVE)
568                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
569                 else if(dq->flags == DRAWFLAG_MODULATE)
570                         GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
571                 else if(dq->flags == DRAWFLAG_2XMODULATE)
572                         GL_BlendFunc(GL_DST_COLOR,GL_SRC_COLOR);
573                 else
574                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
575
576                 GL_DepthMask(true);
577                 GL_DepthTest(false);
578
579                 c[0] = (float) ((color >> 24) & 0xFF) * (1.0f / 255.0f);
580                 c[1] = (float) ((color >> 16) & 0xFF) * (1.0f / 255.0f);
581                 c[2] = (float) ((color >>  8) & 0xFF) * (1.0f / 255.0f);
582                 c[3] = (float) ( color        & 0xFF) * (1.0f / 255.0f);
583                 x = dq->x;
584                 y = dq->y;
585                 w = dq->scalex;
586                 h = dq->scaley;
587
588                 switch(dq->command)
589                 {
590                 case DRAWQUEUE_STRING:
591                         GL_Color(c[0], c[1], c[2], c[3]);
592                         str = (char *)(dq + 1);
593                         batchcount = 0;
594                         m.pointer_vertex = varray_vertex3f;
595                         m.pointer_color = NULL;
596                         m.pointer_texcoord[0] = varray_texcoord2f[0];
597                         m.tex[0] = chartexnum;
598                         R_Mesh_State(&m);
599                         at = varray_texcoord2f[0];
600                         av = varray_vertex3f;
601                         while ((num = *str++) && x < vid_conwidth.integer)
602                         {
603                                 if (num != ' ')
604                                 {
605                                         s = (num & 15)*0.0625f + (0.5f / 256.0f);
606                                         t = (num >> 4)*0.0625f + (0.5f / 256.0f);
607                                         u = 0.0625f - (1.0f / 256.0f);
608                                         v = 0.0625f - (1.0f / 256.0f);
609                                         at[ 0] = s  ;at[ 1] = t  ;
610                                         at[ 2] = s+u;at[ 3] = t  ;
611                                         at[ 4] = s+u;at[ 5] = t+v;
612                                         at[ 6] = s  ;at[ 7] = t+v;
613                                         av[ 0] = x  ;av[ 1] = y  ;av[ 2] = 10;
614                                         av[ 3] = x+w;av[ 4] = y  ;av[ 5] = 10;
615                                         av[ 6] = x+w;av[ 7] = y+h;av[ 8] = 10;
616                                         av[ 9] = x  ;av[10] = y+h;av[11] = 10;
617                                         at += 8;
618                                         av += 12;
619                                         batchcount++;
620                                         if (batchcount >= 128)
621                                         {
622                                                 GL_LockArrays(0, batchcount * 4);
623                                                 R_Mesh_Draw(0, batchcount * 4, batchcount * 2, quadelements);
624                                                 GL_LockArrays(0, 0);
625                                                 batchcount = 0;
626                                                 at = varray_texcoord2f[0];
627                                                 av = varray_vertex3f;
628                                         }
629                                 }
630                                 x += w;
631                         }
632                         if (batchcount > 0)
633                         {
634                                 GL_LockArrays(0, batchcount * 4);
635                                 R_Mesh_Draw(0, batchcount * 4, batchcount * 2, quadelements);
636                                 GL_LockArrays(0, 0);
637                         }
638                         break;
639                 case DRAWQUEUE_MESH:
640                         mesh = (void *)(dq + 1);
641                         m.pointer_vertex = mesh->data_vertex3f;
642                         m.pointer_color = mesh->data_color4f;
643                         m.pointer_texcoord[0] = mesh->data_texcoord2f;
644                         m.tex[0] = R_GetTexture(mesh->texture);
645                         if (!m.tex[0])
646                                 m.pointer_texcoord[0] = NULL;
647                         R_Mesh_State(&m);
648                         GL_LockArrays(0, mesh->num_vertices);
649                         R_Mesh_Draw(0, mesh->num_vertices, mesh->num_triangles, mesh->data_element3i);
650                         GL_LockArrays(0, 0);
651                         break;
652                 case DRAWQUEUE_SETCLIP:
653                         {
654                                 // We have to convert the con coords into real coords
655                                 int x , y, width, height;
656                                 x = dq->x * ((float)vid.width / vid_conwidth.integer);
657                                 // OGL uses top to bottom
658                                 y = dq->y * ((float) vid.height / vid_conheight.integer);
659                                 width = dq->scalex * ((float)vid.width / vid_conwidth.integer);
660                                 height = dq->scaley * ((float)vid.height / vid_conheight.integer);
661
662                                 GL_Scissor(x, y, width, height);
663
664                                 GL_ScissorTest(true);
665                         }
666                         break;
667                 case DRAWQUEUE_RESETCLIP:
668                         GL_ScissorTest(false);
669                         break;
670                 }
671         }
672
673         if (!vid_usinghwgamma)
674         {
675                 // all the blends ignore depth
676                 memset(&m, 0, sizeof(m));
677                 m.pointer_vertex = blendvertex3f;
678                 R_Mesh_State(&m);
679                 GL_DepthMask(true);
680                 GL_DepthTest(false);
681                 if (v_color_enable.integer)
682                 {
683                         c[0] = v_color_white_r.value;
684                         c[1] = v_color_white_g.value;
685                         c[2] = v_color_white_b.value;
686                 }
687                 else
688                         c[0] = c[1] = c[2] = v_contrast.value;
689                 if (c[0] >= 1.01f || c[1] >= 1.01f || c[2] >= 1.01f)
690                 {
691                         GL_BlendFunc(GL_DST_COLOR, GL_ONE);
692                         while (c[0] >= 1.01f || c[1] >= 1.01f || c[2] >= 1.01f)
693                         {
694                                 GL_Color(bound(0, c[0] - 1, 1), bound(0, c[1] - 1, 1), bound(0, c[2] - 1, 1), 1);
695                                 R_Mesh_Draw(0, 3, 1, polygonelements);
696                                 VectorScale(c, 0.5, c);
697                         }
698                 }
699                 if (v_color_enable.integer)
700                 {
701                         c[0] = v_color_black_r.value;
702                         c[1] = v_color_black_g.value;
703                         c[2] = v_color_black_b.value;
704                 }
705                 else
706                         c[0] = c[1] = c[2] = v_brightness.value;
707                 if (c[0] >= 0.01f || c[1] >= 0.01f || c[2] >= 0.01f)
708                 {
709                         GL_BlendFunc(GL_ONE, GL_ONE);
710                         GL_Color(c[0], c[1], c[2], 1);
711                         R_Mesh_Draw(0, 3, 1, polygonelements);
712                 }
713         }
714 }
715