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