]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - gl_draw.c
menu.c - changed M_DrawSlider to take a value and a min/max range, now prints the...
[xonotic/darkplaces.git] / gl_draw.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20
21 #include "quakedef.h"
22 #include "image.h"
23
24 cvar_t scr_conalpha = {CVAR_SAVE, "scr_conalpha", "1"};
25
26 static rtexture_t *char_texture;
27
28 //=============================================================================
29 /* Support Routines */
30
31 #define MAX_CACHED_PICS 256
32 #define CACHEPICHASHSIZE 256
33 static cachepic_t *cachepichash[CACHEPICHASHSIZE];
34 static cachepic_t cachepics[MAX_CACHED_PICS];
35 static int numcachepics;
36
37 static rtexturepool_t *drawtexturepool;
38
39 static qbyte pointerimage[256] =
40 {
41         "333333332......."
42         "26777761........"
43         "2655541........."
44         "265541.........."
45         "2654561........."
46         "26414561........"
47         "251.14561......."
48         "21...14561......"
49         "1.....141......."
50         ".......1........"
51         "................"
52         "................"
53         "................"
54         "................"
55         "................"
56         "................"
57 };
58
59 static rtexture_t *draw_generatemousepointer(void)
60 {
61         int i;
62         qbyte buffer[256][4];
63         for (i = 0;i < 256;i++)
64         {
65                 if (pointerimage[i] == '.')
66                 {
67                         buffer[i][0] = 0;
68                         buffer[i][1] = 0;
69                         buffer[i][2] = 0;
70                         buffer[i][3] = 0;
71                 }
72                 else
73                 {
74                         buffer[i][0] = (pointerimage[i] - '0') * 16;
75                         buffer[i][1] = (pointerimage[i] - '0') * 16;
76                         buffer[i][2] = (pointerimage[i] - '0') * 16;
77                         buffer[i][3] = 255;
78                 }
79         }
80         return R_LoadTexture2D(drawtexturepool, "mousepointer", 16, 16, &buffer[0][0], TEXTYPE_RGBA, TEXF_ALPHA | TEXF_PRECACHE, NULL);
81 }
82
83 // must match NUMCROSSHAIRS in r_crosshairs.c
84 #define NUMCROSSHAIRS 5
85
86 static qbyte *crosshairtexdata[NUMCROSSHAIRS] =
87 {
88         "................"
89         "................"
90         "................"
91         "...33......33..."
92         "...355....553..."
93         "....577..775...."
94         ".....77..77....."
95         "................"
96         "................"
97         ".....77..77....."
98         "....577..775...."
99         "...355....553..."
100         "...33......33..."
101         "................"
102         "................"
103         "................"
104         ,
105         "................"
106         "................"
107         "................"
108         "...3........3..."
109         "....5......5...."
110         ".....7....7....."
111         "......7..7......"
112         "................"
113         "................"
114         "......7..7......"
115         ".....7....7....."
116         "....5......5...."
117         "...3........3..."
118         "................"
119         "................"
120         "................"
121         ,
122         "................"
123         ".......77......."
124         ".......77......."
125         "................"
126         "................"
127         ".......44......."
128         ".......44......."
129         ".77..44..44..77."
130         ".77..44..44..77."
131         ".......44......."
132         ".......44......."
133         "................"
134         ".......77......."
135         ".......77......."
136         "................"
137         "................"
138         ,
139         "................"
140         "................"
141         "................"
142         "................"
143         "................"
144         "................"
145         "................"
146         "................"
147         "........7777777."
148         "........752....."
149         "........72......"
150         "........7......."
151         "........7......."
152         "........7......."
153         "................"
154         "................"
155         ,
156         "................"
157         "................"
158         "................"
159         "................"
160         "................"
161         "........7......."
162         "................"
163         "........4......."
164         ".....7.4.4.7...."
165         "........4......."
166         "................"
167         "........7......."
168         "................"
169         "................"
170         "................"
171         "................"
172 };
173
174 static rtexture_t *draw_generatecrosshair(int num)
175 {
176         int i;
177         char *in;
178         qbyte data[16*16][4];
179         in = crosshairtexdata[num];
180         for (i = 0;i < 16*16;i++)
181         {
182                 if (in[i] == '.')
183                 {
184                         data[i][0] = 255;
185                         data[i][1] = 255;
186                         data[i][2] = 255;
187                         data[i][3] = 0;
188                 }
189                 else
190                 {
191                         data[i][0] = 255;
192                         data[i][1] = 255;
193                         data[i][2] = 255;
194                         data[i][3] = (qbyte) ((int) (in[i] - '0') * 255 / 7);
195                 }
196         }
197         return R_LoadTexture2D(drawtexturepool, va("crosshair%i", num), 16, 16, &data[0][0], TEXTYPE_RGBA, TEXF_ALPHA | TEXF_PRECACHE, NULL);
198 }
199
200 static rtexture_t *draw_generateditherpattern(void)
201 {
202         qbyte data[16];
203         memset(data, 255, sizeof(data));
204         data[0] = data[1] = data[2] = data[12] = data[13] = data[14] = 0;
205         return R_LoadTexture2D(drawtexturepool, "ditherpattern", 2, 2, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_PRECACHE, NULL);
206 }
207
208 /*
209 ================
210 Draw_CachePic
211 ================
212 */
213 // FIXME: move this to client somehow
214 cachepic_t      *Draw_CachePic (char *path)
215 {
216         int i, crc, hashkey;
217         cachepic_t *pic;
218         qpic_t *p;
219
220         crc = CRC_Block(path, strlen(path));
221         hashkey = ((crc >> 8) ^ crc) % CACHEPICHASHSIZE;
222         for (pic = cachepichash[hashkey];pic;pic = pic->chain)
223                 if (!strcmp (path, pic->name))
224                         return pic;
225
226         if (numcachepics == MAX_CACHED_PICS)
227                 Sys_Error ("numcachepics == MAX_CACHED_PICS");
228         pic = cachepics + (numcachepics++);
229         strcpy (pic->name, path);
230         // link into list
231         pic->chain = cachepichash[hashkey];
232         cachepichash[hashkey] = pic;
233
234         // load the pic from disk
235         pic->tex = loadtextureimage(drawtexturepool, path, 0, 0, false, TEXF_ALPHA | TEXF_PRECACHE);
236         if (pic->tex == NULL && !strncmp(path, "gfx/", 4))
237         {
238                 // compatibility with older versions
239                 pic->tex = loadtextureimage(drawtexturepool, path + 4, 0, 0, false, TEXF_ALPHA | TEXF_PRECACHE);
240                 // failed to find gfx/whatever.tga or similar, try the wad
241                 if (pic->tex == NULL && (p = W_GetLumpName (path + 4)))
242                 {
243                         if (!strcmp(path, "gfx/conchars"))
244                         {
245                                 qbyte *pix;
246                                 // conchars is a raw image and with the wrong transparent color
247                                 pix = (qbyte *)p;
248                                 for (i = 0;i < 128 * 128;i++)
249                                         if (pix[i] == 0)
250                                                 pix[i] = 255;
251                                 pic->tex = R_LoadTexture2D(drawtexturepool, path, 128, 128, pix, TEXTYPE_PALETTE, TEXF_ALPHA | TEXF_PRECACHE, palette_complete);
252                         }
253                         else
254                                 pic->tex = R_LoadTexture2D(drawtexturepool, path, p->width, p->height, p->data, TEXTYPE_PALETTE, TEXF_ALPHA | TEXF_PRECACHE, palette_complete);
255                 }
256         }
257         if (pic->tex == NULL && !strcmp(path, "ui/mousepointer.tga"))
258                 pic->tex = draw_generatemousepointer();
259         if (pic->tex == NULL && !strcmp(path, "gfx/crosshair1.tga"))
260                 pic->tex = draw_generatecrosshair(0);
261         if (pic->tex == NULL && !strcmp(path, "gfx/crosshair2.tga"))
262                 pic->tex = draw_generatecrosshair(1);
263         if (pic->tex == NULL && !strcmp(path, "gfx/crosshair3.tga"))
264                 pic->tex = draw_generatecrosshair(2);
265         if (pic->tex == NULL && !strcmp(path, "gfx/crosshair4.tga"))
266                 pic->tex = draw_generatecrosshair(3);
267         if (pic->tex == NULL && !strcmp(path, "gfx/crosshair5.tga"))
268                 pic->tex = draw_generatecrosshair(4);
269         if (pic->tex == NULL && !strcmp(path, "gfx/colorcontrol/ditherpattern.tga"))
270                 pic->tex = draw_generateditherpattern();
271         if (pic->tex == NULL)
272         {
273                 Con_Printf ("Draw_CachePic: failed to load %s\n", path);
274                 pic->tex = r_notexture;
275         }
276
277         pic->width = R_TextureWidth(pic->tex);
278         pic->height = R_TextureHeight(pic->tex);
279         return pic;
280 }
281
282 cachepic_t *Draw_NewPic(char *picname, int width, int height, int alpha, qbyte *pixels)
283 {
284         int crc, hashkey;
285         cachepic_t *pic;
286
287         crc = CRC_Block(picname, strlen(picname));
288         hashkey = ((crc >> 8) ^ crc) % CACHEPICHASHSIZE;
289         for (pic = cachepichash[hashkey];pic;pic = pic->chain)
290                 if (!strcmp (picname, pic->name))
291                         break;
292
293         if (pic)
294         {
295                 if (pic->tex && pic->width == width && pic->height == height)
296                 {
297                         R_UpdateTexture(pic->tex, pixels);
298                         return pic;
299                 }
300         }
301         else
302         {
303                 if (pic == NULL)
304                 {
305                         if (numcachepics == MAX_CACHED_PICS)
306                                 Sys_Error ("numcachepics == MAX_CACHED_PICS");
307                         pic = cachepics + (numcachepics++);
308                         strcpy (pic->name, picname);
309                         // link into list
310                         pic->chain = cachepichash[hashkey];
311                         cachepichash[hashkey] = pic;
312                 }
313         }
314
315         pic->width = width;
316         pic->height = height;
317         if (pic->tex)
318                 R_FreeTexture(pic->tex);
319         pic->tex = R_LoadTexture2D(drawtexturepool, picname, width, height, pixels, TEXTYPE_RGBA, alpha ? TEXF_ALPHA : 0, NULL);
320         return pic;
321 }
322
323 void Draw_FreePic(char *picname)
324 {
325         int crc;
326         int hashkey;
327         cachepic_t *pic;
328         // this doesn't really free the pic, but does free it's texture
329         crc = CRC_Block(picname, strlen(picname));
330         hashkey = ((crc >> 8) ^ crc) % CACHEPICHASHSIZE;
331         for (pic = cachepichash[hashkey];pic;pic = pic->chain)
332         {
333                 if (!strcmp (picname, pic->name))
334                 {
335                         R_FreeTexture(pic->tex);
336                         pic->width = 0;
337                         pic->height = 0;
338                         return;
339                 }
340         }
341 }
342
343 /*
344 ===============
345 Draw_Init
346 ===============
347 */
348 static void gl_draw_start(void)
349 {
350         drawtexturepool = R_AllocTexturePool();
351
352         numcachepics = 0;
353         memset(cachepichash, 0, sizeof(cachepichash));
354
355         char_texture = Draw_CachePic("gfx/conchars")->tex;
356 }
357
358 static void gl_draw_shutdown(void)
359 {
360         R_FreeTexturePool(&drawtexturepool);
361
362         numcachepics = 0;
363         memset(cachepichash, 0, sizeof(cachepichash));
364 }
365
366 static void gl_draw_newmap(void)
367 {
368 }
369
370 void GL_Draw_Init (void)
371 {
372         Cvar_RegisterVariable (&scr_conalpha);
373
374         numcachepics = 0;
375         memset(cachepichash, 0, sizeof(cachepichash));
376
377         R_RegisterModule("GL_Draw", gl_draw_start, gl_draw_shutdown, gl_draw_newmap);
378 }
379
380 int quadelements[768];
381 void R_DrawQueue(void)
382 {
383         int pos, num, chartexnum, overbright, texnum, additive, batch;
384         float x, y, w, h, s, t, u, v, *av, *at, c[4];
385         cachepic_t *pic;
386         drawqueue_t *dq;
387         char *str, *currentpic;
388         int batchcount;
389         unsigned int color;
390         drawqueuemesh_t *mesh;
391         rmeshstate_t m;
392
393         if (!r_render.integer)
394                 return;
395
396         if (!quadelements[1])
397         {
398                 // elements for rendering a series of quads as triangles
399                 for (batch = 0, pos = 0, num = 0;batch < 128;batch++, num += 4)
400                 {
401                         quadelements[pos++] = num;
402                         quadelements[pos++] = num + 1;
403                         quadelements[pos++] = num + 2;
404                         quadelements[pos++] = num;
405                         quadelements[pos++] = num + 2;
406                         quadelements[pos++] = num + 3;
407                 }
408         }
409         GL_SetupView_ViewPort(vid.realx, vid.realy, vid.realwidth, vid.realheight);
410         GL_SetupView_Mode_Ortho(0, 0, vid.conwidth, vid.conheight, -10, 100);
411         qglDepthFunc(GL_LEQUAL);
412         R_Mesh_Start();
413         R_Mesh_Matrix(&r_identitymatrix);
414
415         chartexnum = R_GetTexture(char_texture);
416
417         memset(&m, 0, sizeof(m));
418         m.tex[0] = 0;
419         R_Mesh_TextureState(&m);
420
421         currentpic = "";
422         pic = NULL;
423         texnum = 0;
424         color = 0;
425
426         overbright = v_overbrightbits.integer;
427         batch = false;
428         batchcount = 0;
429         for (pos = 0;pos < r_refdef.drawqueuesize;pos += ((drawqueue_t *)(r_refdef.drawqueue + pos))->size)
430         {
431                 dq = (drawqueue_t *)(r_refdef.drawqueue + pos);
432                 additive = (dq->flags & DRAWFLAG_ADDITIVE) != 0;
433                 color = dq->color;
434                 m.blendfunc1 = GL_SRC_ALPHA;
435                 if (additive)
436                         m.blendfunc2 = GL_ONE;
437                 else
438                         m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
439                 m.depthdisable = true;
440                 R_Mesh_MainState(&m);
441
442                 c[0] = (float) ((color >> 24) & 0xFF) * (1.0f / 255.0f) * r_colorscale;
443                 c[1] = (float) ((color >> 16) & 0xFF) * (1.0f / 255.0f) * r_colorscale;
444                 c[2] = (float) ((color >>  8) & 0xFF) * (1.0f / 255.0f) * r_colorscale;
445                 c[3] = (float) ( color        & 0xFF) * (1.0f / 255.0f);
446                 x = dq->x;
447                 y = dq->y;
448                 w = dq->scalex;
449                 h = dq->scaley;
450
451                 switch(dq->command)
452                 {
453                 case DRAWQUEUE_PIC:
454                         str = (char *)(dq + 1);
455                         if (strcmp(str, currentpic))
456                         {
457                                 currentpic = str;
458                                 if (*str)
459                                 {
460                                         pic = Draw_CachePic(str);
461                                         m.tex[0] = R_GetTexture(pic->tex);
462                                 }
463                                 else
464                                         m.tex[0] = 0;
465                                 R_Mesh_TextureState(&m);
466                         }
467                         if (*str)
468                         {
469                                 if (w == 0)
470                                         w = pic->width;
471                                 if (h == 0)
472                                         h = pic->height;
473                         }
474                         varray_texcoord[0][ 0] = 0;varray_texcoord[0][ 1] = 0;
475                         varray_texcoord[0][ 4] = 1;varray_texcoord[0][ 5] = 0;
476                         varray_texcoord[0][ 8] = 1;varray_texcoord[0][ 9] = 1;
477                         varray_texcoord[0][12] = 0;varray_texcoord[0][13] = 1;
478                         varray_vertex[ 0] = x  ;varray_vertex[ 1] = y  ;varray_vertex[ 2] = 10;
479                         varray_vertex[ 4] = x+w;varray_vertex[ 5] = y  ;varray_vertex[ 6] = 10;
480                         varray_vertex[ 8] = x+w;varray_vertex[ 9] = y+h;varray_vertex[10] = 10;
481                         varray_vertex[12] = x  ;varray_vertex[13] = y+h;varray_vertex[14] = 10;
482                         GL_Color(c[0], c[1], c[2], c[3]);
483                         R_Mesh_Draw(4, 2, quadelements);
484                         break;
485                 case DRAWQUEUE_STRING:
486                         str = (char *)(dq + 1);
487                         if (strcmp("gfx/conchars", currentpic))
488                         {
489                                 currentpic = "gfx/conchars";
490                                 m.tex[0] = chartexnum;
491                                 R_Mesh_TextureState(&m);
492                         }
493                         batchcount = 0;
494                         at = varray_texcoord[0];
495                         av = varray_vertex;
496                         GL_Color(c[0], c[1], c[2], c[3]);
497                         while ((num = *str++) && x < vid.conwidth)
498                         {
499                                 if (num != ' ')
500                                 {
501                                         s = (num & 15)*0.0625f + (0.5f / 256.0f);
502                                         t = (num >> 4)*0.0625f + (0.5f / 256.0f);
503                                         u = 0.0625f - (1.0f / 256.0f);
504                                         v = 0.0625f - (1.0f / 256.0f);
505                                         at[ 0] = s  ;at[ 1] = t  ;
506                                         at[ 4] = s+u;at[ 5] = t  ;
507                                         at[ 8] = s+u;at[ 9] = t+v;
508                                         at[12] = s  ;at[13] = t+v;
509                                         av[ 0] = x  ;av[ 1] = y  ;av[ 2] = 10;
510                                         av[ 4] = x+w;av[ 5] = y  ;av[ 6] = 10;
511                                         av[ 8] = x+w;av[ 9] = y+h;av[10] = 10;
512                                         av[12] = x  ;av[13] = y+h;av[14] = 10;
513                                         at += 16;
514                                         av += 16;
515                                         batchcount++;
516                                         if (batchcount >= 128)
517                                         {
518                                                 R_Mesh_Draw(batchcount * 4, batchcount * 2, quadelements);
519                                                 batchcount = 0;
520                                                 at = varray_texcoord[0];
521                                                 av = varray_vertex;
522                                         }
523                                 }
524                                 x += w;
525                         }
526                         if (batchcount > 0)
527                                 R_Mesh_Draw(batchcount * 4, batchcount * 2, quadelements);
528                         break;
529                 case DRAWQUEUE_MESH:
530                         mesh = (void *)(dq + 1);
531                         m.tex[0] = R_GetTexture(mesh->texture);
532                         R_Mesh_TextureState(&m);
533                         R_Mesh_ResizeCheck(mesh->numvertices);
534                         memcpy(varray_vertex, mesh->vertices, sizeof(float[4]) * mesh->numvertices);
535                         memcpy(varray_texcoord[0], mesh->texcoords, sizeof(float[4]) * mesh->numvertices);
536                         memcpy(varray_color, mesh->colors, sizeof(float[4]) * mesh->numvertices);
537                         GL_UseColorArray();
538                         R_Mesh_Draw(mesh->numvertices, mesh->numtriangles, mesh->indices);
539                         currentpic = "\0";
540                         break;
541                 }
542         }
543
544         if (!vid_usinghwgamma)
545         {
546                 // we use one big triangle for all the screen blends
547                 varray_texcoord[0][0] = 0;varray_texcoord[0][1] = 0;
548                 varray_texcoord[0][4] = 0;varray_texcoord[0][5] = 0;
549                 varray_texcoord[0][8] = 0;varray_texcoord[0][9] = 0;
550                 varray_vertex[0] = -5000;varray_vertex[1] = -5000;varray_vertex[2] = 10;
551                 varray_vertex[4] = 10000;varray_vertex[5] = -5000;varray_vertex[6] = 10;
552                 varray_vertex[8] = -5000;varray_vertex[9] = 10000;varray_vertex[10] = 10;
553                 // all the blends ignore depth
554                 memset(&m, 0, sizeof(m));
555                 m.depthdisable = true;
556                 if (v_color_enable.integer)
557                 {
558                         c[0] = v_color_white_r.value;
559                         c[1] = v_color_white_g.value;
560                         c[2] = v_color_white_b.value;
561                 }
562                 else
563                         c[0] = c[1] = c[2] = v_contrast.value;
564                 VectorScale(c, (float) (1 << v_overbrightbits.integer), c);
565                 if (c[0] >= 1.01f || c[1] >= 1.01f || c[2] >= 1.01f)
566                 {
567                         m.blendfunc1 = GL_DST_COLOR;
568                         m.blendfunc2 = GL_ONE;
569                         R_Mesh_State(&m);
570                         while (c[0] >= 1.01f || c[1] >= 1.01f || c[2] >= 1.01f)
571                         {
572                                 GL_Color(bound(0, c[0] - 1, 1), bound(0, c[1] - 1, 1), bound(0, c[2] - 1, 1), 1);
573                                 R_Mesh_Draw(3, 1, polygonelements);
574                                 VectorScale(c, 0.5, c);
575                         }
576                 }
577                 if (v_color_enable.integer)
578                 {
579                         c[0] = v_color_black_r.value;
580                         c[1] = v_color_black_g.value;
581                         c[2] = v_color_black_b.value;
582                 }
583                 else
584                         c[0] = c[1] = c[2] = v_brightness.value;
585                 if (c[0] >= 0.01f || c[1] >= 0.01f || c[2] >= 0.01f)
586                 {
587                         m.blendfunc1 = GL_ONE;
588                         m.blendfunc2 = GL_ONE;
589                         R_Mesh_State(&m);
590                         GL_Color(c[0], c[1], c[2], 1);
591                         R_Mesh_Draw(3, 1, polygonelements);
592                 }
593         }
594         R_Mesh_Finish();
595 }
596