]> icculus.org git repositories - divverent/darkplaces.git/blob - gl_draw.c
now does batching of transparent surfaces, such as particles, this raised performance...
[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         r_view_width = bound(0, r_refdef.width, vid.width);
497         r_view_height = bound(0, r_refdef.height, vid.height);
498         r_view_depth = 1;
499         r_view_x = bound(0, r_refdef.x, vid.width - r_refdef.width);
500         r_view_y = bound(0, r_refdef.y, vid.height - r_refdef.height);
501         r_view_z = 0;
502         r_view_matrix = r_refdef.viewentitymatrix;
503         GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
504
505         CHECKGLERROR
506         qglViewport(r_view_x, vid.height - (r_view_y + r_view_height), r_view_width, r_view_height);CHECKGLERROR
507         GL_SetupView_Mode_Ortho(0, 0, vid_conwidth.integer, vid_conheight.integer, -10, 100);
508         qglDepthFunc(GL_LEQUAL);CHECKGLERROR
509         R_Mesh_Matrix(&identitymatrix);
510
511         GL_DepthMask(true);
512         GL_DepthTest(false);
513         GL_Color(1,1,1,1);
514
515         r_refdef.draw2dstage = true;
516 }
517
518 void DrawQ_Pic(float x, float y, cachepic_t *pic, float width, float height, float red, float green, float blue, float alpha, int flags)
519 {
520         if (!r_refdef.draw2dstage)
521         {
522                 Con_Printf("DrawQ_Pic: not in 2d rendering stage!\n");
523                 return;
524         }
525         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);
526 }
527
528 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)
529 {
530         int i, num;
531         float *av, *at;
532         int batchcount;
533         float vertex3f[QUADELEMENTS_MAXQUADS*4*3];
534         float texcoord2f[QUADELEMENTS_MAXQUADS*4*2];
535
536         if (!r_refdef.draw2dstage)
537         {
538                 Con_Printf("DrawQ_String: not in 2d rendering stage!\n");
539                 return;
540         }
541
542         if (!r_render.integer)
543                 return;
544
545         if (alpha < (1.0f / 255.0f))
546                 return;
547
548         if(flags == DRAWFLAG_ADDITIVE)
549                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
550         else if(flags == DRAWFLAG_MODULATE)
551                 GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
552         else if(flags == DRAWFLAG_2XMODULATE)
553                 GL_BlendFunc(GL_DST_COLOR,GL_SRC_COLOR);
554         else
555                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
556
557         GL_Color(red, green, blue, alpha);
558
559         R_Mesh_VertexPointer(vertex3f);
560         R_Mesh_ColorPointer(NULL);
561         R_Mesh_ResetTextureState();
562         R_Mesh_TexBind(0, R_GetTexture(char_texture));
563         R_Mesh_TexCoordPointer(0, 2, texcoord2f);
564
565         at = texcoord2f;
566         av = vertex3f;
567         batchcount = 0;
568
569         if (maxlen < 1)
570                 maxlen = 9999;
571         for (i = 0;i < maxlen && x < vid_conwidth.integer && (num = string[i]);i++, x += w)
572         {
573                 float s, t, u, v;
574                 if (num == ' ')
575                         continue;
576                 s = (num & 15)*0.0625f + (0.5f / 256.0f);
577                 t = (num >> 4)*0.0625f + (0.5f / 256.0f);
578                 u = 0.0625f - (1.0f / 256.0f);
579                 v = 0.0625f - (1.0f / 256.0f);
580                 at[ 0] = s  ;at[ 1] = t  ;
581                 at[ 2] = s+u;at[ 3] = t  ;
582                 at[ 4] = s+u;at[ 5] = t+v;
583                 at[ 6] = s  ;at[ 7] = t+v;
584                 av[ 0] = x  ;av[ 1] = y  ;av[ 2] = 10;
585                 av[ 3] = x+w;av[ 4] = y  ;av[ 5] = 10;
586                 av[ 6] = x+w;av[ 7] = y+h;av[ 8] = 10;
587                 av[ 9] = x  ;av[10] = y+h;av[11] = 10;
588                 at += 8;
589                 av += 12;
590                 batchcount++;
591                 if (batchcount >= QUADELEMENTS_MAXQUADS)
592                 {
593                         GL_LockArrays(0, batchcount * 4);
594                         R_Mesh_Draw(0, batchcount * 4, batchcount * 2, quadelements);
595                         GL_LockArrays(0, 0);
596                         batchcount = 0;
597                         at = texcoord2f;
598                         av = vertex3f;
599                 }
600         }
601         if (batchcount > 0)
602         {
603                 GL_LockArrays(0, batchcount * 4);
604                 R_Mesh_Draw(0, batchcount * 4, batchcount * 2, quadelements);
605                 GL_LockArrays(0, 0);
606         }
607 }
608
609 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)
610 {
611         if (!r_refdef.draw2dstage)
612         {
613                 Con_Printf("DrawQ_String: not in 2d rendering stage!\n");
614                 return;
615         }
616
617         if (r_textshadow.integer)
618                 DrawQ_String_Real(x+scalex*0.25,y+scaley*0.25,string,maxlen,scalex,scaley,0,0,0,alpha*0.8,flags);
619
620         DrawQ_String_Real(x,y,string,maxlen,scalex,scaley,red,green,blue,alpha,flags);
621 }
622
623 // color tag printing
624 static vec4_t string_colors[] =
625 {
626         // Quake3 colors
627         // LordHavoc: why on earth is cyan before magenta in Quake3?
628         // LordHavoc: note: Doom3 uses white for [0] and [7]
629         {0.0, 0.0, 0.0, 1.0}, // black
630         {1.0, 0.0, 0.0, 1.0}, // red
631         {0.0, 1.0, 0.0, 1.0}, // green
632         {1.0, 1.0, 0.0, 1.0}, // yellow
633         {0.0, 0.0, 1.0, 1.0}, // blue
634         {0.0, 1.0, 1.0, 1.0}, // cyan
635         {1.0, 0.0, 1.0, 1.0}, // magenta
636         {1.0, 1.0, 1.0, 1.0}, // white
637         // [515]'s BX_COLOREDTEXT extension
638         {1.0, 1.0, 1.0, 0.5}, // half transparent
639         {0.5, 0.5, 0.5, 1.0}  // half brightness
640         // Black's color table
641         //{1.0, 1.0, 1.0, 1.0},
642         //{1.0, 0.0, 0.0, 1.0},
643         //{0.0, 1.0, 0.0, 1.0},
644         //{0.0, 0.0, 1.0, 1.0},
645         //{1.0, 1.0, 0.0, 1.0},
646         //{0.0, 1.0, 1.0, 1.0},
647         //{1.0, 0.0, 1.0, 1.0},
648         //{0.1, 0.1, 0.1, 1.0}
649 };
650
651 #define STRING_COLORS_COUNT     (sizeof(string_colors) / sizeof(vec4_t))
652
653 // color is read and changed in the end
654 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 )
655 {
656         vec_t *color;
657         int len;
658         int colorindex;
659         const char *start, *current;
660
661         if (!r_refdef.draw2dstage)
662         {
663                 Con_Printf("DrawQ_ColoredString: not in 2d rendering stage!\n");
664                 return;
665         }
666         if( !outcolor || *outcolor == -1 ) {
667                 colorindex = STRING_COLOR_DEFAULT;
668         } else {
669                 colorindex = *outcolor;
670         }
671         color = string_colors[colorindex];
672
673         if( maxlen < 1)
674                 len = (int)strlen( text );
675         else
676                 len = min( maxlen, (int) strlen( text ) );
677
678         start = current = text;
679         while( len > 0 ) {
680                 // check for color control char
681                 if( *current == STRING_COLOR_TAG ) {
682                         // get next char
683                         current++;
684                         len--;
685                         if( len == 0 ) {
686                                 break;
687                         }
688                         // display the tag char?
689                         if( *current == STRING_COLOR_TAG ) {
690                                 // only display one of the two
691                                 start = current;
692                                 // get the next char
693                                 current++;
694                                 len--;
695                         } else if( '0' <= *current && *current <= '9' ) {
696                                 colorindex = 0;
697                                 do {
698                                         colorindex = colorindex * 10 + (*current - '0');
699                                         // only read as long as it makes a valid index
700                                         if( colorindex >= (int)STRING_COLORS_COUNT ) {
701                                                 // undo the last operation
702                                                 colorindex /= 10;
703                                                 break;
704                                         }
705                                         current++;
706                                         len--;
707                                 } while( len > 0 && '0' <= *current && *current <= '9' );
708                                 // set the color
709                                 color = string_colors[colorindex];
710                                 // we jump over the color tag
711                                 start = current;
712                         }
713                 }
714                 // go on and read normal text in until the next control char
715                 while( len > 0 && *current != STRING_COLOR_TAG ) {
716                         current++;
717                         len--;
718                 }
719                 // display the text
720                 if( start != current ) {
721                         // draw the string
722                         DrawQ_String( x, y, start, current - start, scalex, scaley, basered * color[0], basegreen * color[1], baseblue * color[2], basealpha * color[3], flags );
723                         // update x to be at the new start position
724                         x += (current - start) * scalex;
725                         // set start accordingly
726                         start = current;
727                 }
728         }
729
730         // return the last colorindex
731         if( outcolor ) {
732                 *outcolor = colorindex;
733         }
734 }
735
736 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)
737 {
738         float floats[36];
739
740         if (!r_refdef.draw2dstage)
741         {
742                 Con_Printf("DrawQ_SuperPic: not in 2d rendering stage!\n");
743                 return;
744         }
745
746         if (!r_render.integer)
747                 return;
748
749         if(flags == DRAWFLAG_ADDITIVE)
750                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
751         else if(flags == DRAWFLAG_MODULATE)
752                 GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
753         else if(flags == DRAWFLAG_2XMODULATE)
754                 GL_BlendFunc(GL_DST_COLOR,GL_SRC_COLOR);
755         else
756                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
757
758         R_Mesh_VertexPointer(floats);
759         R_Mesh_ColorPointer(floats + 20);
760         R_Mesh_ResetTextureState();
761         if (pic)
762         {
763                 if (width == 0)
764                         width = pic->width;
765                 if (height == 0)
766                         height = pic->height;
767                 R_Mesh_TexBind(0, R_GetTexture(pic->tex));
768                 R_Mesh_TexCoordPointer(0, 2, floats + 12);
769                 floats[12] = s1;floats[13] = t1;
770                 floats[14] = s2;floats[15] = t2;
771                 floats[16] = s4;floats[17] = t4;
772                 floats[18] = s3;floats[19] = t3;
773         }
774
775         floats[2] = floats[5] = floats[8] = floats[11] = 0;
776         floats[0] = floats[9] = x;
777         floats[1] = floats[4] = y;
778         floats[3] = floats[6] = x + width;
779         floats[7] = floats[10] = y + height;
780         floats[20] = r1;floats[21] = g1;floats[22] = b1;floats[23] = a1;
781         floats[24] = r2;floats[25] = g2;floats[26] = b2;floats[27] = a2;
782         floats[28] = r4;floats[29] = g4;floats[30] = b4;floats[31] = a4;
783         floats[32] = r3;floats[33] = g3;floats[34] = b3;floats[35] = a3;
784
785         R_Mesh_Draw(0, 4, 2, polygonelements);
786 }
787
788 void DrawQ_Mesh (drawqueuemesh_t *mesh, int flags)
789 {
790         if (!r_refdef.draw2dstage)
791         {
792                 Con_Printf("DrawQ_Mesh: not in 2d rendering stage!\n");
793                 return;
794         }
795
796         if (!r_render.integer)
797                 return;
798
799         if(flags == DRAWFLAG_ADDITIVE)
800                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
801         else if(flags == DRAWFLAG_MODULATE)
802                 GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
803         else if(flags == DRAWFLAG_2XMODULATE)
804                 GL_BlendFunc(GL_DST_COLOR,GL_SRC_COLOR);
805         else
806                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
807
808         R_Mesh_VertexPointer(mesh->data_vertex3f);
809         R_Mesh_ColorPointer(mesh->data_color4f);
810         R_Mesh_ResetTextureState();
811         R_Mesh_TexBind(0, R_GetTexture(mesh->texture));
812         R_Mesh_TexCoordPointer(0, 2, mesh->data_texcoord2f);
813
814         GL_LockArrays(0, mesh->num_vertices);
815         R_Mesh_Draw(0, mesh->num_vertices, mesh->num_triangles, mesh->data_element3i);
816         GL_LockArrays(0, 0);
817 }
818
819 void DrawQ_LineLoop (drawqueuemesh_t *mesh, int flags)
820 {
821         int num;
822
823         if (!r_refdef.draw2dstage)
824         {
825                 Con_Printf("DrawQ_LineLoop: not in 2d rendering stage!\n");
826                 return;
827         }
828
829         if (!r_render.integer)
830                 return;
831
832         CHECKGLERROR
833         if(flags == DRAWFLAG_ADDITIVE)
834                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
835         else if(flags == DRAWFLAG_MODULATE)
836                 GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
837         else if(flags == DRAWFLAG_2XMODULATE)
838                 GL_BlendFunc(GL_DST_COLOR,GL_SRC_COLOR);
839         else
840                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
841
842         GL_Color(1,1,1,1);
843         CHECKGLERROR
844         qglBegin(GL_LINE_LOOP);
845         for (num = 0;num < mesh->num_vertices;num++)
846         {
847                 if (mesh->data_color4f)
848                         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]);
849                 qglVertex2f(mesh->data_vertex3f[num*3+0], mesh->data_vertex3f[num*3+1]);
850         }
851         qglEnd();
852         CHECKGLERROR
853 }
854
855 //LordHavoc: FIXME: this is nasty!
856 void DrawQ_LineWidth (float width)
857 {
858         if (!r_refdef.draw2dstage)
859         {
860                 Con_Printf("DrawQ_LineWidth: not in 2d rendering stage!\n");
861                 return;
862         }
863         CHECKGLERROR
864         qglLineWidth(width);CHECKGLERROR
865 }
866
867 //[515]: this is old, delete
868 void DrawQ_Line (float width, float x1, float y1, float x2, float y2, float r, float g, float b, float alpha, int flags)
869 {
870         if (!r_refdef.draw2dstage)
871         {
872                 Con_Printf("DrawQ_Line: not in 2d rendering stage!\n");
873                 return;
874         }
875
876         if (!r_render.integer)
877                 return;
878
879         CHECKGLERROR
880         if(width > 0)
881                 DrawQ_LineWidth(width);
882
883         if(flags == DRAWFLAG_ADDITIVE)
884                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
885         else if(flags == DRAWFLAG_MODULATE)
886                 GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
887         else if(flags == DRAWFLAG_2XMODULATE)
888                 GL_BlendFunc(GL_DST_COLOR,GL_SRC_COLOR);
889         else
890                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
891
892         GL_Color(r,g,b,alpha);
893         CHECKGLERROR
894         qglBegin(GL_LINES);
895         qglVertex2f(x1, y1);
896         qglVertex2f(x2, y2);
897         qglEnd();
898         CHECKGLERROR
899 }
900
901 void DrawQ_SetClipArea(float x, float y, float width, float height)
902 {
903         if (!r_refdef.draw2dstage)
904         {
905                 Con_Printf("DrawQ_SetClipArea: not in 2d rendering stage!\n");
906                 return;
907         }
908
909         // We have to convert the con coords into real coords
910         // OGL uses top to bottom
911         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)));
912
913         GL_ScissorTest(true);
914 }
915
916 void DrawQ_ResetClipArea(void)
917 {
918         if (!r_refdef.draw2dstage)
919         {
920                 Con_Printf("DrawQ_ResetClipArea: not in 2d rendering stage!\n");
921                 return;
922         }
923         GL_ScissorTest(false);
924 }
925
926 void DrawQ_Finish(void)
927 {
928         if (!r_refdef.draw2dstage)
929         {
930                 Con_Printf("R_DrawQueue: not in 2d rendering stage!\n");
931                 return;
932         }
933
934         r_refdef.draw2dstage = false;
935 }
936
937 static float blendvertex3f[9] = {-5000, -5000, 10, 10000, -5000, 10, -5000, 10000, 10};
938 void R_DrawGamma(void)
939 {
940         float c[4];
941         if (!vid_usinghwgamma)
942         {
943                 // all the blends ignore depth
944                 R_Mesh_VertexPointer(blendvertex3f);
945                 R_Mesh_ColorPointer(NULL);
946                 R_Mesh_ResetTextureState();
947                 GL_DepthMask(true);
948                 GL_DepthTest(false);
949                 if (v_color_enable.integer)
950                 {
951                         c[0] = v_color_white_r.value;
952                         c[1] = v_color_white_g.value;
953                         c[2] = v_color_white_b.value;
954                 }
955                 else
956                         c[0] = c[1] = c[2] = v_contrast.value;
957                 if (c[0] >= 1.01f || c[1] >= 1.01f || c[2] >= 1.01f)
958                 {
959                         GL_BlendFunc(GL_DST_COLOR, GL_ONE);
960                         while (c[0] >= 1.01f || c[1] >= 1.01f || c[2] >= 1.01f)
961                         {
962                                 GL_Color(bound(0, c[0] - 1, 1), bound(0, c[1] - 1, 1), bound(0, c[2] - 1, 1), 1);
963                                 R_Mesh_Draw(0, 3, 1, polygonelements);
964                                 VectorScale(c, 0.5, c);
965                         }
966                 }
967                 if (v_color_enable.integer)
968                 {
969                         c[0] = v_color_black_r.value;
970                         c[1] = v_color_black_g.value;
971                         c[2] = v_color_black_b.value;
972                 }
973                 else
974                         c[0] = c[1] = c[2] = v_brightness.value;
975                 if (c[0] >= 0.01f || c[1] >= 0.01f || c[2] >= 0.01f)
976                 {
977                         GL_BlendFunc(GL_ONE, GL_ONE);
978                         GL_Color(c[0], c[1], c[2], 1);
979                         R_Mesh_Draw(0, 3, 1, polygonelements);
980                 }
981         }
982 }
983