Added in_mouse_x and in_mouse_y, which contain the rel. coords of the mouse.
[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) && pic->tex)
332                 {
333                         R_FreeTexture(pic->tex);
334                         pic->width = 0;
335                         pic->height = 0;
336                         return;
337                 }
338         }
339 }
340
341 /*
342 ===============
343 Draw_Init
344 ===============
345 */
346 static void gl_draw_start(void)
347 {
348         drawtexturepool = R_AllocTexturePool();
349
350         numcachepics = 0;
351         memset(cachepichash, 0, sizeof(cachepichash));
352
353         char_texture = Draw_CachePic("gfx/conchars")->tex;
354 }
355
356 static void gl_draw_shutdown(void)
357 {
358         R_FreeTexturePool(&drawtexturepool);
359
360         numcachepics = 0;
361         memset(cachepichash, 0, sizeof(cachepichash));
362 }
363
364 static void gl_draw_newmap(void)
365 {
366 }
367
368 void GL_Draw_Init (void)
369 {
370         numcachepics = 0;
371         memset(cachepichash, 0, sizeof(cachepichash));
372
373         R_RegisterModule("GL_Draw", gl_draw_start, gl_draw_shutdown, gl_draw_newmap);
374 }
375
376 float blendvertex3f[9] = {-5000, -5000, 10, 10000, -5000, 10, -5000, 10000, 10};
377
378 int quadelements[768];
379 void R_DrawQueue(void)
380 {
381         int pos, num, chartexnum, texnum, batch;
382         float x, y, w, h, s, t, u, v, *av, *at, c[4];
383         cachepic_t *pic;
384         drawqueue_t *dq;
385         char *str, *currentpic;
386         int batchcount;
387         unsigned int color;
388         drawqueuemesh_t *mesh;
389         rmeshstate_t m;
390
391         if (!r_render.integer)
392                 return;
393
394         if (!quadelements[1])
395         {
396                 // elements for rendering a series of quads as triangles
397                 for (batch = 0, pos = 0, num = 0;batch < 128;batch++, num += 4)
398                 {
399                         quadelements[pos++] = num;
400                         quadelements[pos++] = num + 1;
401                         quadelements[pos++] = num + 2;
402                         quadelements[pos++] = num;
403                         quadelements[pos++] = num + 2;
404                         quadelements[pos++] = num + 3;
405                 }
406         }
407         GL_SetupView_ViewPort(vid.realx, vid.realy, vid.realwidth, vid.realheight);
408         GL_SetupView_Mode_Ortho(0, 0, vid.conwidth, vid.conheight, -10, 100);
409         qglDepthFunc(GL_LEQUAL);
410         R_Mesh_Start();
411         R_Mesh_Matrix(&r_identitymatrix);
412
413         chartexnum = R_GetTexture(char_texture);
414
415         memset(&m, 0, sizeof(m));
416         m.tex[0] = 0;
417         R_Mesh_State_Texture(&m);
418
419         currentpic = "";
420         pic = NULL;
421         texnum = 0;
422         color = 0;
423
424         batch = false;
425         batchcount = 0;
426         for (pos = 0;pos < r_refdef.drawqueuesize;pos += ((drawqueue_t *)(r_refdef.drawqueue + pos))->size)
427         {
428                 dq = (drawqueue_t *)(r_refdef.drawqueue + pos);
429                 color = dq->color;
430                 
431                 if(dq->flags == DRAWFLAG_ADDITIVE)
432                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
433                 else if(dq->flags == DRAWFLAG_MODULATE)
434                         GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
435                 else if(dq->flags == DRAWFLAG_2XMODULATE)
436                         GL_BlendFunc(GL_DST_COLOR,GL_SRC_COLOR);
437                 else
438                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
439
440                 GL_DepthMask(true);
441                 GL_DepthTest(false);
442
443                 c[0] = (float) ((color >> 24) & 0xFF) * (1.0f / 255.0f);
444                 c[1] = (float) ((color >> 16) & 0xFF) * (1.0f / 255.0f);
445                 c[2] = (float) ((color >>  8) & 0xFF) * (1.0f / 255.0f);
446                 c[3] = (float) ( color        & 0xFF) * (1.0f / 255.0f);
447                 x = dq->x;
448                 y = dq->y;
449                 w = dq->scalex;
450                 h = dq->scaley;
451
452                 switch(dq->command)
453                 {
454                 case DRAWQUEUE_STRING:
455                         GL_Color(c[0], c[1], c[2], c[3]);
456                         str = (char *)(dq + 1);
457                         if (strcmp("gfx/conchars", currentpic))
458                         {
459                                 currentpic = "gfx/conchars";
460                                 m.tex[0] = chartexnum;
461                         }
462                         batchcount = 0;
463                         GL_VertexPointer(varray_vertex3f);
464                         m.pointer_texcoord[0] = varray_texcoord2f[0];
465                         R_Mesh_State_Texture(&m);
466                         at = varray_texcoord2f[0];
467                         av = varray_vertex3f;
468                         while ((num = *str++) && x < vid.conwidth)
469                         {
470                                 if (num != ' ')
471                                 {
472                                         s = (num & 15)*0.0625f + (0.5f / 256.0f);
473                                         t = (num >> 4)*0.0625f + (0.5f / 256.0f);
474                                         u = 0.0625f - (1.0f / 256.0f);
475                                         v = 0.0625f - (1.0f / 256.0f);
476                                         at[ 0] = s  ;at[ 1] = t  ;
477                                         at[ 2] = s+u;at[ 3] = t  ;
478                                         at[ 4] = s+u;at[ 5] = t+v;
479                                         at[ 6] = s  ;at[ 7] = t+v;
480                                         av[ 0] = x  ;av[ 1] = y  ;av[ 2] = 10;
481                                         av[ 3] = x+w;av[ 4] = y  ;av[ 5] = 10;
482                                         av[ 6] = x+w;av[ 7] = y+h;av[ 8] = 10;
483                                         av[ 9] = x  ;av[10] = y+h;av[11] = 10;
484                                         at += 8;
485                                         av += 12;
486                                         batchcount++;
487                                         if (batchcount >= 128)
488                                         {
489                                                 R_Mesh_Draw(batchcount * 4, batchcount * 2, quadelements);
490                                                 batchcount = 0;
491                                                 at = varray_texcoord2f[0];
492                                                 av = varray_vertex3f;
493                                         }
494                                 }
495                                 x += w;
496                         }
497                         if (batchcount > 0)
498                                 R_Mesh_Draw(batchcount * 4, batchcount * 2, quadelements);
499                         break;
500                 case DRAWQUEUE_MESH:
501                         mesh = (void *)(dq + 1);
502                         GL_VertexPointer(mesh->data_vertex3f);
503                         GL_ColorPointer(mesh->data_color4f);
504                         m.tex[0] = R_GetTexture(mesh->texture);
505                         m.pointer_texcoord[0] = mesh->data_texcoord2f;
506                         R_Mesh_State_Texture(&m);
507                         R_Mesh_Draw(mesh->num_vertices, mesh->num_triangles, mesh->data_element3i);
508                         currentpic = "\0";
509                         break;
510                 case DRAWQUEUE_SETCLIP:
511                         {
512                                 // We have to convert the con coords into real coords
513                                 int x , y, width, height;
514                                 x = dq->x * (vid.realwidth / vid.conwidth) + vid.realx;
515                                 // OGL uses top to bottom 
516                                 y = (dq->y + dq->scaley) * (vid.realheight / vid.conheight) + vid.realy;
517                                 width = dq->scalex * (vid.realwidth / vid.conwidth);
518                                 height = dq->scaley * (vid.realheight / vid.conheight);
519
520                                 GL_Scissor(x, y, width, height);
521
522                                 GL_ScissorTest(true);
523                         }
524                         break;
525                 case DRAWQUEUE_RESETCLIP:
526                         GL_ScissorTest(false);
527                         break;                          
528                 }
529         }
530
531         if (!vid_usinghwgamma)
532         {
533                 // all the blends ignore depth
534                 memset(&m, 0, sizeof(m));
535                 R_Mesh_State_Texture(&m);
536                 GL_DepthMask(true);
537                 GL_DepthTest(false);
538                 if (v_color_enable.integer)
539                 {
540                         c[0] = v_color_white_r.value;
541                         c[1] = v_color_white_g.value;
542                         c[2] = v_color_white_b.value;
543                 }
544                 else
545                         c[0] = c[1] = c[2] = v_contrast.value;
546                 if (c[0] >= 1.01f || c[1] >= 1.01f || c[2] >= 1.01f)
547                 {
548                         GL_BlendFunc(GL_DST_COLOR, GL_ONE);
549                         GL_VertexPointer(blendvertex3f);
550                         while (c[0] >= 1.01f || c[1] >= 1.01f || c[2] >= 1.01f)
551                         {
552                                 GL_Color(bound(0, c[0] - 1, 1), bound(0, c[1] - 1, 1), bound(0, c[2] - 1, 1), 1);
553                                 R_Mesh_Draw(3, 1, polygonelements);
554                                 VectorScale(c, 0.5, c);
555                         }
556                 }
557                 if (v_color_enable.integer)
558                 {
559                         c[0] = v_color_black_r.value;
560                         c[1] = v_color_black_g.value;
561                         c[2] = v_color_black_b.value;
562                 }
563                 else
564                         c[0] = c[1] = c[2] = v_brightness.value;
565                 if (c[0] >= 0.01f || c[1] >= 0.01f || c[2] >= 0.01f)
566                 {
567                         GL_BlendFunc(GL_ONE, GL_ONE);
568                         GL_VertexPointer(blendvertex3f);
569                         GL_Color(c[0], c[1], c[2], 1);
570                         R_Mesh_Draw(3, 1, polygonelements);
571                 }
572         }
573         R_Mesh_Finish();
574 }
575