]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - gl_draw.c
fix for 16bit textures looking awful (bug in the alpha check for 8bit)
[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 int quadelements[768];
381 float textverts[128*4*4];
382 float texttexcoords[128*4*4];
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_TextureState(&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                 m.blendfunc1 = GL_SRC_ALPHA;
437                 if (additive)
438                         m.blendfunc2 = GL_ONE;
439                 else
440                         m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
441                 m.depthdisable = true;
442                 R_Mesh_MainState(&m);
443
444                 c[0] = (float) ((color >> 24) & 0xFF) * (1.0f / 255.0f) * r_colorscale;
445                 c[1] = (float) ((color >> 16) & 0xFF) * (1.0f / 255.0f) * r_colorscale;
446                 c[2] = (float) ((color >>  8) & 0xFF) * (1.0f / 255.0f) * r_colorscale;
447                 c[3] = (float) ( color        & 0xFF) * (1.0f / 255.0f);
448                 x = dq->x;
449                 y = dq->y;
450                 w = dq->scalex;
451                 h = dq->scaley;
452
453                 switch(dq->command)
454                 {
455                 case DRAWQUEUE_PIC:
456                         str = (char *)(dq + 1);
457                         if (strcmp(str, currentpic))
458                         {
459                                 currentpic = str;
460                                 if (*str)
461                                 {
462                                         pic = Draw_CachePic(str);
463                                         m.tex[0] = R_GetTexture(pic->tex);
464                                 }
465                                 else
466                                         m.tex[0] = 0;
467                                 R_Mesh_TextureState(&m);
468                         }
469                         if (*str)
470                         {
471                                 if (w == 0)
472                                         w = pic->width;
473                                 if (h == 0)
474                                         h = pic->height;
475                         }
476                         GL_Color(c[0], c[1], c[2], c[3]);
477                         R_Mesh_GetSpace(4);
478                         varray_texcoord[0][ 0] = 0;varray_texcoord[0][ 1] = 0;
479                         varray_texcoord[0][ 4] = 1;varray_texcoord[0][ 5] = 0;
480                         varray_texcoord[0][ 8] = 1;varray_texcoord[0][ 9] = 1;
481                         varray_texcoord[0][12] = 0;varray_texcoord[0][13] = 1;
482                         varray_vertex[ 0] = x  ;varray_vertex[ 1] = y  ;varray_vertex[ 2] = 10;
483                         varray_vertex[ 4] = x+w;varray_vertex[ 5] = y  ;varray_vertex[ 6] = 10;
484                         varray_vertex[ 8] = x+w;varray_vertex[ 9] = y+h;varray_vertex[10] = 10;
485                         varray_vertex[12] = x  ;varray_vertex[13] = y+h;varray_vertex[14] = 10;
486                         R_Mesh_Draw(4, 2, quadelements);
487                         break;
488                 case DRAWQUEUE_STRING:
489                         str = (char *)(dq + 1);
490                         if (strcmp("gfx/conchars", currentpic))
491                         {
492                                 currentpic = "gfx/conchars";
493                                 m.tex[0] = chartexnum;
494                                 R_Mesh_TextureState(&m);
495                         }
496                         batchcount = 0;
497                         at = texttexcoords;
498                         av = textverts;
499                         GL_Color(c[0], c[1], c[2], c[3]);
500                         while ((num = *str++) && x < vid.conwidth)
501                         {
502                                 if (num != ' ')
503                                 {
504                                         s = (num & 15)*0.0625f + (0.5f / 256.0f);
505                                         t = (num >> 4)*0.0625f + (0.5f / 256.0f);
506                                         u = 0.0625f - (1.0f / 256.0f);
507                                         v = 0.0625f - (1.0f / 256.0f);
508                                         at[ 0] = s  ;at[ 1] = t  ;
509                                         at[ 4] = s+u;at[ 5] = t  ;
510                                         at[ 8] = s+u;at[ 9] = t+v;
511                                         at[12] = s  ;at[13] = t+v;
512                                         av[ 0] = x  ;av[ 1] = y  ;av[ 2] = 10;
513                                         av[ 4] = x+w;av[ 5] = y  ;av[ 6] = 10;
514                                         av[ 8] = x+w;av[ 9] = y+h;av[10] = 10;
515                                         av[12] = x  ;av[13] = y+h;av[14] = 10;
516                                         at += 16;
517                                         av += 16;
518                                         batchcount++;
519                                         if (batchcount >= 128)
520                                         {
521                                                 R_Mesh_GetSpace(batchcount * 4);
522                                                 memcpy(varray_vertex, textverts, sizeof(float[16]) * batchcount);
523                                                 memcpy(varray_texcoord[0], texttexcoords, sizeof(float[16]) * batchcount);
524                                                 R_Mesh_Draw(batchcount * 4, batchcount * 2, quadelements);
525                                                 batchcount = 0;
526                                                 at = texttexcoords;
527                                                 av = textverts;
528                                         }
529                                 }
530                                 x += w;
531                         }
532                         if (batchcount > 0)
533                         {
534                                 R_Mesh_GetSpace(batchcount * 4);
535                                 memcpy(varray_vertex, textverts, sizeof(float[16]) * batchcount);
536                                 memcpy(varray_texcoord[0], texttexcoords, sizeof(float[16]) * batchcount);
537                                 R_Mesh_Draw(batchcount * 4, batchcount * 2, quadelements);
538                         }
539                         break;
540                 case DRAWQUEUE_MESH:
541                         mesh = (void *)(dq + 1);
542                         m.tex[0] = R_GetTexture(mesh->texture);
543                         R_Mesh_TextureState(&m);
544                         GL_UseColorArray();
545                         R_Mesh_GetSpace(mesh->numvertices);
546                         memcpy(varray_vertex, mesh->vertices, sizeof(float[4]) * mesh->numvertices);
547                         memcpy(varray_texcoord[0], mesh->texcoords, sizeof(float[4]) * mesh->numvertices);
548                         memcpy(varray_color, mesh->colors, sizeof(float[4]) * mesh->numvertices);
549                         R_Mesh_Draw(mesh->numvertices, mesh->numtriangles, mesh->indices);
550                         currentpic = "\0";
551                         break;
552                 }
553         }
554
555         if (!vid_usinghwgamma)
556         {
557                 // all the blends ignore depth
558                 memset(&m, 0, sizeof(m));
559                 m.depthdisable = true;
560                 if (v_color_enable.integer)
561                 {
562                         c[0] = v_color_white_r.value;
563                         c[1] = v_color_white_g.value;
564                         c[2] = v_color_white_b.value;
565                 }
566                 else
567                         c[0] = c[1] = c[2] = v_contrast.value;
568                 VectorScale(c, (float) (1 << v_overbrightbits.integer), c);
569                 if (c[0] >= 1.01f || c[1] >= 1.01f || c[2] >= 1.01f)
570                 {
571                         m.blendfunc1 = GL_DST_COLOR;
572                         m.blendfunc2 = GL_ONE;
573                         R_Mesh_State(&m);
574                         while (c[0] >= 1.01f || c[1] >= 1.01f || c[2] >= 1.01f)
575                         {
576                                 GL_Color(bound(0, c[0] - 1, 1), bound(0, c[1] - 1, 1), bound(0, c[2] - 1, 1), 1);
577                                 R_Mesh_GetSpace(3);
578                                 varray_texcoord[0][0] = 0;varray_texcoord[0][1] = 0;
579                                 varray_texcoord[0][4] = 0;varray_texcoord[0][5] = 0;
580                                 varray_texcoord[0][8] = 0;varray_texcoord[0][9] = 0;
581                                 varray_vertex[0] = -5000;varray_vertex[1] = -5000;varray_vertex[2] = 10;
582                                 varray_vertex[4] = 10000;varray_vertex[5] = -5000;varray_vertex[6] = 10;
583                                 varray_vertex[8] = -5000;varray_vertex[9] = 10000;varray_vertex[10] = 10;
584                                 R_Mesh_Draw(3, 1, polygonelements);
585                                 VectorScale(c, 0.5, c);
586                         }
587                 }
588                 if (v_color_enable.integer)
589                 {
590                         c[0] = v_color_black_r.value;
591                         c[1] = v_color_black_g.value;
592                         c[2] = v_color_black_b.value;
593                 }
594                 else
595                         c[0] = c[1] = c[2] = v_brightness.value;
596                 if (c[0] >= 0.01f || c[1] >= 0.01f || c[2] >= 0.01f)
597                 {
598                         m.blendfunc1 = GL_ONE;
599                         m.blendfunc2 = GL_ONE;
600                         R_Mesh_State(&m);
601                         GL_Color(c[0], c[1], c[2], 1);
602                         R_Mesh_GetSpace(3);
603                         varray_texcoord[0][0] = 0;varray_texcoord[0][1] = 0;
604                         varray_texcoord[0][4] = 0;varray_texcoord[0][5] = 0;
605                         varray_texcoord[0][8] = 0;varray_texcoord[0][9] = 0;
606                         varray_vertex[0] = -5000;varray_vertex[1] = -5000;varray_vertex[2] = 10;
607                         varray_vertex[4] = 10000;varray_vertex[5] = -5000;varray_vertex[6] = 10;
608                         varray_vertex[8] = -5000;varray_vertex[9] = 10000;varray_vertex[10] = 10;
609                         R_Mesh_Draw(3, 1, polygonelements);
610                 }
611         }
612         R_Mesh_Finish();
613 }
614