added in_pitch_min and in_pitch_max cvars to limit pitch (default: -90 to +90)
[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
23 //#define GL_COLOR_INDEX8_EXT     0x80E5
24
25 cvar_t scr_conalpha = {CVAR_SAVE, "scr_conalpha", "1"};
26
27 static rtexture_t *char_texture;
28
29 //=============================================================================
30 /* Support Routines */
31
32 #define MAX_CACHED_PICS 256
33 #define CACHEPICHASHSIZE 256
34 static cachepic_t *cachepichash[CACHEPICHASHSIZE];
35 static cachepic_t cachepics[MAX_CACHED_PICS];
36 static int numcachepics;
37
38 static rtexturepool_t *drawtexturepool;
39
40 static byte pointerimage[256] =
41 {
42         "333333332......."
43         "26777761........"
44         "2655541........."
45         "265541.........."
46         "2654561........."
47         "26414561........"
48         "251.14561......."
49         "21...14561......"
50         "1.....141......."
51         ".......1........"
52         "................"
53         "................"
54         "................"
55         "................"
56         "................"
57         "................"
58 };
59
60 static rtexture_t *draw_generatemousepointer(void)
61 {
62         int i;
63         byte buffer[256][4];
64         for (i = 0;i < 256;i++)
65         {
66                 if (pointerimage[i] == '.')
67                 {
68                         buffer[i][0] = 0;
69                         buffer[i][1] = 0;
70                         buffer[i][2] = 0;
71                         buffer[i][3] = 0;
72                 }
73                 else
74                 {
75                         buffer[i][0] = (pointerimage[i] - '0') * 16;
76                         buffer[i][1] = (pointerimage[i] - '0') * 16;
77                         buffer[i][2] = (pointerimage[i] - '0') * 16;
78                         buffer[i][3] = 255;
79                 }
80         }
81         return R_LoadTexture(drawtexturepool, "mousepointer", 16, 16, &buffer[0][0], TEXTYPE_RGBA, TEXF_ALPHA | TEXF_PRECACHE);
82 }
83
84 // must match NUMCROSSHAIRS in r_crosshairs.c
85 #define NUMCROSSHAIRS 5
86
87 static byte *crosshairtexdata[NUMCROSSHAIRS] =
88 {
89         "................"
90         "................"
91         "................"
92         "...33......33..."
93         "...355....553..."
94         "....577..775...."
95         ".....77..77....."
96         "................"
97         "................"
98         ".....77..77....."
99         "....577..775...."
100         "...355....553..."
101         "...33......33..."
102         "................"
103         "................"
104         "................"
105         ,
106         "................"
107         "................"
108         "................"
109         "...3........3..."
110         "....5......5...."
111         ".....7....7....."
112         "......7..7......"
113         "................"
114         "................"
115         "......7..7......"
116         ".....7....7....."
117         "....5......5...."
118         "...3........3..."
119         "................"
120         "................"
121         "................"
122         ,
123         "................"
124         ".......77......."
125         ".......77......."
126         "................"
127         "................"
128         ".......44......."
129         ".......44......."
130         ".77..44..44..77."
131         ".77..44..44..77."
132         ".......44......."
133         ".......44......."
134         "................"
135         ".......77......."
136         ".......77......."
137         "................"
138         "................"
139         ,
140         "................"
141         "................"
142         "................"
143         "................"
144         "................"
145         "................"
146         "................"
147         "................"
148         "........7777777."
149         "........752....."
150         "........72......"
151         "........7......."
152         "........7......."
153         "........7......."
154         "................"
155         "................"
156         ,
157         "................"
158         "................"
159         "................"
160         "................"
161         "................"
162         "........7......."
163         "................"
164         "........4......."
165         ".....7.4.4.7...."
166         "........4......."
167         "................"
168         "........7......."
169         "................"
170         "................"
171         "................"
172         "................"
173 };
174
175 static rtexture_t *draw_generatecrosshair(int num)
176 {
177         int i;
178         char *in;
179         byte data[16*16][4];
180         in = crosshairtexdata[num];
181         for (i = 0;i < 16*16;i++)
182         {
183                 if (in[i] == '.')
184                 {
185                         data[i][0] = 255;
186                         data[i][1] = 255;
187                         data[i][2] = 255;
188                         data[i][3] = 0;
189                 }
190                 else
191                 {
192                         data[i][0] = 255;
193                         data[i][1] = 255;
194                         data[i][2] = 255;
195                         data[i][3] = (byte) ((int) (in[i] - '0') * 255 / 7);
196                 }
197         }
198         return R_LoadTexture(drawtexturepool, va("crosshair%i", num), 16, 16, &data[0][0], TEXTYPE_RGBA, TEXF_ALPHA | TEXF_PRECACHE);
199 }
200
201 /*
202 ================
203 Draw_CachePic
204 ================
205 */
206 // FIXME: move this to client somehow
207 cachepic_t      *Draw_CachePic (char *path)
208 {
209         int i, crc, hashkey;
210         cachepic_t *pic;
211         qpic_t *p;
212
213         crc = CRC_Block(path, strlen(path));
214         hashkey = ((crc >> 8) ^ crc) % CACHEPICHASHSIZE;
215         for (pic = cachepichash[hashkey];pic;pic = pic->chain)
216                 if (!strcmp (path, pic->name))
217                         return pic;
218         //for (pic = cachepics, i = 0;i < numcachepics;pic++, i++)
219         //      if (!strcmp (path, pic->name))
220         //              return pic;
221
222         if (numcachepics == MAX_CACHED_PICS)
223                 Sys_Error ("numcachepics == MAX_CACHED_PICS");
224         pic = cachepics + (numcachepics++);
225         strcpy (pic->name, path);
226         // link into list
227         pic->chain = cachepichash[hashkey];
228         cachepichash[hashkey] = pic;
229
230         // load the pic from disk
231         pic->tex = loadtextureimage(drawtexturepool, path, 0, 0, false, false, true);
232         if (pic->tex == NULL && (p = W_GetLumpName (path)))
233         {
234                 if (!strcmp(path, "conchars"))
235                 {
236                         byte *pix;
237                         // conchars is a raw image and with the wrong transparent color
238                         pix = (byte *)p;
239                         for (i = 0;i < 128 * 128;i++)
240                                 if (pix[i] == 0)
241                                         pix[i] = 255;
242                         pic->tex = R_LoadTexture (drawtexturepool, path, 128, 128, pix, TEXTYPE_QPALETTE, TEXF_ALPHA | TEXF_PRECACHE);
243                 }
244                 else
245                         pic->tex = R_LoadTexture (drawtexturepool, path, p->width, p->height, p->data, TEXTYPE_QPALETTE, TEXF_ALPHA | TEXF_PRECACHE);
246         }
247         if (pic->tex == NULL && !strcmp(path, "ui/mousepointer.tga"))
248                 pic->tex = draw_generatemousepointer();
249         if (pic->tex == NULL && !strcmp(path, "gfx/crosshair1.tga"))
250                 pic->tex = draw_generatecrosshair(0);
251         if (pic->tex == NULL && !strcmp(path, "gfx/crosshair2.tga"))
252                 pic->tex = draw_generatecrosshair(1);
253         if (pic->tex == NULL && !strcmp(path, "gfx/crosshair3.tga"))
254                 pic->tex = draw_generatecrosshair(2);
255         if (pic->tex == NULL && !strcmp(path, "gfx/crosshair4.tga"))
256                 pic->tex = draw_generatecrosshair(3);
257         if (pic->tex == NULL && !strcmp(path, "gfx/crosshair5.tga"))
258                 pic->tex = draw_generatecrosshair(4);
259         if (pic->tex == NULL)
260                 Sys_Error ("Draw_CachePic: failed to load %s", path);
261
262         pic->width = R_TextureWidth(pic->tex);
263         pic->height = R_TextureHeight(pic->tex);
264         return pic;
265 }
266
267 /*
268 ===============
269 Draw_Init
270 ===============
271 */
272 static void gl_draw_start(void)
273 {
274         drawtexturepool = R_AllocTexturePool();
275
276         numcachepics = 0;
277         memset(cachepichash, 0, sizeof(cachepichash));
278
279         char_texture = Draw_CachePic("conchars")->tex;
280 }
281
282 static void gl_draw_shutdown(void)
283 {
284         R_FreeTexturePool(&drawtexturepool);
285
286         numcachepics = 0;
287         memset(cachepichash, 0, sizeof(cachepichash));
288 }
289
290 static void gl_draw_newmap(void)
291 {
292 }
293
294 void GL_Draw_Init (void)
295 {
296         Cvar_RegisterVariable (&scr_conalpha);
297
298         numcachepics = 0;
299         memset(cachepichash, 0, sizeof(cachepichash));
300
301         R_RegisterModule("GL_Draw", gl_draw_start, gl_draw_shutdown, gl_draw_newmap);
302 }
303
304 void R_DrawQueue(void)
305 {
306         int pos, num, chartexnum, overbright;
307         float x, y, w, h, s, t, u, v;
308         cachepic_t *pic;
309         drawqueue_t *dq;
310         char *str, *currentpic;
311         int batch, additive;
312         unsigned int color;
313
314         if (!r_render.integer)
315                 return;
316
317         glViewport(vid.realx, vid.realy, vid.realwidth, vid.realheight);
318
319         glMatrixMode(GL_PROJECTION);
320     glLoadIdentity();
321         glOrtho(0, vid.conwidth, vid.conheight, 0, -99999, 99999);
322
323         glMatrixMode(GL_MODELVIEW);
324     glLoadIdentity();
325
326         glDisable(GL_DEPTH_TEST);
327         glDisable(GL_CULL_FACE);
328         glEnable(GL_BLEND);
329         glEnable(GL_TEXTURE_2D);
330         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
331
332         chartexnum = R_GetTexture(char_texture);
333
334         additive = false;
335         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
336         currentpic = "";
337         pic = NULL;
338         glBindTexture(GL_TEXTURE_2D, 0);
339         color = 0;
340         glColor4ub(0,0,0,0);
341
342         // LordHavoc: NEAREST mode on text if not scaling up
343         /*
344         if (vid.realwidth <= (int) vid.conwidth)
345         {
346                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
347                 CHECKGLERROR
348                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
349                 CHECKGLERROR
350         }
351         else
352         {
353                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
354                 CHECKGLERROR
355                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
356                 CHECKGLERROR
357         }
358         */
359
360         overbright = v_overbrightbits.integer;
361         batch = false;
362         for (pos = 0;pos < r_refdef.drawqueuesize;pos += ((drawqueue_t *)(r_refdef.drawqueue + pos))->size)
363         {
364                 dq = (drawqueue_t *)(r_refdef.drawqueue + pos);
365                 if (dq->flags & DRAWFLAG_ADDITIVE)
366                 {
367                         if (!additive)
368                         {
369                                 if (batch)
370                                 {
371                                         batch = false;
372                                         glEnd();
373                                 }
374                                 additive = true;
375                                 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
376                         }
377                 }
378                 else
379                 {
380                         if (additive)
381                         {
382                                 if (batch)
383                                 {
384                                         batch = false;
385                                         glEnd();
386                                 }
387                                 additive = false;
388                                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
389                         }
390                 }
391                 if (color != dq->color)
392                 {
393                         color = dq->color;
394                         glColor4ub((byte)(((color >> 24) & 0xFF) >> overbright), (byte)(((color >> 16) & 0xFF) >> overbright), (byte)(((color >> 8) & 0xFF) >> overbright), (byte)(color & 0xFF));
395                 }
396                 x = dq->x;
397                 y = dq->y;
398                 w = dq->scalex;
399                 h = dq->scaley;
400                 switch(dq->command)
401                 {
402                 case DRAWQUEUE_PIC:
403                         str = (char *)(dq + 1);
404                         if (*str)
405                         {
406                                 if (strcmp(str, currentpic))
407                                 {
408                                         if (batch)
409                                         {
410                                                 batch = false;
411                                                 glEnd();
412                                         }
413                                         currentpic = str;
414                                         pic = Draw_CachePic(str);
415                                         glBindTexture(GL_TEXTURE_2D, R_GetTexture(pic->tex));
416                                 }
417                                 if (w == 0)
418                                         w = pic->width;
419                                 if (h == 0)
420                                         h = pic->height;
421                                 if (!batch)
422                                 {
423                                         batch = true;
424                                         glBegin(GL_QUADS);
425                                 }
426                                 //DrawQuad(dq->x, dq->y, w, h, 0, 0, 1, 1);
427                                 glTexCoord2f (0, 0);glVertex2f (x  , y  );
428                                 glTexCoord2f (1, 0);glVertex2f (x+w, y  );
429                                 glTexCoord2f (1, 1);glVertex2f (x+w, y+h);
430                                 glTexCoord2f (0, 1);glVertex2f (x  , y+h);
431                         }
432                         else
433                         {
434                                 if (currentpic[0])
435                                 {
436                                         if (batch)
437                                         {
438                                                 batch = false;
439                                                 glEnd();
440                                         }
441                                         currentpic = "";
442                                         glBindTexture(GL_TEXTURE_2D, 0);
443                                 }
444                                 if (!batch)
445                                 {
446                                         batch = true;
447                                         glBegin(GL_QUADS);
448                                 }
449                                 //DrawQuad(dq->x, dq->y, dq->scalex, dq->scaley, 0, 0, 1, 1);
450                                 glTexCoord2f (0, 0);glVertex2f (x  , y  );
451                                 glTexCoord2f (1, 0);glVertex2f (x+w, y  );
452                                 glTexCoord2f (1, 1);glVertex2f (x+w, y+h);
453                                 glTexCoord2f (0, 1);glVertex2f (x  , y+h);
454                         }
455                         break;
456                 case DRAWQUEUE_STRING:
457                         str = (char *)(dq + 1);
458                         if (strcmp("conchars", currentpic))
459                         {
460                                 if (batch)
461                                 {
462                                         batch = false;
463                                         glEnd();
464                                 }
465                                 currentpic = "conchars";
466                                 glBindTexture(GL_TEXTURE_2D, chartexnum);
467                         }
468                         if (!batch)
469                         {
470                                 batch = true;
471                                 glBegin(GL_QUADS);
472                         }
473                         while ((num = *str++) && x < vid.conwidth)
474                         {
475                                 if (num != ' ')
476                                 {
477                                         s = (num & 15)*0.0625f + (0.5f / 256.0f);
478                                         t = (num >> 4)*0.0625f + (0.5f / 256.0f);
479                                         u = 0.0625f - (1.0f / 256.0f);
480                                         v = 0.0625f - (1.0f / 256.0f);
481                                         //DrawQuad(x, y, w, h, (num & 15)*0.0625f + (0.5f / 256.0f), (num >> 4)*0.0625f + (0.5f / 256.0f), 0.0625f - (1.0f / 256.0f), 0.0625f - (1.0f / 256.0f));
482                                         glTexCoord2f (s  , t  );glVertex2f (x  , y  );
483                                         glTexCoord2f (s+u, t  );glVertex2f (x+w, y  );
484                                         glTexCoord2f (s+u, t+v);glVertex2f (x+w, y+h);
485                                         glTexCoord2f (s  , t+v);glVertex2f (x  , y+h);
486                                 }
487                                 x += w;
488                         }
489                         break;
490                 }
491         }
492         if (batch)
493                 glEnd();
494         CHECKGLERROR
495
496         if (!v_hwgamma.integer)
497         {
498                 glDisable(GL_TEXTURE_2D);
499                 CHECKGLERROR
500                 t = v_contrast.value * (float) (1 << v_overbrightbits.integer);
501                 if (t >= 1.01f)
502                 {
503                         glBlendFunc (GL_DST_COLOR, GL_ONE);
504                         CHECKGLERROR
505                         glBegin (GL_TRIANGLES);
506                         while (t >= 1.01f)
507                         {
508                                 if (t >= 2)
509                                         glColor3f (1, 1, 1);
510                                 else
511                                         glColor3f (t-1, t-1, t-1);
512                                 glVertex2f (-5000, -5000);
513                                 glVertex2f (10000, -5000);
514                                 glVertex2f (-5000, 10000);
515                                 t *= 0.5;
516                         }
517                         glEnd ();
518                         CHECKGLERROR
519                 }
520                 else if (t <= 0.99f)
521                 {
522                         glBlendFunc(GL_ZERO, GL_SRC_COLOR);
523                         CHECKGLERROR
524                         glBegin(GL_TRIANGLES);
525                         glColor3f(t, t, t);
526                         glVertex2f(-5000, -5000);
527                         glVertex2f(10000, -5000);
528                         glVertex2f(-5000, 10000);
529                         glEnd();
530                         CHECKGLERROR
531                 }
532                 if (v_brightness.value >= 0.01f)
533                 {
534                         glBlendFunc (GL_ONE, GL_ONE);
535                         CHECKGLERROR
536                         glColor3f (v_brightness.value, v_brightness.value, v_brightness.value);
537                         CHECKGLERROR
538                         glBegin (GL_TRIANGLES);
539                         glVertex2f (-5000, -5000);
540                         glVertex2f (10000, -5000);
541                         glVertex2f (-5000, 10000);
542                         glEnd ();
543                         CHECKGLERROR
544                 }
545                 glEnable(GL_TEXTURE_2D);
546                 CHECKGLERROR
547         }
548
549         glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
550         CHECKGLERROR
551         glEnable (GL_CULL_FACE);
552         CHECKGLERROR
553         glEnable (GL_DEPTH_TEST);
554         CHECKGLERROR
555         glDisable(GL_BLEND);
556         CHECKGLERROR
557         glColor3f(1,1,1);
558         CHECKGLERROR
559 }