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