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