fix unintended use of alpha test on 2d graphics (hud/menu/etc)
[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 cvar_t r_textshadow = {0, "r_textshadow", "0", "draws a shadow on all text to improve readability"};
28
29 static rtexture_t *char_texture;
30 cachepic_t *r_crosshairs[NUMCROSSHAIRS+1];
31
32 //=============================================================================
33 /* Support Routines */
34
35 #define FONT_FILESIZE 13468
36 #define MAX_CACHED_PICS 1024
37 #define CACHEPICHASHSIZE 256
38 static cachepic_t *cachepichash[CACHEPICHASHSIZE];
39 static cachepic_t cachepics[MAX_CACHED_PICS];
40 static int numcachepics;
41
42 static rtexturepool_t *drawtexturepool;
43
44 static unsigned char concharimage[FONT_FILESIZE] =
45 {
46 #include "lhfont.h"
47 };
48
49 static rtexture_t *draw_generateconchars(void)
50 {
51         int i;
52         unsigned char buffer[65536][4], *data = NULL;
53         double random;
54
55         data = LoadTGA (concharimage, FONT_FILESIZE, 256, 256);
56 // Gold numbers
57         for (i = 0;i < 8192;i++)
58         {
59                 random = lhrandom (0.0,1.0);
60                 buffer[i][0] = 83 + (unsigned char)(random * 64);
61                 buffer[i][1] = 71 + (unsigned char)(random * 32);
62                 buffer[i][2] = 23 + (unsigned char)(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 + (unsigned char)(random * 64);
70                 buffer[i][1] = 95 + (unsigned char)(random * 64);
71                 buffer[i][2] = 95 + (unsigned char)(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 + (unsigned char)(random * 64);
79                 buffer[i][1] = 71 + (unsigned char)(random * 32);
80                 buffer[i][2] = 23 + (unsigned char)(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 + (unsigned char)(random * 64);
88                 buffer[i][1] = 43 + (unsigned char)(random * 32);
89                 buffer[i][2] = 27 + (unsigned char)(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         unsigned char 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 static char *crosshairtexdata[NUMCROSSHAIRS] =
145 {
146         "................"
147         "................"
148         "................"
149         "...33......33..."
150         "...355....553..."
151         "....577..775...."
152         ".....77..77....."
153         "................"
154         "................"
155         ".....77..77....."
156         "....577..775...."
157         "...355....553..."
158         "...33......33..."
159         "................"
160         "................"
161         "................"
162         ,
163         "................"
164         "................"
165         "................"
166         "...3........3..."
167         "....5......5...."
168         ".....7....7....."
169         "......7..7......"
170         "................"
171         "................"
172         "......7..7......"
173         ".....7....7....."
174         "....5......5...."
175         "...3........3..."
176         "................"
177         "................"
178         "................"
179         ,
180         "................"
181         ".......77......."
182         ".......77......."
183         "................"
184         "................"
185         ".......44......."
186         ".......44......."
187         ".77..44..44..77."
188         ".77..44..44..77."
189         ".......44......."
190         ".......44......."
191         "................"
192         "................"
193         ".......77......."
194         ".......77......."
195         "................"
196         ,
197         "................"
198         "................"
199         "................"
200         "................"
201         "................"
202         "................"
203         "................"
204         "................"
205         "........7777777."
206         "........752....."
207         "........72......"
208         "........7......."
209         "........7......."
210         "........7......."
211         "........7......."
212         "................"
213         ,
214         "................"
215         "................"
216         "................"
217         "................"
218         "................"
219         "........7......."
220         "................"
221         "........4......."
222         ".....7.4.4.7...."
223         "........4......."
224         "................"
225         "........7......."
226         "................"
227         "................"
228         "................"
229         "................"
230         ,
231         "................"
232         "................"
233         "................"
234         "................"
235         "................"
236         "................"
237         "................"
238         ".......55......."
239         ".......55......."
240         "................"
241         "................"
242         "................"
243         "................"
244         "................"
245         "................"
246         "................"
247 };
248
249 static rtexture_t *draw_generatecrosshair(int num)
250 {
251         int i;
252         char *in;
253         unsigned char data[16*16][4];
254         in = crosshairtexdata[num];
255         for (i = 0;i < 16*16;i++)
256         {
257                 if (in[i] == '.')
258                 {
259                         data[i][0] = 255;
260                         data[i][1] = 255;
261                         data[i][2] = 255;
262                         data[i][3] = 0;
263                 }
264                 else
265                 {
266                         data[i][0] = 255;
267                         data[i][1] = 255;
268                         data[i][2] = 255;
269                         data[i][3] = (unsigned char) ((int) (in[i] - '0') * 255 / 7);
270                 }
271         }
272         return R_LoadTexture2D(drawtexturepool, va("crosshair%i", num), 16, 16, &data[0][0], TEXTYPE_RGBA, TEXF_ALPHA | TEXF_PRECACHE, NULL);
273 }
274
275 static rtexture_t *draw_generateditherpattern(void)
276 {
277 #if 1
278         int x, y;
279         unsigned char data[8*8*4];
280         for (y = 0;y < 8;y++)
281         {
282                 for (x = 0;x < 8;x++)
283                 {
284                         data[(y*8+x)*4+0] = data[(y*8+x)*4+1] = data[(y*8+x)*4+2] = ((x^y) & 4) ? 255 : 0;
285                         data[(y*8+x)*4+3] = 255;
286                 }
287         }
288         return R_LoadTexture2D(drawtexturepool, "ditherpattern", 8, 8, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_PRECACHE, NULL);
289 #else
290         unsigned char data[16];
291         memset(data, 255, sizeof(data));
292         data[0] = data[1] = data[2] = data[12] = data[13] = data[14] = 0;
293         return R_LoadTexture2D(drawtexturepool, "ditherpattern", 2, 2, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_PRECACHE, NULL);
294 #endif
295 }
296
297 /*
298 ================
299 Draw_CachePic
300 ================
301 */
302 // FIXME: move this to client somehow
303 cachepic_t      *Draw_CachePic (const char *path, qboolean persistent)
304 {
305         int crc, hashkey;
306         cachepic_t *pic;
307         qpic_t *p;
308         int flags;
309
310         if (!strncmp(CLVIDEOPREFIX, path, sizeof(CLVIDEOPREFIX) - 1))
311         {
312                 clvideo_t *video;
313
314                 video = CL_GetVideoByName(path);
315                 if( video )
316                         return &video->cpif;
317         }
318
319         crc = CRC_Block((unsigned char *)path, strlen(path));
320         hashkey = ((crc >> 8) ^ crc) % CACHEPICHASHSIZE;
321         for (pic = cachepichash[hashkey];pic;pic = pic->chain)
322                 if (!strcmp (path, pic->name))
323                         return pic;
324
325         if (numcachepics == MAX_CACHED_PICS)
326         {
327                 Con_Printf ("Draw_CachePic: numcachepics == MAX_CACHED_PICS\n");
328                 // FIXME: support NULL in callers?
329                 return cachepics; // return the first one
330         }
331         pic = cachepics + (numcachepics++);
332         strlcpy (pic->name, path, sizeof(pic->name));
333         // link into list
334         pic->chain = cachepichash[hashkey];
335         cachepichash[hashkey] = pic;
336
337         flags = TEXF_ALPHA;
338         if (persistent)
339                 flags |= TEXF_PRECACHE;
340         if (!strcmp(path, "gfx/colorcontrol/ditherpattern"))
341                 flags |= TEXF_CLAMP;
342
343         // load the pic from disk
344         pic->tex = loadtextureimage(drawtexturepool, path, 0, 0, false, flags);
345         if (pic->tex == NULL && !strncmp(path, "gfx/", 4))
346         {
347                 // compatibility with older versions
348                 pic->tex = loadtextureimage(drawtexturepool, path + 4, 0, 0, false, flags);
349                 // failed to find gfx/whatever.tga or similar, try the wad
350                 if (pic->tex == NULL && (p = (qpic_t *)W_GetLumpName (path + 4)))
351                 {
352                         if (!strcmp(path, "gfx/conchars"))
353                         {
354                                 // conchars is a raw image and with color 0 as transparent instead of 255
355                                 pic->tex = R_LoadTexture2D(drawtexturepool, path, 128, 128, (unsigned char *)p, TEXTYPE_PALETTE, flags, palette_font);
356                         }
357                         else
358                                 pic->tex = R_LoadTexture2D(drawtexturepool, path, p->width, p->height, p->data, TEXTYPE_PALETTE, flags, palette_transparent);
359                 }
360         }
361
362         if (pic->tex == NULL && !strcmp(path, "gfx/conchars"))
363                 pic->tex = draw_generateconchars();
364         if (pic->tex == NULL && !strcmp(path, "ui/mousepointer"))
365                 pic->tex = draw_generatemousepointer();
366         if (pic->tex == NULL && !strcmp(path, "gfx/prydoncursor001"))
367                 pic->tex = draw_generatemousepointer();
368         if (pic->tex == NULL && !strcmp(path, "gfx/crosshair1"))
369                 pic->tex = draw_generatecrosshair(0);
370         if (pic->tex == NULL && !strcmp(path, "gfx/crosshair2"))
371                 pic->tex = draw_generatecrosshair(1);
372         if (pic->tex == NULL && !strcmp(path, "gfx/crosshair3"))
373                 pic->tex = draw_generatecrosshair(2);
374         if (pic->tex == NULL && !strcmp(path, "gfx/crosshair4"))
375                 pic->tex = draw_generatecrosshair(3);
376         if (pic->tex == NULL && !strcmp(path, "gfx/crosshair5"))
377                 pic->tex = draw_generatecrosshair(4);
378         if (pic->tex == NULL && !strcmp(path, "gfx/crosshair6"))
379                 pic->tex = draw_generatecrosshair(5);
380         if (pic->tex == NULL && !strcmp(path, "gfx/colorcontrol/ditherpattern"))
381                 pic->tex = draw_generateditherpattern();
382         if (pic->tex == NULL)
383         {
384                 Con_Printf("Draw_CachePic: failed to load %s\n", path);
385                 pic->tex = r_texture_notexture;
386         }
387
388         pic->width = R_TextureWidth(pic->tex);
389         pic->height = R_TextureHeight(pic->tex);
390         return pic;
391 }
392
393 cachepic_t *Draw_NewPic(const char *picname, int width, int height, int alpha, unsigned char *pixels)
394 {
395         int crc, hashkey;
396         cachepic_t *pic;
397
398         crc = CRC_Block((unsigned char *)picname, strlen(picname));
399         hashkey = ((crc >> 8) ^ crc) % CACHEPICHASHSIZE;
400         for (pic = cachepichash[hashkey];pic;pic = pic->chain)
401                 if (!strcmp (picname, pic->name))
402                         break;
403
404         if (pic)
405         {
406                 if (pic->tex && pic->width == width && pic->height == height)
407                 {
408                         R_UpdateTexture(pic->tex, pixels, 0, 0, width, height);
409                         return pic;
410                 }
411         }
412         else
413         {
414                 if (pic == NULL)
415                 {
416                         if (numcachepics == MAX_CACHED_PICS)
417                         {
418                                 Con_Printf ("Draw_NewPic: numcachepics == MAX_CACHED_PICS\n");
419                                 // FIXME: support NULL in callers?
420                                 return cachepics; // return the first one
421                         }
422                         pic = cachepics + (numcachepics++);
423                         strcpy (pic->name, picname);
424                         // link into list
425                         pic->chain = cachepichash[hashkey];
426                         cachepichash[hashkey] = pic;
427                 }
428         }
429
430         pic->width = width;
431         pic->height = height;
432         if (pic->tex)
433                 R_FreeTexture(pic->tex);
434         pic->tex = R_LoadTexture2D(drawtexturepool, picname, width, height, pixels, TEXTYPE_RGBA, alpha ? TEXF_ALPHA : 0, NULL);
435         return pic;
436 }
437
438 void Draw_FreePic(const char *picname)
439 {
440         int crc;
441         int hashkey;
442         cachepic_t *pic;
443         // this doesn't really free the pic, but does free it's texture
444         crc = CRC_Block((unsigned char *)picname, strlen(picname));
445         hashkey = ((crc >> 8) ^ crc) % CACHEPICHASHSIZE;
446         for (pic = cachepichash[hashkey];pic;pic = pic->chain)
447         {
448                 if (!strcmp (picname, pic->name) && pic->tex)
449                 {
450                         R_FreeTexture(pic->tex);
451                         pic->width = 0;
452                         pic->height = 0;
453                         return;
454                 }
455         }
456 }
457
458 /*
459 ===============
460 Draw_Init
461 ===============
462 */
463 static void gl_draw_start(void)
464 {
465         int i;
466         drawtexturepool = R_AllocTexturePool();
467
468         numcachepics = 0;
469         memset(cachepichash, 0, sizeof(cachepichash));
470
471         char_texture = Draw_CachePic("gfx/conchars", true)->tex;
472         for (i = 1;i <= NUMCROSSHAIRS;i++)
473                 r_crosshairs[i] = Draw_CachePic(va("gfx/crosshair%i", i), true);
474 }
475
476 static void gl_draw_shutdown(void)
477 {
478         R_FreeTexturePool(&drawtexturepool);
479
480         numcachepics = 0;
481         memset(cachepichash, 0, sizeof(cachepichash));
482 }
483
484 static void gl_draw_newmap(void)
485 {
486 }
487
488 void GL_Draw_Init (void)
489 {
490         Cvar_RegisterVariable(&r_textshadow);
491         R_RegisterModule("GL_Draw", gl_draw_start, gl_draw_shutdown, gl_draw_newmap);
492 }
493
494 void DrawQ_Begin(void)
495 {
496         GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
497
498         CHECKGLERROR
499         qglViewport(r_view.x, vid.height - (r_view.y + r_view.height), r_view.width, r_view.height);CHECKGLERROR
500         GL_SetupView_Mode_Ortho(0, 0, vid_conwidth.integer, vid_conheight.integer, -10, 100);
501         qglDepthFunc(GL_LEQUAL);CHECKGLERROR
502         R_Mesh_Matrix(&identitymatrix);
503
504         GL_DepthMask(true);
505         GL_DepthTest(false);
506         GL_Color(1,1,1,1);
507         GL_AlphaTest(false);
508         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
509
510         r_refdef.draw2dstage = true;
511 }
512
513 static void _DrawQ_ProcessDrawFlag(int flags)
514 {
515         CHECKGLERROR
516         if(flags == DRAWFLAG_ADDITIVE)
517                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
518         else if(flags == DRAWFLAG_MODULATE)
519                 GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
520         else if(flags == DRAWFLAG_2XMODULATE)
521                 GL_BlendFunc(GL_DST_COLOR,GL_SRC_COLOR);
522         else
523                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
524 }
525
526 void DrawQ_Pic(float x, float y, cachepic_t *pic, float width, float height, float red, float green, float blue, float alpha, int flags)
527 {
528         if (!r_refdef.draw2dstage)
529         {
530                 Con_Printf("DrawQ_Pic: not in 2d rendering stage!\n");
531                 return;
532         }
533         DrawQ_SuperPic(x,y,pic,width,height,0,0,red,green,blue,alpha,1,0,red,green,blue,alpha,0,1,red,green,blue,alpha,1,1,red,green,blue,alpha,flags);
534 }
535
536 void DrawQ_String_Real(float x, float y, const char *string, int maxlen, float w, float h, float red, float green, float blue, float alpha, int flags)
537 {
538         int i, num;
539         float *av, *at;
540         int batchcount;
541         float vertex3f[QUADELEMENTS_MAXQUADS*4*3];
542         float texcoord2f[QUADELEMENTS_MAXQUADS*4*2];
543
544         if (!r_refdef.draw2dstage)
545         {
546                 Con_Printf("DrawQ_String: not in 2d rendering stage!\n");
547                 return;
548         }
549
550         if (alpha < (1.0f / 255.0f))
551                 return;
552
553         _DrawQ_ProcessDrawFlag(flags);
554
555         GL_Color(red, green, blue, alpha);
556
557         R_Mesh_VertexPointer(vertex3f);
558         R_Mesh_ColorPointer(NULL);
559         R_Mesh_ResetTextureState();
560         R_Mesh_TexBind(0, R_GetTexture(char_texture));
561         R_Mesh_TexCoordPointer(0, 2, texcoord2f);
562
563         at = texcoord2f;
564         av = vertex3f;
565         batchcount = 0;
566
567         if (maxlen < 1)
568                 maxlen = 9999;
569         for (i = 0;i < maxlen && x < vid_conwidth.integer && (num = string[i]);i++, x += w)
570         {
571                 float s, t, u, v;
572                 if (num == ' ')
573                         continue;
574                 s = (num & 15)*0.0625f + (0.5f / 256.0f);
575                 t = (num >> 4)*0.0625f + (0.5f / 256.0f);
576                 u = 0.0625f - (1.0f / 256.0f);
577                 v = 0.0625f - (1.0f / 256.0f);
578                 at[ 0] = s  ;at[ 1] = t  ;
579                 at[ 2] = s+u;at[ 3] = t  ;
580                 at[ 4] = s+u;at[ 5] = t+v;
581                 at[ 6] = s  ;at[ 7] = t+v;
582                 av[ 0] = x  ;av[ 1] = y  ;av[ 2] = 10;
583                 av[ 3] = x+w;av[ 4] = y  ;av[ 5] = 10;
584                 av[ 6] = x+w;av[ 7] = y+h;av[ 8] = 10;
585                 av[ 9] = x  ;av[10] = y+h;av[11] = 10;
586                 at += 8;
587                 av += 12;
588                 batchcount++;
589                 if (batchcount >= QUADELEMENTS_MAXQUADS)
590                 {
591                         GL_LockArrays(0, batchcount * 4);
592                         R_Mesh_Draw(0, batchcount * 4, batchcount * 2, quadelements);
593                         GL_LockArrays(0, 0);
594                         batchcount = 0;
595                         at = texcoord2f;
596                         av = vertex3f;
597                 }
598         }
599         if (batchcount > 0)
600         {
601                 GL_LockArrays(0, batchcount * 4);
602                 R_Mesh_Draw(0, batchcount * 4, batchcount * 2, quadelements);
603                 GL_LockArrays(0, 0);
604         }
605 }
606
607 void DrawQ_String(float x, float y, const char *string, int maxlen, float scalex, float scaley, float red, float green, float blue, float alpha, int flags)
608 {
609         if (!r_refdef.draw2dstage)
610         {
611                 Con_Printf("DrawQ_String: not in 2d rendering stage!\n");
612                 return;
613         }
614
615         if (r_textshadow.integer)
616                 DrawQ_String_Real(x+scalex*0.25,y+scaley*0.25,string,maxlen,scalex,scaley,0,0,0,alpha*0.8,flags);
617
618         DrawQ_String_Real(x,y,string,maxlen,scalex,scaley,red,green,blue,alpha,flags);
619 }
620
621 // color tag printing
622 static vec4_t string_colors[] =
623 {
624         // Quake3 colors
625         // LordHavoc: why on earth is cyan before magenta in Quake3?
626         // LordHavoc: note: Doom3 uses white for [0] and [7]
627         {0.0, 0.0, 0.0, 1.0}, // black
628         {1.0, 0.0, 0.0, 1.0}, // red
629         {0.0, 1.0, 0.0, 1.0}, // green
630         {1.0, 1.0, 0.0, 1.0}, // yellow
631         {0.0, 0.0, 1.0, 1.0}, // blue
632         {0.0, 1.0, 1.0, 1.0}, // cyan
633         {1.0, 0.0, 1.0, 1.0}, // magenta
634         {1.0, 1.0, 1.0, 1.0}, // white
635         // [515]'s BX_COLOREDTEXT extension
636         {1.0, 1.0, 1.0, 0.5}, // half transparent
637         {0.5, 0.5, 0.5, 1.0}  // half brightness
638         // Black's color table
639         //{1.0, 1.0, 1.0, 1.0},
640         //{1.0, 0.0, 0.0, 1.0},
641         //{0.0, 1.0, 0.0, 1.0},
642         //{0.0, 0.0, 1.0, 1.0},
643         //{1.0, 1.0, 0.0, 1.0},
644         //{0.0, 1.0, 1.0, 1.0},
645         //{1.0, 0.0, 1.0, 1.0},
646         //{0.1, 0.1, 0.1, 1.0}
647 };
648
649 #define STRING_COLORS_COUNT     (sizeof(string_colors) / sizeof(vec4_t))
650
651 // color is read and changed in the end
652 void DrawQ_ColoredString( float x, float y, const char *text, int maxlen, float scalex, float scaley, float basered, float basegreen, float baseblue, float basealpha, int flags, int *outcolor )
653 {
654         vec_t *color;
655         int len;
656         int colorindex;
657         const char *start, *current;
658
659         if (!r_refdef.draw2dstage)
660         {
661                 Con_Printf("DrawQ_ColoredString: not in 2d rendering stage!\n");
662                 return;
663         }
664         if( !outcolor || *outcolor == -1 ) {
665                 colorindex = STRING_COLOR_DEFAULT;
666         } else {
667                 colorindex = *outcolor;
668         }
669         color = string_colors[colorindex];
670
671         if( maxlen < 1)
672                 len = (int)strlen( text );
673         else
674                 len = min( maxlen, (int) strlen( text ) );
675
676         start = current = text;
677         while( len > 0 ) {
678                 // check for color control char
679                 if( *current == STRING_COLOR_TAG ) {
680                         // get next char
681                         current++;
682                         len--;
683                         if( len == 0 ) {
684                                 break;
685                         }
686                         // display the tag char?
687                         if( *current == STRING_COLOR_TAG ) {
688                                 // only display one of the two
689                                 start = current;
690                                 // get the next char
691                                 current++;
692                                 len--;
693                         } else if( '0' <= *current && *current <= '9' ) {
694                                 colorindex = 0;
695                                 do {
696                                         colorindex = colorindex * 10 + (*current - '0');
697                                         // only read as long as it makes a valid index
698                                         if( colorindex >= (int)STRING_COLORS_COUNT ) {
699                                                 // undo the last operation
700                                                 colorindex /= 10;
701                                                 break;
702                                         }
703                                         current++;
704                                         len--;
705                                 } while( len > 0 && '0' <= *current && *current <= '9' );
706                                 // set the color
707                                 color = string_colors[colorindex];
708                                 // we jump over the color tag
709                                 start = current;
710                         }
711                 }
712                 // go on and read normal text in until the next control char
713                 while( len > 0 && *current != STRING_COLOR_TAG ) {
714                         current++;
715                         len--;
716                 }
717                 // display the text
718                 if( start != current ) {
719                         // draw the string
720                         DrawQ_String( x, y, start, current - start, scalex, scaley, basered * color[0], basegreen * color[1], baseblue * color[2], basealpha * color[3], flags );
721                         // update x to be at the new start position
722                         x += (current - start) * scalex;
723                         // set start accordingly
724                         start = current;
725                 }
726         }
727
728         // return the last colorindex
729         if( outcolor ) {
730                 *outcolor = colorindex;
731         }
732 }
733
734 void DrawQ_SuperPic(float x, float y, cachepic_t *pic, float width, float height, float s1, float t1, float r1, float g1, float b1, float a1, float s2, float t2, float r2, float g2, float b2, float a2, float s3, float t3, float r3, float g3, float b3, float a3, float s4, float t4, float r4, float g4, float b4, float a4, int flags)
735 {
736         float floats[36];
737
738         if (!r_refdef.draw2dstage)
739         {
740                 Con_Printf("DrawQ_SuperPic: not in 2d rendering stage!\n");
741                 return;
742         }
743
744         _DrawQ_ProcessDrawFlag(flags);
745
746         R_Mesh_VertexPointer(floats);
747         R_Mesh_ColorPointer(floats + 20);
748         R_Mesh_ResetTextureState();
749         if (pic)
750         {
751                 if (width == 0)
752                         width = pic->width;
753                 if (height == 0)
754                         height = pic->height;
755                 R_Mesh_TexBind(0, R_GetTexture(pic->tex));
756                 R_Mesh_TexCoordPointer(0, 2, floats + 12);
757                 floats[12] = s1;floats[13] = t1;
758                 floats[14] = s2;floats[15] = t2;
759                 floats[16] = s4;floats[17] = t4;
760                 floats[18] = s3;floats[19] = t3;
761         }
762
763         floats[2] = floats[5] = floats[8] = floats[11] = 0;
764         floats[0] = floats[9] = x;
765         floats[1] = floats[4] = y;
766         floats[3] = floats[6] = x + width;
767         floats[7] = floats[10] = y + height;
768         floats[20] = r1;floats[21] = g1;floats[22] = b1;floats[23] = a1;
769         floats[24] = r2;floats[25] = g2;floats[26] = b2;floats[27] = a2;
770         floats[28] = r4;floats[29] = g4;floats[30] = b4;floats[31] = a4;
771         floats[32] = r3;floats[33] = g3;floats[34] = b3;floats[35] = a3;
772
773         R_Mesh_Draw(0, 4, 2, polygonelements);
774 }
775
776 void DrawQ_Mesh (drawqueuemesh_t *mesh, int flags)
777 {
778         if (!r_refdef.draw2dstage)
779         {
780                 Con_Printf("DrawQ_Mesh: not in 2d rendering stage!\n");
781                 return;
782         }
783
784         _DrawQ_ProcessDrawFlag(flags);
785
786         R_Mesh_VertexPointer(mesh->data_vertex3f);
787         R_Mesh_ColorPointer(mesh->data_color4f);
788         R_Mesh_ResetTextureState();
789         R_Mesh_TexBind(0, R_GetTexture(mesh->texture));
790         R_Mesh_TexCoordPointer(0, 2, mesh->data_texcoord2f);
791
792         GL_LockArrays(0, mesh->num_vertices);
793         R_Mesh_Draw(0, mesh->num_vertices, mesh->num_triangles, mesh->data_element3i);
794         GL_LockArrays(0, 0);
795 }
796
797 void DrawQ_LineLoop (drawqueuemesh_t *mesh, int flags)
798 {
799         int num;
800
801         if (!r_refdef.draw2dstage)
802         {
803                 Con_Printf("DrawQ_LineLoop: not in 2d rendering stage!\n");
804                 return;
805         }
806
807         _DrawQ_ProcessDrawFlag(flags);
808
809         GL_Color(1,1,1,1);
810         CHECKGLERROR
811         qglBegin(GL_LINE_LOOP);
812         for (num = 0;num < mesh->num_vertices;num++)
813         {
814                 if (mesh->data_color4f)
815                         GL_Color(mesh->data_color4f[num*4+0], mesh->data_color4f[num*4+1], mesh->data_color4f[num*4+2], mesh->data_color4f[num*4+3]);
816                 qglVertex2f(mesh->data_vertex3f[num*3+0], mesh->data_vertex3f[num*3+1]);
817         }
818         qglEnd();
819         CHECKGLERROR
820 }
821
822 //LordHavoc: FIXME: this is nasty!
823 void DrawQ_LineWidth (float width)
824 {
825         if (!r_refdef.draw2dstage)
826         {
827                 Con_Printf("DrawQ_LineWidth: not in 2d rendering stage!\n");
828                 return;
829         }
830         CHECKGLERROR
831         qglLineWidth(width);CHECKGLERROR
832 }
833
834 //[515]: this is old, delete
835 void DrawQ_Line (float width, float x1, float y1, float x2, float y2, float r, float g, float b, float alpha, int flags)
836 {
837         if (!r_refdef.draw2dstage)
838         {
839                 Con_Printf("DrawQ_Line: not in 2d rendering stage!\n");
840                 return;
841         }
842
843         CHECKGLERROR
844         if(width > 0)
845                 DrawQ_LineWidth(width);
846
847         _DrawQ_ProcessDrawFlag(flags);
848
849         GL_Color(r,g,b,alpha);
850         CHECKGLERROR
851         qglBegin(GL_LINES);
852         qglVertex2f(x1, y1);
853         qglVertex2f(x2, y2);
854         qglEnd();
855         CHECKGLERROR
856 }
857
858 void DrawQ_SetClipArea(float x, float y, float width, float height)
859 {
860         if (!r_refdef.draw2dstage)
861         {
862                 Con_Printf("DrawQ_SetClipArea: not in 2d rendering stage!\n");
863                 return;
864         }
865
866         // We have to convert the con coords into real coords
867         // OGL uses top to bottom
868         GL_Scissor((int)(x * ((float)vid.width / vid_conwidth.integer)), (int)(y * ((float) vid.height / vid_conheight.integer)), (int)(width * ((float)vid.width / vid_conwidth.integer)), (int)(height * ((float)vid.height / vid_conheight.integer)));
869
870         GL_ScissorTest(true);
871 }
872
873 void DrawQ_ResetClipArea(void)
874 {
875         if (!r_refdef.draw2dstage)
876         {
877                 Con_Printf("DrawQ_ResetClipArea: not in 2d rendering stage!\n");
878                 return;
879         }
880         GL_ScissorTest(false);
881 }
882
883 void DrawQ_Finish(void)
884 {
885         if (!r_refdef.draw2dstage)
886         {
887                 Con_Printf("R_DrawQueue: not in 2d rendering stage!\n");
888                 return;
889         }
890
891         r_refdef.draw2dstage = false;
892 }
893
894 static float blendvertex3f[9] = {-5000, -5000, 10, 10000, -5000, 10, -5000, 10000, 10};
895 void R_DrawGamma(void)
896 {
897         float c[4];
898         if (!vid_usinghwgamma)
899         {
900                 // all the blends ignore depth
901                 R_Mesh_VertexPointer(blendvertex3f);
902                 R_Mesh_ColorPointer(NULL);
903                 R_Mesh_ResetTextureState();
904                 GL_DepthMask(true);
905                 GL_DepthTest(false);
906                 if (v_color_enable.integer)
907                 {
908                         c[0] = v_color_white_r.value;
909                         c[1] = v_color_white_g.value;
910                         c[2] = v_color_white_b.value;
911                 }
912                 else
913                         c[0] = c[1] = c[2] = v_contrast.value;
914                 if (c[0] >= 1.01f || c[1] >= 1.01f || c[2] >= 1.01f)
915                 {
916                         GL_BlendFunc(GL_DST_COLOR, GL_ONE);
917                         while (c[0] >= 1.01f || c[1] >= 1.01f || c[2] >= 1.01f)
918                         {
919                                 GL_Color(bound(0, c[0] - 1, 1), bound(0, c[1] - 1, 1), bound(0, c[2] - 1, 1), 1);
920                                 R_Mesh_Draw(0, 3, 1, polygonelements);
921                                 VectorScale(c, 0.5, c);
922                         }
923                 }
924                 if (v_color_enable.integer)
925                 {
926                         c[0] = v_color_black_r.value;
927                         c[1] = v_color_black_g.value;
928                         c[2] = v_color_black_b.value;
929                 }
930                 else
931                         c[0] = c[1] = c[2] = v_brightness.value;
932                 if (c[0] >= 0.01f || c[1] >= 0.01f || c[2] >= 0.01f)
933                 {
934                         GL_BlendFunc(GL_ONE, GL_ONE);
935                         GL_Color(c[0], c[1], c[2], 1);
936                         R_Mesh_Draw(0, 3, 1, polygonelements);
937                 }
938         }
939 }
940