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