most of Q2's keyboard handling ported over - what this means: keypad is now separatel...
[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 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 /*
201 ================
202 Draw_CachePic
203 ================
204 */
205 // FIXME: move this to client somehow
206 cachepic_t      *Draw_CachePic (char *path)
207 {
208         int i, crc, hashkey;
209         cachepic_t *pic;
210         qpic_t *p;
211
212         crc = CRC_Block(path, strlen(path));
213         hashkey = ((crc >> 8) ^ crc) % CACHEPICHASHSIZE;
214         for (pic = cachepichash[hashkey];pic;pic = pic->chain)
215                 if (!strcmp (path, pic->name))
216                         return pic;
217
218         if (numcachepics == MAX_CACHED_PICS)
219                 Sys_Error ("numcachepics == MAX_CACHED_PICS");
220         pic = cachepics + (numcachepics++);
221         strcpy (pic->name, path);
222         // link into list
223         pic->chain = cachepichash[hashkey];
224         cachepichash[hashkey] = pic;
225
226         // load the pic from disk
227         pic->tex = loadtextureimage(drawtexturepool, path, 0, 0, false, TEXF_ALPHA | TEXF_PRECACHE);
228         if (pic->tex == NULL && !strncmp(path, "gfx/", 4))
229         {
230                 // compatibility with older versions
231                 pic->tex = loadtextureimage(drawtexturepool, path + 4, 0, 0, false, TEXF_ALPHA | TEXF_PRECACHE);
232                 // failed to find gfx/whatever.tga or similar, try the wad
233                 if (pic->tex == NULL && (p = W_GetLumpName (path + 4)))
234                 {
235                         if (!strcmp(path, "gfx/conchars"))
236                         {
237                                 qbyte *pix;
238                                 // conchars is a raw image and with the wrong transparent color
239                                 pix = (qbyte *)p;
240                                 for (i = 0;i < 128 * 128;i++)
241                                         if (pix[i] == 0)
242                                                 pix[i] = 255;
243                                 pic->tex = R_LoadTexture2D(drawtexturepool, path, 128, 128, pix, TEXTYPE_PALETTE, TEXF_ALPHA | TEXF_PRECACHE, palette_complete);
244                         }
245                         else
246                                 pic->tex = R_LoadTexture2D(drawtexturepool, path, p->width, p->height, p->data, TEXTYPE_PALETTE, TEXF_ALPHA | TEXF_PRECACHE, palette_complete);
247                 }
248         }
249         if (pic->tex == NULL && !strcmp(path, "ui/mousepointer.tga"))
250                 pic->tex = draw_generatemousepointer();
251         if (pic->tex == NULL && !strcmp(path, "gfx/crosshair1.tga"))
252                 pic->tex = draw_generatecrosshair(0);
253         if (pic->tex == NULL && !strcmp(path, "gfx/crosshair2.tga"))
254                 pic->tex = draw_generatecrosshair(1);
255         if (pic->tex == NULL && !strcmp(path, "gfx/crosshair3.tga"))
256                 pic->tex = draw_generatecrosshair(2);
257         if (pic->tex == NULL && !strcmp(path, "gfx/crosshair4.tga"))
258                 pic->tex = draw_generatecrosshair(3);
259         if (pic->tex == NULL && !strcmp(path, "gfx/crosshair5.tga"))
260                 pic->tex = draw_generatecrosshair(4);
261         if (pic->tex == NULL)
262         {
263                 Con_Printf ("Draw_CachePic: failed to load %s\n", path);
264                 pic->tex = r_notexture;
265         }
266
267         pic->width = R_TextureWidth(pic->tex);
268         pic->height = R_TextureHeight(pic->tex);
269         return pic;
270 }
271
272 cachepic_t *Draw_NewPic(char *picname, int width, int height, int alpha, qbyte *pixels)
273 {
274         int crc, hashkey;
275         cachepic_t *pic;
276
277         crc = CRC_Block(picname, strlen(picname));
278         hashkey = ((crc >> 8) ^ crc) % CACHEPICHASHSIZE;
279         for (pic = cachepichash[hashkey];pic;pic = pic->chain)
280                 if (!strcmp (picname, pic->name))
281                         break;
282
283         if (pic)
284         {
285                 if (pic->tex && pic->width == width && pic->height == height)
286                 {
287                         R_UpdateTexture(pic->tex, pixels);
288                         return pic;
289                 }
290         }
291         else
292         {
293                 if (pic == NULL)
294                 {
295                         if (numcachepics == MAX_CACHED_PICS)
296                                 Sys_Error ("numcachepics == MAX_CACHED_PICS");
297                         pic = cachepics + (numcachepics++);
298                         strcpy (pic->name, picname);
299                         // link into list
300                         pic->chain = cachepichash[hashkey];
301                         cachepichash[hashkey] = pic;
302                 }
303         }
304
305         pic->width = width;
306         pic->height = height;
307         if (pic->tex)
308                 R_FreeTexture(pic->tex);
309         pic->tex = R_LoadTexture2D(drawtexturepool, picname, width, height, pixels, TEXTYPE_RGBA, alpha ? TEXF_ALPHA : 0, NULL);
310         return pic;
311 }
312
313 void Draw_FreePic(char *picname)
314 {
315         int crc;
316         int hashkey;
317         cachepic_t *pic;
318         // this doesn't really free the pic, but does free it's texture
319         crc = CRC_Block(picname, strlen(picname));
320         hashkey = ((crc >> 8) ^ crc) % CACHEPICHASHSIZE;
321         for (pic = cachepichash[hashkey];pic;pic = pic->chain)
322         {
323                 if (!strcmp (picname, pic->name))
324                 {
325                         R_FreeTexture(pic->tex);
326                         pic->width = 0;
327                         pic->height = 0;
328                         return;
329                 }
330         }
331 }
332
333 /*
334 ===============
335 Draw_Init
336 ===============
337 */
338 static void gl_draw_start(void)
339 {
340         drawtexturepool = R_AllocTexturePool();
341
342         numcachepics = 0;
343         memset(cachepichash, 0, sizeof(cachepichash));
344
345         char_texture = Draw_CachePic("gfx/conchars")->tex;
346 }
347
348 static void gl_draw_shutdown(void)
349 {
350         R_FreeTexturePool(&drawtexturepool);
351
352         numcachepics = 0;
353         memset(cachepichash, 0, sizeof(cachepichash));
354 }
355
356 static void gl_draw_newmap(void)
357 {
358 }
359
360 void GL_Draw_Init (void)
361 {
362         Cvar_RegisterVariable (&scr_conalpha);
363
364         numcachepics = 0;
365         memset(cachepichash, 0, sizeof(cachepichash));
366
367         R_RegisterModule("GL_Draw", gl_draw_start, gl_draw_shutdown, gl_draw_newmap);
368 }
369
370 int quadelements[768];
371 void R_DrawQueue(void)
372 {
373         int pos, num, chartexnum, overbright, texnum, additive, batch;
374         float x, y, w, h, s, t, u, v, cr, cg, cb, ca, *av, *at;
375         cachepic_t *pic;
376         drawqueue_t *dq;
377         char *str, *currentpic;
378         int batchcount;
379         unsigned int color;
380         drawqueuemesh_t *mesh;
381         rmeshstate_t m;
382
383         if (!r_render.integer)
384                 return;
385
386         if (!quadelements[1])
387         {
388                 // elements for rendering a series of quads as triangles
389                 for (batch = 0, pos = 0, num = 0;batch < 128;batch++, num += 4)
390                 {
391                         quadelements[pos++] = num;
392                         quadelements[pos++] = num + 1;
393                         quadelements[pos++] = num + 2;
394                         quadelements[pos++] = num;
395                         quadelements[pos++] = num + 2;
396                         quadelements[pos++] = num + 3;
397                 }
398         }
399         GL_SetupView_ViewPort(vid.realx, vid.realy, vid.realwidth, vid.realheight);
400         GL_SetupView_Mode_Ortho(0, 0, vid.conwidth, vid.conheight, -10, 100);
401         qglDepthFunc(GL_LEQUAL);
402         R_Mesh_Start();
403         R_Mesh_Matrix(&r_identitymatrix);
404
405         memset(&m, 0, sizeof(m));
406         chartexnum = R_GetTexture(char_texture);
407         m.tex[0] = chartexnum;
408         R_Mesh_TextureState(&m);
409
410         currentpic = "";
411         pic = NULL;
412         texnum = 0;
413         color = 0;
414
415         overbright = v_overbrightbits.integer;
416         batch = false;
417         batchcount = 0;
418         for (pos = 0;pos < r_refdef.drawqueuesize;pos += ((drawqueue_t *)(r_refdef.drawqueue + pos))->size)
419         {
420                 dq = (drawqueue_t *)(r_refdef.drawqueue + pos);
421                 additive = (dq->flags & DRAWFLAG_ADDITIVE) != 0;
422                 color = dq->color;
423                 m.blendfunc1 = GL_SRC_ALPHA;
424                 if (additive)
425                         m.blendfunc2 = GL_ONE;
426                 else
427                         m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
428                 m.depthdisable = true;
429                 R_Mesh_MainState(&m);
430
431                 cr = (float) ((color >> 24) & 0xFF) * (1.0f / 255.0f) * r_colorscale;
432                 cg = (float) ((color >> 16) & 0xFF) * (1.0f / 255.0f) * r_colorscale;
433                 cb = (float) ((color >>  8) & 0xFF) * (1.0f / 255.0f) * r_colorscale;
434                 ca = (float) ( color        & 0xFF) * (1.0f / 255.0f);
435                 x = dq->x;
436                 y = dq->y;
437                 w = dq->scalex;
438                 h = dq->scaley;
439
440                 switch(dq->command)
441                 {
442                 case DRAWQUEUE_PIC:
443                         str = (char *)(dq + 1);
444                         if (strcmp(str, currentpic))
445                         {
446                                 currentpic = str;
447                                 if (*str)
448                                 {
449                                         pic = Draw_CachePic(str);
450                                         m.tex[0] = R_GetTexture(pic->tex);
451                                 }
452                                 else
453                                         m.tex[0] = 0;
454                                 R_Mesh_TextureState(&m);
455                         }
456                         if (*str)
457                         {
458                                 if (w == 0)
459                                         w = pic->width;
460                                 if (h == 0)
461                                         h = pic->height;
462                         }
463                         varray_texcoord[0][ 0] = 0;varray_texcoord[0][ 1] = 0;
464                         varray_texcoord[0][ 4] = 1;varray_texcoord[0][ 5] = 0;
465                         varray_texcoord[0][ 8] = 1;varray_texcoord[0][ 9] = 1;
466                         varray_texcoord[0][12] = 0;varray_texcoord[0][13] = 1;
467                         varray_vertex[ 0] = x  ;varray_vertex[ 1] = y  ;varray_vertex[ 2] = 10;
468                         varray_vertex[ 4] = x+w;varray_vertex[ 5] = y  ;varray_vertex[ 6] = 10;
469                         varray_vertex[ 8] = x+w;varray_vertex[ 9] = y+h;varray_vertex[10] = 10;
470                         varray_vertex[12] = x  ;varray_vertex[13] = y+h;varray_vertex[14] = 10;
471                         GL_Color(cr, cg, cb, ca);
472                         R_Mesh_Draw(4, 2, quadelements);
473                         break;
474                 case DRAWQUEUE_STRING:
475                         str = (char *)(dq + 1);
476                         if (strcmp("gfx/conchars", currentpic))
477                         {
478                                 currentpic = "gfx/conchars";
479                                 m.tex[0] = chartexnum;
480                                 R_Mesh_TextureState(&m);
481                         }
482                         batchcount = 0;
483                         at = varray_texcoord[0];
484                         av = varray_vertex;
485                         GL_Color(cr, cg, cb, ca);
486                         while ((num = *str++) && x < vid.conwidth)
487                         {
488                                 if (num != ' ')
489                                 {
490                                         s = (num & 15)*0.0625f + (0.5f / 256.0f);
491                                         t = (num >> 4)*0.0625f + (0.5f / 256.0f);
492                                         u = 0.0625f - (1.0f / 256.0f);
493                                         v = 0.0625f - (1.0f / 256.0f);
494                                         at[ 0] = s  ;at[ 1] = t  ;
495                                         at[ 4] = s+u;at[ 5] = t  ;
496                                         at[ 8] = s+u;at[ 9] = t+v;
497                                         at[12] = s  ;at[13] = t+v;
498                                         av[ 0] = x  ;av[ 1] = y  ;av[ 2] = 10;
499                                         av[ 4] = x+w;av[ 5] = y  ;av[ 6] = 10;
500                                         av[ 8] = x+w;av[ 9] = y+h;av[10] = 10;
501                                         av[12] = x  ;av[13] = y+h;av[14] = 10;
502                                         at += 16;
503                                         av += 16;
504                                         batchcount++;
505                                         if (batchcount >= 128)
506                                         {
507                                                 R_Mesh_Draw(batchcount * 4, batchcount * 2, quadelements);
508                                                 batchcount = 0;
509                                                 at = varray_texcoord[0];
510                                                 av = varray_vertex;
511                                         }
512                                 }
513                                 x += w;
514                         }
515                         if (batchcount > 0)
516                                 R_Mesh_Draw(batchcount * 4, batchcount * 2, quadelements);
517                         break;
518                 case DRAWQUEUE_MESH:
519                         mesh = (void *)(dq + 1);
520                         m.tex[0] = R_GetTexture(mesh->texture);
521                         R_Mesh_TextureState(&m);
522                         R_Mesh_ResizeCheck(mesh->numvertices);
523                         memcpy(varray_vertex, mesh->vertices, sizeof(float[4]) * mesh->numvertices);
524                         memcpy(varray_texcoord[0], mesh->texcoords, sizeof(float[4]) * mesh->numvertices);
525                         memcpy(varray_color, mesh->colors, sizeof(float[4]) * mesh->numvertices);
526                         GL_UseColorArray();
527                         R_Mesh_Draw(mesh->numvertices, mesh->numtriangles, mesh->indices);
528                         currentpic = "\0";
529                         break;
530                 }
531         }
532
533         if (!v_hwgamma.integer)
534         {
535                 // we use one big triangle for all the screen blends
536                 varray_texcoord[0][0] = 0;varray_texcoord[0][1] = 0;
537                 varray_texcoord[0][4] = 0;varray_texcoord[0][5] = 0;
538                 varray_texcoord[0][8] = 0;varray_texcoord[0][9] = 0;
539                 varray_vertex[0] = -5000;varray_vertex[1] = -5000;varray_vertex[2] = 10;
540                 varray_vertex[4] = 10000;varray_vertex[5] = -5000;varray_vertex[6] = 10;
541                 varray_vertex[8] = -5000;varray_vertex[9] = 10000;varray_vertex[10] = 10;
542                 // all the blends ignore depth
543                 memset(&m, 0, sizeof(m));
544                 m.depthdisable = true;
545                 t = v_contrast.value * (float) (1 << v_overbrightbits.integer);
546                 if (t >= 1.01f)
547                 {
548                         m.blendfunc1 = GL_DST_COLOR;
549                         m.blendfunc2 = GL_ONE;
550                         R_Mesh_State(&m);
551                         while (t >= 1.01f)
552                         {
553                                 cr = t - 1.0f;
554                                 if (cr > 1.0f)
555                                         cr = 1.0f;
556                                 GL_Color(cr, cr, cr, 1);
557                                 R_Mesh_Draw(3, 1, polygonelements);
558                                 t *= 0.5;
559                         }
560                 }
561                 else if (t <= 0.99f)
562                 {
563                         m.blendfunc1 = GL_ZERO;
564                         m.blendfunc2 = GL_SRC_COLOR;
565                         R_Mesh_State(&m);
566                         GL_Color(t, t, t, 1);
567                         R_Mesh_Draw(3, 1, polygonelements);
568                 }
569                 if (v_brightness.value >= 0.01f)
570                 {
571                         m.blendfunc1 = GL_ONE;
572                         m.blendfunc2 = GL_ONE;
573                         R_Mesh_State(&m);
574                         GL_Color(v_brightness.value, v_brightness.value, v_brightness.value, 1);
575                         R_Mesh_Draw(3, 1, polygonelements);
576                 }
577         }
578         R_Mesh_Finish();
579 }
580