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