]> icculus.org git repositories - divverent/darkplaces.git/blob - gl_draw.c
GAME_NEXUIZ no longer loads a number of gfx/ pics that it does not use
[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 (const char *path, qboolean persistent)
266 {
267         int i, crc, hashkey;
268         cachepic_t *pic;
269         qpic_t *p;
270         int persistentflag;
271
272     if (!strncmp(CLVIDEOPREFIX, path, sizeof(CLVIDEOPREFIX) - 1)) {
273                 clvideo_t *video;
274
275                 video = CL_GetVideo(path);
276                 if( video )
277                         return &video->cpif;
278         }
279
280         if (persistent) {
281                 persistentflag = TEXF_PRECACHE;
282         } else {
283                 persistentflag = 0;
284         }
285
286         crc = CRC_Block(path, strlen(path));
287         hashkey = ((crc >> 8) ^ crc) % CACHEPICHASHSIZE;
288         for (pic = cachepichash[hashkey];pic;pic = pic->chain)
289                 if (!strcmp (path, pic->name))
290                         return pic;
291
292         if (numcachepics == MAX_CACHED_PICS)
293                 Sys_Error ("numcachepics == MAX_CACHED_PICS");
294         pic = cachepics + (numcachepics++);
295         strcpy (pic->name, path);
296         // link into list
297         pic->chain = cachepichash[hashkey];
298         cachepichash[hashkey] = pic;
299
300         // load the pic from disk
301         pic->tex = loadtextureimage(drawtexturepool, path, 0, 0, false, TEXF_ALPHA | persistentflag);
302         if (pic->tex == NULL && !strncmp(path, "gfx/", 4))
303         {
304                 // compatibility with older versions
305                 pic->tex = loadtextureimage(drawtexturepool, path + 4, 0, 0, false, TEXF_ALPHA | persistentflag);
306                 // failed to find gfx/whatever.tga or similar, try the wad
307                 if (pic->tex == NULL && (p = W_GetLumpName (path + 4)))
308                 {
309                         if (!strcmp(path, "gfx/conchars"))
310                         {
311                                 qbyte *pix;
312                                 // conchars is a raw image and with the wrong transparent color
313                                 pix = (qbyte *)p;
314                                 for (i = 0;i < 128 * 128;i++)
315                                         if (pix[i] == 0)
316                                                 pix[i] = 255;
317                                 pic->tex = R_LoadTexture2D(drawtexturepool, path, 128, 128, pix, TEXTYPE_PALETTE, TEXF_ALPHA | persistentflag, palette_complete);
318                         }
319                         else
320                                 pic->tex = R_LoadTexture2D(drawtexturepool, path, p->width, p->height, p->data, TEXTYPE_PALETTE, TEXF_ALPHA | persistentflag, palette_complete);
321                 }
322         }
323
324         if (pic->tex == NULL && !strcmp(path, "gfx/conchars"))
325                 pic->tex = draw_generateconchars();
326         if (pic->tex == NULL && !strcmp(path, "ui/mousepointer.tga"))
327                 pic->tex = draw_generatemousepointer();
328         if (pic->tex == NULL && !strcmp(path, "gfx/prydoncursor001.tga"))
329                 pic->tex = draw_generatemousepointer();
330         if (pic->tex == NULL && !strcmp(path, "gfx/crosshair1.tga"))
331                 pic->tex = draw_generatecrosshair(0);
332         if (pic->tex == NULL && !strcmp(path, "gfx/crosshair2.tga"))
333                 pic->tex = draw_generatecrosshair(1);
334         if (pic->tex == NULL && !strcmp(path, "gfx/crosshair3.tga"))
335                 pic->tex = draw_generatecrosshair(2);
336         if (pic->tex == NULL && !strcmp(path, "gfx/crosshair4.tga"))
337                 pic->tex = draw_generatecrosshair(3);
338         if (pic->tex == NULL && !strcmp(path, "gfx/crosshair5.tga"))
339                 pic->tex = draw_generatecrosshair(4);
340         if (pic->tex == NULL && !strcmp(path, "gfx/colorcontrol/ditherpattern.tga"))
341                 pic->tex = draw_generateditherpattern();
342         if (pic->tex == NULL)
343         {
344                 Con_Printf("Draw_CachePic: failed to load %s\n", path);
345                 pic->tex = r_texture_notexture;
346         }
347
348         pic->width = R_TextureWidth(pic->tex);
349         pic->height = R_TextureHeight(pic->tex);
350         return pic;
351 }
352
353 cachepic_t *Draw_NewPic(const char *picname, int width, int height, int alpha, qbyte *pixels)
354 {
355         int crc, hashkey;
356         cachepic_t *pic;
357
358         crc = CRC_Block(picname, strlen(picname));
359         hashkey = ((crc >> 8) ^ crc) % CACHEPICHASHSIZE;
360         for (pic = cachepichash[hashkey];pic;pic = pic->chain)
361                 if (!strcmp (picname, pic->name))
362                         break;
363
364         if (pic)
365         {
366                 if (pic->tex && pic->width == width && pic->height == height)
367                 {
368                         R_UpdateTexture(pic->tex, pixels);
369                         return pic;
370                 }
371         }
372         else
373         {
374                 if (pic == NULL)
375                 {
376                         if (numcachepics == MAX_CACHED_PICS)
377                                 Sys_Error ("numcachepics == MAX_CACHED_PICS");
378                         pic = cachepics + (numcachepics++);
379                         strcpy (pic->name, picname);
380                         // link into list
381                         pic->chain = cachepichash[hashkey];
382                         cachepichash[hashkey] = pic;
383                 }
384         }
385
386         pic->width = width;
387         pic->height = height;
388         if (pic->tex)
389                 R_FreeTexture(pic->tex);
390         pic->tex = R_LoadTexture2D(drawtexturepool, picname, width, height, pixels, TEXTYPE_RGBA, alpha ? TEXF_ALPHA : 0, NULL);
391         return pic;
392 }
393
394 void Draw_FreePic(const char *picname)
395 {
396         int crc;
397         int hashkey;
398         cachepic_t *pic;
399         // this doesn't really free the pic, but does free it's texture
400         crc = CRC_Block(picname, strlen(picname));
401         hashkey = ((crc >> 8) ^ crc) % CACHEPICHASHSIZE;
402         for (pic = cachepichash[hashkey];pic;pic = pic->chain)
403         {
404                 if (!strcmp (picname, pic->name) && pic->tex)
405                 {
406                         R_FreeTexture(pic->tex);
407                         pic->width = 0;
408                         pic->height = 0;
409                         return;
410                 }
411         }
412 }
413
414 /*
415 ===============
416 Draw_Init
417 ===============
418 */
419 static void gl_draw_start(void)
420 {
421         drawtexturepool = R_AllocTexturePool();
422
423         numcachepics = 0;
424         memset(cachepichash, 0, sizeof(cachepichash));
425
426         char_texture = Draw_CachePic("gfx/conchars", true)->tex;
427 }
428
429 static void gl_draw_shutdown(void)
430 {
431         R_FreeTexturePool(&drawtexturepool);
432
433         numcachepics = 0;
434         memset(cachepichash, 0, sizeof(cachepichash));
435 }
436
437 static void gl_draw_newmap(void)
438 {
439 }
440
441 void GL_Draw_Init (void)
442 {
443         numcachepics = 0;
444         memset(cachepichash, 0, sizeof(cachepichash));
445
446         R_RegisterModule("GL_Draw", gl_draw_start, gl_draw_shutdown, gl_draw_newmap);
447 }
448
449 float blendvertex3f[9] = {-5000, -5000, 10, 10000, -5000, 10, -5000, 10000, 10};
450
451 int quadelements[768];
452 void R_DrawQueue(void)
453 {
454         int pos, num, chartexnum, texnum, batch;
455         float x, y, w, h, s, t, u, v, *av, *at, c[4];
456         cachepic_t *pic;
457         drawqueue_t *dq;
458         char *str;
459         int batchcount;
460         unsigned int color;
461         drawqueuemesh_t *mesh;
462         rmeshstate_t m;
463
464         if (!r_render.integer)
465                 return;
466
467         if (!quadelements[1])
468         {
469                 // elements for rendering a series of quads as triangles
470                 for (batch = 0, pos = 0, num = 0;batch < 128;batch++, num += 4)
471                 {
472                         quadelements[pos++] = num;
473                         quadelements[pos++] = num + 1;
474                         quadelements[pos++] = num + 2;
475                         quadelements[pos++] = num;
476                         quadelements[pos++] = num + 2;
477                         quadelements[pos++] = num + 3;
478                 }
479         }
480
481         r_view_width = bound(0, r_refdef.width, vid.realwidth);
482         r_view_height = bound(0, r_refdef.height, vid.realheight);
483         r_view_depth = 1;
484         r_view_x = bound(0, r_refdef.x, vid.realwidth - r_refdef.width);
485         r_view_y = bound(0, r_refdef.y, vid.realheight - r_refdef.height);
486         r_view_z = 0;
487         r_view_fov_x = bound(0.1, r_refdef.fov_x, 170);
488         r_view_fov_y = bound(0.1, r_refdef.fov_y, 170);
489         r_view_matrix = r_refdef.viewentitymatrix;
490         GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
491
492         qglViewport(r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
493         GL_SetupView_Mode_Ortho(0, 0, vid.conwidth, vid.conheight, -10, 100);
494         qglDepthFunc(GL_LEQUAL);
495         R_Mesh_Matrix(&r_identitymatrix);
496
497         chartexnum = R_GetTexture(char_texture);
498
499         memset(&m, 0, sizeof(m));
500
501         pic = NULL;
502         texnum = 0;
503         color = 0;
504         GL_Color(1,1,1,1);
505
506         batch = false;
507         batchcount = 0;
508         for (pos = 0;pos < r_refdef.drawqueuesize;pos += ((drawqueue_t *)(r_refdef.drawqueue + pos))->size)
509         {
510                 dq = (drawqueue_t *)(r_refdef.drawqueue + pos);
511                 color = dq->color;
512
513                 if(dq->flags == DRAWFLAG_ADDITIVE)
514                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
515                 else if(dq->flags == DRAWFLAG_MODULATE)
516                         GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
517                 else if(dq->flags == DRAWFLAG_2XMODULATE)
518                         GL_BlendFunc(GL_DST_COLOR,GL_SRC_COLOR);
519                 else
520                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
521
522                 GL_DepthMask(true);
523                 GL_DepthTest(false);
524
525                 c[0] = (float) ((color >> 24) & 0xFF) * (1.0f / 255.0f);
526                 c[1] = (float) ((color >> 16) & 0xFF) * (1.0f / 255.0f);
527                 c[2] = (float) ((color >>  8) & 0xFF) * (1.0f / 255.0f);
528                 c[3] = (float) ( color        & 0xFF) * (1.0f / 255.0f);
529                 x = dq->x;
530                 y = dq->y;
531                 w = dq->scalex;
532                 h = dq->scaley;
533
534                 switch(dq->command)
535                 {
536                 case DRAWQUEUE_STRING:
537                         GL_Color(c[0], c[1], c[2], c[3]);
538                         str = (char *)(dq + 1);
539                         batchcount = 0;
540                         m.pointer_vertex = varray_vertex3f;
541                         m.pointer_color = NULL;
542                         m.pointer_texcoord[0] = varray_texcoord2f[0];
543                         m.tex[0] = chartexnum;
544                         R_Mesh_State(&m);
545                         at = varray_texcoord2f[0];
546                         av = varray_vertex3f;
547                         while ((num = *str++) && x < vid.conwidth)
548                         {
549                                 if (num != ' ')
550                                 {
551                                         s = (num & 15)*0.0625f + (0.5f / 256.0f);
552                                         t = (num >> 4)*0.0625f + (0.5f / 256.0f);
553                                         u = 0.0625f - (1.0f / 256.0f);
554                                         v = 0.0625f - (1.0f / 256.0f);
555                                         at[ 0] = s  ;at[ 1] = t  ;
556                                         at[ 2] = s+u;at[ 3] = t  ;
557                                         at[ 4] = s+u;at[ 5] = t+v;
558                                         at[ 6] = s  ;at[ 7] = t+v;
559                                         av[ 0] = x  ;av[ 1] = y  ;av[ 2] = 10;
560                                         av[ 3] = x+w;av[ 4] = y  ;av[ 5] = 10;
561                                         av[ 6] = x+w;av[ 7] = y+h;av[ 8] = 10;
562                                         av[ 9] = x  ;av[10] = y+h;av[11] = 10;
563                                         at += 8;
564                                         av += 12;
565                                         batchcount++;
566                                         if (batchcount >= 128)
567                                         {
568                                                 GL_LockArrays(0, batchcount * 4);
569                                                 R_Mesh_Draw(0, batchcount * 4, batchcount * 2, quadelements);
570                                                 GL_LockArrays(0, 0);
571                                                 batchcount = 0;
572                                                 at = varray_texcoord2f[0];
573                                                 av = varray_vertex3f;
574                                         }
575                                 }
576                                 x += w;
577                         }
578                         if (batchcount > 0)
579                         {
580                                 GL_LockArrays(0, batchcount * 4);
581                                 R_Mesh_Draw(0, batchcount * 4, batchcount * 2, quadelements);
582                                 GL_LockArrays(0, 0);
583                         }
584                         break;
585                 case DRAWQUEUE_MESH:
586                         mesh = (void *)(dq + 1);
587                         m.pointer_vertex = mesh->data_vertex3f;
588                         m.pointer_color = mesh->data_color4f;
589                         m.pointer_texcoord[0] = mesh->data_texcoord2f;
590                         m.tex[0] = R_GetTexture(mesh->texture);
591                         if (!m.tex[0])
592                                 m.pointer_texcoord[0] = NULL;
593                         R_Mesh_State(&m);
594                         GL_LockArrays(0, mesh->num_vertices);
595                         R_Mesh_Draw(0, mesh->num_vertices, mesh->num_triangles, mesh->data_element3i);
596                         GL_LockArrays(0, 0);
597                         break;
598                 case DRAWQUEUE_SETCLIP:
599                         {
600                                 // We have to convert the con coords into real coords
601                                 int x , y, width, height;
602                                 x = dq->x * ((float)vid.realwidth / vid.conwidth);
603                                 // OGL uses top to bottom
604                                 y = dq->y * ((float) vid.realheight / vid.conheight);
605                                 width = dq->scalex * ((float)vid.realwidth / vid.conwidth);
606                                 height = dq->scaley * ((float)vid.realheight / vid.conheight);
607
608                                 GL_Scissor(x, y, width, height);
609
610                                 GL_ScissorTest(true);
611                         }
612                         break;
613                 case DRAWQUEUE_RESETCLIP:
614                         GL_ScissorTest(false);
615                         break;
616                 }
617         }
618
619         if (!vid_usinghwgamma)
620         {
621                 // all the blends ignore depth
622                 memset(&m, 0, sizeof(m));
623                 m.pointer_vertex = blendvertex3f;
624                 R_Mesh_State(&m);
625                 GL_DepthMask(true);
626                 GL_DepthTest(false);
627                 if (v_color_enable.integer)
628                 {
629                         c[0] = v_color_white_r.value;
630                         c[1] = v_color_white_g.value;
631                         c[2] = v_color_white_b.value;
632                 }
633                 else
634                         c[0] = c[1] = c[2] = v_contrast.value;
635                 if (c[0] >= 1.01f || c[1] >= 1.01f || c[2] >= 1.01f)
636                 {
637                         GL_BlendFunc(GL_DST_COLOR, GL_ONE);
638                         while (c[0] >= 1.01f || c[1] >= 1.01f || c[2] >= 1.01f)
639                         {
640                                 GL_Color(bound(0, c[0] - 1, 1), bound(0, c[1] - 1, 1), bound(0, c[2] - 1, 1), 1);
641                                 R_Mesh_Draw(0, 3, 1, polygonelements);
642                                 VectorScale(c, 0.5, c);
643                         }
644                 }
645                 if (v_color_enable.integer)
646                 {
647                         c[0] = v_color_black_r.value;
648                         c[1] = v_color_black_g.value;
649                         c[2] = v_color_black_b.value;
650                 }
651                 else
652                         c[0] = c[1] = c[2] = v_brightness.value;
653                 if (c[0] >= 0.01f || c[1] >= 0.01f || c[2] >= 0.01f)
654                 {
655                         GL_BlendFunc(GL_ONE, GL_ONE);
656                         GL_Color(c[0], c[1], c[2], 1);
657                         R_Mesh_Draw(0, 3, 1, polygonelements);
658                 }
659         }
660 }
661