2 Copyright (C) 1996-1997 Id Software, Inc.
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.
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.
13 See the GNU General Public License for more details.
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.
21 // draw.c -- this is the only file outside the refresh that touches the
26 #define GL_COLOR_INDEX8_EXT 0x80E5
28 extern unsigned char d_15to8table[65536];
30 cvar_t qsg_version = {"qsg_version", "1"};
31 cvar_t scr_conalpha = {"scr_conalpha", "1"};
33 byte *draw_chars; // 8*8 graphic characters
44 byte conback_buffer[sizeof(qpic_t) + sizeof(glpic_t)];
45 qpic_t *conback = (qpic_t *)&conback_buffer;
48 =============================================================================
52 Allocate all the little status bar obejcts into a single texture
53 to crutch up stupid hardware / drivers
55 =============================================================================
59 #define BLOCK_WIDTH 256
60 #define BLOCK_HEIGHT 256
62 int scrap_allocated[MAX_SCRAPS][BLOCK_WIDTH];
63 byte scrap_texels[MAX_SCRAPS][BLOCK_WIDTH*BLOCK_HEIGHT*4];
66 // returns a texture number and the position inside it
67 int Scrap_AllocBlock (int w, int h, int *x, int *y)
73 for (texnum=0 ; texnum<MAX_SCRAPS ; texnum++)
77 for (i=0 ; i<BLOCK_WIDTH-w ; i++)
83 if (scrap_allocated[texnum][i+j] >= best)
85 if (scrap_allocated[texnum][i+j] > best2)
86 best2 = scrap_allocated[texnum][i+j];
89 { // this is a valid spot
95 if (best + h > BLOCK_HEIGHT)
99 scrap_allocated[texnum][*x + i] = best + h;
104 Sys_Error ("Scrap_AllocBlock: full");
109 int scraptexnum[MAX_SCRAPS];
111 void Scrap_Upload (void)
117 for (texnum=0 ; texnum<MAX_SCRAPS ; texnum++)
118 scraptexnum[texnum] = GL_LoadTexture (va("scrapslot%d", texnum), BLOCK_WIDTH, BLOCK_HEIGHT, scrap_texels[texnum], false, true, 1);
122 //=============================================================================
123 /* Support Routines */
125 typedef struct cachepic_s
127 char name[MAX_QPATH];
129 byte padding[32]; // for appended glpic
132 #define MAX_CACHED_PICS 128
133 cachepic_t menu_cachepics[MAX_CACHED_PICS];
134 int menu_numcachepics;
136 byte menuplyr_pixels[4096];
141 int GL_LoadPicTexture (qpic_t *pic);
143 qpic_t *Draw_PicFromWad (char *name)
148 p = W_GetLumpName (name);
149 gl = (glpic_t *)p->data;
151 // load little ones into the scrap
152 if (p->width < 64 && p->height < 64)
158 texnum = Scrap_AllocBlock (p->width, p->height, &x, &y);
161 for (i=0 ; i<p->height ; i++)
162 for (j=0 ; j<p->width ; j++, k++)
163 scrap_texels[texnum][(y+i)*BLOCK_WIDTH + x + j] = p->data[k];
164 if (!scraptexnum[texnum])
165 scraptexnum[texnum] = GL_LoadTexture (va("scrapslot%d", texnum), BLOCK_WIDTH, BLOCK_HEIGHT, scrap_texels[texnum], false, true, 1);
166 gl->texnum = scraptexnum[texnum];
167 gl->sl = (x+0.01)/(float)BLOCK_WIDTH;
168 gl->sh = (x+p->width-0.01)/(float)BLOCK_WIDTH;
169 gl->tl = (y+0.01)/(float)BLOCK_WIDTH;
170 gl->th = (y+p->height-0.01)/(float)BLOCK_WIDTH;
173 pic_texels += p->width*p->height;
177 gl->texnum = GL_LoadPicTexture (p);
192 qpic_t *Draw_CachePic (char *path)
199 for (pic=menu_cachepics, i=0 ; i<menu_numcachepics ; pic++, i++)
200 if (!strcmp (path, pic->name))
203 if (menu_numcachepics == MAX_CACHED_PICS)
204 Sys_Error ("menu_numcachepics == MAX_CACHED_PICS");
206 strcpy (pic->name, path);
209 // load the pic from disk
211 dat = (qpic_t *)COM_LoadTempFile (path, false);
213 Sys_Error ("Draw_CachePic: failed to load %s", path);
216 // HACK HACK HACK --- we need to keep the bytes for
217 // the translatable player picture just for the menu
218 // configuration dialog
219 if (!strcmp (path, "gfx/menuplyr.lmp"))
220 memcpy (menuplyr_pixels, dat->data, dat->width*dat->height);
222 pic->pic.width = dat->width;
223 pic->pic.height = dat->height;
225 gl = (glpic_t *)pic->pic.data;
226 gl->texnum = GL_LoadPicTexture (dat);
235 extern void LoadSky_f(void);
237 extern char *QSG_EXTENSIONS;
244 void rmain_registercvars();
245 extern int buildnumber;
252 // load the console background and the charset
253 // by hand, because we need to write the version
254 // string into the background before turning
256 char_texture = loadtextureimage ("conchars", 0, 0, false, false);
259 draw_chars = W_GetLumpName ("conchars");
260 for (i=0 ; i<256*64 ; i++)
261 if (draw_chars[i] == 0)
262 draw_chars[i] = 255; // proper transparent color
264 // now turn them into textures
265 char_texture = GL_LoadTexture ("charset", 128, 128, draw_chars, false, true, 1);
268 gl = (glpic_t *)conback->data;
269 gl->texnum = loadtextureimage("gfx/conback", 0, 0, false, false);
274 conback->width = vid.width;
275 conback->height = vid.height;
277 memset(scraptexnum, 0, sizeof(scraptexnum));
279 // get the other pics we need
280 draw_disc = Draw_PicFromWad ("disc");
283 void gl_draw_shutdown()
287 char engineversion[40];
288 int engineversionx, engineversiony;
290 extern void GL_Textures_Init();
291 void GL_Draw_Init (void)
294 Cvar_RegisterVariable (&qsg_version);
295 Cvar_RegisterVariable (&scr_conalpha);
297 Cmd_AddCommand ("loadsky", &LoadSky_f);
300 #if defined(__linux__)
301 sprintf (engineversion, "DPNehahra Linux GL %.2f build %3i", (float) VERSION, buildnumber);
303 sprintf (engineversion, "DPNehahra Windows GL %.2f build %3i", (float) VERSION, buildnumber);
305 sprintf (engineversion, "DPNehahra Unknown GL %.2f build %3i", (float) VERSION, buildnumber);
308 #if defined(__linux__)
309 sprintf (engineversion, "DarkPlaces Linux GL %.2f build %3i", (float) VERSION, buildnumber);
311 sprintf (engineversion, "DarkPlaces Windows GL %.2f build %3i", (float) VERSION, buildnumber);
313 sprintf (engineversion, "DarkPlaces Unknown GL %.2f build %3i", (float) VERSION, buildnumber);
316 for (i = 0;i < 40 && engineversion[i];i++)
317 engineversion[i] += 0x80; // shift to orange
318 engineversionx = vid.width - strlen(engineversion) * 8 - 8;
319 engineversiony = vid.height - 8;
322 R_RegisterModule("GL_Draw", gl_draw_start, gl_draw_shutdown);
329 Draws one 8*8 graphics character with 0 being transparent.
330 It can be clipped to the top of the screen to allow the console to be
331 smoothly scrolled off.
334 void Draw_Character (int x, int y, int num)
337 float frow, fcol, size;
345 return; // totally off screen
356 glBindTexture(GL_TEXTURE_2D, char_texture);
357 // LordHavoc: NEAREST mode on text if not scaling up
358 if ((int) vid.width < glwidth)
360 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
361 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
366 glTexCoord2f (fcol, frow);
368 glTexCoord2f (fcol + size, frow);
370 glTexCoord2f (fcol + size, frow + size);
371 glVertex2f (x+8, y+8);
372 glTexCoord2f (fcol, frow + size);
376 // LordHavoc: revert to LINEAR mode
377 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
378 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
386 // LordHavoc: sped this up a lot, and added maxlen
387 void Draw_String (int x, int y, char *str, int maxlen)
393 if (y <= -8 || y >= (int) vid.height || x >= (int) vid.width || *str == 0) // completely offscreen or no text to print
396 maxlen = strlen(str);
397 else if (maxlen > (int) strlen(str))
398 maxlen = strlen(str);
399 glBindTexture(GL_TEXTURE_2D, char_texture);
401 // LordHavoc: NEAREST mode on text if not scaling up
402 if ((int) vid.width < glwidth)
404 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
405 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
410 while (maxlen-- && x < (int) vid.width) // stop rendering when out of characters or room
412 if ((num = *str++) != 32) // skip spaces
414 frow = (float) ((int) num >> 4)*0.0625;
415 fcol = (float) ((int) num & 15)*0.0625;
416 glTexCoord2f (fcol, frow);
418 glTexCoord2f (fcol + 0.0625, frow);
420 glTexCoord2f (fcol + 0.0625, frow + 0.0625);
421 glVertex2f (x+8, y+8);
422 glTexCoord2f (fcol, frow + 0.0625);
429 // LordHavoc: revert to LINEAR mode
430 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
431 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
434 void Draw_GenericPic (int texnum, float red, float green, float blue, float alpha, float x, float y, float width, float height)
438 glDisable(GL_ALPHA_TEST);
439 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
440 glColor4f(red,green,blue,alpha);
441 glBindTexture(GL_TEXTURE_2D, texnum);
442 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
447 glVertex2f (x+width, y);
449 glVertex2f (x+width, y+height);
451 glVertex2f (x, y+height);
461 void Draw_AlphaPic (int x, int y, qpic_t *pic, float alpha)
467 gl = (glpic_t *)pic->data;
470 glColor4f(1,1,1,alpha);
471 glBindTexture(GL_TEXTURE_2D, gl->texnum);
473 glTexCoord2f (gl->sl, gl->tl);
475 glTexCoord2f (gl->sh, gl->tl);
476 glVertex2f (x+pic->width, y);
477 glTexCoord2f (gl->sh, gl->th);
478 glVertex2f (x+pic->width, y+pic->height);
479 glTexCoord2f (gl->sl, gl->th);
480 glVertex2f (x, y+pic->height);
490 void Draw_Pic (int x, int y, qpic_t *pic)
496 gl = (glpic_t *)pic->data;
500 glBindTexture(GL_TEXTURE_2D, gl->texnum);
502 glTexCoord2f (gl->sl, gl->tl);
504 glTexCoord2f (gl->sh, gl->tl);
505 glVertex2f (x+pic->width, y);
506 glTexCoord2f (gl->sh, gl->th);
507 glVertex2f (x+pic->width, y+pic->height);
508 glTexCoord2f (gl->sl, gl->th);
509 glVertex2f (x, y+pic->height);
518 Only used for the player color selection menu
521 void Draw_PicTranslate (int x, int y, qpic_t *pic, byte *translation)
524 byte *trans, *src, *dest;
526 c = pic->width * pic->height;
527 src = menuplyr_pixels;
528 dest = trans = malloc(c);
529 for (i = 0;i < c;i++)
530 *dest++ = translation[*src++];
532 c = GL_LoadTexture ("translatedplayerpic", pic->width, pic->height, trans, false, true, 1);
537 glBindTexture(GL_TEXTURE_2D, c);
543 glVertex2f (x+pic->width, y);
545 glVertex2f (x+pic->width, y+pic->height);
547 glVertex2f (x, y+pic->height);
554 Draw_ConsoleBackground
558 void Draw_ConsoleBackground (int lines)
560 if (lines >= (int) vid.height)
561 Draw_Pic(0, lines - vid.height, conback);
563 Draw_AlphaPic (0, lines - vid.height, conback, scr_conalpha.value*lines/vid.height);
564 // LordHavoc: draw version
565 Draw_String(engineversionx, lines - vid.height + engineversiony, engineversion, 9999);
572 Fills a box of pixels with a single color
575 void Draw_Fill (int x, int y, int w, int h, int c)
579 glDisable (GL_TEXTURE_2D);
580 glColor3f (host_basepal[c*3]/255.0, host_basepal[c*3+1]/255.0, host_basepal[c*3+2]/255.0);
586 glVertex2f (x+w, y+h);
591 glEnable (GL_TEXTURE_2D);
593 //=============================================================================
595 //=============================================================================
601 Setup as if the screen was 320*200
608 glViewport (glx, gly, glwidth, glheight);
610 glMatrixMode(GL_PROJECTION);
612 glOrtho (0, vid.width, vid.height, 0, -99999, 99999);
614 glMatrixMode(GL_MODELVIEW);
617 glDisable (GL_DEPTH_TEST);
618 glDisable (GL_CULL_FACE);
620 glDisable (GL_ALPHA_TEST);
621 glEnable(GL_TEXTURE_2D);
623 // LordHavoc: added this
624 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
625 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
630 // LordHavoc: SHOWLMP stuff
631 #define SHOWLMP_MAXLABELS 256
632 typedef struct showlmp_s
641 showlmp_t showlmp[SHOWLMP_MAXLABELS];
643 void SHOWLMP_decodehide()
647 lmplabel = MSG_ReadString();
648 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
649 if (showlmp[i].isactive && strcmp(showlmp[i].label, lmplabel) == 0)
651 showlmp[i].isactive = false;
656 void SHOWLMP_decodeshow()
659 byte lmplabel[256], picname[256];
661 strcpy(lmplabel,MSG_ReadString());
662 strcpy(picname, MSG_ReadString());
666 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
667 if (showlmp[i].isactive)
669 if (strcmp(showlmp[i].label, lmplabel) == 0)
672 break; // drop out to replace it
675 else if (k < 0) // find first empty one to replace
678 return; // none found to replace
679 // change existing one
680 showlmp[k].isactive = true;
681 strcpy(showlmp[k].label, lmplabel);
682 strcpy(showlmp[k].pic, picname);
687 void SHOWLMP_drawall()
690 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
691 if (showlmp[i].isactive)
692 Draw_Pic(showlmp[i].x, showlmp[i].y, Draw_CachePic(showlmp[i].pic));
698 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
699 showlmp[i].isactive = false;