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