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