added newmap function to render modules (so explosions and other things are reset...
[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 // draw.c -- this is the only file outside the refresh that touches the
22 // vid buffer
23
24 #include "quakedef.h"
25
26 //#define GL_COLOR_INDEX8_EXT     0x80E5
27
28 cvar_t          scr_conalpha = {"scr_conalpha", "1"};
29
30 byte            *draw_chars;                            // 8*8 graphic characters
31 qpic_t          *draw_disc;
32
33 rtexture_t      *char_texture;
34
35 typedef struct
36 {
37         rtexture_t      *tex;
38 } glpic_t;
39
40 rtexture_t      *conbacktex;
41
42 //=============================================================================
43 /* Support Routines */
44
45 typedef struct cachepic_s
46 {
47         char            name[MAX_QPATH];
48         qpic_t          pic;
49         byte            padding[32];    // for appended glpic
50 } cachepic_t;
51
52 #define MAX_CACHED_PICS         128
53 cachepic_t      menu_cachepics[MAX_CACHED_PICS];
54 int                     menu_numcachepics;
55
56 byte            menuplyr_pixels[4096];
57
58 int             pic_texels;
59 int             pic_count;
60
61 qpic_t *Draw_PicFromWad (char *name)
62 {
63         qpic_t  *p;
64         glpic_t *gl;
65
66         p = W_GetLumpName (name);
67         gl = (glpic_t *)p->data;
68
69         gl->tex = R_LoadTexture (name, p->width, p->height, p->data, TEXF_ALPHA | TEXF_PRECACHE);
70         return p;
71 }
72
73
74 /*
75 ================
76 Draw_CachePic
77 ================
78 */
79 qpic_t  *Draw_CachePic (char *path)
80 {
81         cachepic_t      *pic;
82         int                     i;
83         qpic_t          *dat;
84         glpic_t         *gl;
85
86         for (pic=menu_cachepics, i=0 ; i<menu_numcachepics ; pic++, i++)
87                 if (!strcmp (path, pic->name))
88                         return &pic->pic;
89
90         if (menu_numcachepics == MAX_CACHED_PICS)
91                 Sys_Error ("menu_numcachepics == MAX_CACHED_PICS");
92         menu_numcachepics++;
93         strcpy (pic->name, path);
94
95 //
96 // load the pic from disk
97 //
98         dat = (qpic_t *)COM_LoadMallocFile (path, false);
99         if (!dat)
100                 Sys_Error ("Draw_CachePic: failed to load %s", path);
101         SwapPic (dat);
102
103         // HACK HACK HACK --- we need to keep the bytes for
104         // the translatable player picture just for the menu
105         // configuration dialog
106         if (!strcmp (path, "gfx/menuplyr.lmp"))
107                 memcpy (menuplyr_pixels, dat->data, dat->width*dat->height);
108
109         pic->pic.width = dat->width;
110         pic->pic.height = dat->height;
111
112         gl = (glpic_t *)pic->pic.data;
113         gl->tex = loadtextureimage(path, 0, 0, false, false, true);
114         if (!gl->tex)
115                 gl->tex = R_LoadTexture (path, dat->width, dat->height, dat->data, TEXF_ALPHA | TEXF_PRECACHE);
116
117         qfree(dat);
118
119         return &pic->pic;
120 }
121
122 extern void LoadSky_f(void);
123
124 /*
125 ===============
126 Draw_Init
127 ===============
128 */
129 void rmain_registercvars();
130
131 void gl_draw_start()
132 {
133         int             i;
134
135         char_texture = loadtextureimage ("conchars", 0, 0, false, false, true);
136         if (!char_texture)
137         {
138                 draw_chars = W_GetLumpName ("conchars");
139                 for (i=0 ; i<128*128 ; i++)
140                         if (draw_chars[i] == 0)
141                                 draw_chars[i] = 255;    // proper transparent color
142
143                 // now turn them into textures
144                 char_texture = R_LoadTexture ("charset", 128, 128, draw_chars, TEXF_ALPHA | TEXF_PRECACHE);
145         }
146
147         conbacktex = loadtextureimage("gfx/conback", 0, 0, false, false, true);
148
149         // get the other pics we need
150         draw_disc = Draw_PicFromWad ("disc");
151 }
152
153 void gl_draw_shutdown()
154 {
155 }
156
157 void gl_draw_newmap()
158 {
159 }
160
161 char engineversion[40];
162 int engineversionx, engineversiony;
163
164 extern void R_Textures_Init();
165 void GL_Draw_Init (void)
166 {
167         int i;
168         Cvar_RegisterVariable (&scr_conalpha);
169
170         Cmd_AddCommand ("loadsky", &LoadSky_f);
171
172 #if defined(__linux__)
173         sprintf (engineversion, "DarkPlaces Linux   GL %.2f build %3i", (float) VERSION, buildnumber);
174 #elif defined(WIN32)
175         sprintf (engineversion, "DarkPlaces Windows GL %.2f build %3i", (float) VERSION, buildnumber);
176 #else
177         sprintf (engineversion, "DarkPlaces Unknown GL %.2f build %3i", (float) VERSION, buildnumber);
178 #endif
179         for (i = 0;i < 40 && engineversion[i];i++)
180                 engineversion[i] += 0x80; // shift to orange
181         engineversionx = vid.width - strlen(engineversion) * 8 - 8;
182         engineversiony = vid.height - 8;
183
184         R_Textures_Init();
185         R_RegisterModule("GL_Draw", gl_draw_start, gl_draw_shutdown, gl_draw_newmap);
186 }
187
188 /*
189 ================
190 Draw_Character
191
192 Draws one 8*8 graphics character with 0 being transparent.
193 It can be clipped to the top of the screen to allow the console to be
194 smoothly scrolled off.
195 ================
196 */
197 void Draw_Character (int x, int y, int num)
198 {
199         int                             row, col;
200         float                   frow, fcol, size;
201
202         if (num == 32)
203                 return;         // space
204
205         num &= 255;
206         
207         if (y <= -8)
208                 return;                 // totally off screen
209
210         row = num>>4;
211         col = num&15;
212
213         frow = row*0.0625;
214         fcol = col*0.0625;
215         size = 0.0625;
216
217         if (!r_render.value)
218                 return;
219         glBindTexture(GL_TEXTURE_2D, R_GetTexture(char_texture));
220         // LordHavoc: NEAREST mode on text if not scaling up
221         if (glwidth <= (int) vid.width)
222         {
223                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
224                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
225         }
226         else
227         {
228                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
229                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
230         }
231
232         glColor3f(1,1,1);
233         glBegin (GL_QUADS);
234         glTexCoord2f (fcol, frow);
235         glVertex2f (x, y);
236         glTexCoord2f (fcol + size, frow);
237         glVertex2f (x+8, y);
238         glTexCoord2f (fcol + size, frow + size);
239         glVertex2f (x+8, y+8);
240         glTexCoord2f (fcol, frow + size);
241         glVertex2f (x, y+8);
242         glEnd ();
243
244         // LordHavoc: revert to LINEAR mode
245 //      if (glwidth < (int) vid.width)
246 //      {
247 //              glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
248 //              glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
249 //      }
250 }
251
252 /*
253 ================
254 Draw_String
255 ================
256 */
257 // LordHavoc: sped this up a lot, and added maxlen
258 void Draw_String (int x, int y, char *str, int maxlen)
259 {
260         int num;
261         float frow, fcol;
262         if (!r_render.value)
263                 return;
264         if (y <= -8 || y >= (int) vid.height || x >= (int) vid.width || *str == 0) // completely offscreen or no text to print
265                 return;
266         if (maxlen < 1)
267                 maxlen = strlen(str);
268         else if (maxlen > (int) strlen(str))
269                 maxlen = strlen(str);
270         glBindTexture(GL_TEXTURE_2D, R_GetTexture(char_texture));
271
272         // LordHavoc: NEAREST mode on text if not scaling up
273         if (glwidth <= (int) vid.width)
274         {
275                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
276                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
277         }
278         else
279         {
280                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
281                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
282         }
283
284         glColor3f(1,1,1);
285         glBegin (GL_QUADS);
286         while (maxlen-- && x < (int) vid.width) // stop rendering when out of characters or room
287         {
288                 if ((num = *str++) != 32) // skip spaces
289                 {
290                         frow = (float) ((int) num >> 4)*0.0625;
291                         fcol = (float) ((int) num & 15)*0.0625;
292                         glTexCoord2f (fcol         , frow         );glVertex2f (x, y);
293                         glTexCoord2f (fcol + 0.0625, frow         );glVertex2f (x+8, y);
294                         glTexCoord2f (fcol + 0.0625, frow + 0.0625);glVertex2f (x+8, y+8);
295                         glTexCoord2f (fcol         , frow + 0.0625);glVertex2f (x, y+8);
296                 }
297                 x += 8;
298         }
299         glEnd ();
300
301         // LordHavoc: revert to LINEAR mode
302 //      if (glwidth < (int) vid.width)
303 //      {
304 //              glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
305 //              glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
306 //      }
307 }
308
309 void Draw_GenericPic (rtexture_t *tex, float red, float green, float blue, float alpha, int x, int y, int width, int height)
310 {
311         if (!r_render.value)
312                 return;
313         glColor4f(red,green,blue,alpha);
314         glBindTexture(GL_TEXTURE_2D, R_GetTexture(tex));
315         glBegin (GL_QUADS);
316         glTexCoord2f (0, 0);glVertex2f (x, y);
317         glTexCoord2f (1, 0);glVertex2f (x+width, y);
318         glTexCoord2f (1, 1);glVertex2f (x+width, y+height);
319         glTexCoord2f (0, 1);glVertex2f (x, y+height);
320         glEnd ();
321 }
322
323 /*
324 =============
325 Draw_AlphaPic
326 =============
327 */
328 void Draw_AlphaPic (int x, int y, qpic_t *pic, float alpha)
329 {
330         Draw_GenericPic(((glpic_t *)pic->data)->tex, 1,1,1,alpha, x,y,pic->width, pic->height);
331 }
332
333
334 /*
335 =============
336 Draw_Pic
337 =============
338 */
339 void Draw_Pic (int x, int y, qpic_t *pic)
340 {
341         Draw_GenericPic(((glpic_t *)pic->data)->tex, 1,1,1,1, x,y,pic->width, pic->height);
342 }
343
344
345 /*
346 =============
347 Draw_PicTranslate
348
349 Only used for the player color selection menu
350 =============
351 */
352 void Draw_PicTranslate (int x, int y, qpic_t *pic, byte *translation)
353 {
354         int                             i, c;
355         byte                    *trans, *src, *dest;
356         rtexture_t              *rt;
357
358         c = pic->width * pic->height;
359         src = menuplyr_pixels;
360         dest = trans = qmalloc(c);
361         for (i = 0;i < c;i++)
362                 *dest++ = translation[*src++];
363
364         rt = R_LoadTexture ("translatedplayerpic", pic->width, pic->height, trans, TEXF_ALPHA | TEXF_PRECACHE);
365         qfree(trans);
366
367         if (!r_render.value)
368                 return;
369         Draw_GenericPic (rt, 1,1,1,1, x, y, pic->width, pic->height);
370 }
371
372
373 /*
374 ================
375 Draw_ConsoleBackground
376
377 ================
378 */
379 void Draw_ConsoleBackground (int lines)
380 {
381         Draw_GenericPic (conbacktex, 1,1,1,scr_conalpha.value*lines/vid.height, 0, lines - vid.height, vid.width, vid.height);
382         // LordHavoc: draw version
383         Draw_String(engineversionx, lines - vid.height + engineversiony, engineversion, 9999);
384 }
385
386 /*
387 =============
388 Draw_Fill
389
390 Fills a box of pixels with a single color
391 =============
392 */
393 void Draw_Fill (int x, int y, int w, int h, int c)
394 {
395         if (!r_render.value)
396                 return;
397         glDisable (GL_TEXTURE_2D);
398         glColor3f (host_basepal[c*3]/255.0, host_basepal[c*3+1]/255.0, host_basepal[c*3+2]/255.0);
399
400         glBegin (GL_QUADS);
401
402         glVertex2f (x,y);
403         glVertex2f (x+w, y);
404         glVertex2f (x+w, y+h);
405         glVertex2f (x, y+h);
406
407         glEnd ();
408         glColor3f(1,1,1);
409         glEnable (GL_TEXTURE_2D);
410 }
411 //=============================================================================
412
413 //=============================================================================
414
415 /*
416 ================
417 GL_Set2D
418
419 Setup as if the screen was 320*200
420 ================
421 */
422 void GL_Set2D (void)
423 {
424         if (!r_render.value)
425                 return;
426         glViewport (glx, gly, glwidth, glheight);
427
428         glMatrixMode(GL_PROJECTION);
429     glLoadIdentity ();
430         glOrtho  (0, vid.width, vid.height, 0, -99999, 99999);
431
432         glMatrixMode(GL_MODELVIEW);
433     glLoadIdentity ();
434
435         glDisable (GL_DEPTH_TEST);
436         glDisable (GL_CULL_FACE);
437         glEnable (GL_BLEND);
438         glDisable (GL_ALPHA_TEST);
439         glEnable(GL_TEXTURE_2D);
440
441         // LordHavoc: added this
442         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
443         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
444
445         glColor3f(1,1,1);
446 }
447
448 // LordHavoc: SHOWLMP stuff
449 #define SHOWLMP_MAXLABELS 256
450 typedef struct showlmp_s
451 {
452         qboolean        isactive;
453         float           x;
454         float           y;
455         char            label[32];
456         char            pic[128];
457 } showlmp_t;
458
459 showlmp_t showlmp[SHOWLMP_MAXLABELS];
460
461 void SHOWLMP_decodehide()
462 {
463         int i;
464         byte *lmplabel;
465         lmplabel = MSG_ReadString();
466         for (i = 0;i < SHOWLMP_MAXLABELS;i++)
467                 if (showlmp[i].isactive && strcmp(showlmp[i].label, lmplabel) == 0)
468                 {
469                         showlmp[i].isactive = false;
470                         return;
471                 }
472 }
473
474 void SHOWLMP_decodeshow()
475 {
476         int i, k;
477         byte lmplabel[256], picname[256];
478         float x, y;
479         strcpy(lmplabel,MSG_ReadString());
480         strcpy(picname, MSG_ReadString());
481         if (nehahra) // LordHavoc: nasty old legacy junk
482         {
483                 x = MSG_ReadByte();
484                 y = MSG_ReadByte();
485         }
486         else
487         {
488                 x = MSG_ReadShort();
489                 y = MSG_ReadShort();
490         }
491         k = -1;
492         for (i = 0;i < SHOWLMP_MAXLABELS;i++)
493                 if (showlmp[i].isactive)
494                 {
495                         if (strcmp(showlmp[i].label, lmplabel) == 0)
496                         {
497                                 k = i;
498                                 break; // drop out to replace it
499                         }
500                 }
501                 else if (k < 0) // find first empty one to replace
502                         k = i;
503         if (k < 0)
504                 return; // none found to replace
505         // change existing one
506         showlmp[k].isactive = true;
507         strcpy(showlmp[k].label, lmplabel);
508         strcpy(showlmp[k].pic, picname);
509         showlmp[k].x = x;
510         showlmp[k].y = y;
511 }
512
513 void SHOWLMP_drawall()
514 {
515         int i;
516         for (i = 0;i < SHOWLMP_MAXLABELS;i++)
517                 if (showlmp[i].isactive)
518                         Draw_Pic(showlmp[i].x, showlmp[i].y, Draw_CachePic(showlmp[i].pic));
519 }
520
521 void SHOWLMP_clear()
522 {
523         int i;
524         for (i = 0;i < SHOWLMP_MAXLABELS;i++)
525                 showlmp[i].isactive = false;
526 }