aboutsummaryrefslogtreecommitdiffstats
path: root/QW/client/gl_draw.c
diff options
context:
space:
mode:
Diffstat (limited to 'QW/client/gl_draw.c')
-rw-r--r--QW/client/gl_draw.c1378
1 files changed, 1378 insertions, 0 deletions
diff --git a/QW/client/gl_draw.c b/QW/client/gl_draw.c
new file mode 100644
index 0000000..07d8411
--- /dev/null
+++ b/QW/client/gl_draw.c
@@ -0,0 +1,1378 @@
+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+// draw.c -- this is the only file outside the refresh that touches the
+// vid buffer
+
+#include "quakedef.h"
+
+extern unsigned char d_15to8table[65536];
+extern cvar_t crosshair, cl_crossx, cl_crossy, crosshaircolor;
+
+cvar_t gl_nobind = {"gl_nobind", "0"};
+cvar_t gl_max_size = {"gl_max_size", "1024"};
+cvar_t gl_picmip = {"gl_picmip", "0"};
+
+byte *draw_chars; // 8*8 graphic characters
+qpic_t *draw_disc;
+qpic_t *draw_backtile;
+
+int translate_texture;
+int char_texture;
+int cs_texture; // crosshair texture
+
+static byte cs_data[64] = {
+ 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff,
+ 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff,
+ 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+};
+
+
+typedef struct
+{
+ int texnum;
+ float sl, tl, sh, th;
+} glpic_t;
+
+byte conback_buffer[sizeof(qpic_t) + sizeof(glpic_t)];
+qpic_t *conback = (qpic_t *)&conback_buffer;
+
+int gl_lightmap_format = 4;
+int gl_solid_format = 3;
+int gl_alpha_format = 4;
+
+int gl_filter_min = GL_LINEAR_MIPMAP_NEAREST;
+int gl_filter_max = GL_LINEAR;
+
+
+int texels;
+
+typedef struct
+{
+ int texnum;
+ char identifier[64];
+ int width, height;
+ qboolean mipmap;
+} gltexture_t;
+
+#define MAX_GLTEXTURES 1024
+gltexture_t gltextures[MAX_GLTEXTURES];
+int numgltextures;
+
+void GL_Bind (int texnum)
+{
+ if (gl_nobind.value)
+ texnum = char_texture;
+ if (currenttexture == texnum)
+ return;
+ currenttexture = texnum;
+#ifdef _WIN32
+ bindTexFunc (GL_TEXTURE_2D, texnum);
+#else
+ glBindTexture (GL_TEXTURE_2D, texnum);
+#endif
+}
+
+
+/*
+=============================================================================
+
+ scrap allocation
+
+ Allocate all the little status bar obejcts into a single texture
+ to crutch up stupid hardware / drivers
+
+=============================================================================
+*/
+
+#define MAX_SCRAPS 1
+#define BLOCK_WIDTH 256
+#define BLOCK_HEIGHT 256
+
+int scrap_allocated[MAX_SCRAPS][BLOCK_WIDTH];
+byte scrap_texels[MAX_SCRAPS][BLOCK_WIDTH*BLOCK_HEIGHT*4];
+qboolean scrap_dirty;
+int scrap_texnum;
+
+// returns a texture number and the position inside it
+int Scrap_AllocBlock (int w, int h, int *x, int *y)
+{
+ int i, j;
+ int best, best2;
+ int texnum;
+
+ for (texnum=0 ; texnum<MAX_SCRAPS ; texnum++)
+ {
+ best = BLOCK_HEIGHT;
+
+ for (i=0 ; i<BLOCK_WIDTH-w ; i++)
+ {
+ best2 = 0;
+
+ for (j=0 ; j<w ; j++)
+ {
+ if (scrap_allocated[texnum][i+j] >= best)
+ break;
+ if (scrap_allocated[texnum][i+j] > best2)
+ best2 = scrap_allocated[texnum][i+j];
+ }
+ if (j == w)
+ { // this is a valid spot
+ *x = i;
+ *y = best = best2;
+ }
+ }
+
+ if (best + h > BLOCK_HEIGHT)
+ continue;
+
+ for (i=0 ; i<w ; i++)
+ scrap_allocated[texnum][*x + i] = best + h;
+
+ return texnum;
+ }
+
+ Sys_Error ("Scrap_AllocBlock: full");
+ return 0;
+}
+
+int scrap_uploads;
+
+void Scrap_Upload (void)
+{
+ scrap_uploads++;
+ GL_Bind(scrap_texnum);
+ GL_Upload8 (scrap_texels[0], BLOCK_WIDTH, BLOCK_HEIGHT, false, true);
+ scrap_dirty = false;
+}
+
+//=============================================================================
+/* Support Routines */
+
+typedef struct cachepic_s
+{
+ char name[MAX_QPATH];
+ qpic_t pic;
+ byte padding[32]; // for appended glpic
+} cachepic_t;
+
+#define MAX_CACHED_PICS 128
+cachepic_t menu_cachepics[MAX_CACHED_PICS];
+int menu_numcachepics;
+
+byte menuplyr_pixels[4096];
+
+int pic_texels;
+int pic_count;
+
+qpic_t *Draw_PicFromWad (char *name)
+{
+ qpic_t *p;
+ glpic_t *gl;
+
+ p = W_GetLumpName (name);
+ gl = (glpic_t *)p->data;
+
+ // load little ones into the scrap
+ if (p->width < 64 && p->height < 64)
+ {
+ int x, y;
+ int i, j, k;
+ int texnum;
+
+ texnum = Scrap_AllocBlock (p->width, p->height, &x, &y);
+ scrap_dirty = true;
+ k = 0;
+ for (i=0 ; i<p->height ; i++)
+ for (j=0 ; j<p->width ; j++, k++)
+ scrap_texels[texnum][(y+i)*BLOCK_WIDTH + x + j] = p->data[k];
+ texnum += scrap_texnum;
+ gl->texnum = texnum;
+ gl->sl = (x+0.01)/(float)BLOCK_WIDTH;
+ gl->sh = (x+p->width-0.01)/(float)BLOCK_WIDTH;
+ gl->tl = (y+0.01)/(float)BLOCK_WIDTH;
+ gl->th = (y+p->height-0.01)/(float)BLOCK_WIDTH;
+
+ pic_count++;
+ pic_texels += p->width*p->height;
+ }
+ else
+ {
+ gl->texnum = GL_LoadPicTexture (p);
+ gl->sl = 0;
+ gl->sh = 1;
+ gl->tl = 0;
+ gl->th = 1;
+ }
+ return p;
+}
+
+
+/*
+================
+Draw_CachePic
+================
+*/
+qpic_t *Draw_CachePic (char *path)
+{
+ cachepic_t *pic;
+ int i;
+ qpic_t *dat;
+ glpic_t *gl;
+
+ for (pic=menu_cachepics, i=0 ; i<menu_numcachepics ; pic++, i++)
+ if (!strcmp (path, pic->name))
+ return &pic->pic;
+
+ if (menu_numcachepics == MAX_CACHED_PICS)
+ Sys_Error ("menu_numcachepics == MAX_CACHED_PICS");
+ menu_numcachepics++;
+ strcpy (pic->name, path);
+
+//
+// load the pic from disk
+//
+ dat = (qpic_t *)COM_LoadTempFile (path);
+ if (!dat)
+ Sys_Error ("Draw_CachePic: failed to load %s", path);
+ SwapPic (dat);
+
+ // HACK HACK HACK --- we need to keep the bytes for
+ // the translatable player picture just for the menu
+ // configuration dialog
+ if (!strcmp (path, "gfx/menuplyr.lmp"))
+ memcpy (menuplyr_pixels, dat->data, dat->width*dat->height);
+
+ pic->pic.width = dat->width;
+ pic->pic.height = dat->height;
+
+ gl = (glpic_t *)pic->pic.data;
+ gl->texnum = GL_LoadPicTexture (dat);
+ gl->sl = 0;
+ gl->sh = 1;
+ gl->tl = 0;
+ gl->th = 1;
+
+ return &pic->pic;
+}
+
+
+void Draw_CharToConback (int num, byte *dest)
+{
+ int row, col;
+ byte *source;
+ int drawline;
+ int x;
+
+ row = num>>4;
+ col = num&15;
+ source = draw_chars + (row<<10) + (col<<3);
+
+ drawline = 8;
+
+ while (drawline--)
+ {
+ for (x=0 ; x<8 ; x++)
+ if (source[x] != 255)
+ dest[x] = 0x60 + source[x];
+ source += 128;
+ dest += 320;
+ }
+
+}
+
+typedef struct
+{
+ char *name;
+ int minimize, maximize;
+} glmode_t;
+
+glmode_t modes[] = {
+ {"GL_NEAREST", GL_NEAREST, GL_NEAREST},
+ {"GL_LINEAR", GL_LINEAR, GL_LINEAR},
+ {"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST},
+ {"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR},
+ {"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST},
+ {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR}
+};
+
+/*
+===============
+Draw_TextureMode_f
+===============
+*/
+void Draw_TextureMode_f (void)
+{
+ int i;
+ gltexture_t *glt;
+
+ if (Cmd_Argc() == 1)
+ {
+ for (i=0 ; i< 6 ; i++)
+ if (gl_filter_min == modes[i].minimize)
+ {
+ Con_Printf ("%s\n", modes[i].name);
+ return;
+ }
+ Con_Printf ("current filter is unknown???\n");
+ return;
+ }
+
+ for (i=0 ; i< 6 ; i++)
+ {
+ if (!Q_strcasecmp (modes[i].name, Cmd_Argv(1) ) )
+ break;
+ }
+ if (i == 6)
+ {
+ Con_Printf ("bad filter name\n");
+ return;
+ }
+
+ gl_filter_min = modes[i].minimize;
+ gl_filter_max = modes[i].maximize;
+
+ // change all the existing mipmap texture objects
+ for (i=0, glt=gltextures ; i<numgltextures ; i++, glt++)
+ {
+ if (glt->mipmap)
+ {
+ GL_Bind (glt->texnum);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
+ }
+ }
+}
+
+/*
+===============
+Draw_Init
+===============
+*/
+void Draw_Init (void)
+{
+ int i;
+ qpic_t *cb;
+ byte *dest;
+ int x;
+ char ver[40];
+ glpic_t *gl;
+ int start;
+ byte *ncdata;
+
+ Cvar_RegisterVariable (&gl_nobind);
+ Cvar_RegisterVariable (&gl_max_size);
+ Cvar_RegisterVariable (&gl_picmip);
+
+ // 3dfx can only handle 256 wide textures
+ if (!Q_strncasecmp ((char *)gl_renderer, "3dfx",4) ||
+ !Q_strncasecmp ((char *)gl_renderer, "Mesa",4))
+ Cvar_Set ("gl_max_size", "256");
+
+ Cmd_AddCommand ("gl_texturemode", &Draw_TextureMode_f);
+
+ // load the console background and the charset
+ // by hand, because we need to write the version
+ // string into the background before turning
+ // it into a texture
+ draw_chars = W_GetLumpName ("conchars");
+ for (i=0 ; i<256*64 ; i++)
+ if (draw_chars[i] == 0)
+ draw_chars[i] = 255; // proper transparent color
+
+ // now turn them into textures
+ char_texture = GL_LoadTexture ("charset", 128, 128, draw_chars, false, true);
+// Draw_CrosshairAdjust();
+ cs_texture = GL_LoadTexture ("crosshair", 8, 8, cs_data, false, true);
+
+ start = Hunk_LowMark ();
+
+ cb = (qpic_t *)COM_LoadHunkFile ("gfx/conback.lmp");
+ if (!cb)
+ Sys_Error ("Couldn't load gfx/conback.lmp");
+ SwapPic (cb);
+
+ sprintf (ver, "%4.2f", VERSION);
+ dest = cb->data + 320 + 320*186 - 11 - 8*strlen(ver);
+ for (x=0 ; x<strlen(ver) ; x++)
+ Draw_CharToConback (ver[x], dest+(x<<3));
+
+#if 0
+ conback->width = vid.conwidth;
+ conback->height = vid.conheight;
+
+ // scale console to vid size
+ dest = ncdata = Hunk_AllocName(vid.conwidth * vid.conheight, "conback");
+
+ for (y=0 ; y<vid.conheight ; y++, dest += vid.conwidth)
+ {
+ src = cb->data + cb->width * (y*cb->height/vid.conheight);
+ if (vid.conwidth == cb->width)
+ memcpy (dest, src, vid.conwidth);
+ else
+ {
+ f = 0;
+ fstep = cb->width*0x10000/vid.conwidth;
+ for (x=0 ; x<vid.conwidth ; x+=4)
+ {
+ dest[x] = src[f>>16];
+ f += fstep;
+ dest[x+1] = src[f>>16];
+ f += fstep;
+ dest[x+2] = src[f>>16];
+ f += fstep;
+ dest[x+3] = src[f>>16];
+ f += fstep;
+ }
+ }
+ }
+#else
+ conback->width = cb->width;
+ conback->height = cb->height;
+ ncdata = cb->data;
+#endif
+
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+ gl = (glpic_t *)conback->data;
+ gl->texnum = GL_LoadTexture ("conback", conback->width, conback->height, ncdata, false, false);
+ gl->sl = 0;
+ gl->sh = 1;
+ gl->tl = 0;
+ gl->th = 1;
+ conback->width = vid.conwidth;
+ conback->height = vid.conheight;
+
+ // free loaded console
+ Hunk_FreeToLowMark (start);
+
+ // save a texture slot for translated picture
+ translate_texture = texture_extension_number++;
+
+ // save slots for scraps
+ scrap_texnum = texture_extension_number;
+ texture_extension_number += MAX_SCRAPS;
+
+ //
+ // get the other pics we need
+ //
+ draw_disc = Draw_PicFromWad ("disc");
+ draw_backtile = Draw_PicFromWad ("backtile");
+}
+
+
+
+/*
+================
+Draw_Character
+
+Draws one 8*8 graphics character with 0 being transparent.
+It can be clipped to the top of the screen to allow the console to be
+smoothly scrolled off.
+================
+*/
+void Draw_Character (int x, int y, int num)
+{
+ int row, col;
+ float frow, fcol, size;
+
+ if (num == 32)
+ return; // space
+
+ num &= 255;
+
+ if (y <= -8)
+ return; // totally off screen
+
+ row = num>>4;
+ col = num&15;
+
+ frow = row*0.0625;
+ fcol = col*0.0625;
+ size = 0.0625;
+
+ GL_Bind (char_texture);
+
+ glBegin (GL_QUADS);
+ glTexCoord2f (fcol, frow);
+ glVertex2f (x, y);
+ glTexCoord2f (fcol + size, frow);
+ glVertex2f (x+8, y);
+ glTexCoord2f (fcol + size, frow + size);
+ glVertex2f (x+8, y+8);
+ glTexCoord2f (fcol, frow + size);
+ glVertex2f (x, y+8);
+ glEnd ();
+}
+
+/*
+================
+Draw_String
+================
+*/
+void Draw_String (int x, int y, char *str)
+{
+ while (*str)
+ {
+ Draw_Character (x, y, *str);
+ str++;
+ x += 8;
+ }
+}
+
+/*
+================
+Draw_Alt_String
+================
+*/
+void Draw_Alt_String (int x, int y, char *str)
+{
+ while (*str)
+ {
+ Draw_Character (x, y, (*str) | 0x80);
+ str++;
+ x += 8;
+ }
+}
+
+void Draw_Crosshair(void)
+{
+ int x, y;
+ extern vrect_t scr_vrect;
+ unsigned char *pColor;
+
+ if (crosshair.value == 2) {
+ x = scr_vrect.x + scr_vrect.width/2 - 3 + cl_crossx.value;
+ y = scr_vrect.y + scr_vrect.height/2 - 3 + cl_crossy.value;
+
+ glTexEnvf ( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
+ pColor = (unsigned char *) &d_8to24table[(byte) crosshaircolor.value];
+ glColor4ubv ( pColor );
+ GL_Bind (cs_texture);
+
+ glBegin (GL_QUADS);
+ glTexCoord2f (0, 0);
+ glVertex2f (x - 4, y - 4);
+ glTexCoord2f (1, 0);
+ glVertex2f (x+12, y-4);
+ glTexCoord2f (1, 1);
+ glVertex2f (x+12, y+12);
+ glTexCoord2f (0, 1);
+ glVertex2f (x - 4, y+12);
+ glEnd ();
+
+ glTexEnvf ( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
+ } else if (crosshair.value)
+ Draw_Character (scr_vrect.x + scr_vrect.width/2-4 + cl_crossx.value,
+ scr_vrect.y + scr_vrect.height/2-4 + cl_crossy.value,
+ '+');
+}
+
+
+/*
+================
+Draw_DebugChar
+
+Draws a single character directly to the upper right corner of the screen.
+This is for debugging lockups by drawing different chars in different parts
+of the code.
+================
+*/
+void Draw_DebugChar (char num)
+{
+}
+
+/*
+=============
+Draw_Pic
+=============
+*/
+void Draw_Pic (int x, int y, qpic_t *pic)
+{
+ glpic_t *gl;
+
+ if (scrap_dirty)
+ Scrap_Upload ();
+ gl = (glpic_t *)pic->data;
+ glColor4f (1,1,1,1);
+ GL_Bind (gl->texnum);
+ glBegin (GL_QUADS);
+ glTexCoord2f (gl->sl, gl->tl);
+ glVertex2f (x, y);
+ glTexCoord2f (gl->sh, gl->tl);
+ glVertex2f (x+pic->width, y);
+ glTexCoord2f (gl->sh, gl->th);
+ glVertex2f (x+pic->width, y+pic->height);
+ glTexCoord2f (gl->sl, gl->th);
+ glVertex2f (x, y+pic->height);
+ glEnd ();
+}
+
+/*
+=============
+Draw_AlphaPic
+=============
+*/
+void Draw_AlphaPic (int x, int y, qpic_t *pic, float alpha)
+{
+ glpic_t *gl;
+
+ if (scrap_dirty)
+ Scrap_Upload ();
+ gl = (glpic_t *)pic->data;
+ glDisable(GL_ALPHA_TEST);
+ glEnable (GL_BLEND);
+// glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glCullFace(GL_FRONT);
+ glColor4f (1,1,1,alpha);
+ GL_Bind (gl->texnum);
+ glBegin (GL_QUADS);
+ glTexCoord2f (gl->sl, gl->tl);
+ glVertex2f (x, y);
+ glTexCoord2f (gl->sh, gl->tl);
+ glVertex2f (x+pic->width, y);
+ glTexCoord2f (gl->sh, gl->th);
+ glVertex2f (x+pic->width, y+pic->height);
+ glTexCoord2f (gl->sl, gl->th);
+ glVertex2f (x, y+pic->height);
+ glEnd ();
+ glColor4f (1,1,1,1);
+ glEnable(GL_ALPHA_TEST);
+ glDisable (GL_BLEND);
+}
+
+void Draw_SubPic(int x, int y, qpic_t *pic, int srcx, int srcy, int width, int height)
+{
+ glpic_t *gl;
+ float newsl, newtl, newsh, newth;
+ float oldglwidth, oldglheight;
+
+ if (scrap_dirty)
+ Scrap_Upload ();
+ gl = (glpic_t *)pic->data;
+
+ oldglwidth = gl->sh - gl->sl;
+ oldglheight = gl->th - gl->tl;
+
+ newsl = gl->sl + (srcx*oldglwidth)/pic->width;
+ newsh = newsl + (width*oldglwidth)/pic->width;
+
+ newtl = gl->tl + (srcy*oldglheight)/pic->height;
+ newth = newtl + (height*oldglheight)/pic->height;
+
+ glColor4f (1,1,1,1);
+ GL_Bind (gl->texnum);
+ glBegin (GL_QUADS);
+ glTexCoord2f (newsl, newtl);
+ glVertex2f (x, y);
+ glTexCoord2f (newsh, newtl);
+ glVertex2f (x+width, y);
+ glTexCoord2f (newsh, newth);
+ glVertex2f (x+width, y+height);
+ glTexCoord2f (newsl, newth);
+ glVertex2f (x, y+height);
+ glEnd ();
+}
+
+/*
+=============
+Draw_TransPic
+=============
+*/
+void Draw_TransPic (int x, int y, qpic_t *pic)
+{
+
+ if (x < 0 || (unsigned)(x + pic->width) > vid.width || y < 0 ||
+ (unsigned)(y + pic->height) > vid.height)
+ {
+ Sys_Error ("Draw_TransPic: bad coordinates");
+ }
+
+ Draw_Pic (x, y, pic);
+}
+
+
+/*
+=============
+Draw_TransPicTranslate
+
+Only used for the player color selection menu
+=============
+*/
+void Draw_TransPicTranslate (int x, int y, qpic_t *pic, byte *translation)
+{
+ int v, u, c;
+ unsigned trans[64*64], *dest;
+ byte *src;
+ int p;
+
+ GL_Bind (translate_texture);
+
+ c = pic->width * pic->height;
+
+ dest = trans;
+ for (v=0 ; v<64 ; v++, dest += 64)
+ {
+ src = &menuplyr_pixels[ ((v*pic->height)>>6) *pic->width];
+ for (u=0 ; u<64 ; u++)
+ {
+ p = src[(u*pic->width)>>6];
+ if (p == 255)
+ dest[u] = p;
+ else
+ dest[u] = d_8to24table[translation[p]];
+ }
+ }
+
+ glTexImage2D (GL_TEXTURE_2D, 0, gl_alpha_format, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, trans);
+
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+ glColor3f (1,1,1);
+ glBegin (GL_QUADS);
+ glTexCoord2f (0, 0);
+ glVertex2f (x, y);
+ glTexCoord2f (1, 0);
+ glVertex2f (x+pic->width, y);
+ glTexCoord2f (1, 1);
+ glVertex2f (x+pic->width, y+pic->height);
+ glTexCoord2f (0, 1);
+ glVertex2f (x, y+pic->height);
+ glEnd ();
+}
+
+
+/*
+================
+Draw_ConsoleBackground
+
+================
+*/
+void Draw_ConsoleBackground (int lines)
+{
+ char ver[80];
+ int x, i;
+ int y;
+
+ y = (vid.height * 3) >> 2;
+ if (lines > y)
+ Draw_Pic(0, lines-vid.height, conback);
+ else
+ Draw_AlphaPic (0, lines - vid.height, conback, (float)(1.2 * lines)/y);
+
+ // hack the version number directly into the pic
+// y = lines-186;
+ y = lines-14;
+ if (!cls.download) {
+#ifdef __linux__
+ sprintf (ver, "LinuxGL (%4.2f) QuakeWorld", LINUX_VERSION);
+#else
+ sprintf (ver, "GL (%4.2f) QuakeWorld", GLQUAKE_VERSION);
+#endif
+ x = vid.conwidth - (strlen(ver)*8 + 11) - (vid.conwidth*8/320)*7;
+ for (i=0 ; i<strlen(ver) ; i++)
+ Draw_Character (x + i * 8, y, ver[i] | 0x80);
+ }
+}
+
+
+/*
+=============
+Draw_TileClear
+
+This repeats a 64*64 tile graphic to fill the screen around a sized down
+refresh window.
+=============
+*/
+void Draw_TileClear (int x, int y, int w, int h)
+{
+ glColor3f (1,1,1);
+ GL_Bind (*(int *)draw_backtile->data);
+ glBegin (GL_QUADS);
+ glTexCoord2f (x/64.0, y/64.0);
+ glVertex2f (x, y);
+ glTexCoord2f ( (x+w)/64.0, y/64.0);
+ glVertex2f (x+w, y);
+ glTexCoord2f ( (x+w)/64.0, (y+h)/64.0);
+ glVertex2f (x+w, y+h);
+ glTexCoord2f ( x/64.0, (y+h)/64.0 );
+ glVertex2f (x, y+h);
+ glEnd ();
+}
+
+
+/*
+=============
+Draw_Fill
+
+Fills a box of pixels with a single color
+=============
+*/
+void Draw_Fill (int x, int y, int w, int h, int c)
+{
+ glDisable (GL_TEXTURE_2D);
+ glColor3f (host_basepal[c*3]/255.0,
+ host_basepal[c*3+1]/255.0,
+ host_basepal[c*3+2]/255.0);
+
+ glBegin (GL_QUADS);
+
+ glVertex2f (x,y);
+ glVertex2f (x+w, y);
+ glVertex2f (x+w, y+h);
+ glVertex2f (x, y+h);
+
+ glEnd ();
+ glColor3f (1,1,1);
+ glEnable (GL_TEXTURE_2D);
+}
+//=============================================================================
+
+/*
+================
+Draw_FadeScreen
+
+================
+*/
+void Draw_FadeScreen (void)
+{
+ glEnable (GL_BLEND);
+ glDisable (GL_TEXTURE_2D);
+ glColor4f (0, 0, 0, 0.8);
+ glBegin (GL_QUADS);
+
+ glVertex2f (0,0);
+ glVertex2f (vid.width, 0);
+ glVertex2f (vid.width, vid.height);
+ glVertex2f (0, vid.height);
+
+ glEnd ();
+ glColor4f (1,1,1,1);
+ glEnable (GL_TEXTURE_2D);
+ glDisable (GL_BLEND);
+
+ Sbar_Changed();
+}
+
+//=============================================================================
+
+/*
+================
+Draw_BeginDisc
+
+Draws the little blue disc in the corner of the screen.
+Call before beginning any disc IO.
+================
+*/
+void Draw_BeginDisc (void)
+{
+ if (!draw_disc)
+ return;
+ glDrawBuffer (GL_FRONT);
+ Draw_Pic (vid.width - 24, 0, draw_disc);
+ glDrawBuffer (GL_BACK);
+}
+
+
+/*
+================
+Draw_EndDisc
+
+Erases the disc icon.
+Call after completing any disc IO
+================
+*/
+void Draw_EndDisc (void)
+{
+}
+
+/*
+================
+GL_Set2D
+
+Setup as if the screen was 320*200
+================
+*/
+void GL_Set2D (void)
+{
+ glViewport (glx, gly, glwidth, glheight);
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity ();
+ glOrtho (0, vid.width, vid.height, 0, -99999, 99999);
+
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity ();
+
+ glDisable (GL_DEPTH_TEST);
+ glDisable (GL_CULL_FACE);
+ glDisable (GL_BLEND);
+ glEnable (GL_ALPHA_TEST);
+// glDisable (GL_ALPHA_TEST);
+
+ glColor4f (1,1,1,1);
+}
+
+//====================================================================
+
+/*
+================
+GL_FindTexture
+================
+*/
+int GL_FindTexture (char *identifier)
+{
+ int i;
+ gltexture_t *glt;
+
+ for (i=0, glt=gltextures ; i<numgltextures ; i++, glt++)
+ {
+ if (!strcmp (identifier, glt->identifier))
+ return gltextures[i].texnum;
+ }
+
+ return -1;
+}
+
+/*
+================
+GL_ResampleTexture
+================
+*/
+void GL_ResampleTexture (unsigned *in, int inwidth, int inheight, unsigned *out, int outwidth, int outheight)
+{
+ int i, j;
+ unsigned *inrow;
+ unsigned frac, fracstep;
+
+ fracstep = inwidth*0x10000/outwidth;
+ for (i=0 ; i<outheight ; i++, out += outwidth)
+ {
+ inrow = in + inwidth*(i*inheight/outheight);
+ frac = fracstep >> 1;
+ for (j=0 ; j<outwidth ; j+=4)
+ {
+ out[j] = inrow[frac>>16];
+ frac += fracstep;
+ out[j+1] = inrow[frac>>16];
+ frac += fracstep;
+ out[j+2] = inrow[frac>>16];
+ frac += fracstep;
+ out[j+3] = inrow[frac>>16];
+ frac += fracstep;
+ }
+ }
+}
+
+/*
+================
+GL_Resample8BitTexture -- JACK
+================
+*/
+void GL_Resample8BitTexture (unsigned char *in, int inwidth, int inheight, unsigned char *out, int outwidth, int outheight)
+{
+ int i, j;
+ unsigned char *inrow;
+ unsigned frac, fracstep;
+
+ fracstep = inwidth*0x10000/outwidth;
+ for (i=0 ; i<outheight ; i++, out += outwidth)
+ {
+ inrow = in + inwidth*(i*inheight/outheight);
+ frac = fracstep >> 1;
+ for (j=0 ; j<outwidth ; j+=4)
+ {
+ out[j] = inrow[frac>>16];
+ frac += fracstep;
+ out[j+1] = inrow[frac>>16];
+ frac += fracstep;
+ out[j+2] = inrow[frac>>16];
+ frac += fracstep;
+ out[j+3] = inrow[frac>>16];
+ frac += fracstep;
+ }
+ }
+}
+
+/*
+================
+GL_MipMap
+
+Operates in place, quartering the size of the texture
+================
+*/
+void GL_MipMap (byte *in, int width, int height)
+{
+ int i, j;
+ byte *out;
+
+ width <<=2;
+ height >>= 1;
+ out = in;
+ for (i=0 ; i<height ; i++, in+=width)
+ {
+ for (j=0 ; j<width ; j+=8, out+=4, in+=8)
+ {
+ out[0] = (in[0] + in[4] + in[width+0] + in[width+4])>>2;
+ out[1] = (in[1] + in[5] + in[width+1] + in[width+5])>>2;
+ out[2] = (in[2] + in[6] + in[width+2] + in[width+6])>>2;
+ out[3] = (in[3] + in[7] + in[width+3] + in[width+7])>>2;
+ }
+ }
+}
+
+/*
+================
+GL_MipMap8Bit
+
+Mipping for 8 bit textures
+================
+*/
+void GL_MipMap8Bit (byte *in, int width, int height)
+{
+ int i, j;
+ byte *out;
+ unsigned short r,g,b;
+ byte *at1, *at2, *at3, *at4;
+
+ height >>= 1;
+ out = in;
+ for (i=0 ; i<height ; i++, in+=width)
+ for (j=0 ; j<width ; j+=2, out+=1, in+=2)
+ {
+ at1 = (byte *) &d_8to24table[in[0]];
+ at2 = (byte *) &d_8to24table[in[1]];
+ at3 = (byte *) &d_8to24table[in[width+0]];
+ at4 = (byte *) &d_8to24table[in[width+1]];
+
+ r = (at1[0]+at2[0]+at3[0]+at4[0]); r>>=5;
+ g = (at1[1]+at2[1]+at3[1]+at4[1]); g>>=5;
+ b = (at1[2]+at2[2]+at3[2]+at4[2]); b>>=5;
+
+ out[0] = d_15to8table[(r<<0) + (g<<5) + (b<<10)];
+ }
+}
+
+/*
+===============
+GL_Upload32
+===============
+*/
+void GL_Upload32 (unsigned *data, int width, int height, qboolean mipmap, qboolean alpha)
+{
+ int samples;
+static unsigned scaled[1024*512]; // [512*256];
+ int scaled_width, scaled_height;
+
+ for (scaled_width = 1 ; scaled_width < width ; scaled_width<<=1)
+ ;
+ for (scaled_height = 1 ; scaled_height < height ; scaled_height<<=1)
+ ;
+
+ scaled_width >>= (int)gl_picmip.value;
+ scaled_height >>= (int)gl_picmip.value;
+
+ if (scaled_width > gl_max_size.value)
+ scaled_width = gl_max_size.value;
+ if (scaled_height > gl_max_size.value)
+ scaled_height = gl_max_size.value;
+
+ if (scaled_width * scaled_height > sizeof(scaled)/4)
+ Sys_Error ("GL_LoadTexture: too big");
+
+ samples = alpha ? gl_alpha_format : gl_solid_format;
+
+#if 0
+ if (mipmap)
+ gluBuild2DMipmaps (GL_TEXTURE_2D, samples, width, height, GL_RGBA, GL_UNSIGNED_BYTE, trans);
+ else if (scaled_width == width && scaled_height == height)
+ glTexImage2D (GL_TEXTURE_2D, 0, samples, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, trans);
+ else
+ {
+ gluScaleImage (GL_RGBA, width, height, GL_UNSIGNED_BYTE, trans,
+ scaled_width, scaled_height, GL_UNSIGNED_BYTE, scaled);
+ glTexImage2D (GL_TEXTURE_2D, 0, samples, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaled);
+ }
+#else
+texels += scaled_width * scaled_height;
+
+ if (scaled_width == width && scaled_height == height)
+ {
+ if (!mipmap)
+ {
+ glTexImage2D (GL_TEXTURE_2D, 0, samples, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
+ goto done;
+ }
+ memcpy (scaled, data, width*height*4);
+ }
+ else
+ GL_ResampleTexture (data, width, height, scaled, scaled_width, scaled_height);
+
+ glTexImage2D (GL_TEXTURE_2D, 0, samples, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaled);
+ if (mipmap)
+ {
+ int miplevel;
+
+ miplevel = 0;
+ while (scaled_width > 1 || scaled_height > 1)
+ {
+ GL_MipMap ((byte *)scaled, scaled_width, scaled_height);
+ scaled_width >>= 1;
+ scaled_height >>= 1;
+ if (scaled_width < 1)
+ scaled_width = 1;
+ if (scaled_height < 1)
+ scaled_height = 1;
+ miplevel++;
+ glTexImage2D (GL_TEXTURE_2D, miplevel, samples, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaled);
+ }
+ }
+done: ;
+#endif
+
+
+ if (mipmap)
+ {
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
+ }
+ else
+ {
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_max);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
+ }
+}
+
+void GL_Upload8_EXT (byte *data, int width, int height, qboolean mipmap, qboolean alpha)
+{
+ int i, s;
+ qboolean noalpha;
+ int samples;
+ static unsigned char scaled[1024*512]; // [512*256];
+ int scaled_width, scaled_height;
+
+ s = width*height;
+ // if there are no transparent pixels, make it a 3 component
+ // texture even if it was specified as otherwise
+ if (alpha)
+ {
+ noalpha = true;
+ for (i=0 ; i<s ; i++)
+ {
+ if (data[i] == 255)
+ noalpha = false;
+ }
+
+ if (alpha && noalpha)
+ alpha = false;
+ }
+ for (scaled_width = 1 ; scaled_width < width ; scaled_width<<=1)
+ ;
+ for (scaled_height = 1 ; scaled_height < height ; scaled_height<<=1)
+ ;
+
+ scaled_width >>= (int)gl_picmip.value;
+ scaled_height >>= (int)gl_picmip.value;
+
+ if (scaled_width > gl_max_size.value)
+ scaled_width = gl_max_size.value;
+ if (scaled_height > gl_max_size.value)
+ scaled_height = gl_max_size.value;
+
+ if (scaled_width * scaled_height > sizeof(scaled))
+ Sys_Error ("GL_LoadTexture: too big");
+
+ samples = 1; // alpha ? gl_alpha_format : gl_solid_format;
+
+ texels += scaled_width * scaled_height;
+
+ if (scaled_width == width && scaled_height == height)
+ {
+ if (!mipmap)
+ {
+ glTexImage2D (GL_TEXTURE_2D, 0, GL_COLOR_INDEX8_EXT, scaled_width, scaled_height, 0, GL_COLOR_INDEX , GL_UNSIGNED_BYTE, data);
+ goto done;
+ }
+ memcpy (scaled, data, width*height);
+ }
+ else
+ GL_Resample8BitTexture (data, width, height, scaled, scaled_width, scaled_height);
+
+ glTexImage2D (GL_TEXTURE_2D, 0, GL_COLOR_INDEX8_EXT, scaled_width, scaled_height, 0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, scaled);
+ if (mipmap)
+ {
+ int miplevel;
+
+ miplevel = 0;
+ while (scaled_width > 1 || scaled_height > 1)
+ {
+ GL_MipMap8Bit ((byte *)scaled, scaled_width, scaled_height);
+ scaled_width >>= 1;
+ scaled_height >>= 1;
+ if (scaled_width < 1)
+ scaled_width = 1;
+ if (scaled_height < 1)
+ scaled_height = 1;
+ miplevel++;
+ glTexImage2D (GL_TEXTURE_2D, miplevel, GL_COLOR_INDEX8_EXT, scaled_width, scaled_height, 0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, scaled);
+ }
+ }
+done: ;
+
+ if (mipmap)
+ {
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
+ }
+ else
+ {
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_max);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
+ }
+}
+
+extern qboolean VID_Is8bit();
+
+/*
+===============
+GL_Upload8
+===============
+*/
+void GL_Upload8 (byte *data, int width, int height, qboolean mipmap, qboolean alpha)
+{
+static unsigned trans[640*480]; // FIXME, temporary
+ int i, s;
+ qboolean noalpha;
+ int p;
+
+ s = width*height;
+ // if there are no transparent pixels, make it a 3 component
+ // texture even if it was specified as otherwise
+ if (alpha)
+ {
+ noalpha = true;
+ for (i=0 ; i<s ; i++)
+ {
+ p = data[i];
+ if (p == 255)
+ noalpha = false;
+ trans[i] = d_8to24table[p];
+ }
+
+ if (alpha && noalpha)
+ alpha = false;
+ }
+ else
+ {
+ if (s&3)
+ Sys_Error ("GL_Upload8: s&3");
+ for (i=0 ; i<s ; i+=4)
+ {
+ trans[i] = d_8to24table[data[i]];
+ trans[i+1] = d_8to24table[data[i+1]];
+ trans[i+2] = d_8to24table[data[i+2]];
+ trans[i+3] = d_8to24table[data[i+3]];
+ }
+ }
+
+ if (VID_Is8bit() && !alpha && (data!=scrap_texels[0])) {
+ GL_Upload8_EXT (data, width, height, mipmap, alpha);
+ return;
+ }
+
+ GL_Upload32 (trans, width, height, mipmap, alpha);
+}
+
+/*
+================
+GL_LoadTexture
+================
+*/
+int GL_LoadTexture (char *identifier, int width, int height, byte *data, qboolean mipmap, qboolean alpha)
+{
+ int i;
+ gltexture_t *glt;
+
+ // see if the texture is allready present
+ if (identifier[0])
+ {
+ for (i=0, glt=gltextures ; i<numgltextures ; i++, glt++)
+ {
+ if (!strcmp (identifier, glt->identifier))
+ {
+ if (width != glt->width || height != glt->height)
+ Sys_Error ("GL_LoadTexture: cache mismatch");
+ return gltextures[i].texnum;
+ }
+ }
+ }
+ else
+ glt = &gltextures[numgltextures];
+ numgltextures++;
+
+ strcpy (glt->identifier, identifier);
+ glt->texnum = texture_extension_number;
+ glt->width = width;
+ glt->height = height;
+ glt->mipmap = mipmap;
+
+ GL_Bind(texture_extension_number );
+
+ GL_Upload8 (data, width, height, mipmap, alpha);
+
+ texture_extension_number++;
+
+ return texture_extension_number-1;
+}
+
+/*
+================
+GL_LoadPicTexture
+================
+*/
+int GL_LoadPicTexture (qpic_t *pic)
+{
+ return GL_LoadTexture ("", pic->width, pic->height, pic->data, false, true);
+}
+
+/****************************************/
+
+static GLenum oldtarget = TEXTURE0_SGIS;
+
+void GL_SelectTexture (GLenum target)
+{
+ if (!gl_mtexable)
+ return;
+#ifndef __linux__ // no multitexture under Linux yet
+ qglSelectTextureSGIS(target);
+#endif
+ if (target == oldtarget)
+ return;
+ cnttextures[oldtarget-TEXTURE0_SGIS] = currenttexture;
+ currenttexture = cnttextures[target-TEXTURE0_SGIS];
+ oldtarget = target;
+}