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