f435ed62081a9dda7c8396546842caa74402b186
[xonotic/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                                 pic = Draw_CachePic(str);
447                                 m.tex[0] = R_GetTexture(pic->tex);
448                                 R_Mesh_TextureState(&m);
449                         }
450                         if (*str)
451                         {
452                                 if (w == 0)
453                                         w = pic->width;
454                                 if (h == 0)
455                                         h = pic->height;
456                         }
457                         varray_color[0] = varray_color[4] = varray_color[ 8] = varray_color[12] = cr;
458                         varray_color[1] = varray_color[5] = varray_color[ 9] = varray_color[13] = cg;
459                         varray_color[2] = varray_color[6] = varray_color[10] = varray_color[14] = cb;
460                         varray_color[3] = varray_color[7] = varray_color[11] = varray_color[15] = ca;
461                         varray_texcoord[0][0] = 0;varray_texcoord[0][1] = 0;
462                         varray_texcoord[0][2] = 1;varray_texcoord[0][3] = 0;
463                         varray_texcoord[0][4] = 1;varray_texcoord[0][5] = 1;
464                         varray_texcoord[0][6] = 0;varray_texcoord[0][7] = 1;
465                         varray_vertex[ 0] = x  ;varray_vertex[ 1] = y  ;varray_vertex[ 2] = 10;
466                         varray_vertex[ 4] = x+w;varray_vertex[ 5] = y  ;varray_vertex[ 6] = 10;
467                         varray_vertex[ 8] = x+w;varray_vertex[ 9] = y+h;varray_vertex[10] = 10;
468                         varray_vertex[12] = x  ;varray_vertex[13] = y+h;varray_vertex[14] = 10;
469                         R_Mesh_Draw(4, 2, quadelements);
470                         break;
471                 case DRAWQUEUE_STRING:
472                         str = (char *)(dq + 1);
473                         if (strcmp("gfx/conchars", currentpic))
474                         {
475                                 currentpic = "gfx/conchars";
476                                 m.tex[0] = chartexnum;
477                                 R_Mesh_TextureState(&m);
478                         }
479                         batchcount = 0;
480                         ac = varray_color;
481                         at = varray_texcoord[0];
482                         av = varray_vertex;
483                         while ((num = *str++) && x < vid.conwidth)
484                         {
485                                 if (num != ' ')
486                                 {
487                                         s = (num & 15)*0.0625f + (0.5f / 256.0f);
488                                         t = (num >> 4)*0.0625f + (0.5f / 256.0f);
489                                         u = 0.0625f - (1.0f / 256.0f);
490                                         v = 0.0625f - (1.0f / 256.0f);
491                                         ac[0] = ac[4] = ac[ 8] = ac[12] = cr;
492                                         ac[1] = ac[5] = ac[ 9] = ac[13] = cg;
493                                         ac[2] = ac[6] = ac[10] = ac[14] = cb;
494                                         ac[3] = ac[7] = ac[11] = ac[15] = ca;
495                                         at[0] = s  ;at[1] = t  ;
496                                         at[2] = s+u;at[3] = t  ;
497                                         at[4] = s+u;at[5] = t+v;
498                                         at[6] = s  ;at[7] = t+v;
499                                         av[ 0] = x  ;av[ 1] = y  ;av[ 2] = 10;
500                                         av[ 4] = x+w;av[ 5] = y  ;av[ 6] = 10;
501                                         av[ 8] = x+w;av[ 9] = y+h;av[10] = 10;
502                                         av[12] = x  ;av[13] = y+h;av[14] = 10;
503                                         ac += 16;
504                                         at += 8;
505                                         av += 16;
506                                         batchcount++;
507                                         if (batchcount >= 128)
508                                         {
509                                                 R_Mesh_Draw(batchcount * 4, batchcount * 2, quadelements);
510                                                 batchcount = 0;
511                                                 ac = varray_color;
512                                                 at = varray_texcoord[0];
513                                                 av = varray_vertex;
514                                         }
515                                 }
516                                 x += w;
517                         }
518                         if (batchcount > 0)
519                                 R_Mesh_Draw(batchcount * 4, batchcount * 2, quadelements);
520                         break;
521                 case DRAWQUEUE_MESH:
522                         mesh = (void *)(dq + 1);
523                         m.tex[0] = R_GetTexture(mesh->texture);
524                         R_Mesh_TextureState(&m);
525                         R_Mesh_ResizeCheck(mesh->numvertices);
526                         memcpy(varray_vertex, mesh->vertices, sizeof(float[4]) * mesh->numvertices);
527                         memcpy(varray_texcoord[0], mesh->texcoords, sizeof(float[2]) * mesh->numvertices);
528                         memcpy(varray_color, mesh->colors, sizeof(float[4]) * mesh->numvertices);
529                         R_Mesh_Draw(mesh->numvertices, mesh->numtriangles, mesh->indices);
530                         currentpic = "\0";
531                         break;
532                 }
533         }
534
535         if (!v_hwgamma.integer)
536         {
537                 // we use one big triangle for all the screen blends
538                 varray_texcoord[0][0] = 0;varray_texcoord[0][1] = 0;
539                 varray_texcoord[0][2] = 0;varray_texcoord[0][3] = 0;
540                 varray_texcoord[0][4] = 0;varray_texcoord[0][5] = 0;
541                 varray_vertex[0] = -5000;varray_vertex[1] = -5000;varray_vertex[2] = 10;
542                 varray_vertex[4] = 10000;varray_vertex[1] = -5000;varray_vertex[2] = 10;
543                 varray_vertex[8] = -5000;varray_vertex[1] = 10000;varray_vertex[2] = 10;
544                 // alpha is 1 for all these
545                 varray_color[3] = varray_color[7] = varray_color[11] = 1;
546                 // all the blends ignore depth
547                 m.depthdisable = true;
548                 t = v_contrast.value * (float) (1 << v_overbrightbits.integer);
549                 if (t >= 1.01f)
550                 {
551                         m.blendfunc1 = GL_DST_COLOR;
552                         m.blendfunc2 = GL_ONE;
553                         R_Mesh_State(&m);
554                         while (t >= 1.01f)
555                         {
556                                 cr = t - 1.0f;
557                                 if (cr > 1.0f)
558                                         cr = 1.0f;
559                                 varray_color[0] = varray_color[4] = varray_color[ 8] = cr;
560                                 varray_color[1] = varray_color[5] = varray_color[ 9] = cr;
561                                 varray_color[2] = varray_color[6] = varray_color[10] = cr;
562                                 R_Mesh_Draw(3, 1, polygonelements);
563                                 t *= 0.5;
564                         }
565                 }
566                 else if (t <= 0.99f)
567                 {
568                         m.blendfunc1 = GL_ZERO;
569                         m.blendfunc2 = GL_SRC_COLOR;
570                         R_Mesh_State(&m);
571                         varray_color[0] = varray_color[4] = varray_color[ 8] = varray_color[12] = t;
572                         varray_color[1] = varray_color[5] = varray_color[ 9] = varray_color[13] = t;
573                         varray_color[2] = varray_color[6] = varray_color[10] = varray_color[14] = t;
574                         R_Mesh_Draw(3, 1, polygonelements);
575                 }
576                 if (v_brightness.value >= 0.01f)
577                 {
578                         m.blendfunc1 = GL_ONE;
579                         m.blendfunc2 = GL_ONE;
580                         R_Mesh_State(&m);
581                         varray_color[0] = varray_color[4] = varray_color[ 8] = varray_color[12] = v_brightness.value;
582                         varray_color[1] = varray_color[5] = varray_color[ 9] = varray_color[13] = v_brightness.value;
583                         varray_color[2] = varray_color[6] = varray_color[10] = varray_color[14] = v_brightness.value;
584                         R_Mesh_Draw(3, 1, polygonelements);
585                 }
586         }
587         R_Mesh_Finish();
588 }
589