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