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