added scr_conbrightness cvar
[divverent/darkplaces.git] / gl_draw.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20
21 #include "quakedef.h"
22 #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, overbright, texnum, additive, 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         overbright = v_overbrightbits.integer;
425         batch = false;
426         batchcount = 0;
427         for (pos = 0;pos < r_refdef.drawqueuesize;pos += ((drawqueue_t *)(r_refdef.drawqueue + pos))->size)
428         {
429                 dq = (drawqueue_t *)(r_refdef.drawqueue + pos);
430                 additive = (dq->flags & DRAWFLAG_ADDITIVE) != 0;
431                 color = dq->color;
432                 GL_BlendFunc(GL_SRC_ALPHA, additive ? GL_ONE : GL_ONE_MINUS_SRC_ALPHA);
433                 GL_DepthMask(true);
434                 GL_DepthTest(false);
435
436                 c[0] = (float) ((color >> 24) & 0xFF) * (1.0f / 255.0f) * r_colorscale;
437                 c[1] = (float) ((color >> 16) & 0xFF) * (1.0f / 255.0f) * r_colorscale;
438                 c[2] = (float) ((color >>  8) & 0xFF) * (1.0f / 255.0f) * r_colorscale;
439                 c[3] = (float) ( color        & 0xFF) * (1.0f / 255.0f);
440                 x = dq->x;
441                 y = dq->y;
442                 w = dq->scalex;
443                 h = dq->scaley;
444
445                 switch(dq->command)
446                 {
447                 case DRAWQUEUE_STRING:
448                         GL_Color(c[0], c[1], c[2], c[3]);
449                         str = (char *)(dq + 1);
450                         if (strcmp("gfx/conchars", currentpic))
451                         {
452                                 currentpic = "gfx/conchars";
453                                 m.tex[0] = chartexnum;
454                         }
455                         batchcount = 0;
456                         GL_VertexPointer(varray_vertex3f);
457                         m.pointer_texcoord[0] = varray_texcoord2f[0];
458                         R_Mesh_State_Texture(&m);
459                         at = varray_texcoord2f[0];
460                         av = varray_vertex3f;
461                         while ((num = *str++) && x < vid.conwidth)
462                         {
463                                 if (num != ' ')
464                                 {
465                                         s = (num & 15)*0.0625f + (0.5f / 256.0f);
466                                         t = (num >> 4)*0.0625f + (0.5f / 256.0f);
467                                         u = 0.0625f - (1.0f / 256.0f);
468                                         v = 0.0625f - (1.0f / 256.0f);
469                                         at[ 0] = s  ;at[ 1] = t  ;
470                                         at[ 2] = s+u;at[ 3] = t  ;
471                                         at[ 4] = s+u;at[ 5] = t+v;
472                                         at[ 6] = s  ;at[ 7] = t+v;
473                                         av[ 0] = x  ;av[ 1] = y  ;av[ 2] = 10;
474                                         av[ 3] = x+w;av[ 4] = y  ;av[ 5] = 10;
475                                         av[ 6] = x+w;av[ 7] = y+h;av[ 8] = 10;
476                                         av[ 9] = x  ;av[10] = y+h;av[11] = 10;
477                                         at += 8;
478                                         av += 12;
479                                         batchcount++;
480                                         if (batchcount >= 128)
481                                         {
482                                                 R_Mesh_Draw(batchcount * 4, batchcount * 2, quadelements);
483                                                 batchcount = 0;
484                                                 at = varray_texcoord2f[0];
485                                                 av = varray_vertex3f;
486                                         }
487                                 }
488                                 x += w;
489                         }
490                         if (batchcount > 0)
491                                 R_Mesh_Draw(batchcount * 4, batchcount * 2, quadelements);
492                         break;
493                 case DRAWQUEUE_MESH:
494                         mesh = (void *)(dq + 1);
495                         GL_VertexPointer(mesh->vertex3f);
496                         GL_ColorPointer(mesh->color4f);
497                         m.tex[0] = R_GetTexture(mesh->texture);
498                         m.pointer_texcoord[0] = mesh->texcoord2f;
499                         R_Mesh_State_Texture(&m);
500                         R_Mesh_Draw(mesh->numvertices, mesh->numtriangles, mesh->element3i);
501                         currentpic = "\0";
502                         break;
503                 }
504         }
505
506         if (!vid_usinghwgamma)
507         {
508                 // all the blends ignore depth
509                 memset(&m, 0, sizeof(m));
510                 R_Mesh_State_Texture(&m);
511                 GL_DepthMask(true);
512                 GL_DepthTest(false);
513                 if (v_color_enable.integer)
514                 {
515                         c[0] = v_color_white_r.value;
516                         c[1] = v_color_white_g.value;
517                         c[2] = v_color_white_b.value;
518                 }
519                 else
520                         c[0] = c[1] = c[2] = v_contrast.value;
521                 VectorScale(c, (float) (1 << v_overbrightbits.integer), c);
522                 if (c[0] >= 1.01f || c[1] >= 1.01f || c[2] >= 1.01f)
523                 {
524                         GL_BlendFunc(GL_DST_COLOR, GL_ONE);
525                         GL_VertexPointer(blendvertex3f);
526                         while (c[0] >= 1.01f || c[1] >= 1.01f || c[2] >= 1.01f)
527                         {
528                                 GL_Color(bound(0, c[0] - 1, 1), bound(0, c[1] - 1, 1), bound(0, c[2] - 1, 1), 1);
529                                 R_Mesh_Draw(3, 1, polygonelements);
530                                 VectorScale(c, 0.5, c);
531                         }
532                 }
533                 if (v_color_enable.integer)
534                 {
535                         c[0] = v_color_black_r.value;
536                         c[1] = v_color_black_g.value;
537                         c[2] = v_color_black_b.value;
538                 }
539                 else
540                         c[0] = c[1] = c[2] = v_brightness.value;
541                 if (c[0] >= 0.01f || c[1] >= 0.01f || c[2] >= 0.01f)
542                 {
543                         GL_BlendFunc(GL_ONE, GL_ONE);
544                         GL_VertexPointer(blendvertex3f);
545                         GL_Color(c[0], c[1], c[2], 1);
546                         R_Mesh_Draw(3, 1, polygonelements);
547                 }
548         }
549         R_Mesh_Finish();
550 }
551