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