]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - gl_draw.c
bmodel shadow volumes
[xonotic/darkplaces.git] / gl_draw.c
index 61aaf7a1ac260c1fdd34b426e00dc1859cd1487a..717f0b8983874b90ff0cb43cb08c519e2714737d 100644 (file)
--- a/gl_draw.c
+++ b/gl_draw.c
@@ -8,7 +8,7 @@ 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.  
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 See the GNU General Public License for more details.
 
@@ -18,1396 +18,563 @@ 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"
 
-#define GL_COLOR_INDEX8_EXT     0x80E5
-
-extern unsigned char d_15to8table[65536];
-
-cvar_t         qsg_version = {"qsg_version", "1"};
-cvar_t         gl_max_size = {"gl_max_size", "1024"};
-cvar_t         gl_picmip = {"gl_picmip", "0"};
-cvar_t         gl_conalpha = {"gl_conalpha", "1"};
-cvar_t         gl_lerpimages = {"gl_lerpimages", "1"};
-
-byte           *draw_chars;                            // 8*8 graphic characters
-qpic_t         *draw_disc;
-
-int                    translate_texture;
-int                    char_texture;
-
-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_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;
-// LordHavoc: 32bit textures
-       int             bytesperpixel;
-// LordHavoc: CRC to identify cache mismatchs
-       int             crc;
-       int             lerped; // whether this texture was uploaded with or without interpolation
-} gltexture_t;
-
-#define        MAX_GLTEXTURES  4096
-gltexture_t    gltextures[MAX_GLTEXTURES];
-int                    numgltextures;
+cvar_t scr_conalpha = {CVAR_SAVE, "scr_conalpha", "1"};
 
-/*
-=============================================================================
-
-  scrap allocation
+static rtexture_t *char_texture;
 
-  Allocate all the little status bar obejcts into a single texture
-  to crutch up stupid hardware / drivers
-
-=============================================================================
-*/
-
-#define        MAX_SCRAPS              2
-#define        BLOCK_WIDTH             256
-#define        BLOCK_HEIGHT    256
+//=============================================================================
+/* Support Routines */
 
-int                    scrap_allocated[MAX_SCRAPS][BLOCK_WIDTH];
-byte           scrap_texels[MAX_SCRAPS][BLOCK_WIDTH*BLOCK_HEIGHT*4];
-qboolean       scrap_dirty;
-int                    scrap_texnum;
+#define MAX_CACHED_PICS 256
+#define CACHEPICHASHSIZE 256
+static cachepic_t *cachepichash[CACHEPICHASHSIZE];
+static cachepic_t cachepics[MAX_CACHED_PICS];
+static int numcachepics;
+
+static rtexturepool_t *drawtexturepool;
+
+static qbyte pointerimage[256] =
+{
+       "333333332......."
+       "26777761........"
+       "2655541........."
+       "265541.........."
+       "2654561........."
+       "26414561........"
+       "251.14561......."
+       "21...14561......"
+       "1.....141......."
+       ".......1........"
+       "................"
+       "................"
+       "................"
+       "................"
+       "................"
+       "................"
+};
 
-// returns a texture number and the position inside it
-int Scrap_AllocBlock (int w, int h, int *x, int *y)
+static rtexture_t *draw_generatemousepointer(void)
 {
-       int             i, j;
-       int             best, best2;
-       int             texnum;
-
-       for (texnum=0 ; texnum<MAX_SCRAPS ; texnum++)
+       int i;
+       qbyte buffer[256][4];
+       for (i = 0;i < 256;i++)
        {
-               best = BLOCK_HEIGHT;
-
-               for (i=0 ; i<BLOCK_WIDTH-w ; i++)
+               if (pointerimage[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;
-                       }
+                       buffer[i][0] = 0;
+                       buffer[i][1] = 0;
+                       buffer[i][2] = 0;
+                       buffer[i][3] = 0;
+               }
+               else
+               {
+                       buffer[i][0] = (pointerimage[i] - '0') * 16;
+                       buffer[i][1] = (pointerimage[i] - '0') * 16;
+                       buffer[i][2] = (pointerimage[i] - '0') * 16;
+                       buffer[i][3] = 255;
                }
-
-               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");
-}
-
-int    scrap_uploads;
-
-void Scrap_Upload (void)
-{
-       int             texnum;
-
-       scrap_uploads++;
-
-       for (texnum=0 ; texnum<MAX_SCRAPS ; texnum++)
-       {
-               glBindTexture(GL_TEXTURE_2D, scrap_texnum + texnum);
-               GL_Upload8 (scrap_texels[texnum], 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;
-
-int GL_LoadPicTexture (qpic_t *pic);
+       return R_LoadTexture(drawtexturepool, "mousepointer", 16, 16, &buffer[0][0], TEXTYPE_RGBA, TEXF_ALPHA | TEXF_PRECACHE);
+}
+
+// must match NUMCROSSHAIRS in r_crosshairs.c
+#define NUMCROSSHAIRS 5
+
+static qbyte *crosshairtexdata[NUMCROSSHAIRS] =
+{
+       "................"
+       "................"
+       "................"
+       "...33......33..."
+       "...355....553..."
+       "....577..775...."
+       ".....77..77....."
+       "................"
+       "................"
+       ".....77..77....."
+       "....577..775...."
+       "...355....553..."
+       "...33......33..."
+       "................"
+       "................"
+       "................"
+       ,
+       "................"
+       "................"
+       "................"
+       "...3........3..."
+       "....5......5...."
+       ".....7....7....."
+       "......7..7......"
+       "................"
+       "................"
+       "......7..7......"
+       ".....7....7....."
+       "....5......5...."
+       "...3........3..."
+       "................"
+       "................"
+       "................"
+       ,
+       "................"
+       ".......77......."
+       ".......77......."
+       "................"
+       "................"
+       ".......44......."
+       ".......44......."
+       ".77..44..44..77."
+       ".77..44..44..77."
+       ".......44......."
+       ".......44......."
+       "................"
+       ".......77......."
+       ".......77......."
+       "................"
+       "................"
+       ,
+       "................"
+       "................"
+       "................"
+       "................"
+       "................"
+       "................"
+       "................"
+       "................"
+       "........7777777."
+       "........752....."
+       "........72......"
+       "........7......."
+       "........7......."
+       "........7......."
+       "................"
+       "................"
+       ,
+       "................"
+       "................"
+       "................"
+       "................"
+       "................"
+       "........7......."
+       "................"
+       "........4......."
+       ".....7.4.4.7...."
+       "........4......."
+       "................"
+       "........7......."
+       "................"
+       "................"
+       "................"
+       "................"
+};
 
-qpic_t *Draw_PicFromWad (char *name)
+static rtexture_t *draw_generatecrosshair(int num)
 {
-       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;
-               // LordHavoc: LINEAR interpolation
-               glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-               glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-       }
-       else
+       int i;
+       char *in;
+       qbyte data[16*16][4];
+       in = crosshairtexdata[num];
+       for (i = 0;i < 16*16;i++)
        {
-               gl->texnum = GL_LoadPicTexture (p);
-               gl->sl = 0;
-               gl->sh = 1;
-               gl->tl = 0;
-               gl->th = 1;
-               // LordHavoc: LINEAR interpolation
-               glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); //NEAREST);
-               glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); //NEAREST);
+               if (in[i] == '.')
+               {
+                       data[i][0] = 255;
+                       data[i][1] = 255;
+                       data[i][2] = 255;
+                       data[i][3] = 0;
+               }
+               else
+               {
+                       data[i][0] = 255;
+                       data[i][1] = 255;
+                       data[i][2] = 255;
+                       data[i][3] = (qbyte) ((int) (in[i] - '0') * 255 / 7);
+               }
        }
-       return p;
+       return R_LoadTexture(drawtexturepool, va("crosshair%i", num), 16, 16, &data[0][0], TEXTYPE_RGBA, TEXF_ALPHA | TEXF_PRECACHE);
 }
 
-
 /*
 ================
 Draw_CachePic
 ================
 */
-qpic_t *Draw_CachePic (char *path)
+// FIXME: move this to client somehow
+cachepic_t     *Draw_CachePic (char *path)
 {
-       cachepic_t      *pic;
-       int                     i;
-       qpic_t          *dat;
-       glpic_t         *gl;
+       int i, crc, hashkey;
+       cachepic_t *pic;
+       qpic_t *p;
 
-       for (pic=menu_cachepics, i=0 ; i<menu_numcachepics ; pic++, i++)
+       crc = CRC_Block(path, strlen(path));
+       hashkey = ((crc >> 8) ^ crc) % CACHEPICHASHSIZE;
+       for (pic = cachepichash[hashkey];pic;pic = pic->chain)
                if (!strcmp (path, pic->name))
-                       return &pic->pic;
+                       return pic;
 
-       if (menu_numcachepics == MAX_CACHED_PICS)
-               Sys_Error ("menu_numcachepics == MAX_CACHED_PICS");
-       menu_numcachepics++;
+       if (numcachepics == MAX_CACHED_PICS)
+               Sys_Error ("numcachepics == MAX_CACHED_PICS");
+       pic = cachepics + (numcachepics++);
        strcpy (pic->name, path);
-
-//
-// load the pic from disk
-//
-       dat = (qpic_t *)COM_LoadTempFile (path, false);
-       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)
+       // link into list
+       pic->chain = cachepichash[hashkey];
+       cachepichash[hashkey] = pic;
+
+       // load the pic from disk
+       pic->tex = loadtextureimage(drawtexturepool, path, 0, 0, false, false, true);
+       if (pic->tex == NULL && !strncmp(path, "gfx/", 4))
+       {
+               // compatibility with older versions
+               pic->tex = loadtextureimage(drawtexturepool, path + 4, 0, 0, false, false, true);
+               // failed to find gfx/whatever.tga or similar, try the wad
+               if (pic->tex == NULL && (p = W_GetLumpName (path + 4)))
+               {
+                       if (!strcmp(path, "gfx/conchars"))
                        {
-                               Con_Printf ("%s\n", modes[i].name);
-                               return;
+                               qbyte *pix;
+                               // conchars is a raw image and with the wrong transparent color
+                               pix = (qbyte *)p;
+                               for (i = 0;i < 128 * 128;i++)
+                                       if (pix[i] == 0)
+                                               pix[i] = 255;
+                               pic->tex = R_LoadTexture (drawtexturepool, path, 128, 128, pix, TEXTYPE_QPALETTE, TEXF_ALPHA | TEXF_PRECACHE);
                        }
-               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)
-               {
-                       glBindTexture(GL_TEXTURE_2D, glt->texnum);
-                       glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
-                       glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
+                       else
+                               pic->tex = R_LoadTexture (drawtexturepool, path, p->width, p->height, p->data, TEXTYPE_QPALETTE, TEXF_ALPHA | TEXF_PRECACHE);
                }
        }
-}
-
-extern void LoadSky_f(void);
-
-extern char *QSG_EXTENSIONS;
-
-/*
-===============
-Draw_Init
-===============
-*/
-void rmain_registercvars();
-void Draw_Init (void)
-{
-       int             i;
-       qpic_t  *cb;
-       byte    *dest;
-       int             x, y;
-       char    ver[40];
-       glpic_t *gl;
-       int             start;
-
-       Cvar_RegisterVariable (&qsg_version);
-       Cvar_RegisterVariable (&gl_max_size);
-       Cvar_RegisterVariable (&gl_picmip);
-       Cvar_RegisterVariable (&gl_conalpha);
-       Cvar_RegisterVariable (&gl_lerpimages);
-
-       // 3dfx can only handle 256 wide textures
-       if (!Q_strncasecmp ((char *)gl_renderer, "3dfx",4) ||
-               strstr((char *)gl_renderer, "Glide"))
-               Cvar_Set ("gl_max_size", "256");
-
-       Cmd_AddCommand ("gl_texturemode", &Draw_TextureMode_f);
-
-       Cmd_AddCommand ("loadsky", &LoadSky_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, 1);
-
-       start = Hunk_LowMark();
-
-       cb = (qpic_t *)COM_LoadTempFile ("gfx/conback.lmp", false);
-       if (!cb)
-               Sys_Error ("Couldn't load gfx/conback.lmp");
-       SwapPic (cb);
-
-       // hack the version number directly into the pic
-#ifdef NEHAHRA
-#if defined(__linux__)
-       sprintf (ver, "(DPNehahra %.2f, Linux %2.2f, gl %.2f) %.2f", (float) DP_VERSION, (float)LINUX_VERSION, (float)GLQUAKE_VERSION, (float)VERSION);
-#else
-       sprintf (ver, "(DPNehahra %.2f, gl %.2f) %.2f", (float) DP_VERSION, (float)GLQUAKE_VERSION, (float)VERSION);
-#endif
-#else
-#if defined(__linux__)
-       sprintf (ver, "(DarkPlaces %.2f, Linux %2.2f, gl %.2f) %.2f", (float) DP_VERSION, (float)LINUX_VERSION, (float)GLQUAKE_VERSION, (float)VERSION);
-#else
-       sprintf (ver, "(DarkPlaces %.2f, gl %.2f) %.2f", (float) DP_VERSION, (float)GLQUAKE_VERSION, (float)VERSION);
-#endif
-#endif
-       dest = cb->data + 320*186 + 320 - 11 - 8*strlen(ver);
-       y = strlen(ver);
-       for (x=0 ; x<y ; x++)
-               Draw_CharToConback (ver[x], dest+(x<<3));
-
-       gl = (glpic_t *)conback->data;
-       gl->texnum = GL_LoadTexture ("conback", cb->width, cb->height, cb->data, false, false, 1);
-       gl->sl = 0;
-       gl->sh = 1;
-       gl->tl = 0;
-       gl->th = 1;
-       conback->width = vid.width;
-       conback->height = vid.height;
-
-       // 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");
-
-       rmain_registercvars();
-}
-
-
-/*
-================
-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;
-
-       glBindTexture(GL_TEXTURE_2D, char_texture);
-       // LordHavoc: NEAREST mode on text if not scaling up
-       if ((int) vid.width < glwidth)
+       if (pic->tex == NULL && !strcmp(path, "ui/mousepointer.tga"))
+               pic->tex = draw_generatemousepointer();
+       if (pic->tex == NULL && !strcmp(path, "gfx/crosshair1.tga"))
+               pic->tex = draw_generatecrosshair(0);
+       if (pic->tex == NULL && !strcmp(path, "gfx/crosshair2.tga"))
+               pic->tex = draw_generatecrosshair(1);
+       if (pic->tex == NULL && !strcmp(path, "gfx/crosshair3.tga"))
+               pic->tex = draw_generatecrosshair(2);
+       if (pic->tex == NULL && !strcmp(path, "gfx/crosshair4.tga"))
+               pic->tex = draw_generatecrosshair(3);
+       if (pic->tex == NULL && !strcmp(path, "gfx/crosshair5.tga"))
+               pic->tex = draw_generatecrosshair(4);
+       if (pic->tex == NULL)
        {
-               glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-               glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+               Con_Printf ("Draw_CachePic: failed to load %s\n", path);
+               pic->tex = r_notexture;
        }
 
-       glColor3f(1,1,1);
-       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 ();
-
-       // LordHavoc: revert to LINEAR mode
-       glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-       glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+       pic->width = R_TextureWidth(pic->tex);
+       pic->height = R_TextureHeight(pic->tex);
+       return pic;
 }
 
-/*
-================
-Draw_String
-================
-*/
-// LordHavoc: sped this up a lot, and added maxlen
-void Draw_String (int x, int y, char *str, int maxlen)
+cachepic_t *Draw_NewPic(char *picname, int width, int height, int alpha, qbyte *pixels)
 {
-       int num;
-       float frow, fcol;
-       if (y <= -8 || y >= (int) vid.height || x >= (int) vid.width || *str == 0) // completely offscreen or no text to print
-               return;
-       if (maxlen < 1)
-               maxlen = strlen(str);
-       else if (maxlen > (int) strlen(str))
-               maxlen = strlen(str);
-       glBindTexture(GL_TEXTURE_2D, char_texture);
+       int crc, hashkey;
+       cachepic_t *pic;
 
-       // LordHavoc: NEAREST mode on text if not scaling up
-       if ((int) vid.width < glwidth)
+       crc = CRC_Block(picname, strlen(picname));
+       hashkey = ((crc >> 8) ^ crc) % CACHEPICHASHSIZE;
+       for (pic = cachepichash[hashkey];pic;pic = pic->chain)
+               if (!strcmp (picname, pic->name))
+                       break;
+
+       if (pic)
        {
-               glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-               glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+               if (pic->tex && pic->width == width && pic->height == height)
+               {
+                       R_UpdateTexture(pic->tex, pixels);
+                       return pic;
+               }
        }
-
-       glColor3f(1,1,1);
-       glBegin (GL_QUADS);
-       while (maxlen-- && x < (int) vid.width) // stop rendering when out of characters or room
+       else
        {
-               if ((num = *str++) != 32) // skip spaces
+               if (pic == NULL)
                {
-                       frow = (float) ((int) num >> 4)*0.0625;
-                       fcol = (float) ((int) num & 15)*0.0625;
-                       glTexCoord2f (fcol, frow);
-                       glVertex2f (x, y);
-                       glTexCoord2f (fcol + 0.0625, frow);
-                       glVertex2f (x+8, y);
-                       glTexCoord2f (fcol + 0.0625, frow + 0.0625);
-                       glVertex2f (x+8, y+8);
-                       glTexCoord2f (fcol, frow + 0.0625);
-                       glVertex2f (x, y+8);
+                       if (numcachepics == MAX_CACHED_PICS)
+                               Sys_Error ("numcachepics == MAX_CACHED_PICS");
+                       pic = cachepics + (numcachepics++);
+                       strcpy (pic->name, picname);
+                       // link into list
+                       pic->chain = cachepichash[hashkey];
+                       cachepichash[hashkey] = pic;
                }
-               x += 8;
        }
-       glEnd ();
 
-       // LordHavoc: revert to LINEAR mode
-       glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-       glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+       pic->width = width;
+       pic->height = height;
+       if (pic->tex)
+               R_FreeTexture(pic->tex);
+       pic->tex = R_LoadTexture (drawtexturepool, picname, width, height, pixels, TEXTYPE_RGBA, alpha ? TEXF_ALPHA : 0);
+       return pic;
 }
 
-/*
-=============
-Draw_AlphaPic
-=============
-*/
-void Draw_AlphaPic (int x, int y, qpic_t *pic, float alpha)
+void Draw_FreePic(char *picname)
 {
-       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(0.8,0.8,0.8,alpha);
-       glBindTexture(GL_TEXTURE_2D, gl->texnum);
-//     glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-       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 ();
-       glColor3f(1,1,1);
-//     glEnable(GL_ALPHA_TEST);
-//     glDisable (GL_BLEND);
-}
-
-
-/*
-=============
-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;
-       glColor3f(0.8,0.8,0.8);
-       glBindTexture(GL_TEXTURE_2D, 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_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");
-
-//     glEnable(GL_BLEND);
-//     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-//     glDisable(GL_ALPHA_TEST);
-       Draw_Pic (x, y, pic);
-//     glDisable(GL_BLEND);
-}
-
-
-/*
-=============
-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;
-
-       glBindTexture(GL_TEXTURE_2D, translate_texture);
-
-       c = pic->width * pic->height;
-
-       dest = trans;
-       for (v=0 ; v<64 ; v++, dest += 64)
+       int crc;
+       int hashkey;
+       cachepic_t *pic;
+       // this doesn't really free the pic, but does free it's texture
+       crc = CRC_Block(picname, strlen(picname));
+       hashkey = ((crc >> 8) ^ crc) % CACHEPICHASHSIZE;
+       for (pic = cachepichash[hashkey];pic;pic = pic->chain)
        {
-               src = &menuplyr_pixels[ ((v*pic->height)>>6) *pic->width];
-               for (u=0 ; u<64 ; u++)
+               if (!strcmp (picname, pic->name))
                {
-                       p = src[(u*pic->width)>>6];
-                       if (p == 255)
-                               dest[u] = p;
-                       else
-                               dest[u] =  d_8to24table[translation[p]];
+                       R_FreeTexture(pic->tex);
+                       pic->width = 0;
+                       pic->height = 0;
+                       return;
                }
        }
-
-       glTexImage2D (GL_TEXTURE_2D, 0, 4, 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(0.8,0.8,0.8);
-       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)
-{
-       // LordHavoc: changed alpha
-       //int y = (vid.height >> 1);
-
-       if (lines >= (int) vid.height)
-               Draw_Pic(0, lines - vid.height, conback);
-       else
-               Draw_AlphaPic (0, lines - vid.height, conback, gl_conalpha.value*lines/vid.height);
-       //      Draw_AlphaPic (0, lines - vid.height, conback, (float)(1.2 * lines)/y);
 }
 
 /*
-=============
-Draw_Fill
-
-Fills a box of pixels with a single color
-=============
+===============
+Draw_Init
+===============
 */
-void Draw_Fill (int x, int y, int w, int h, int c)
+static void gl_draw_start(void)
 {
-       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);
+       drawtexturepool = R_AllocTexturePool();
 
-       glBegin (GL_QUADS);
+       numcachepics = 0;
+       memset(cachepichash, 0, sizeof(cachepichash));
 
-       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);
+       char_texture = Draw_CachePic("gfx/conchars")->tex;
 }
-//=============================================================================
 
-//=============================================================================
-
-/*
-================
-GL_Set2D
-
-Setup as if the screen was 320*200
-================
-*/
-void GL_Set2D (void)
+static void gl_draw_shutdown(void)
 {
-       glViewport (glx, gly, glwidth, glheight);
-
-       glMatrixMode(GL_PROJECTION);
-    glLoadIdentity ();
-       glOrtho  (0, vid.width, vid.height, 0, -99999, 99999);
-
-       glMatrixMode(GL_MODELVIEW);
-    glLoadIdentity ();
+       R_FreeTexturePool(&drawtexturepool);
 
-       glDisable (GL_DEPTH_TEST);
-       glDisable (GL_CULL_FACE);
-       glEnable (GL_BLEND); // was Disable
-//     glEnable (GL_ALPHA_TEST);
-       glDisable (GL_ALPHA_TEST);
-       glEnable(GL_TEXTURE_2D);
-
-       // LordHavoc: added this
-       glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-       glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-
-       glColor3f(1,1,1);
+       numcachepics = 0;
+       memset(cachepichash, 0, sizeof(cachepichash));
 }
 
-// LordHavoc: SHOWLMP stuff
-#define SHOWLMP_MAXLABELS 256
-typedef struct showlmp_s
+static void gl_draw_newmap(void)
 {
-       qboolean        isactive;
-       float           x;
-       float           y;
-       char            label[32];
-       char            pic[128];
-} showlmp_t;
-
-showlmp_t showlmp[SHOWLMP_MAXLABELS];
-
-void SHOWLMP_decodehide()
-{
-       int i;
-       byte *lmplabel;
-       lmplabel = MSG_ReadString();
-       for (i = 0;i < SHOWLMP_MAXLABELS;i++)
-               if (showlmp[i].isactive && strcmp(showlmp[i].label, lmplabel) == 0)
-               {
-                       showlmp[i].isactive = false;
-                       return;
-               }
 }
 
-void SHOWLMP_decodeshow()
+void GL_Draw_Init (void)
 {
-       int i, k;
-       byte lmplabel[256], picname[256];
-       float x, y;
-       strcpy(lmplabel,MSG_ReadString());
-       strcpy(picname, MSG_ReadString());
-       x = MSG_ReadByte();
-       y = MSG_ReadByte();
-       k = -1;
-       for (i = 0;i < SHOWLMP_MAXLABELS;i++)
-               if (showlmp[i].isactive)
-               {
-                       if (strcmp(showlmp[i].label, lmplabel) == 0)
-                       {
-                               k = i;
-                               break; // drop out to replace it
-                       }
-               }
-               else if (k < 0) // find first empty one to replace
-                       k = i;
-       if (k < 0)
-               return; // none found to replace
-       // change existing one
-       showlmp[k].isactive = true;
-       strcpy(showlmp[k].label, lmplabel);
-       strcpy(showlmp[k].pic, picname);
-       showlmp[k].x = x;
-       showlmp[k].y = y;
-}
+       Cvar_RegisterVariable (&scr_conalpha);
 
-void SHOWLMP_drawall()
-{
-       int i;
-       for (i = 0;i < SHOWLMP_MAXLABELS;i++)
-               if (showlmp[i].isactive)
-                       Draw_TransPic(showlmp[i].x, showlmp[i].y, Draw_CachePic(showlmp[i].pic));
-}
+       numcachepics = 0;
+       memset(cachepichash, 0, sizeof(cachepichash));
 
-void SHOWLMP_clear()
-{
-       int i;
-       for (i = 0;i < SHOWLMP_MAXLABELS;i++)
-               showlmp[i].isactive = false;
+       R_RegisterModule("GL_Draw", gl_draw_start, gl_draw_shutdown, gl_draw_newmap);
 }
 
-//====================================================================
-
-/*
-================
-GL_FindTexture
-================
-*/
-int GL_FindTexture (char *identifier)
+int quadelements[768];
+void R_DrawQueue(void)
 {
-       int             i;
-       gltexture_t     *glt;
+       int pos, num, chartexnum, overbright, texnum, additive, batch;
+       float x, y, w, h, s, t, u, v, cr, cg, cb, ca, *av, *at, *ac;
+       cachepic_t *pic;
+       drawqueue_t *dq;
+       char *str, *currentpic;
+       int batchcount;
+       unsigned int color;
+       drawqueuemesh_t *mesh;
+       rmeshstate_t m;
 
-       for (i=0, glt=gltextures ; i<numgltextures ; i++, glt++)
-       {
-               if (!strcmp (identifier, glt->identifier))
-                       return gltextures[i].texnum;
-       }
-
-       return -1;
-}
-
-extern byte gamma[];
+       if (!r_render.integer)
+               return;
 
-// LordHavoc: gamma correction and improved resampling
-void GL_ResampleTextureLerpLine (byte *in, byte *out, int inwidth, int outwidth)
-{
-       int             j, xi, oldx = 0;
-       float   f, fstep, l1, l2;
-       fstep = (float) inwidth/outwidth;
-       for (j = 0,f = 0;j < outwidth;j++, f += fstep)
+       if (!quadelements[1])
        {
-               xi = (int) f;
-               if (xi != oldx)
-               {
-                       in += (xi - oldx) * 4;
-                       oldx = xi;
-               }
-               if (xi < (inwidth-1))
-               {
-                       l2 = f - xi;
-                       l1 = 1 - l2;
-                       *out++ = gamma[(byte) (in[0] * l1 + in[4] * l2)];
-                       *out++ = gamma[(byte) (in[1] * l1 + in[5] * l2)];
-                       *out++ = gamma[(byte) (in[2] * l1 + in[6] * l2)];
-                       *out++ =       (byte) (in[3] * l1 + in[7] * l2) ;
-               }
-               else // last pixel of the line has no pixel to lerp to
+               // elements for rendering a series of quads as triangles
+               for (batch = 0, pos = 0, num = 0;batch < 128;batch++, num += 4)
                {
-                       *out++ = gamma[in[0]];
-                       *out++ = gamma[in[1]];
-                       *out++ = gamma[in[2]];
-                       *out++ =       in[3] ;
+                       quadelements[pos++] = num;
+                       quadelements[pos++] = num + 1;
+                       quadelements[pos++] = num + 2;
+                       quadelements[pos++] = num;
+                       quadelements[pos++] = num + 2;
+                       quadelements[pos++] = num + 3;
                }
        }
-}
-
-/*
-================
-GL_ResampleTexture
-================
-*/
-void GL_ResampleTexture (void *indata, int inwidth, int inheight, void *outdata,  int outwidth, int outheight)
-{
-       // LordHavoc: gamma correction and greatly improved resampling
-       if (gl_lerpimages.value)
-       {
-               int             i, j, yi, oldy;
-               byte    *inrow, *out, *row1, *row2;
-               float   f, fstep, l1, l2;
-               out = outdata;
-               fstep = (float) inheight/outheight;
-
-               row1 = malloc(outwidth*4);
-               row2 = malloc(outwidth*4);
-               inrow = indata;
-               oldy = 0;
-               GL_ResampleTextureLerpLine (inrow, row1, inwidth, outwidth);
-               GL_ResampleTextureLerpLine (inrow + inwidth*4, row2, inwidth, outwidth);
-               for (i = 0, f = 0;i < outheight;i++,f += fstep)
+       GL_SetupView_ViewPort(vid.realx, vid.realy, vid.realwidth, vid.realheight);
+       GL_SetupView_Mode_Ortho(0, 0, vid.conwidth, vid.conheight, -10, 100);
+       qglDepthFunc(GL_LEQUAL);
+       R_Mesh_Start();
+       R_Mesh_Matrix(&r_identitymatrix);
+
+       memset(&m, 0, sizeof(m));
+       chartexnum = R_GetTexture(char_texture);
+       m.tex[0] = chartexnum;
+       R_Mesh_TextureState(&m);
+
+       currentpic = "";
+       pic = NULL;
+       texnum = 0;
+       color = 0;
+
+       overbright = v_overbrightbits.integer;
+       batch = false;
+       batchcount = 0;
+       for (pos = 0;pos < r_refdef.drawqueuesize;pos += ((drawqueue_t *)(r_refdef.drawqueue + pos))->size)
+       {
+               dq = (drawqueue_t *)(r_refdef.drawqueue + pos);
+               additive = (dq->flags & DRAWFLAG_ADDITIVE) != 0;
+               color = dq->color;
+               m.blendfunc1 = GL_SRC_ALPHA;
+               if (additive)
+                       m.blendfunc2 = GL_ONE;
+               else
+                       m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
+               m.depthdisable = true;
+               R_Mesh_MainState(&m);
+
+               cr = (float) ((color >> 24) & 0xFF) * (1.0f / 255.0f) * r_colorscale;
+               cg = (float) ((color >> 16) & 0xFF) * (1.0f / 255.0f) * r_colorscale;
+               cb = (float) ((color >>  8) & 0xFF) * (1.0f / 255.0f) * r_colorscale;
+               ca = (float) ( color        & 0xFF) * (1.0f / 255.0f);
+               x = dq->x;
+               y = dq->y;
+               w = dq->scalex;
+               h = dq->scaley;
+
+               switch(dq->command)
                {
-                       yi = (int) f;
-                       if (yi != oldy)
+               case DRAWQUEUE_PIC:
+                       str = (char *)(dq + 1);
+                       if (strcmp(str, currentpic))
                        {
-                               inrow = (byte *)((int)indata + inwidth*4*yi);
-                               if (yi == oldy+1)
-                                       memcpy(row1, row2, outwidth*4);
-                               else
-                                       GL_ResampleTextureLerpLine (inrow, row1, inwidth, outwidth);
-                               if (yi < (inheight-1))
-                                       GL_ResampleTextureLerpLine (inrow + inwidth*4, row2, inwidth, outwidth);
-                               else
-                                       memcpy(row2, row1, outwidth*4);
-                               oldy = yi;
-                       }
-                       if (yi < (inheight-1))
-                       {
-                               l2 = f - yi;
-                               l1 = 1 - l2;
-                               for (j = 0;j < outwidth;j++)
+                               currentpic = str;
+                               if (*str)
                                {
-                                       *out++ = (byte) (*row1++ * l1 + *row2++ * l2);
-                                       *out++ = (byte) (*row1++ * l1 + *row2++ * l2);
-                                       *out++ = (byte) (*row1++ * l1 + *row2++ * l2);
-                                       *out++ = (byte) (*row1++ * l1 + *row2++ * l2);
+                                       pic = Draw_CachePic(str);
+                                       m.tex[0] = R_GetTexture(pic->tex);
                                }
-                               row1 -= outwidth*4;
-                               row2 -= outwidth*4;
+                               else
+                                       m.tex[0] = 0;
+                               R_Mesh_TextureState(&m);
                        }
-                       else // last line has no pixels to lerp to
+                       if (*str)
                        {
-                               for (j = 0;j < outwidth;j++)
-                               {
-                                       *out++ = *row1++;
-                                       *out++ = *row1++;
-                                       *out++ = *row1++;
-                                       *out++ = *row1++;
-                               }
-                               row1 -= outwidth*4;
+                               if (w == 0)
+                                       w = pic->width;
+                               if (h == 0)
+                                       h = pic->height;
                        }
-               }
-               free(row1);
-               free(row2);
-       }
-       else
-       {
-               int             i, j;
-               unsigned        frac, fracstep;
-               byte    *inrow, *out, *inpix;
-               out = outdata;
-
-               fracstep = inwidth*0x10000/outwidth;
-               for (i=0 ; i<outheight ; i++)
-               {
-                       inrow = (byte *)indata + inwidth*(i*inheight/outheight)*4;
-                       frac = fracstep >> 1;
-                       for (j=0 ; j<outwidth ; j+=4)
+                       varray_texcoord[0][0] = 0;varray_texcoord[0][1] = 0;
+                       varray_texcoord[0][2] = 1;varray_texcoord[0][3] = 0;
+                       varray_texcoord[0][4] = 1;varray_texcoord[0][5] = 1;
+                       varray_texcoord[0][6] = 0;varray_texcoord[0][7] = 1;
+                       varray_vertex[ 0] = x  ;varray_vertex[ 1] = y  ;varray_vertex[ 2] = 10;
+                       varray_vertex[ 4] = x+w;varray_vertex[ 5] = y  ;varray_vertex[ 6] = 10;
+                       varray_vertex[ 8] = x+w;varray_vertex[ 9] = y+h;varray_vertex[10] = 10;
+                       varray_vertex[12] = x  ;varray_vertex[13] = y+h;varray_vertex[14] = 10;
+                       GL_Color(cr, cg, cb, ca);
+                       R_Mesh_Draw(4, 2, quadelements);
+                       break;
+               case DRAWQUEUE_STRING:
+                       str = (char *)(dq + 1);
+                       if (strcmp("gfx/conchars", currentpic))
                        {
-                               inpix = inrow + ((frac >> 14) & ~3);*out++ = gamma[*inpix++];*out++ = gamma[*inpix++];*out++ = gamma[*inpix++];*out++ =       *inpix++ ;frac += fracstep;
-                               inpix = inrow + ((frac >> 14) & ~3);*out++ = gamma[*inpix++];*out++ = gamma[*inpix++];*out++ = gamma[*inpix++];*out++ =       *inpix++ ;frac += fracstep;
-                               inpix = inrow + ((frac >> 14) & ~3);*out++ = gamma[*inpix++];*out++ = gamma[*inpix++];*out++ = gamma[*inpix++];*out++ =       *inpix++ ;frac += fracstep;
-                               inpix = inrow + ((frac >> 14) & ~3);*out++ = gamma[*inpix++];*out++ = gamma[*inpix++];*out++ = gamma[*inpix++];*out++ =       *inpix++ ;frac += fracstep;
+                               currentpic = "gfx/conchars";
+                               m.tex[0] = chartexnum;
+                               R_Mesh_TextureState(&m);
                        }
-               }
-       }
-}
-
-/*
-================
-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;
-       unsigned short     r,g,b;
-       byte    *out, *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 (void *data, int width, int height,  qboolean mipmap, qboolean alpha)
-{
-       int samples, scaled_width, scaled_height, i;
-       byte *in, *out, *scaled;
-
-       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;
-
-       samples = alpha ? gl_alpha_format : gl_solid_format;
-
-#if 0
-       if (mipmap)
-               gluBuild2DMipmaps (GL_TEXTURE_2D, samples, width, height, GL_RGBA, GL_UNSIGNED_BYTE, scaled);
-       else if (scaled_width == width && scaled_height == height)
-               glTexImage2D (GL_TEXTURE_2D, 0, samples, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaled);
-       else
-       {
-               gluScaleImage (GL_RGBA, width, height, GL_UNSIGNED_BYTE, scaled, 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;
-
-       scaled = malloc(scaled_width*scaled_height*4);
-       if (scaled_width == width && scaled_height == height)
-       {
-               // LordHavoc: gamma correct while copying
-               in = (byte *)data;
-               out = (byte *)scaled;
-               for (i = 0;i < width*height;i++)
-               {
-                       *out++ = gamma[*in++];
-                       *out++ = gamma[*in++];
-                       *out++ = gamma[*in++];
-                       *out++ = *in++;
-               }
-       }
-       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);
-               }
-       }
-#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);
-       }
-       free(scaled);
-}
-
-void GL_Upload8_EXT (byte *data, int width, int height,  qboolean mipmap)
-{
-       int             scaled_width, scaled_height;
-       byte    *scaled;
-
-       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;
-
-       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;
-               }
-               scaled = malloc(scaled_width*scaled_height*4);
-               memcpy (scaled, data, width*height);
-       }
-       else
-       {
-               scaled = malloc(scaled_width*scaled_height*4);
-               GL_Resample8BitTexture (data, width, height, (void*) &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);
-       }
-       free(scaled);
-}
-
-qboolean VID_Is8bit();
-
-/*
-===============
-GL_Upload8
-===============
-*/
-void GL_Upload8 (byte *data, int width, int height,  qboolean mipmap, qboolean alpha)
-{
-       static  unsigned *trans;
-       int                     i, s;
-       qboolean        noalpha;
-       int                     p;
-       byte    *indata;
-       int             *outdata;
-
-       s = width*height;
-       trans = malloc(s*4);
-       // 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)
-                               trans[i] = d_8to24table[p];
-                       else
+                       batchcount = 0;
+                       at = varray_texcoord[0];
+                       av = varray_vertex;
+                       GL_Color(cr, cg, cb, ca);
+                       while ((num = *str++) && x < vid.conwidth)
                        {
-                               trans[i] = 0; // force to black
-                               noalpha = false;
+                               if (num != ' ')
+                               {
+                                       s = (num & 15)*0.0625f + (0.5f / 256.0f);
+                                       t = (num >> 4)*0.0625f + (0.5f / 256.0f);
+                                       u = 0.0625f - (1.0f / 256.0f);
+                                       v = 0.0625f - (1.0f / 256.0f);
+                                       at[0] = s  ;at[1] = t  ;
+                                       at[2] = s+u;at[3] = t  ;
+                                       at[4] = s+u;at[5] = t+v;
+                                       at[6] = s  ;at[7] = t+v;
+                                       av[ 0] = x  ;av[ 1] = y  ;av[ 2] = 10;
+                                       av[ 4] = x+w;av[ 5] = y  ;av[ 6] = 10;
+                                       av[ 8] = x+w;av[ 9] = y+h;av[10] = 10;
+                                       av[12] = x  ;av[13] = y+h;av[14] = 10;
+                                       ac += 16;
+                                       at += 8;
+                                       av += 16;
+                                       batchcount++;
+                                       if (batchcount >= 128)
+                                       {
+                                               R_Mesh_Draw(batchcount * 4, batchcount * 2, quadelements);
+                                               batchcount = 0;
+                                               at = varray_texcoord[0];
+                                               av = varray_vertex;
+                                       }
+                               }
+                               x += w;
                        }
+                       if (batchcount > 0)
+                               R_Mesh_Draw(batchcount * 4, batchcount * 2, quadelements);
+                       break;
+               case DRAWQUEUE_MESH:
+                       mesh = (void *)(dq + 1);
+                       m.tex[0] = R_GetTexture(mesh->texture);
+                       R_Mesh_TextureState(&m);
+                       R_Mesh_ResizeCheck(mesh->numvertices);
+                       memcpy(varray_vertex, mesh->vertices, sizeof(float[4]) * mesh->numvertices);
+                       memcpy(varray_texcoord[0], mesh->texcoords, sizeof(float[2]) * mesh->numvertices);
+                       memcpy(varray_color, mesh->colors, sizeof(float[4]) * mesh->numvertices);
+                       GL_UseColorArray();
+                       R_Mesh_Draw(mesh->numvertices, mesh->numtriangles, mesh->indices);
+                       currentpic = "\0";
+                       break;
                }
+       }
 
-               if (noalpha)
+       if (!v_hwgamma.integer)
+       {
+               // we use one big triangle for all the screen blends
+               varray_texcoord[0][0] = 0;varray_texcoord[0][1] = 0;
+               varray_texcoord[0][2] = 0;varray_texcoord[0][3] = 0;
+               varray_texcoord[0][4] = 0;varray_texcoord[0][5] = 0;
+               varray_vertex[0] = -5000;varray_vertex[1] = -5000;varray_vertex[2] = 10;
+               varray_vertex[4] = 10000;varray_vertex[5] = -5000;varray_vertex[6] = 10;
+               varray_vertex[8] = -5000;varray_vertex[9] = 10000;varray_vertex[10] = 10;
+               // all the blends ignore depth
+               memset(&m, 0, sizeof(m));
+               m.depthdisable = true;
+               t = v_contrast.value * (float) (1 << v_overbrightbits.integer);
+               if (t >= 1.01f)
                {
-                       if (VID_Is8bit() && (data!=scrap_texels[0]))
+                       m.blendfunc1 = GL_DST_COLOR;
+                       m.blendfunc2 = GL_ONE;
+                       R_Mesh_State(&m);
+                       while (t >= 1.01f)
                        {
-                               GL_Upload8_EXT (data, width, height, mipmap);
-                               free(trans);
-                               return;
+                               cr = t - 1.0f;
+                               if (cr > 1.0f)
+                                       cr = 1.0f;
+                               GL_Color(cr, cr, cr, 1);
+                               R_Mesh_Draw(3, 1, polygonelements);
+                               t *= 0.5;
                        }
-                       alpha = false;
                }
-       }
-       else
-       {
-               // LordHavoc: dodge the copy if it will be uploaded as 8bit
-               if (VID_Is8bit() && (data!=scrap_texels[0]))
+               else if (t <= 0.99f)
                {
-                       GL_Upload8_EXT (data, width, height, mipmap);
-                       free(trans);
-                       return;
+                       m.blendfunc1 = GL_ZERO;
+                       m.blendfunc2 = GL_SRC_COLOR;
+                       R_Mesh_State(&m);
+                       GL_Color(t, t, t, 1);
+                       R_Mesh_Draw(3, 1, polygonelements);
                }
-               //if (s&3)
-               //      Sys_Error ("GL_Upload8: s&3");
-               indata = data;
-               outdata = trans;
-               if (s&1)
-                       *outdata++ = d_8to24table[*indata++];
-               if (s&2)
-               {
-                       *outdata++ = d_8to24table[*indata++];
-                       *outdata++ = d_8to24table[*indata++];
-               }
-               for (i = 0;i < s;i+=4)
-               {
-                       *outdata++ = d_8to24table[*indata++];
-                       *outdata++ = d_8to24table[*indata++];
-                       *outdata++ = d_8to24table[*indata++];
-                       *outdata++ = d_8to24table[*indata++];
-               }
-       }
-
-       GL_Upload32 (trans, width, height, mipmap, alpha);
-       free(trans);
-}
-
-/*
-================
-GL_LoadTexture
-================
-*/
-int GL_LoadTexture (char *identifier, int width, int height, byte *data, qboolean mipmap, qboolean alpha, int bytesperpixel)
-{
-       unsigned short  crc;
-       int                             i;
-       gltexture_t             *glt;
-
-       if (isDedicated)
-               return 1;
-
-       // LordHavoc: do a CRC to confirm the data really is the same as previous occurances.
-       crc = CRC_Block(data, width*height*bytesperpixel);
-       // see if the texture is already present
-       if (identifier[0])
-       {
-               for (i=0, glt=gltextures ; i<numgltextures ; i++, glt++)
+               if (v_brightness.value >= 0.01f)
                {
-                       if (!strcmp (identifier, glt->identifier))
-                       {
-                               // LordHavoc: everyone hates cache mismatchs, so I fixed it
-                               if (crc != glt->crc || width != glt->width || height != glt->height)
-                               {
-                                       Con_DPrintf("GL_LoadTexture: cache mismatch, replacing old texture\n");
-                                       goto GL_LoadTexture_setup; // drop out with glt pointing to the texture to replace
-                                       //Sys_Error ("GL_LoadTexture: cache mismatch");
-                               }
-                               if ((gl_lerpimages.value != 0) != glt->lerped)
-                                       goto GL_LoadTexture_setup; // drop out with glt pointing to the texture to replace
-                               return glt->texnum;
-                       }
+                       m.blendfunc1 = GL_ONE;
+                       m.blendfunc2 = GL_ONE;
+                       R_Mesh_State(&m);
+                       GL_Color(v_brightness.value, v_brightness.value, v_brightness.value, 1);
+                       R_Mesh_Draw(3, 1, polygonelements);
                }
        }
-       // LordHavoc: although this could be an else condition as it was in the original id code,
-       //            it is more clear this way
-       // LordHavoc: check if there are still slots available
-       if (numgltextures >= MAX_GLTEXTURES)
-               Sys_Error ("GL_LoadTexture: ran out of texture slots (%d)\n", MAX_GLTEXTURES);
-       glt = &gltextures[numgltextures++];
-
-       strcpy (glt->identifier, identifier);
-       glt->texnum = texture_extension_number;
-       texture_extension_number++;
-// LordHavoc: label to drop out of the loop into the setup code
-GL_LoadTexture_setup:
-       glt->crc = crc; // LordHavoc: used to verify textures are identical
-       glt->width = width;
-       glt->height = height;
-       glt->mipmap = mipmap;
-       glt->bytesperpixel = bytesperpixel;
-       glt->lerped = gl_lerpimages.value != 0;
-
-       glBindTexture(GL_TEXTURE_2D, glt->texnum);
-
-       if (bytesperpixel == 1) // 8bit
-               GL_Upload8 (data, width, height, mipmap, alpha);
-       else // 32bit
-               GL_Upload32 (data, width, height, mipmap, true);
-       glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-
-       return glt->texnum;
+       R_Mesh_Finish();
 }
 
-/*
-================
-GL_LoadPicTexture
-================
-*/
-int GL_LoadPicTexture (qpic_t *pic)
-{
-       return GL_LoadTexture ("", pic->width, pic->height, pic->data, false, true, 1);
-}
-
-int GL_GetTextureSlots (int count)
-{
-       gltexture_t             *glt, *first;
-
-       first = glt = &gltextures[numgltextures];
-       while (count--)
-       {
-               glt->identifier[0] = 0;
-               glt->texnum = texture_extension_number++;
-               glt->crc = 0;
-               glt->width = 0;
-               glt->height = 0;
-               glt->bytesperpixel = 0;
-               glt++;
-               numgltextures++;
-       }
-       return first->texnum;
-}