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