varray_* rewritten to remove padding (varray_vertex3f, varray_texcoord2f, varray_texc...
[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 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 float blendtexcoord2f[6] = {0, 0, 0, 0, 0, 0};
381 float blendvertex3f[9] = {-5000, -5000, 10, 10000, -5000, 10, -5000, 10000, 10};
382
383 int quadelements[768];
384 float textverts[128*4*3];
385 float texttexcoords[128*4*2];
386 void R_DrawQueue(void)
387 {
388         int pos, num, chartexnum, overbright, texnum, additive, batch;
389         float x, y, w, h, s, t, u, v, *av, *at, c[4];
390         cachepic_t *pic;
391         drawqueue_t *dq;
392         char *str, *currentpic;
393         int batchcount;
394         unsigned int color;
395         drawqueuemesh_t *mesh;
396         rmeshstate_t m;
397
398         if (!r_render.integer)
399                 return;
400
401         if (!quadelements[1])
402         {
403                 // elements for rendering a series of quads as triangles
404                 for (batch = 0, pos = 0, num = 0;batch < 128;batch++, num += 4)
405                 {
406                         quadelements[pos++] = num;
407                         quadelements[pos++] = num + 1;
408                         quadelements[pos++] = num + 2;
409                         quadelements[pos++] = num;
410                         quadelements[pos++] = num + 2;
411                         quadelements[pos++] = num + 3;
412                 }
413         }
414         GL_SetupView_ViewPort(vid.realx, vid.realy, vid.realwidth, vid.realheight);
415         GL_SetupView_Mode_Ortho(0, 0, vid.conwidth, vid.conheight, -10, 100);
416         qglDepthFunc(GL_LEQUAL);
417         R_Mesh_Start();
418         R_Mesh_Matrix(&r_identitymatrix);
419
420         chartexnum = R_GetTexture(char_texture);
421
422         memset(&m, 0, sizeof(m));
423         m.tex[0] = 0;
424         R_Mesh_TextureState(&m);
425
426         currentpic = "";
427         pic = NULL;
428         texnum = 0;
429         color = 0;
430
431         overbright = v_overbrightbits.integer;
432         batch = false;
433         batchcount = 0;
434         for (pos = 0;pos < r_refdef.drawqueuesize;pos += ((drawqueue_t *)(r_refdef.drawqueue + pos))->size)
435         {
436                 dq = (drawqueue_t *)(r_refdef.drawqueue + pos);
437                 additive = (dq->flags & DRAWFLAG_ADDITIVE) != 0;
438                 color = dq->color;
439                 m.blendfunc1 = GL_SRC_ALPHA;
440                 if (additive)
441                         m.blendfunc2 = GL_ONE;
442                 else
443                         m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
444                 m.depthdisable = true;
445                 R_Mesh_MainState(&m);
446
447                 c[0] = (float) ((color >> 24) & 0xFF) * (1.0f / 255.0f) * r_colorscale;
448                 c[1] = (float) ((color >> 16) & 0xFF) * (1.0f / 255.0f) * r_colorscale;
449                 c[2] = (float) ((color >>  8) & 0xFF) * (1.0f / 255.0f) * r_colorscale;
450                 c[3] = (float) ( color        & 0xFF) * (1.0f / 255.0f);
451                 x = dq->x;
452                 y = dq->y;
453                 w = dq->scalex;
454                 h = dq->scaley;
455
456                 switch(dq->command)
457                 {
458                 case DRAWQUEUE_PIC:
459                         str = (char *)(dq + 1);
460                         if (strcmp(str, currentpic))
461                         {
462                                 currentpic = str;
463                                 if (*str)
464                                 {
465                                         pic = Draw_CachePic(str);
466                                         m.tex[0] = R_GetTexture(pic->tex);
467                                 }
468                                 else
469                                         m.tex[0] = 0;
470                                 R_Mesh_TextureState(&m);
471                         }
472                         if (*str)
473                         {
474                                 if (w == 0)
475                                         w = pic->width;
476                                 if (h == 0)
477                                         h = pic->height;
478                         }
479                         GL_Color(c[0], c[1], c[2], c[3]);
480                         R_Mesh_GetSpace(4);
481                         varray_texcoord2f[0][0] = 0;varray_texcoord2f[0][1] = 0;
482                         varray_texcoord2f[0][2] = 1;varray_texcoord2f[0][3] = 0;
483                         varray_texcoord2f[0][4] = 1;varray_texcoord2f[0][5] = 1;
484                         varray_texcoord2f[0][6] = 0;varray_texcoord2f[0][7] = 1;
485                         varray_vertex3f[ 0] = x  ;varray_vertex3f[ 1] = y  ;varray_vertex3f[ 2] = 10;
486                         varray_vertex3f[ 3] = x+w;varray_vertex3f[ 4] = y  ;varray_vertex3f[ 5] = 10;
487                         varray_vertex3f[ 6] = x+w;varray_vertex3f[ 7] = y+h;varray_vertex3f[ 8] = 10;
488                         varray_vertex3f[ 9] = x  ;varray_vertex3f[10] = y+h;varray_vertex3f[11] = 10;
489                         R_Mesh_Draw(4, 2, quadelements);
490                         break;
491                 case DRAWQUEUE_STRING:
492                         str = (char *)(dq + 1);
493                         if (strcmp("gfx/conchars", currentpic))
494                         {
495                                 currentpic = "gfx/conchars";
496                                 m.tex[0] = chartexnum;
497                                 R_Mesh_TextureState(&m);
498                         }
499                         batchcount = 0;
500                         at = texttexcoords;
501                         av = textverts;
502                         GL_Color(c[0], c[1], c[2], c[3]);
503                         while ((num = *str++) && x < vid.conwidth)
504                         {
505                                 if (num != ' ')
506                                 {
507                                         s = (num & 15)*0.0625f + (0.5f / 256.0f);
508                                         t = (num >> 4)*0.0625f + (0.5f / 256.0f);
509                                         u = 0.0625f - (1.0f / 256.0f);
510                                         v = 0.0625f - (1.0f / 256.0f);
511                                         at[ 0] = s  ;at[ 1] = t  ;
512                                         at[ 2] = s+u;at[ 3] = t  ;
513                                         at[ 4] = s+u;at[ 5] = t+v;
514                                         at[ 6] = s  ;at[ 7] = t+v;
515                                         av[ 0] = x  ;av[ 1] = y  ;av[ 2] = 10;
516                                         av[ 3] = x+w;av[ 4] = y  ;av[ 5] = 10;
517                                         av[ 6] = x+w;av[ 7] = y+h;av[ 8] = 10;
518                                         av[ 9] = x  ;av[10] = y+h;av[11] = 10;
519                                         at += 8;
520                                         av += 12;
521                                         batchcount++;
522                                         if (batchcount >= 128)
523                                         {
524                                                 R_Mesh_GetSpace(batchcount * 4);
525                                                 R_Mesh_CopyVertex3f(textverts, batchcount * 4);
526                                                 R_Mesh_CopyTexCoord2f(0, texttexcoords, batchcount * 4);
527                                                 R_Mesh_Draw(batchcount * 4, batchcount * 2, quadelements);
528                                                 batchcount = 0;
529                                                 at = texttexcoords;
530                                                 av = textverts;
531                                         }
532                                 }
533                                 x += w;
534                         }
535                         if (batchcount > 0)
536                         {
537                                 R_Mesh_GetSpace(batchcount * 4);
538                                 R_Mesh_CopyVertex3f(textverts, batchcount * 4);
539                                 R_Mesh_CopyTexCoord2f(0, texttexcoords, batchcount * 4);
540                                 R_Mesh_Draw(batchcount * 4, batchcount * 2, quadelements);
541                         }
542                         break;
543                 case DRAWQUEUE_MESH:
544                         mesh = (void *)(dq + 1);
545                         m.tex[0] = R_GetTexture(mesh->texture);
546                         R_Mesh_TextureState(&m);
547                         GL_UseColorArray();
548                         R_Mesh_GetSpace(mesh->numvertices);
549                         R_Mesh_CopyVertex3f(mesh->vertex3f, mesh->numvertices);
550                         R_Mesh_CopyTexCoord2f(0, mesh->texcoord2f, mesh->numvertices);
551                         R_Mesh_CopyColor4f(mesh->color4f, mesh->numvertices);
552                         R_Mesh_Draw(mesh->numvertices, mesh->numtriangles, mesh->element3i);
553                         currentpic = "\0";
554                         break;
555                 }
556         }
557
558         if (!vid_usinghwgamma)
559         {
560                 // all the blends ignore depth
561                 memset(&m, 0, sizeof(m));
562                 m.depthdisable = true;
563                 if (v_color_enable.integer)
564                 {
565                         c[0] = v_color_white_r.value;
566                         c[1] = v_color_white_g.value;
567                         c[2] = v_color_white_b.value;
568                 }
569                 else
570                         c[0] = c[1] = c[2] = v_contrast.value;
571                 VectorScale(c, (float) (1 << v_overbrightbits.integer), c);
572                 if (c[0] >= 1.01f || c[1] >= 1.01f || c[2] >= 1.01f)
573                 {
574                         m.blendfunc1 = GL_DST_COLOR;
575                         m.blendfunc2 = GL_ONE;
576                         R_Mesh_State(&m);
577                         while (c[0] >= 1.01f || c[1] >= 1.01f || c[2] >= 1.01f)
578                         {
579                                 GL_Color(bound(0, c[0] - 1, 1), bound(0, c[1] - 1, 1), bound(0, c[2] - 1, 1), 1);
580                                 R_Mesh_GetSpace(3);
581                                 R_Mesh_CopyVertex3f(blendvertex3f, 3);
582                                 R_Mesh_CopyTexCoord2f(0, blendtexcoord2f, 3);
583                                 R_Mesh_Draw(3, 1, polygonelements);
584                                 VectorScale(c, 0.5, c);
585                         }
586                 }
587                 if (v_color_enable.integer)
588                 {
589                         c[0] = v_color_black_r.value;
590                         c[1] = v_color_black_g.value;
591                         c[2] = v_color_black_b.value;
592                 }
593                 else
594                         c[0] = c[1] = c[2] = v_brightness.value;
595                 if (c[0] >= 0.01f || c[1] >= 0.01f || c[2] >= 0.01f)
596                 {
597                         m.blendfunc1 = GL_ONE;
598                         m.blendfunc2 = GL_ONE;
599                         R_Mesh_State(&m);
600                         GL_Color(c[0], c[1], c[2], 1);
601                         R_Mesh_GetSpace(3);
602                         R_Mesh_CopyVertex3f(blendvertex3f, 3);
603                         R_Mesh_CopyTexCoord2f(0, blendtexcoord2f, 3);
604                         R_Mesh_Draw(3, 1, polygonelements);
605                 }
606         }
607         R_Mesh_Finish();
608 }
609