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