updated to version 1.50, build 75.
authorlordhavoc <lordhavoc@d7cf8633-e32d-0410-b094-e92efae38249>
Fri, 17 Nov 2000 08:35:39 +0000 (08:35 +0000)
committerlordhavoc <lordhavoc@d7cf8633-e32d-0410-b094-e92efae38249>
Fri, 17 Nov 2000 08:35:39 +0000 (08:35 +0000)
change log as best I can remember:
rewrote model loading and rendering
multi-pass colormapping on any model (NO UPLOADS!)
fullbrights on models (feature of new multi-pass model renderer)
rewrote texture management
rewrote texture uploading
heavily optimized static light sampling
fancy new crosshair
fixed network angle rounding (shots are fired where you're pointing, not down and to the right)
HL map hull sizes are supported (still sink into grates though)
removal of some commented out junk
other minor stuff I can't remember now

git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@76 d7cf8633-e32d-0410-b094-e92efae38249

43 files changed:
buildnumber.c
cl_main.c
cl_parse.c
cl_tent.c
client.h
common.c
draw.h
gl_draw.c
gl_models.c [new file with mode: 0644]
gl_poly.c
gl_rmain.c
gl_rmisc.c
gl_rsurf.c
gl_screen.c
gl_textures.c [new file with mode: 0644]
gl_warp.c
glquake.h
host.c
host_cmd.c
image.c
image.h [new file with mode: 0644]
model_alias.c
model_alias.h
model_brush.c
model_shared.c
model_shared.h
modelgen.h
net_wins.c
pr_exec.c
quakedef.h
r_crosshairs.c [new file with mode: 0644]
r_light.c
r_light.h [new file with mode: 0644]
r_modules.c [new file with mode: 0644]
r_modules.h [new file with mode: 0644]
r_part.c
render.h
sv_main.c
vid_glx.c
vid_shared.c
vid_wgl.c
view.c
world.c

index f2fa786..cd04131 100644 (file)
@@ -1,4 +1,4 @@
 
-#define BUILDNUMBER 73
+#define BUILDNUMBER 75
 
 int buildnumber = BUILDNUMBER;
index 34a0b42..538b19c 100644 (file)
--- a/cl_main.c
+++ b/cl_main.c
@@ -466,9 +466,31 @@ void CL_RelinkEntities (void)
                if (ent->msgtime != cl.mtime[0])
                {
                        ent->model = NULL;
+                       // LordHavoc: free on the same frame, not the next
+                       if (ent->forcelink)
+                               R_RemoveEfrags (ent);   // just became empty
                        continue;
                }
 
+               // LordHavoc: animation interpolation, note: framegroups partially override this in the renderer
+               /*
+               if (ent->model != ent->lerp_model || ent->lerp_time > cl.time)
+               {
+                       ent->lerp_frame1 = ent->lerp_frame2 = ent->frame;
+                       ent->lerp_time = cl.time;
+                       ent->lerp = 0;
+               }
+               else if (ent->frame != ent->lerp_frame2)
+               {
+                       ent->lerp_frame1 = ent->lerpframe2;
+                       ent->lerp_frame2 = ent->frame;
+                       ent->lerp_time = cl.time;
+                       ent->lerp = 0;
+               }
+               else
+                       ent->lerp = bound(0, (cl.time - ent->lerp_time) * 10.0f, 1);
+               */
+
                VectorCopy (ent->origin, oldorg);
 
                if (ent->forcelink)
index 75d53fe..028dda2 100644 (file)
@@ -105,7 +105,7 @@ entity_t    *CL_EntityNum (int num)
                        Host_Error ("CL_EntityNum: %i is an invalid number",num);
                while (cl.num_entities<=num)
                {
-                       cl_entities[cl.num_entities].colormap = 0; //vid.colormap;
+                       cl_entities[cl.num_entities].colormap = -1; // no special coloring
                        cl.num_entities++;
                }
        }
@@ -516,8 +516,6 @@ void CL_ParseUpdate (int bits)
                        ent->syncbase = model->synctype == ST_RAND ? (float)(rand()&0x7fff) / 0x7fff : 0.0;
                else
                        forcelink = true;       // hack to make null model players work
-               if (num > 0 && num <= cl.maxclients)
-                       R_TranslatePlayerSkin(num - 1);
        }
 
        ent->frame = ((bits & U_FRAME) ? MSG_ReadByte() : (baseline->frame & 0xFF));
@@ -525,20 +523,18 @@ void CL_ParseUpdate (int bits)
        i = bits & U_COLORMAP ? MSG_ReadByte() : baseline->colormap;
        ent->deltabaseline.colormap = i;
        if (!i)
-               ent->colormap = 0; //vid.colormap;
+               ent->colormap = -1; // no special coloring
        else
        {
                if (i > cl.maxclients)
                        Host_Error ("i >= cl.maxclients");
-               ent->colormap = i; //vid.colormap; // cl.scores[i-1].translations;
+               ent->colormap = cl.scores[i-1].colors; // color it
        }
 
        skin = bits & U_SKIN ? MSG_ReadByte() : baseline->skin;
        if (skin != ent->skinnum)
        {
                ent->skinnum = skin;
-               if (num > 0 && num <= cl.maxclients)
-                       R_TranslatePlayerSkin(num - 1);
        }
        ent->deltabaseline.skin = skin;
 
@@ -769,7 +765,7 @@ void CL_ParseStatic (void)
 // copy it to the current state
        ent->model = cl.model_precache[ent->baseline.modelindex];
        ent->frame = ent->baseline.frame;
-       ent->colormap = 0; //vid.colormap;
+       ent->colormap = -1; // no special coloring
        ent->skinnum = ent->baseline.skin;
        ent->effects = ent->baseline.effects;
        ent->alpha = 1;
@@ -963,7 +959,6 @@ void CL_ParseServerMessage (void)
                        if (i >= cl.maxclients)
                                Host_Error ("CL_ParseServerMessage: svc_updatecolors > MAX_SCOREBOARD");
                        cl.scores[i].colors = MSG_ReadByte ();
-                       R_TranslatePlayerSkin(i);
                        break;
                        
                case svc_particle:
index d60ed56..d6d4247 100644 (file)
--- a/cl_tent.c
+++ b/cl_tent.c
@@ -104,6 +104,21 @@ void R_BloodShower (vec3_t mins, vec3_t maxs, float velspeed, int count);
 void R_ParticleCube (vec3_t mins, vec3_t maxs, vec3_t dir, int count, int colorbase, int gravity, int randomvel);
 void R_ParticleRain (vec3_t mins, vec3_t maxs, vec3_t dir, int count, int colorbase, int type);
 
+// attempts to find the nearest non-solid location, used for explosions mainly
+void FindNonSolidLocation(vec3_t pos)
+{
+       if (SV_HullPointContents (cl.worldmodel->hulls, 0, pos) != CONTENTS_SOLID) return;
+       pos[0]-=1;if (SV_HullPointContents (cl.worldmodel->hulls, 0, pos) != CONTENTS_SOLID) return;
+       pos[0]+=2;if (SV_HullPointContents (cl.worldmodel->hulls, 0, pos) != CONTENTS_SOLID) return;
+       pos[0]-=1;
+       pos[1]-=1;if (SV_HullPointContents (cl.worldmodel->hulls, 0, pos) != CONTENTS_SOLID) return;
+       pos[1]+=2;if (SV_HullPointContents (cl.worldmodel->hulls, 0, pos) != CONTENTS_SOLID) return;
+       pos[1]-=1;
+       pos[2]-=1;if (SV_HullPointContents (cl.worldmodel->hulls, 0, pos) != CONTENTS_SOLID) return;
+       pos[2]+=2;if (SV_HullPointContents (cl.worldmodel->hulls, 0, pos) != CONTENTS_SOLID) return;
+       pos[2]-=1;
+}
+
 /*
 =================
 CL_ParseTEnt
@@ -345,6 +360,7 @@ void CL_ParseTEnt (void)
                pos[0] = MSG_ReadCoord ();
                pos[1] = MSG_ReadCoord ();
                pos[2] = MSG_ReadCoord ();
+               FindNonSolidLocation(pos);
                R_ParticleExplosion (pos, false);
 //             R_BlastParticles (pos, 120, 120);
                dl = CL_AllocDlight (0);
@@ -360,6 +376,7 @@ void CL_ParseTEnt (void)
                pos[0] = MSG_ReadCoord ();
                pos[1] = MSG_ReadCoord ();
                pos[2] = MSG_ReadCoord ();
+               FindNonSolidLocation(pos);
                R_ParticleExplosion (pos, false);
 //             R_BlastParticles (pos, 120, 480);
                dl = CL_AllocDlight (0);
@@ -376,6 +393,7 @@ void CL_ParseTEnt (void)
                pos[0] = MSG_ReadCoord ();
                pos[1] = MSG_ReadCoord ();
                pos[2] = MSG_ReadCoord ();
+               FindNonSolidLocation(pos);
                R_ParticleExplosion (pos, true);
                dl = CL_AllocDlight (0);
                VectorCopy (pos, dl->origin);
@@ -391,6 +409,7 @@ void CL_ParseTEnt (void)
                pos[0] = MSG_ReadCoord ();
                pos[1] = MSG_ReadCoord ();
                pos[2] = MSG_ReadCoord ();
+               FindNonSolidLocation(pos);
                R_ParticleExplosion (pos, false);
 //             R_BlastParticles (pos, 120, 120);
                dl = CL_AllocDlight (0);
@@ -406,6 +425,7 @@ void CL_ParseTEnt (void)
                pos[0] = MSG_ReadCoord ();
                pos[1] = MSG_ReadCoord ();
                pos[2] = MSG_ReadCoord ();
+               FindNonSolidLocation(pos);
                R_ParticleExplosion (pos, false);
 //             R_BlastParticles (pos, 120, 120);
                dl = CL_AllocDlight (0);
@@ -421,6 +441,7 @@ void CL_ParseTEnt (void)
                pos[0] = MSG_ReadCoord ();
                pos[1] = MSG_ReadCoord ();
                pos[2] = MSG_ReadCoord ();
+               FindNonSolidLocation(pos);
                R_BlobExplosion (pos);
 //             R_BlastParticles (pos, 120, 120);
 
@@ -475,6 +496,7 @@ void CL_ParseTEnt (void)
                pos[0] = MSG_ReadCoord ();
                pos[1] = MSG_ReadCoord ();
                pos[2] = MSG_ReadCoord ();
+               FindNonSolidLocation(pos);
                colorStart = MSG_ReadByte ();
                colorLength = MSG_ReadByte ();
                R_ParticleExplosion2 (pos, colorStart, colorLength);
@@ -514,8 +536,7 @@ entity_t *CL_NewTempEntity (void)
        cl_visedicts[cl_numvisedicts] = ent;
        cl_numvisedicts++;
 
-//     ent->colormap = vid.colormap;
-       ent->colormap = 0;
+       ent->colormap = -1; // no special coloring
        ent->scale = 1;
        ent->alpha = 1;
        ent->colormod[0] = ent->colormod[1] = ent->colormod[2] = 1;
index 45ae787..563f3cd 100644 (file)
--- a/client.h
+++ b/client.h
@@ -41,7 +41,7 @@ typedef struct
        float   entertime;
        int             frags;
        int             colors;                 // two 4 bit fields
-       byte    translations[256]; // LordHavoc: major memory reduction (was VID_GRADES*256, and VID_GRADES is 64), and weirdness cleanup
+//     byte    translations[256]; // LordHavoc: major memory reduction (was VID_GRADES*256, and VID_GRADES is 64), and weirdness cleanup
 } scoreboard_t;
 
 typedef struct
@@ -65,20 +65,7 @@ typedef struct
 
 #define        SIGNONS         4                       // signon messages to receive before connected
 
-// LordHavoc: 256 dynamic lights
-#define        MAX_DLIGHTS             256
-typedef struct
-{
-       vec3_t  origin;
-       float   radius;
-       float   die;                            // stop lighting after this time
-       float   decay;                          // drop this each second
-       float   minlight;                       // don't add when contributing less
-       int             key;
-       vec3_t  color;                          // LordHavoc: colored lighting
-       qboolean        dark;                   // subtracts light instead of adding
-} dlight_t;
-
+#include "r_light.h"
 
 #define        MAX_BEAMS       24
 typedef struct
index 2c9c8cc..e31b48d 100644 (file)
--- a/common.c
+++ b/common.c
@@ -588,17 +588,18 @@ void MSG_WriteCoord (sizebuf_t *sb, float f)
        if (dpprotocol)
                MSG_WriteFloat(sb, f);
        else
-               MSG_WriteShort (sb, (int)(f*8));
+               MSG_WriteShort (sb, (int)(f*8.0f + 0.5f));
 }
 
 void MSG_WritePreciseAngle (sizebuf_t *sb, float f)
 {
-       MSG_WriteShort (sb, (int) (f*65536.0f/360) & 65535);
+       MSG_WriteShort (sb, (int)(f*(65536.0f/360.0f) + 0.5f) & 65535);
 }
 
+// LordHavoc: round to nearest value, rather than rounding down, fixes crosshair problem
 void MSG_WriteAngle (sizebuf_t *sb, float f)
 {
-       MSG_WriteByte (sb, ((int)f*256/360) & 255);
+       MSG_WriteByte (sb, (int)(f*(256.0f/360.0f) + 0.5f) & 255);
 }
 
 //
diff --git a/draw.h b/draw.h
index db8a860..ddb8e35 100644 (file)
--- a/draw.h
+++ b/draw.h
@@ -25,6 +25,7 @@ extern        qpic_t          *draw_disc;     // also used on sbar
 
 void Draw_Init (void);
 void Draw_Character (int x, int y, int num);
+void Draw_GenericPic (int texnum, float red, float green, float blue, float alpha, float x, float y, float width, float height);
 void Draw_Pic (int x, int y, qpic_t *pic);
 void Draw_TransPic (int x, int y, qpic_t *pic);
 void Draw_TransPicTranslate (int x, int y, qpic_t *pic, byte *translation);
index 7777801..69c8d7b 100644 (file)
--- a/gl_draw.c
+++ b/gl_draw.c
@@ -28,15 +28,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 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                  translate_texture;
 int                    char_texture;
 
 typedef struct
@@ -48,29 +45,6 @@ typedef struct
 byte           conback_buffer[sizeof(qpic_t) + sizeof(glpic_t)];
 qpic_t         *conback = (qpic_t *)&conback_buffer;
 
-int            gl_filter_min = GL_LINEAR_MIPMAP_LINEAR; //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;
-
 /*
 =============================================================================
 
@@ -89,7 +63,6 @@ int                   numgltextures;
 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)
@@ -134,6 +107,7 @@ int Scrap_AllocBlock (int w, int h, int *x, int *y)
 }
 
 int    scrap_uploads;
+int scraptexnum[MAX_SCRAPS];
 
 void Scrap_Upload (void)
 {
@@ -142,10 +116,7 @@ void Scrap_Upload (void)
        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);
-       }
+               scraptexnum[texnum] = GL_LoadTexture (va("scrapslot%d", texnum), BLOCK_WIDTH, BLOCK_HEIGHT, scrap_texels[texnum], false, true, 1);
        scrap_dirty = false;
 }
 
@@ -191,8 +162,9 @@ qpic_t *Draw_PicFromWad (char *name)
                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;
+               if (!scraptexnum[texnum])
+                       scraptexnum[texnum] = GL_LoadTexture (va("scrapslot%d", texnum), BLOCK_WIDTH, BLOCK_HEIGHT, scrap_texels[texnum], false, true, 1);
+               gl->texnum = scraptexnum[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;
@@ -200,9 +172,6 @@ qpic_t *Draw_PicFromWad (char *name)
 
                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
        {
@@ -211,9 +180,6 @@ qpic_t *Draw_PicFromWad (char *name)
                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);
        }
        return p;
 }
@@ -267,7 +233,7 @@ qpic_t      *Draw_CachePic (char *path)
        return &pic->pic;
 }
 
-
+/*
 void Draw_CharToConback (int num, byte *dest)
 {
        int             row, col;
@@ -291,69 +257,7 @@ void Draw_CharToConback (int num, byte *dest)
        }
 
 }
-
-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)
-               {
-                       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);
-               }
-       }
-}
 
 extern void LoadSky_f(void);
 
@@ -366,101 +270,85 @@ Draw_Init
 */
 void rmain_registercvars();
 extern int buildnumber;
-void Draw_Init (void)
+
+void gl_draw_start()
 {
        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
+       char_texture = loadtextureimage ("conchars", 0, 0, false, false);
+       if (!char_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);
+               // now turn them into textures
+               char_texture = GL_LoadTexture ("charset", 128, 128, draw_chars, false, true, 1);
+       }
 
-       start = Hunk_LowMark();
+       gl = (glpic_t *)conback->data;
+       gl->texnum = loadtextureimage("gfx/conback", 0, 0, false, false);
+       gl->sl = 0;
+       gl->sh = 1;
+       gl->tl = 0;
+       gl->th = 1;
+       conback->width = vid.width;
+       conback->height = vid.height;
+
+       memset(scraptexnum, 0, sizeof(scraptexnum));
+
+       // get the other pics we need
+       draw_disc = Draw_PicFromWad ("disc");
+}
 
-       cb = (qpic_t *)COM_LoadMallocFile ("gfx/conback.lmp", false);
-       if (!cb)
-               Sys_Error ("Couldn't load gfx/conback.lmp");
-       SwapPic (cb);
+void gl_draw_shutdown()
+{
+}
+
+char engineversion[40];
+int engineversionx, engineversiony;
+
+extern void GL_Textures_Init();
+void GL_Draw_Init (void)
+{
+       int i;
+       Cvar_RegisterVariable (&qsg_version);
+       Cvar_RegisterVariable (&gl_conalpha);
+
+       Cmd_AddCommand ("loadsky", &LoadSky_f);
 
-       // hack the version number directly into the pic
 #ifdef NEHAHRA
 #if defined(__linux__)
-       sprintf (ver, "DPNehahra Linux GL %.2f build %5i", (float) VERSION, buildnumber);
+       sprintf (engineversion, "DPNehahra Linux   GL %.2f build %3i", (float) VERSION, buildnumber);
 #elif defined(WIN32)
-       sprintf (ver, "DPNehahra Windows GL %.2f build %5i", (float) VERSION, buildnumber);
+       sprintf (engineversion, "DPNehahra Windows GL %.2f build %3i", (float) VERSION, buildnumber);
 #else
-       sprintf (ver, "DPNehahra Unknown GL %.2f build %5i", (float) VERSION, buildnumber);
+       sprintf (engineversion, "DPNehahra Unknown GL %.2f build %3i", (float) VERSION, buildnumber);
 #endif
 #else
 #if defined(__linux__)
-       sprintf (ver, "DarkPlaces Linux GL %.2f build %5i", (float) VERSION, buildnumber);
+       sprintf (engineversion, "DarkPlaces Linux   GL %.2f build %3i", (float) VERSION, buildnumber);
 #elif defined(WIN32)
-       sprintf (ver, "DarkPlaces Windows GL %.2f build %5i", (float) VERSION, buildnumber);
+       sprintf (engineversion, "DarkPlaces Windows GL %.2f build %3i", (float) VERSION, buildnumber);
 #else
-       sprintf (ver, "DarkPlaces Unknown GL %.2f build %5i", (float) VERSION, buildnumber);
+       sprintf (engineversion, "DarkPlaces Unknown GL %.2f build %3i", (float) VERSION, buildnumber);
 #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
-       free(cb);
-
-       // save a texture slot for translated picture
-       translate_texture = texture_extension_number++;
+       for (i = 0;i < 40 && engineversion[i];i++)
+               engineversion[i] += 0x80; // shift to orange
+       engineversionx = vid.width - strlen(engineversion) * 8 - 8;
+       engineversiony = vid.height - 8;
 
-       // 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();
+       GL_Textures_Init();
+       R_RegisterModule("GL_Draw", gl_draw_start, gl_draw_shutdown);
 }
 
-
 /*
 ================
 Draw_Character
@@ -566,6 +454,30 @@ void Draw_String (int x, int y, char *str, int maxlen)
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 }
 
+void Draw_GenericPic (int texnum, float red, float green, float blue, float alpha, float x, float y, float width, float height)
+{
+       glDisable(GL_ALPHA_TEST);
+//     glEnable (GL_BLEND);
+       glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+//     glCullFace(GL_FRONT);
+       glColor4f(red,green,blue,alpha);
+       glBindTexture(GL_TEXTURE_2D, texnum);
+       glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+       glBegin (GL_QUADS);
+       glTexCoord2f (0, 0);
+       glVertex2f (x, y);
+       glTexCoord2f (1, 0);
+       glVertex2f (x+width, y);
+       glTexCoord2f (1, 1);
+       glVertex2f (x+width, y+height);
+       glTexCoord2f (0, 1);
+       glVertex2f (x, y+height);
+       glEnd ();
+       glColor3f(1,1,1);
+//     glEnable(GL_ALPHA_TEST);
+//     glDisable (GL_BLEND);
+}
+
 /*
 =============
 Draw_AlphaPic
@@ -660,8 +572,6 @@ void Draw_TransPicTranslate (int x, int y, qpic_t *pic, byte *translation)
        byte                    *src;
        int                             p;
 
-       glBindTexture(GL_TEXTURE_2D, translate_texture);
-
        c = pic->width * pic->height;
 
        dest = trans;
@@ -678,10 +588,7 @@ void Draw_TransPicTranslate (int x, int y, qpic_t *pic, byte *translation)
                }
        }
 
-       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);
+       glBindTexture(GL_TEXTURE_2D, GL_LoadTexture ("translatedplayerpic", 64, 64, (void *) trans, false, true, 1));
 
        glColor3f(0.8,0.8,0.8);
        glBegin (GL_QUADS);
@@ -713,6 +620,8 @@ void Draw_ConsoleBackground (int lines)
        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);
+       // LordHavoc: draw version
+       Draw_String(engineversionx, lines - vid.height + engineversiony, engineversion, 9999);
 }
 
 /*
@@ -845,587 +754,3 @@ void SHOWLMP_clear()
        for (i = 0;i < SHOWLMP_MAXLABELS;i++)
                showlmp[i].isactive = false;
 }
-
-//====================================================================
-
-/*
-================
-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;
-}
-
-extern byte qgamma[];
-
-// 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)
-       {
-               xi = (int) f;
-               if (xi != oldx)
-               {
-                       in += (xi - oldx) * 4;
-                       oldx = xi;
-               }
-               if (xi < (inwidth-1))
-               {
-                       l2 = f - xi;
-                       l1 = 1 - l2;
-                       *out++ = qgamma[(byte) (in[0] * l1 + in[4] * l2)];
-                       *out++ = qgamma[(byte) (in[1] * l1 + in[5] * l2)];
-                       *out++ = qgamma[(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
-               {
-                       *out++ = qgamma[in[0]];
-                       *out++ = qgamma[in[1]];
-                       *out++ = qgamma[in[2]];
-                       *out++ =        in[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)
-               {
-                       yi = (int) f;
-                       if (yi != oldy)
-                       {
-                               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++)
-                               {
-                                       *out++ = (byte) (*row1++ * l1 + *row2++ * l2);
-                                       *out++ = (byte) (*row1++ * l1 + *row2++ * l2);
-                                       *out++ = (byte) (*row1++ * l1 + *row2++ * l2);
-                                       *out++ = (byte) (*row1++ * l1 + *row2++ * l2);
-                               }
-                               row1 -= outwidth*4;
-                               row2 -= outwidth*4;
-                       }
-                       else // last line has no pixels to lerp to
-                       {
-                               for (j = 0;j < outwidth;j++)
-                               {
-                                       *out++ = *row1++;
-                                       *out++ = *row1++;
-                                       *out++ = *row1++;
-                                       *out++ = *row1++;
-                               }
-                               row1 -= outwidth*4;
-                       }
-               }
-               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)
-                       {
-                               inpix = inrow + ((frac >> 14) & ~3);*out++ = qgamma[*inpix++];*out++ = qgamma[*inpix++];*out++ = qgamma[*inpix++];*out++ =       *inpix++ ;frac += fracstep;
-                               inpix = inrow + ((frac >> 14) & ~3);*out++ = qgamma[*inpix++];*out++ = qgamma[*inpix++];*out++ = qgamma[*inpix++];*out++ =       *inpix++ ;frac += fracstep;
-                               inpix = inrow + ((frac >> 14) & ~3);*out++ = qgamma[*inpix++];*out++ = qgamma[*inpix++];*out++ = qgamma[*inpix++];*out++ =       *inpix++ ;frac += fracstep;
-                               inpix = inrow + ((frac >> 14) & ~3);*out++ = qgamma[*inpix++];*out++ = qgamma[*inpix++];*out++ = qgamma[*inpix++];*out++ =       *inpix++ ;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;
-       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;
-
-       if (alpha)
-       {
-               alpha = false;
-               in = data;
-               for (i = 3;i < width*height*4;i += 4)
-                       if (in[i] != 255)
-                       {
-                               alpha = true;
-                               break;
-                       }
-       }
-
-       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++ = qgamma[*in++];
-                       *out++ = qgamma[*in++];
-                       *out++ = qgamma[*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 = NULL;
-
-       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
-                       {
-                               trans[i] = 0; // force to black
-                               noalpha = false;
-                       }
-               }
-
-               if (noalpha)
-               {
-                       if (VID_Is8bit() && (data!=scrap_texels[0]))
-                       {
-                               GL_Upload8_EXT (data, width, height, mipmap);
-                               free(trans);
-                               return;
-                       }
-                       alpha = false;
-               }
-       }
-       else
-       {
-               // LordHavoc: dodge the copy if it will be uploaded as 8bit
-               if (VID_Is8bit() && (data!=scrap_texels[0]))
-               {
-                       GL_Upload8_EXT (data, width, height, mipmap);
-                       free(trans);
-                       return;
-               }
-               //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 (!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;
-                       }
-               }
-       }
-       // 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;
-}
-
-/*
-================
-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;
-}
diff --git a/gl_models.c b/gl_models.c
new file mode 100644 (file)
index 0000000..636018d
--- /dev/null
@@ -0,0 +1,802 @@
+
+#include "quakedef.h"
+
+// LordHavoc: vertex array
+float *aliasvert;
+float *aliasvertnorm;
+byte *aliasvertcolor;
+byte *aliasvertcolor2;
+
+int chrometexture;
+
+void makechrometexture()
+{
+       int i;
+       byte noise[64*64];
+       byte data[64*64][4];
+
+       fractalnoise(noise, 64);
+
+       // convert to RGBA data
+       for (i = 0;i < 64*64;i++)
+       {
+               data[i][0] = data[i][1] = data[i][2] = noise[i];
+               data[i][3] = 255;
+       }
+
+       chrometexture = GL_LoadTexture ("chrometexture", 64, 64, &data[0][0], true, false, 4);
+}
+
+void gl_models_start()
+{
+       // allocate vertex processing arrays
+       aliasvert = malloc(sizeof(float[MD2MAX_VERTS][3]));
+       aliasvertnorm = malloc(sizeof(float[MD2MAX_VERTS][3]));
+       aliasvertcolor = malloc(sizeof(byte[MD2MAX_VERTS][4]));
+       aliasvertcolor2 = malloc(sizeof(byte[MD2MAX_VERTS][4])); // used temporarily for tinted coloring
+       makechrometexture();
+}
+
+void gl_models_shutdown()
+{
+       free(aliasvert);
+       free(aliasvertnorm);
+       free(aliasvertcolor);
+       free(aliasvertcolor2);
+}
+
+void GL_Models_Init()
+{
+       R_RegisterModule("GL_Models", gl_models_start, gl_models_shutdown);
+}
+
+extern vec3_t softwaretransform_x;
+extern vec3_t softwaretransform_y;
+extern vec3_t softwaretransform_z;
+extern vec_t softwaretransform_scale;
+extern vec3_t softwaretransform_offset;
+void R_AliasLerpVerts(int vertcount, float lerp, trivert2 *verts1, vec3_t scale1, vec3_t translate1, trivert2 *verts2, vec3_t scale2, vec3_t translate2)
+{
+       int i;
+       vec3_t point, matrix_x, matrix_y, matrix_z;
+       float *av, *avn;
+       av = aliasvert;
+       avn = aliasvertnorm;
+       VectorScale(softwaretransform_x, softwaretransform_scale, matrix_x);
+       VectorScale(softwaretransform_y, softwaretransform_scale, matrix_y);
+       VectorScale(softwaretransform_z, softwaretransform_scale, matrix_z);
+       if (lerp < 0) lerp = 0;
+       if (lerp > 1) lerp = 1;
+       if (lerp != 0)
+       {
+               float ilerp, ilerp127, lerp127, scalex1, scalex2, translatex, scaley1, scaley2, translatey, scalez1, scalez2, translatez;
+               if (lerp < 0) lerp = 0;
+               if (lerp > 1) lerp = 1;
+               ilerp = 1 - lerp;
+               ilerp127 = ilerp * (1.0 / 127.0);
+               lerp127 = lerp * (1.0 / 127.0);
+               // calculate combined interpolation variables
+               scalex1 = scale1[0] * ilerp;scalex2 = scale2[0] *  lerp;translatex = translate1[0] * ilerp + translate2[0] *  lerp;
+               scaley1 = scale1[1] * ilerp;scaley2 = scale2[1] *  lerp;translatey = translate1[1] * ilerp + translate2[1] *  lerp;
+               scalez1 = scale1[2] * ilerp;scalez2 = scale2[2] *  lerp;translatez = translate1[2] * ilerp + translate2[2] *  lerp;
+               // generate vertices
+               for (i = 0;i < vertcount;i++)
+               {
+                       // rotate, scale, and translate the vertex locations
+                       point[0] = verts1->v[0] * scalex1 + verts2->v[0] * scalex2 + translatex;
+                       point[1] = verts1->v[1] * scaley1 + verts2->v[1] * scaley2 + translatey;
+                       point[2] = verts1->v[2] * scalez1 + verts2->v[2] * scalez2 + translatez;
+                       *av++ = point[0] * matrix_x[0] + point[1] * matrix_y[0] + point[2] * matrix_z[0] + softwaretransform_offset[0];
+                       *av++ = point[0] * matrix_x[1] + point[1] * matrix_y[1] + point[2] * matrix_z[1] + softwaretransform_offset[1];
+                       *av++ = point[0] * matrix_x[2] + point[1] * matrix_y[2] + point[2] * matrix_z[2] + softwaretransform_offset[2];
+                       // rotate the normals
+                       point[0] = verts1->n[0] * ilerp127 + verts2->n[0] * lerp127;
+                       point[1] = verts1->n[1] * ilerp127 + verts2->n[1] * lerp127;
+                       point[2] = verts1->n[2] * ilerp127 + verts2->n[2] * lerp127;
+                       *avn++ = point[0] * softwaretransform_x[0] + point[1] * softwaretransform_y[0] + point[2] * softwaretransform_z[0];
+                       *avn++ = point[0] * softwaretransform_x[1] + point[1] * softwaretransform_y[1] + point[2] * softwaretransform_z[1];
+                       *avn++ = point[0] * softwaretransform_x[2] + point[1] * softwaretransform_y[2] + point[2] * softwaretransform_z[2];
+                       verts1++;verts2++;
+               }
+       }
+       else
+       {
+               // generate vertices
+               for (i = 0;i < vertcount;i++)
+               {
+                       // rotate, scale, and translate the vertex locations
+                       point[0] = verts1->v[0] * scale1[0] + translate1[0];
+                       point[1] = verts1->v[1] * scale1[1] + translate1[1];
+                       point[2] = verts1->v[2] * scale1[2] + translate1[2];
+                       *av++ = point[0] * matrix_x[0] + point[1] * matrix_y[0] + point[2] * matrix_z[0] + softwaretransform_offset[0];
+                       *av++ = point[0] * matrix_x[1] + point[1] * matrix_y[1] + point[2] * matrix_z[1] + softwaretransform_offset[1];
+                       *av++ = point[0] * matrix_x[2] + point[1] * matrix_y[2] + point[2] * matrix_z[2] + softwaretransform_offset[2];
+                       // rotate the normals
+                       point[0] = verts1->n[0] * (1.0f / 127.0f);
+                       point[1] = verts1->n[1] * (1.0f / 127.0f);
+                       point[2] = verts1->n[2] * (1.0f / 127.0f);
+                       *avn++ = point[0] * softwaretransform_x[0] + point[1] * softwaretransform_y[0] + point[2] * softwaretransform_z[0];
+                       *avn++ = point[0] * softwaretransform_x[1] + point[1] * softwaretransform_y[1] + point[2] * softwaretransform_z[1];
+                       *avn++ = point[0] * softwaretransform_x[2] + point[1] * softwaretransform_y[2] + point[2] * softwaretransform_z[2];
+                       verts1++;
+               }
+       }
+}
+
+float R_CalcAnimLerp(entity_t *ent, int pose, float lerpscale)
+{
+       if (ent->draw_lastmodel == ent->model && ent->draw_lerpstart <= cl.time)
+       {
+               if (pose != ent->draw_pose)
+               {
+                       ent->draw_lastpose = ent->draw_pose;
+                       ent->draw_pose = pose;
+                       ent->draw_lerpstart = cl.time;
+                       return 0;
+               }
+               else
+                       return ((cl.time - ent->draw_lerpstart) * lerpscale);
+       }
+       else // uninitialized
+       {
+               ent->draw_lastmodel = ent->model;
+               ent->draw_lastpose = ent->draw_pose = pose;
+               ent->draw_lerpstart = cl.time;
+               return 0;
+       }
+}
+
+extern cvar_t gl_vertexarrays;
+extern qboolean lighthalf;
+void GL_DrawModelMesh(int skin, byte *colors, maliashdr_t *maliashdr)
+{
+       int i;
+       glBindTexture(GL_TEXTURE_2D, skin);
+       if (!colors)
+       {
+               if (lighthalf)
+                       glColor3f(0.5f, 0.5f, 0.5f);
+               else
+                       glColor3f(1.0f, 1.0f, 1.0f);
+       }
+       if (gl_vertexarrays.value)
+       {
+//             qglVertexPointer(3, GL_FLOAT, 0, aliasvert);
+//             glEnableClientState(GL_VERTEX_ARRAY);
+               if (colors)
+               {
+                       qglColorPointer(4, GL_UNSIGNED_BYTE, 0, colors);
+                       glEnableClientState(GL_COLOR_ARRAY);
+               }
+
+               qglTexCoordPointer(2, GL_FLOAT, 0, (void *)((int) maliashdr->texdata + (int) maliashdr));
+               glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+
+               qglDrawElements(GL_TRIANGLES, maliashdr->numtris * 3, GL_UNSIGNED_SHORT, (void *)((int) maliashdr + maliashdr->tridata));
+
+               glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+               /*
+               // draw the front faces
+               qglTexCoordPointer(2, GL_FLOAT, 0, (void *)((int) paliashdr->texcoords + (int) paliashdr));
+               glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+               qglDrawElements(GL_TRIANGLES, paliashdr->frontfaces * 3, GL_UNSIGNED_SHORT, (void *)((int) paliashdr->vertindices + (int) paliashdr));
+               glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+
+               // draw the back faces
+               qglTexCoordPointer(2, GL_FLOAT, 0, (void *)((int) paliashdr->texcoords + sizeof(float[2]) * paliashdr->numverts + (int) paliashdr));
+               glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+               qglDrawElements(GL_TRIANGLES, paliashdr->backfaces * 3, GL_UNSIGNED_SHORT, (void *)((int) paliashdr->vertindices + sizeof(unsigned short[3]) * paliashdr->frontfaces + (int) paliashdr));
+               glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+               */
+
+               if (colors)
+                       glDisableClientState(GL_COLOR_ARRAY);
+//             glDisableClientState(GL_VERTEX_ARRAY);
+       }
+       else
+       {
+               unsigned short *in, index;
+               float *tex;
+               in = (void *)((int) maliashdr + maliashdr->tridata);
+               glBegin(GL_TRIANGLES);
+               tex = (void *)((int) maliashdr + maliashdr->texdata);
+               for (i = 0;i < maliashdr->numtris * 3;i++)
+               {
+                       index = *in++;
+                       glTexCoord2f(tex[index*2], tex[index*2+1]);
+                       if (colors)
+                               glColor4f(colors[index*4] * (1.0f / 255.0f), colors[index*4+1] * (1.0f / 255.0f), colors[index*4+2] * (1.0f / 255.0f), colors[index*4+3] * (1.0f / 255.0f));
+                       glVertex3fv(&aliasvert[index*3]);
+               }
+               glEnd();
+               /*
+               in = (void *)((int) paliashdr->vertindices + (int) paliashdr);
+               glBegin(GL_TRIANGLES);
+               // draw the front faces
+               tex = (void *)((int) paliashdr->texcoords + (int) paliashdr);
+               //if (isG200)
+               //{
+                       for (i = 0;i < paliashdr->frontfaces * 3;i++)
+                       {
+                               index = *in++;
+                               glTexCoord2f(tex[index*2], tex[index*2+1]);
+                               if (colors)
+                                       glColor4f(colors[index*4] * (1.0f / 255.0f), colors[index*4+1] * (1.0f / 255.0f), colors[index*4+2] * (1.0f / 255.0f), colors[index*4+3] * (1.0f / 255.0f));
+                               glVertex3fv(&aliasvert[index*3]);
+                       }
+               */
+               /*
+               }
+               else
+               {
+                       for (i = 0;i < paliashdr->frontfaces * 3;i++)
+                       {
+                               index = *in++;
+                               glTexCoord2f(tex[index*2], tex[index*2+1]);
+                               glColor4ub(colors[index*4], colors[index*4+1], colors[index*4+2], colors[index*4+3]);
+                               glVertex3fv(&aliasvert[index*3]);
+                       }
+               }
+               */
+               /*
+               // draw the back faces
+               tex += 2 * paliashdr->numverts;
+               //if (isG200)
+               //{
+                       for (i = 0;i < paliashdr->backfaces * 3;i++)
+                       {
+                               index = *in++;
+                               glTexCoord2f(tex[index*2], tex[index*2+1]);
+                               if (colors)
+                                       glColor4f(colors[index*4] * (1.0f / 255.0f), colors[index*4+1] * (1.0f / 255.0f), colors[index*4+2] * (1.0f / 255.0f), colors[index*4+3] * (1.0f / 255.0f));
+                               glVertex3fv(&aliasvert[index*3]);
+                       }
+               */
+               /*
+               }
+               else
+               {
+                       for (i = 0;i < paliashdr->backfaces * 3;i++)
+                       {
+                               index = *in++;
+                               glTexCoord2f(tex[index*2], tex[index*2+1]);
+                               glColor4ub(colors[index*4], colors[index*4+1], colors[index*4+2], colors[index*4+3]);
+                               glVertex3fv(&aliasvert[index*3]);
+                       }
+               }
+               */
+               /*
+               glEnd();
+               */
+       }
+       // leave it in a state for additional passes
+       glDepthMask(0);
+       glEnable(GL_BLEND);
+       glBlendFunc(GL_SRC_ALPHA, GL_ONE); // additive
+}
+
+void R_TintModel(byte *in, byte *out, int verts, byte *color)
+{
+       int i;
+       byte r = color[0];
+       byte g = color[1];
+       byte b = color[2];
+       for (i = 0;i < verts;i++)
+       {
+               out[0] = (byte) ((in[0] * r) >> 8);
+               out[1] = (byte) ((in[1] * g) >> 8);
+               out[2] = (byte) ((in[2] * b) >> 8);
+               out[3] =          in[3];
+               in += 4;
+               out += 4;
+       }
+}
+
+/*
+=================
+R_DrawAliasFrame
+
+=================
+*/
+extern vec3_t lightspot;
+void R_LightModel(int numverts, vec3_t center, vec3_t basecolor);
+void R_DrawAliasFrame (maliashdr_t *maliashdr, float alpha, vec3_t color, entity_t *ent, int shadow, vec3_t org, int frame, int *skin, int colormap, int effects, int flags)
+{
+       int             i, pose;
+       float   lerpscale, lerp;
+       maliasframe_t *frameinfo;
+
+       softwaretransformforentity(ent);
+
+       if ((frame >= maliashdr->numframes) || (frame < 0))
+       {
+               Con_DPrintf ("R_AliasSetupFrame: no such frame %d\n", frame);
+               frame = 0;
+       }
+
+       frameinfo = ((maliasframe_t *)((int) maliashdr + maliashdr->framedata)) + frame;
+       pose = frameinfo->start;
+
+       if (frameinfo->length > 1)
+       {
+               lerpscale = frameinfo->rate;
+               pose += (int)(cl.time * frameinfo->rate) % frameinfo->length;
+       }
+       else
+               lerpscale = 10.0f;
+
+       lerp = R_CalcAnimLerp(ent, pose, lerpscale);
+
+       R_AliasLerpVerts(maliashdr->numverts, lerp, (trivert2 *)((int) maliashdr + maliashdr->posedata) + ent->draw_lastpose * maliashdr->numverts, maliashdr->scale, maliashdr->scale_origin, (trivert2 *)((int) maliashdr + maliashdr->posedata) + ent->draw_pose * maliashdr->numverts, maliashdr->scale, maliashdr->scale_origin);
+
+       // prep the vertex array as early as possible
+       if (gl_vertexarrays.value)
+       {
+               qglVertexPointer(3, GL_FLOAT, 0, aliasvert);
+               glEnableClientState(GL_VERTEX_ARRAY);
+       }
+
+       R_LightModel(maliashdr->numverts, org, color);
+
+       glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+       glShadeModel(GL_SMOOTH);
+       if (effects & EF_ADDITIVE)
+       {
+               glBlendFunc(GL_SRC_ALPHA, GL_ONE); // additive rendering
+               glEnable(GL_BLEND);
+               glDepthMask(0);
+       }
+       else if (alpha != 1.0)
+       {
+               glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+               glEnable(GL_BLEND);
+               glDepthMask(0);
+       }
+       else
+       {
+               glDisable(GL_BLEND);
+               glDepthMask(1);
+       }
+
+       if (colormap >= 0)
+       {
+               if (!skin[0] && !skin[1] && !skin[2] && !skin[3])
+                       GL_DrawModelMesh(0, NULL, maliashdr);
+               else
+               {
+                       int c;
+                       if (skin[0])
+                               GL_DrawModelMesh(skin[0], aliasvertcolor, maliashdr);
+                       if (skin[1])
+                       {
+                               c = (colormap & 0xF) << 4;c += (c >= 128 && c < 224) ? 4 : 12; // 128-224 are backwards ranges
+                               R_TintModel(aliasvertcolor, aliasvertcolor2, maliashdr->numverts, (byte *) (&d_8to24table[c]));
+                               GL_DrawModelMesh(skin[1], aliasvertcolor2, maliashdr);
+                       }
+                       if (skin[2])
+                       {
+                               c = colormap & 0xF0      ;c += (c >= 128 && c < 224) ? 4 : 12; // 128-224 are backwards ranges
+                               R_TintModel(aliasvertcolor, aliasvertcolor2, maliashdr->numverts, (byte *) (&d_8to24table[c]));
+                               GL_DrawModelMesh(skin[2], aliasvertcolor2, maliashdr);
+                       }
+                       if (skin[3]) GL_DrawModelMesh(skin[3], NULL, maliashdr);
+               }
+       }
+       else
+       {
+               if (!skin[3] && !skin[4])
+                       GL_DrawModelMesh(0, NULL, maliashdr);
+               else
+               {
+                       if (skin[4]) GL_DrawModelMesh(skin[4], aliasvertcolor, maliashdr);
+                       if (skin[3]) GL_DrawModelMesh(skin[3], NULL, maliashdr);
+               }
+       }
+
+       if (fogenabled)
+       {
+               vec3_t diff;
+               glDisable (GL_TEXTURE_2D);
+               glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+               glEnable (GL_BLEND);
+               glDepthMask(0); // disable zbuffer updates
+
+               VectorSubtract(org, r_refdef.vieworg, diff);
+               glColor4f(fogcolor[0], fogcolor[1], fogcolor[2], exp(fogdensity/DotProduct(diff,diff)));
+
+               if (gl_vertexarrays.value)
+               {
+//                     qglVertexPointer(3, GL_FLOAT, 0, aliasvert);
+//                     glEnableClientState(GL_VERTEX_ARRAY);
+                       qglDrawElements(GL_TRIANGLES, maliashdr->numtris * 3, GL_UNSIGNED_SHORT, (void *)((int) maliashdr + maliashdr->tridata));
+//                     glDisableClientState(GL_VERTEX_ARRAY);
+               }
+               else
+               {
+                       unsigned short *in;
+                       in = (void *)((int) maliashdr + maliashdr->tridata);
+                       glBegin(GL_TRIANGLES);
+                       for (i = 0;i < maliashdr->numtris * 3;i++)
+                               glVertex3fv(&aliasvert[*in++ * 3]);
+                       glEnd();
+               }
+
+               glEnable (GL_TEXTURE_2D);
+               glColor3f (1,1,1);
+       }
+       if (gl_vertexarrays.value)
+               glDisableClientState(GL_VERTEX_ARRAY);
+
+       if (!fogenabled && r_shadows.value && !(effects & EF_ADDITIVE) && shadow)
+       {
+               // flatten it to make a shadow
+               float *av = aliasvert + 2, l = lightspot[2] + 0.125;
+               av = aliasvert + 2;
+               for (i = 0;i < maliashdr->numverts;i++, av+=3)
+                       if (*av > l)
+                               *av = l;
+               glDisable (GL_TEXTURE_2D);
+               glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+               glEnable (GL_BLEND);
+               glDepthMask(0); // disable zbuffer updates
+               glColor4f (0,0,0,0.5 * alpha);
+
+               if (gl_vertexarrays.value)
+               {
+                       qglVertexPointer(3, GL_FLOAT, 0, aliasvert);
+                       glEnableClientState(GL_VERTEX_ARRAY);
+                       qglDrawElements(GL_TRIANGLES, maliashdr->numtris * 3, GL_UNSIGNED_SHORT, (void *)((int) maliashdr + maliashdr->tridata));
+                       glDisableClientState(GL_VERTEX_ARRAY);
+               }
+               else
+               {
+                       unsigned short *in;
+                       in = (void *)((int) maliashdr + maliashdr->tridata);
+                       glBegin(GL_TRIANGLES);
+                       for (i = 0;i < maliashdr->numtris * 3;i++)
+                               glVertex3fv(&aliasvert[*in++ * 3]);
+                       glEnd();
+               }
+
+               glEnable (GL_TEXTURE_2D);
+               glColor3f (1,1,1);
+       }
+
+       glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+       glEnable (GL_BLEND);
+       glDepthMask(1);
+}
+
+/*
+=================
+R_DrawQ2AliasFrame
+
+=================
+*/
+void R_DrawQ2AliasFrame (md2mem_t *pheader, float alpha, vec3_t color, entity_t *ent, int shadow, vec3_t org, int frame, int skin, int effects, int flags)
+{
+       int *order, count;
+       float lerp;
+       md2memframe_t *frame1, *frame2;
+
+       glBindTexture(GL_TEXTURE_2D, skin);
+
+       softwaretransformforentity(ent);
+
+       if ((frame >= pheader->num_frames) || (frame < 0))
+       {
+               Con_DPrintf ("R_SetupQ2AliasFrame: no such frame %d\n", frame);
+               frame = 0;
+       }
+
+       lerp = R_CalcAnimLerp(ent, frame, 10);
+
+       frame1 = (void *)((int) pheader + pheader->ofs_frames + (pheader->framesize * ent->draw_lastpose));
+       frame2 = (void *)((int) pheader + pheader->ofs_frames + (pheader->framesize * ent->draw_pose));
+       R_AliasLerpVerts(pheader->num_xyz, lerp, frame1->verts, frame1->scale, frame1->translate, frame2->verts, frame2->scale, frame2->translate);
+
+       R_LightModel(pheader->num_xyz, org, color);
+
+       if (gl_vertexarrays.value)
+       {
+               // LordHavoc: big mess...
+               // using arrays only slightly, although it is enough to prevent duplicates
+               // (saving half the transforms)
+               qglVertexPointer(3, GL_FLOAT, 0, aliasvert);
+               qglColorPointer(4, GL_UNSIGNED_BYTE, 0, aliasvertcolor);
+               glEnableClientState(GL_VERTEX_ARRAY);
+               glEnableClientState(GL_COLOR_ARRAY);
+
+               order = (int *)((int)pheader + pheader->ofs_glcmds);
+               while(1)
+               {
+                       if (!(count = *order++))
+                               break;
+                       if (count > 0)
+                               glBegin(GL_TRIANGLE_STRIP);
+                       else
+                       {
+                               glBegin(GL_TRIANGLE_FAN);
+                               count = -count;
+                       }
+                       do
+                       {
+                               glTexCoord2f(((float *)order)[0], ((float *)order)[1]);
+                               qglArrayElement(order[2]);
+                               order += 3;
+                       }
+                       while (count--);
+               }
+
+               glDisableClientState(GL_COLOR_ARRAY);
+               glDisableClientState(GL_VERTEX_ARRAY);
+       }
+       else
+       {
+               order = (int *)((int)pheader + pheader->ofs_glcmds);
+               while(1)
+               {
+                       if (!(count = *order++))
+                               break;
+                       if (count > 0)
+                               glBegin(GL_TRIANGLE_STRIP);
+                       else
+                       {
+                               glBegin(GL_TRIANGLE_FAN);
+                               count = -count;
+                       }
+                       //if (isG200)
+                       //{
+                               do
+                               {
+                                       glTexCoord2f(((float *)order)[0], ((float *)order)[1]);
+                                       glColor4f(aliasvertcolor[order[2] * 4] * (1.0f / 255.0f), aliasvertcolor[order[2] * 4 + 1] * (1.0f / 255.0f), aliasvertcolor[order[2] * 4 + 2] * (1.0f / 255.0f), aliasvertcolor[order[2] * 4 + 3] * (1.0f / 255.0f));
+                                       glVertex3fv(&aliasvert[order[2] * 3]);
+                                       order += 3;
+                               }
+                               while (count--);
+                       /*
+                       }
+                       else
+                       {
+                               do
+                               {
+                                       glTexCoord2f(((float *)order)[0], ((float *)order)[1]);
+                                       glColor4ub(aliasvertcolor[order[2] * 4], aliasvertcolor[order[2] * 4 + 1], aliasvertcolor[order[2] * 4 + 2], aliasvertcolor[order[2] * 4 + 3]);
+                                       glVertex3fv(&aliasvert[order[2] * 3]);
+                                       order += 3;
+                               }
+                               while (count--);
+                       }
+                       */
+               }
+       }
+
+       if (fogenabled)
+       {
+               glDisable (GL_TEXTURE_2D);
+               glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+               glEnable (GL_BLEND);
+               glDepthMask(0); // disable zbuffer updates
+               {
+                       vec3_t diff;
+                       VectorSubtract(org, r_refdef.vieworg, diff);
+                       glColor4f(fogcolor[0], fogcolor[1], fogcolor[2], exp(fogdensity/DotProduct(diff,diff)));
+               }
+
+               if (gl_vertexarrays.value)
+               {
+                       // LordHavoc: big mess...
+                       // using arrays only slightly, although it is enough to prevent duplicates
+                       // (saving half the transforms)
+                       qglVertexPointer(3, GL_FLOAT, 0, aliasvert);
+                       glEnableClientState(GL_VERTEX_ARRAY);
+
+                       order = (int *)((int)pheader + pheader->ofs_glcmds);
+                       while(1)
+                       {
+                               if (!(count = *order++))
+                                       break;
+                               if (count > 0)
+                                       glBegin(GL_TRIANGLE_STRIP);
+                               else
+                               {
+                                       glBegin(GL_TRIANGLE_FAN);
+                                       count = -count;
+                               }
+                               do
+                               {
+                                       qglArrayElement(order[2]);
+                                       order += 3;
+                               }
+                               while (count--);
+                       }
+
+                       glDisableClientState(GL_VERTEX_ARRAY);
+               }
+               else
+               {
+                       order = (int *)((int)pheader + pheader->ofs_glcmds);
+                       while(1)
+                       {
+                               if (!(count = *order++))
+                                       break;
+                               if (count > 0)
+                                       glBegin(GL_TRIANGLE_STRIP);
+                               else
+                               {
+                                       glBegin(GL_TRIANGLE_FAN);
+                                       count = -count;
+                               }
+                               do
+                               {
+                                       glVertex3fv(&aliasvert[order[2] * 3]);
+                                       order += 3;
+                               }
+                               while (count--);
+                       }
+               }
+
+               glEnable (GL_TEXTURE_2D);
+               glColor3f (1,1,1);
+       }
+
+       if (!fogenabled && r_shadows.value && !(effects & EF_ADDITIVE) && shadow)
+       {
+               int i;
+               float *av = aliasvert + 2, l = lightspot[2] + 0.125;
+               av = aliasvert + 2;
+               for (i = 0;i < pheader->num_xyz;i++, av+=3)
+                       if (*av > l)
+                               *av = l;
+               glDisable (GL_TEXTURE_2D);
+               glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+               glEnable (GL_BLEND);
+               glDepthMask(0); // disable zbuffer updates
+               glColor4f (0,0,0,0.5 * alpha);
+
+               if (gl_vertexarrays.value)
+               {
+                       qglVertexPointer(3, GL_FLOAT, 0, aliasvert);
+                       glEnableClientState(GL_VERTEX_ARRAY);
+                                               
+                       while(1)
+                       {
+                               if (!(count = *order++))
+                                       break;
+                               if (count > 0)
+                                       glBegin(GL_TRIANGLE_STRIP);
+                               else
+                               {
+                                       glBegin(GL_TRIANGLE_FAN);
+                                       count = -count;
+                               }
+                               do
+                               {
+                                       qglArrayElement(order[2]);
+                                       order += 3;
+                               }
+                               while (count--);
+                       }
+
+                       glDisableClientState(GL_VERTEX_ARRAY);
+               }
+               else
+               {
+                       while(1)
+                       {
+                               if (!(count = *order++))
+                                       break;
+                               if (count > 0)
+                                       glBegin(GL_TRIANGLE_STRIP);
+                               else
+                               {
+                                       glBegin(GL_TRIANGLE_FAN);
+                                       count = -count;
+                               }
+                               do
+                               {
+                                       glVertex3fv(&aliasvert[order[2] * 3]);
+                                       order += 3;
+                               }
+                               while (count--);
+                       }
+               }
+
+               glEnable (GL_TEXTURE_2D);
+               glColor3f (1,1,1);
+       }
+
+       glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+       glEnable (GL_BLEND);
+       glDepthMask(1);
+}
+
+int modeldlightbits[8];
+extern int r_dlightframecount;
+extern void R_LightPoint (vec3_t color, vec3_t p);
+
+/*
+=================
+R_DrawAliasModel
+
+=================
+*/
+void R_DrawAliasModel (entity_t *ent, int cull, float alpha, model_t *clmodel, int frame, int skin, vec3_t org, int effects, int flags, int colormap)
+{
+       int                     i;
+       vec3_t          mins, maxs, color;
+//     aliashdr_t      *paliashdr = NULL;
+//     md2mem_t        *pheader = NULL;
+       mleaf_t         *leaf;
+       void            *modelheader;
+       int                     *skinset;
+
+       if (alpha < (1.0 / 64.0))
+               return; // basically completely transparent
+
+       VectorAdd (org, clmodel->mins, mins);
+       VectorAdd (org, clmodel->maxs, maxs);
+
+       if (cull && R_CullBox (mins, maxs))
+               return;
+
+       leaf = Mod_PointInLeaf (org, cl.worldmodel);
+       if (leaf->dlightframe == r_dlightframecount)
+               for (i = 0;i < 8;i++)
+                       modeldlightbits[i] = leaf->dlightbits[i];
+       else
+               for (i = 0;i < 8;i++)
+                       modeldlightbits[i] = 0;
+
+       // get lighting information
+
+       if ((flags & EF_FULLBRIGHT) || (effects & EF_FULLBRIGHT))
+               color[0] = color[1] = color[2] = 256;
+       else
+       {
+               // HACK HACK HACK -- no fullbright colors, so make torches full light
+               if (!strcmp (clmodel->name, "progs/flame2.mdl") || !strcmp (clmodel->name, "progs/flame.mdl") )
+                       color[0] = color[1] = color[2] = 128;
+               else
+                       R_LightPoint (color, org);
+       }
+
+       glDisable(GL_ALPHA_TEST);
+
+       if (frame < 0 || frame >= clmodel->numframes)
+       {
+               frame = 0;
+               Con_DPrintf("invalid skin number %d for model %s\n", frame, clmodel->name);
+       }
+
+       if (skin < 0 || skin >= clmodel->numskins)
+       {
+               skin = 0;
+               Con_DPrintf("invalid skin number %d for model %s\n", skin, clmodel->name);
+       }
+
+       modelheader = Mod_Extradata (clmodel);
+
+       {
+//             int *skinanimrange = (int *) (clmodel->skinanimrange + (int) modelheader) + skin * 2;
+//             int *skinanim = (int *) (clmodel->skinanim + (int) modelheader);
+               int *skinanimrange = clmodel->skinanimrange + skin * 2;
+               int *skinanim = clmodel->skinanim;
+               i = skinanimrange[0];
+               if (skinanimrange[1] > 1) // animated
+                       i += ((int) (cl.time * 10) % skinanimrange[1]);
+               skinset = skinanim + i*5;
+       }
+
+//     glBindTexture(GL_TEXTURE_2D, paliashdr->gl_texturenum[skin][(int)(cl.time*10) & 3]);
+//     glBindTexture(GL_TEXTURE_2D, pheader->gl_texturenum[skin]);
+
+       glEnable (GL_TEXTURE_2D);
+
+       c_alias_polys += clmodel->numtris;
+       if (clmodel->aliastype == ALIASTYPE_MD2)
+               R_DrawQ2AliasFrame (modelheader, alpha, color, ent, ent != &cl.viewent, org, frame, skinset[0], effects, flags);
+       else
+               R_DrawAliasFrame (modelheader, alpha, color, ent, ent != &cl.viewent, org, frame, skinset, colormap, effects, flags);
+}
index 3947bbd..9750a34 100644 (file)
--- a/gl_poly.c
+++ b/gl_poly.c
@@ -34,11 +34,9 @@ float transviewdist; // distance of view origin along the view normal
 
 float transreciptable[256];
 
-void glpoly_init()
+void gl_poly_start()
 {
        int i;
-       Cvar_RegisterVariable (&gl_multitexture);
-       Cvar_RegisterVariable (&gl_vertexarrays);
        transvert = malloc(MAX_TRANSVERTS * sizeof(transvert_t));
        transpoly = malloc(MAX_TRANSPOLYS * sizeof(transpoly_t));
        transpolyindex = malloc(MAX_TRANSPOLYS * sizeof(unsigned short));
@@ -50,6 +48,23 @@ void glpoly_init()
        for (i = 1;i < 256;i++)
                transreciptable[i] = 1.0f / i;
 }
+void gl_poly_shutdown()
+{
+       free(transvert);
+       free(transpoly);
+       free(transpolyindex);
+       free(wallvert);
+       free(wallpoly);
+       free(skyvert);
+       free(skypoly);
+}
+
+void GL_Poly_Init()
+{
+       Cvar_RegisterVariable (&gl_multitexture);
+       Cvar_RegisterVariable (&gl_vertexarrays);
+       R_RegisterModule("GL_Poly", gl_poly_start, gl_poly_shutdown);
+}
 
 void transpolyclear()
 {
index 753f34e..e880dbd 100644 (file)
@@ -39,7 +39,7 @@ qboolean      envmap;                         // true during envmap command capture
 
 // LordHavoc: moved all code related to particles into r_part.c
 //int                  particletexture;        // little dot for particles
-int                    playertextures;         // up to 16 color translated skins
+//int                  playertextures;         // up to 16 color translated skins
 
 extern qboolean isG200, isRagePro; // LordHavoc: special card hacks
 
@@ -82,17 +82,9 @@ cvar_t       r_novis = {"r_novis","0"};
 cvar_t r_waterripple = {"r_waterripple","0"};
 cvar_t r_fullbrights = {"r_fullbrights", "1"};
 
-//cvar_t       gl_cull = {"gl_cull","1"};
-//cvar_t       gl_affinemodels = {"gl_affinemodels","0"};
-//cvar_t       gl_polyblend = {"gl_polyblend","1"};
-cvar_t gl_playermip = {"gl_playermip","0"};
-//cvar_t       gl_nocolors = {"gl_nocolors","0"};
-//cvar_t       gl_keeptjunctions = {"gl_keeptjunctions","1"};
-//cvar_t       gl_reporttjunctions = {"gl_reporttjunctions","0"};
 cvar_t contrast = {"contrast", "1.0", TRUE}; // LordHavoc: a method of operating system independent color correction
 cvar_t brightness = {"brightness", "1.0", TRUE}; // LordHavoc: a method of operating system independent color correction
 cvar_t gl_lightmode = {"gl_lightmode", "1", TRUE}; // LordHavoc: overbright lighting
-//cvar_t       r_dynamicwater = {"r_dynamicwater", "1"};
 //cvar_t       r_dynamicbothsides = {"r_dynamicbothsides", "1"}; // LordHavoc: can disable dynamic lighting of backfaces, but quake maps are weird so it doesn't always work right...
 cvar_t r_farclip = {"r_farclip", "6144"};
 
@@ -105,74 +97,6 @@ cvar_t      gl_fogstart = {"gl_fogstart", "0"};
 cvar_t gl_fogend = {"gl_fogend","0"};
 cvar_t glfog = {"glfog", "0"};
 
-int chrometexture;
-
-void makechrometextures()
-{
-       int x, y, g, g2, amplitude, noise[64][64], min, max;
-       byte data[64][64][4];
-       //
-       // particle texture
-       //
-       chrometexture = texture_extension_number++;
-    glBindTexture(GL_TEXTURE_2D, chrometexture);
-
-#define n(x,y) noise[(y)&63][(x)&63]
-
-       amplitude = 16777215;
-       g2 = 64;
-       noise[0][0] = 0;
-       for (;(g = g2 >> 1) >= 1;g2 >>= 1)
-       {
-               // subdivide, diamond-square algorythm (really this has little to do with squares)
-               // diamond
-               for (y = 0;y < 64;y += g2)
-                       for (x = 0;x < 64;x += g2)
-                               n(x+g,y+g) = (n(x,y) + n(x+g2,y) + n(x,y+g2) + n(x+g2,y+g2)) >> 2;
-               // square
-               for (y = 0;y < 64;y += g2)
-                       for (x = 0;x < 64;x += g2)
-                       {
-                               n(x+g,y) = (n(x,y) + n(x+g2,y) + n(x+g,y-g) + n(x+g,y+g)) >> 2;
-                               n(x,y+g) = (n(x,y) + n(x,y+g2) + n(x-g,y+g) + n(x+g,y+g)) >> 2;
-                       }
-               // brownian motion theory
-               amplitude >>= 1;
-               for (y = 0;y < 64;y += g)
-                       for (x = 0;x < 64;x += g)
-                               noise[y][x] += rand()&amplitude;
-       }
-       // normalize the noise range
-       min = max = 0;
-       for (y = 0;y < 64;y++)
-               for (x = 0;x < 64;x++)
-               {
-                       if (n(x,y) < min) min = n(x,y);
-                       if (n(x,y) > max) max = n(x,y);
-               }
-       max -= min;
-       for (y = 0;y < 64;y++)
-               for (x = 0;x < 64;x++)
-                       n(x,y) = (n(x,y) - min) * 255 / max;
-
-#undef n
-
-       // convert to RGBA data
-       for (y = 0;y < 64;y++)
-               for (x = 0;x < 64;x++)
-               {
-                       data[y][x][0] = data[y][x][1] = data[y][x][2] = (byte) noise[y][x];
-                       data[y][x][3] = 255;
-               }
-
-       glTexImage2D (GL_TEXTURE_2D, 0, 4, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
-
-       glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-
-       glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-       glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-}
-
 extern qboolean isRagePro;
 
 qboolean lighthalf;
@@ -286,22 +210,16 @@ void FOG_registercvars()
        }
 }
 
-void glpoly_init();
-void glrsurf_init();
-void rlight_init();
-
-// LordHavoc: vertex array
-float *aliasvert;
-float *aliasvertnorm;
-byte *aliasvertcolor;
+void glmain_start()
+{
+}
 
-void rmain_registercvars()
+void glmain_shutdown()
 {
-       // allocate vertex processing arrays
-       aliasvert = malloc(sizeof(float[MD2MAX_VERTS][3]));
-       aliasvertnorm = malloc(sizeof(float[MD2MAX_VERTS][3]));
-       aliasvertcolor = malloc(sizeof(byte[MD2MAX_VERTS][4]));
+}
 
+void GL_Main_Init()
+{
        FOG_registercvars();
        Cvar_RegisterVariable (&r_speeds2);
        Cvar_RegisterVariable (&contrast);
@@ -315,10 +233,34 @@ void rmain_registercvars()
 //     if (gl_vendor && strstr(gl_vendor, "3Dfx"))
 //             gl_lightmode.value = 0;
        Cvar_RegisterVariable (&r_fullbright);
-       makechrometextures();
-       glpoly_init();
-       glrsurf_init();
-       rlight_init();
+       R_RegisterModule("GL_Main", glmain_start, glmain_shutdown);
+}
+
+extern void GL_Draw_Init();
+extern void GL_Main_Init();
+extern void GL_Models_Init();
+extern void GL_Poly_Init();
+extern void GL_Surf_Init();
+extern void GL_Screen_Init();
+extern void GL_Misc_Init();
+extern void R_Crosshairs_Init();
+extern void R_Light_Init();
+extern void R_Particles_Init();
+
+void Render_Init()
+{
+       R_ShutdownModules();
+       GL_Draw_Init();
+       GL_Main_Init();
+       GL_Models_Init();
+       GL_Poly_Init();
+       GL_Surf_Init();
+       GL_Screen_Init();
+       GL_Misc_Init();
+       R_Crosshairs_Init();
+       R_Light_Init();
+       R_Particles_Init();
+       R_StartModules();
 }
 
 /*
@@ -347,32 +289,9 @@ vec3_t     shadecolor;
 
 float  modelalpha;
 
-void R_LightPoint (vec3_t color, vec3_t p);
-void R_DynamicLightPoint(vec3_t color, vec3_t org, int *dlightbits);
-void R_DynamicLightPointNoMask(vec3_t color, vec3_t org);
-
-float R_CalcAnimLerp(int pose, float lerpscale)
-{
-       if (currententity->draw_lastmodel == currententity->model && currententity->draw_lerpstart <= cl.time)
-       {
-               if (pose != currententity->draw_pose)
-               {
-                       currententity->draw_lastpose = currententity->draw_pose;
-                       currententity->draw_pose = pose;
-                       currententity->draw_lerpstart = cl.time;
-                       return 0;
-               }
-               else
-                       return ((cl.time - currententity->draw_lerpstart) * lerpscale);
-       }
-       else // uninitialized
-       {
-               currententity->draw_lastmodel = currententity->model;
-               currententity->draw_lastpose = currententity->draw_pose = pose;
-               currententity->draw_lerpstart = cl.time;
-               return 0;
-       }
-}
+extern void R_LightPoint (vec3_t color, vec3_t p);
+extern void R_DynamicLightPoint(vec3_t color, vec3_t org, int *dlightbits);
+extern void R_DynamicLightPointNoMask(vec3_t color, vec3_t org);
 
 /*
 =============================================================
@@ -530,668 +449,6 @@ void R_DrawSpriteModel (entity_t *e)
                GL_DrawSpriteImage(newframe, org, up, right, shadecolor[0],shadecolor[1],shadecolor[2],e->alpha*255*lerp);
 }
 
-/*
-=============================================================
-
-  ALIAS MODELS
-
-=============================================================
-*/
-
-extern vec3_t softwaretransform_x;
-extern vec3_t softwaretransform_y;
-extern vec3_t softwaretransform_z;
-extern vec_t softwaretransform_scale;
-extern vec3_t softwaretransform_offset;
-void R_AliasLerpVerts(int vertcount, float lerp, trivert2 *verts1, vec3_t scale1, vec3_t translate1, trivert2 *verts2, vec3_t scale2, vec3_t translate2)
-{
-       int i;
-       vec3_t point, matrix_x, matrix_y, matrix_z;
-       float *av, *avn;
-       av = aliasvert;
-       avn = aliasvertnorm;
-       if (lerp < 0) lerp = 0;
-       if (lerp > 1) lerp = 1;
-       if (lerp != 0)
-       {
-               float ilerp, ilerp127, lerp127, scalex1, scalex2, translatex, scaley1, scaley2, translatey, scalez1, scalez2, translatez;
-               if (lerp < 0) lerp = 0;
-               if (lerp > 1) lerp = 1;
-               ilerp = 1 - lerp;
-               ilerp127 = ilerp * (1.0 / 127.0);
-               lerp127 = lerp * (1.0 / 127.0);
-               VectorScale(softwaretransform_x, softwaretransform_scale, matrix_x);
-               VectorScale(softwaretransform_y, softwaretransform_scale, matrix_y);
-               VectorScale(softwaretransform_z, softwaretransform_scale, matrix_z);
-               // calculate combined interpolation variables
-               scalex1 = scale1[0] * ilerp;scalex2 = scale2[0] *  lerp;translatex = translate1[0] * ilerp + translate2[0] *  lerp;
-               scaley1 = scale1[1] * ilerp;scaley2 = scale2[1] *  lerp;translatey = translate1[1] * ilerp + translate2[1] *  lerp;
-               scalez1 = scale1[2] * ilerp;scalez2 = scale2[2] *  lerp;translatez = translate1[2] * ilerp + translate2[2] *  lerp;
-               // generate vertices
-               for (i = 0;i < vertcount;i++)
-               {
-                       // rotate, scale, and translate the vertex locations
-                       point[0] = verts1->v[0] * scalex1 + verts2->v[0] * scalex2 + translatex;
-                       point[1] = verts1->v[1] * scaley1 + verts2->v[1] * scaley2 + translatey;
-                       point[2] = verts1->v[2] * scalez1 + verts2->v[2] * scalez2 + translatez;
-                       *av++ = point[0] * matrix_x[0] + point[1] * matrix_y[0] + point[2] * matrix_z[0] + softwaretransform_offset[0];
-                       *av++ = point[0] * matrix_x[1] + point[1] * matrix_y[1] + point[2] * matrix_z[1] + softwaretransform_offset[1];
-                       *av++ = point[0] * matrix_x[2] + point[1] * matrix_y[2] + point[2] * matrix_z[2] + softwaretransform_offset[2];
-                       // rotate the normals
-                       point[0] = verts1->n[0] * ilerp127 + verts2->n[0] * lerp127;
-                       point[1] = verts1->n[1] * ilerp127 + verts2->n[1] * lerp127;
-                       point[2] = verts1->n[2] * ilerp127 + verts2->n[2] * lerp127;
-                       *avn++ = point[0] * softwaretransform_x[0] + point[1] * softwaretransform_y[0] + point[2] * softwaretransform_z[0];
-                       *avn++ = point[0] * softwaretransform_x[1] + point[1] * softwaretransform_y[1] + point[2] * softwaretransform_z[1];
-                       *avn++ = point[0] * softwaretransform_x[2] + point[1] * softwaretransform_y[2] + point[2] * softwaretransform_z[2];
-                       verts1++;verts2++;
-               }
-       }
-       else
-       {
-               float i127;
-               i127 = 1.0f / 127.0f;
-               VectorScale(softwaretransform_x, softwaretransform_scale, matrix_x);
-               VectorScale(softwaretransform_y, softwaretransform_scale, matrix_y);
-               VectorScale(softwaretransform_z, softwaretransform_scale, matrix_z);
-               // generate vertices
-               for (i = 0;i < vertcount;i++)
-               {
-                       // rotate, scale, and translate the vertex locations
-                       point[0] = verts1->v[0] * scale1[0] + translate1[0];
-                       point[1] = verts1->v[1] * scale1[1] + translate1[1];
-                       point[2] = verts1->v[2] * scale1[2] + translate1[2];
-                       *av++ = point[0] * matrix_x[0] + point[1] * matrix_y[0] + point[2] * matrix_z[0] + softwaretransform_offset[0];
-                       *av++ = point[0] * matrix_x[1] + point[1] * matrix_y[1] + point[2] * matrix_z[1] + softwaretransform_offset[1];
-                       *av++ = point[0] * matrix_x[2] + point[1] * matrix_y[2] + point[2] * matrix_z[2] + softwaretransform_offset[2];
-                       // rotate the normals
-                       point[0] = verts1->n[0] * i127;
-                       point[1] = verts1->n[1] * i127;
-                       point[2] = verts1->n[2] * i127;
-                       *avn++ = point[0] * softwaretransform_x[0] + point[1] * softwaretransform_y[0] + point[2] * softwaretransform_z[0];
-                       *avn++ = point[0] * softwaretransform_x[1] + point[1] * softwaretransform_y[1] + point[2] * softwaretransform_z[1];
-                       *avn++ = point[0] * softwaretransform_x[2] + point[1] * softwaretransform_y[2] + point[2] * softwaretransform_z[2];
-                       verts1++;
-               }
-       }
-}
-
-/*
-=================
-R_DrawAliasFrame
-
-=================
-*/
-extern vec3_t lightspot;
-void R_LightModel(int numverts, vec3_t center);
-extern cvar_t gl_vertexarrays;
-void R_DrawAliasFrame (aliashdr_t *paliashdr)
-{
-       int                             i, pose, frame = currententity->frame;
-       float                   lerpscale, lerp;
-
-       softwaretransformforentity(currententity);
-
-       if ((frame >= paliashdr->numframes) || (frame < 0))
-       {
-               Con_DPrintf ("R_AliasSetupFrame: no such frame %d\n", frame);
-               frame = 0;
-       }
-
-       pose = paliashdr->frames[frame].firstpose;
-
-       if (paliashdr->frames[frame].numposes > 1)
-       {
-               lerpscale = 1.0 / paliashdr->frames[frame].interval;
-               pose += (int)(cl.time * lerpscale) % paliashdr->frames[frame].numposes;
-       }
-       else
-               lerpscale = 10.0;
-
-       lerp = R_CalcAnimLerp(pose, lerpscale);
-
-       R_AliasLerpVerts(paliashdr->numverts, lerp, (trivert2 *)((byte *)paliashdr + paliashdr->posedata) + currententity->draw_lastpose * paliashdr->numverts, paliashdr->scale, paliashdr->scale_origin, (trivert2 *)((byte *)paliashdr + paliashdr->posedata) + currententity->draw_pose * paliashdr->numverts, paliashdr->scale, paliashdr->scale_origin);
-
-       R_LightModel(paliashdr->numverts, currententity->origin);
-
-       glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-       glShadeModel(GL_SMOOTH);
-       if (currententity->effects & EF_ADDITIVE)
-       {
-               glBlendFunc(GL_SRC_ALPHA, GL_ONE); // additive rendering
-               glEnable(GL_BLEND);
-               glDepthMask(0);
-       }
-       else if (modelalpha != 1.0)
-       {
-               glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-               glEnable(GL_BLEND);
-               glDepthMask(0);
-       }
-       else
-       {
-               glDisable(GL_BLEND);
-               glDepthMask(1);
-       }
-
-       if (gl_vertexarrays.value)
-       {
-               // LordHavoc: I would use InterleavedArrays here,
-               // but the texture coordinates are a seperate array,
-               // and it would be wasteful to copy them into the main array...
-       //      glColor4f(shadecolor[0], shadecolor[1], shadecolor[2], modelalpha);
-               qglVertexPointer(3, GL_FLOAT, 0, aliasvert);
-               qglColorPointer(4, GL_UNSIGNED_BYTE, 0, aliasvertcolor);
-               glEnableClientState(GL_VERTEX_ARRAY);
-               glEnableClientState(GL_COLOR_ARRAY);
-
-               // draw the front faces
-               qglTexCoordPointer(2, GL_FLOAT, 0, (void *)((int) paliashdr->texcoords + (int) paliashdr));
-               glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-               qglDrawElements(GL_TRIANGLES, paliashdr->frontfaces * 3, GL_UNSIGNED_SHORT, (void *)((int) paliashdr->vertindices + (int) paliashdr));
-               glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-
-               // draw the back faces
-               qglTexCoordPointer(2, GL_FLOAT, 0, (void *)((int) paliashdr->texcoords + sizeof(float[2]) * paliashdr->numverts + (int) paliashdr));
-               glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-               qglDrawElements(GL_TRIANGLES, paliashdr->backfaces * 3, GL_UNSIGNED_SHORT, (void *)((int) paliashdr->vertindices + sizeof(unsigned short[3]) * paliashdr->frontfaces + (int) paliashdr));
-               glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-
-               glDisableClientState(GL_COLOR_ARRAY);
-               glDisableClientState(GL_VERTEX_ARRAY);
-       }
-       else
-       {
-               unsigned short *in, index;
-               float *tex;
-               in = (void *)((int) paliashdr->vertindices + (int) paliashdr);
-               glBegin(GL_TRIANGLES);
-               // draw the front faces
-               tex = (void *)((int) paliashdr->texcoords + (int) paliashdr);
-               //if (isG200)
-               //{
-                       for (i = 0;i < paliashdr->frontfaces * 3;i++)
-                       {
-                               index = *in++;
-                               glTexCoord2f(tex[index*2], tex[index*2+1]);
-                               glColor4f(aliasvertcolor[index*4] * (1.0f / 255.0f), aliasvertcolor[index*4+1] * (1.0f / 255.0f), aliasvertcolor[index*4+2] * (1.0f / 255.0f), aliasvertcolor[index*4+3] * (1.0f / 255.0f));
-                               glVertex3fv(&aliasvert[index*3]);
-                       }
-               /*
-               }
-               else
-               {
-                       for (i = 0;i < paliashdr->frontfaces * 3;i++)
-                       {
-                               index = *in++;
-                               glTexCoord2f(tex[index*2], tex[index*2+1]);
-                               glColor4ub(aliasvertcolor[index*4], aliasvertcolor[index*4+1], aliasvertcolor[index*4+2], aliasvertcolor[index*4+3]);
-                               glVertex3fv(&aliasvert[index*3]);
-                       }
-               }
-               */
-               // draw the back faces
-               tex += 2 * paliashdr->numverts;
-               //if (isG200)
-               //{
-                       for (i = 0;i < paliashdr->backfaces * 3;i++)
-                       {
-                               index = *in++;
-                               glTexCoord2f(tex[index*2], tex[index*2+1]);
-                               glColor4f(aliasvertcolor[index*4] * (1.0f / 255.0f), aliasvertcolor[index*4+1] * (1.0f / 255.0f), aliasvertcolor[index*4+2] * (1.0f / 255.0f), aliasvertcolor[index*4+3] * (1.0f / 255.0f));
-                               glVertex3fv(&aliasvert[index*3]);
-                       }
-               /*
-               }
-               else
-               {
-                       for (i = 0;i < paliashdr->backfaces * 3;i++)
-                       {
-                               index = *in++;
-                               glTexCoord2f(tex[index*2], tex[index*2+1]);
-                               glColor4ub(aliasvertcolor[index*4], aliasvertcolor[index*4+1], aliasvertcolor[index*4+2], aliasvertcolor[index*4+3]);
-                               glVertex3fv(&aliasvert[index*3]);
-                       }
-               }
-               */
-               glEnd();
-       }
-
-       if (fogenabled)
-       {
-               vec3_t diff;
-               glDisable (GL_TEXTURE_2D);
-               glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-               glEnable (GL_BLEND);
-               glDepthMask(0); // disable zbuffer updates
-
-               VectorSubtract(currententity->origin, r_refdef.vieworg, diff);
-               glColor4f(fogcolor[0], fogcolor[1], fogcolor[2], exp(fogdensity/DotProduct(diff,diff)));
-
-               if (gl_vertexarrays.value)
-               {
-                       qglVertexPointer(3, GL_FLOAT, 0, aliasvert);
-                       glEnableClientState(GL_VERTEX_ARRAY);
-                       qglDrawElements(GL_TRIANGLES, paliashdr->numtris * 3, GL_UNSIGNED_SHORT, (void *)((int) paliashdr->vertindices + (int) paliashdr));
-                       glDisableClientState(GL_VERTEX_ARRAY);
-               }
-               else
-               {
-                       unsigned short *in;
-                       in = (void *)((int) paliashdr->vertindices + (int) paliashdr);
-                       glBegin(GL_TRIANGLES);
-                       for (i = 0;i < paliashdr->numtris * 3;i++)
-                               glVertex3fv(&aliasvert[*in++ * 3]);
-                       glEnd();
-               }
-
-               glEnable (GL_TEXTURE_2D);
-               glColor3f (1,1,1);
-       }
-
-       if (!fogenabled && r_shadows.value && !(currententity->effects & EF_ADDITIVE) && currententity != &cl.viewent)
-       {
-               // flatten it to make a shadow
-               float *av = aliasvert + 2, l = lightspot[2] + 0.125;
-               av = aliasvert + 2;
-               for (i = 0;i < paliashdr->numverts;i++, av+=3)
-                       if (*av > l)
-                               *av = l;
-               glDisable (GL_TEXTURE_2D);
-               glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-               glEnable (GL_BLEND);
-               glDepthMask(0); // disable zbuffer updates
-               glColor4f (0,0,0,0.5 * modelalpha);
-
-               if (gl_vertexarrays.value)
-               {
-                       qglVertexPointer(3, GL_FLOAT, 0, aliasvert);
-                       glEnableClientState(GL_VERTEX_ARRAY);
-                       qglDrawElements(GL_TRIANGLES, paliashdr->numtris * 3, GL_UNSIGNED_SHORT, (void *)((int) paliashdr->vertindices + (int) paliashdr));
-                       glDisableClientState(GL_VERTEX_ARRAY);
-               }
-               else
-               {
-                       unsigned short *in;
-                       in = (void *)((int) paliashdr->vertindices + (int) paliashdr);
-                       glBegin(GL_TRIANGLES);
-                       for (i = 0;i < paliashdr->numtris * 3;i++)
-                               glVertex3fv(&aliasvert[*in++ * 3]);
-                       glEnd();
-               }
-
-               glEnable (GL_TEXTURE_2D);
-               glColor3f (1,1,1);
-       }
-
-       glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-       glEnable (GL_BLEND);
-       glDepthMask(1);
-}
-
-/*
-=================
-R_DrawQ2AliasFrame
-
-=================
-*/
-void R_DrawQ2AliasFrame (md2mem_t *pheader)
-{
-       int *order, count, frame = currententity->frame;
-       float lerp;
-       md2memframe_t *frame1, *frame2;
-
-       softwaretransformforentity(currententity);
-
-       if ((frame >= pheader->num_frames) || (frame < 0))
-       {
-               Con_DPrintf ("R_SetupQ2AliasFrame: no such frame %d\n", frame);
-               frame = 0;
-       }
-
-       lerp = R_CalcAnimLerp(frame, 10);
-
-       frame1 = (void *)((int) pheader + pheader->ofs_frames + (pheader->framesize * currententity->draw_lastpose));
-       frame2 = (void *)((int) pheader + pheader->ofs_frames + (pheader->framesize * currententity->draw_pose));
-       R_AliasLerpVerts(pheader->num_xyz, lerp, frame1->verts, frame1->scale, frame1->translate, frame2->verts, frame2->scale, frame2->translate);
-
-       R_LightModel(pheader->num_xyz, currententity->origin);
-
-       if (gl_vertexarrays.value)
-       {
-               // LordHavoc: big mess...
-               // using arrays only slightly, although it is enough to prevent duplicates
-               // (saving half the transforms)
-               //glColor4f(shadecolor[0], shadecolor[1], shadecolor[2], modelalpha);
-               qglVertexPointer(3, GL_FLOAT, 0, aliasvert);
-               qglColorPointer(4, GL_UNSIGNED_BYTE, 0, aliasvertcolor);
-               glEnableClientState(GL_VERTEX_ARRAY);
-               glEnableClientState(GL_COLOR_ARRAY);
-
-               order = (int *)((int)pheader + pheader->ofs_glcmds);
-               while(1)
-               {
-                       if (!(count = *order++))
-                               break;
-                       if (count > 0)
-                               glBegin(GL_TRIANGLE_STRIP);
-                       else
-                       {
-                               glBegin(GL_TRIANGLE_FAN);
-                               count = -count;
-                       }
-                       do
-                       {
-                               glTexCoord2f(((float *)order)[0], ((float *)order)[1]);
-                               qglArrayElement(order[2]);
-                               order += 3;
-                       }
-                       while (count--);
-               }
-
-               glDisableClientState(GL_COLOR_ARRAY);
-               glDisableClientState(GL_VERTEX_ARRAY);
-       }
-       else
-       {
-               order = (int *)((int)pheader + pheader->ofs_glcmds);
-               while(1)
-               {
-                       if (!(count = *order++))
-                               break;
-                       if (count > 0)
-                               glBegin(GL_TRIANGLE_STRIP);
-                       else
-                       {
-                               glBegin(GL_TRIANGLE_FAN);
-                               count = -count;
-                       }
-                       //if (isG200)
-                       //{
-                               do
-                               {
-                                       glTexCoord2f(((float *)order)[0], ((float *)order)[1]);
-                                       glColor4f(aliasvertcolor[order[2] * 4] * (1.0f / 255.0f), aliasvertcolor[order[2] * 4 + 1] * (1.0f / 255.0f), aliasvertcolor[order[2] * 4 + 2] * (1.0f / 255.0f), aliasvertcolor[order[2] * 4 + 3] * (1.0f / 255.0f));
-                                       glVertex3fv(&aliasvert[order[2] * 3]);
-                                       order += 3;
-                               }
-                               while (count--);
-                       /*
-                       }
-                       else
-                       {
-                               do
-                               {
-                                       glTexCoord2f(((float *)order)[0], ((float *)order)[1]);
-                                       glColor4ub(aliasvertcolor[order[2] * 4], aliasvertcolor[order[2] * 4 + 1], aliasvertcolor[order[2] * 4 + 2], aliasvertcolor[order[2] * 4 + 3]);
-                                       glVertex3fv(&aliasvert[order[2] * 3]);
-                                       order += 3;
-                               }
-                               while (count--);
-                       }
-                       */
-               }
-       }
-
-       if (fogenabled)
-       {
-               glDisable (GL_TEXTURE_2D);
-               glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-               glEnable (GL_BLEND);
-               glDepthMask(0); // disable zbuffer updates
-               {
-                       vec3_t diff;
-                       VectorSubtract(currententity->origin, r_refdef.vieworg, diff);
-                       glColor4f(fogcolor[0], fogcolor[1], fogcolor[2], exp(fogdensity/DotProduct(diff,diff)));
-               }
-
-               if (gl_vertexarrays.value)
-               {
-                       // LordHavoc: big mess...
-                       // using arrays only slightly, although it is enough to prevent duplicates
-                       // (saving half the transforms)
-                       //glColor4f(shadecolor[0], shadecolor[1], shadecolor[2], modelalpha);
-                       qglVertexPointer(3, GL_FLOAT, 0, aliasvert);
-                       glEnableClientState(GL_VERTEX_ARRAY);
-
-                       order = (int *)((int)pheader + pheader->ofs_glcmds);
-                       while(1)
-                       {
-                               if (!(count = *order++))
-                                       break;
-                               if (count > 0)
-                                       glBegin(GL_TRIANGLE_STRIP);
-                               else
-                               {
-                                       glBegin(GL_TRIANGLE_FAN);
-                                       count = -count;
-                               }
-                               do
-                               {
-                                       qglArrayElement(order[2]);
-                                       order += 3;
-                               }
-                               while (count--);
-                       }
-
-                       glDisableClientState(GL_VERTEX_ARRAY);
-               }
-               else
-               {
-                       order = (int *)((int)pheader + pheader->ofs_glcmds);
-                       while(1)
-                       {
-                               if (!(count = *order++))
-                                       break;
-                               if (count > 0)
-                                       glBegin(GL_TRIANGLE_STRIP);
-                               else
-                               {
-                                       glBegin(GL_TRIANGLE_FAN);
-                                       count = -count;
-                               }
-                               do
-                               {
-                                       glVertex3fv(&aliasvert[order[2] * 3]);
-                                       order += 3;
-                               }
-                               while (count--);
-                       }
-               }
-
-               glEnable (GL_TEXTURE_2D);
-               glColor3f (1,1,1);
-       }
-
-       if (!fogenabled && r_shadows.value && !(currententity->effects & EF_ADDITIVE) && currententity != &cl.viewent)
-       {
-               int i;
-               float *av = aliasvert + 2, l = lightspot[2] + 0.125;
-               av = aliasvert + 2;
-               for (i = 0;i < pheader->num_xyz;i++, av+=3)
-                       if (*av > l)
-                               *av = l;
-               glDisable (GL_TEXTURE_2D);
-               glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-               glEnable (GL_BLEND);
-               glDepthMask(0); // disable zbuffer updates
-               glColor4f (0,0,0,0.5 * modelalpha);
-
-               if (gl_vertexarrays.value)
-               {
-                       qglVertexPointer(3, GL_FLOAT, 0, aliasvert);
-                       glEnableClientState(GL_VERTEX_ARRAY);
-                                               
-                       while(1)
-                       {
-                               if (!(count = *order++))
-                                       break;
-                               if (count > 0)
-                                       glBegin(GL_TRIANGLE_STRIP);
-                               else
-                               {
-                                       glBegin(GL_TRIANGLE_FAN);
-                                       count = -count;
-                               }
-                               do
-                               {
-                                       qglArrayElement(order[2]);
-                                       order += 3;
-                               }
-                               while (count--);
-                       }
-
-                       glDisableClientState(GL_VERTEX_ARRAY);
-               }
-               else
-               {
-                       while(1)
-                       {
-                               if (!(count = *order++))
-                                       break;
-                               if (count > 0)
-                                       glBegin(GL_TRIANGLE_STRIP);
-                               else
-                               {
-                                       glBegin(GL_TRIANGLE_FAN);
-                                       count = -count;
-                               }
-                               do
-                               {
-                                       glVertex3fv(&aliasvert[order[2] * 3]);
-                                       order += 3;
-                               }
-                               while (count--);
-                       }
-               }
-
-               glEnable (GL_TEXTURE_2D);
-               glColor3f (1,1,1);
-       }
-
-       glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-       glEnable (GL_BLEND);
-       glDepthMask(1);
-}
-
-int modeldlightbits[8];
-extern int r_dlightframecount;
-
-/*
-=================
-R_DrawAliasModel
-
-=================
-*/
-void R_DrawAliasModel (entity_t *e, int cull)
-{
-       int                     i;
-       model_t         *clmodel;
-       vec3_t          mins, maxs;
-       aliashdr_t      *paliashdr = NULL;
-       md2mem_t                *pheader = NULL;
-       int                     anim;
-
-       if (modelalpha < (1.0 / 64.0))
-               return; // basically completely transparent
-
-       clmodel = currententity->model;
-
-       VectorAdd (currententity->origin, clmodel->mins, mins);
-       VectorAdd (currententity->origin, clmodel->maxs, maxs);
-
-       if (cull && R_CullBox (mins, maxs))
-               return;
-
-       VectorCopy (currententity->origin, r_entorigin);
-       VectorSubtract (r_origin, r_entorigin, modelorg);
-
-       {
-               mleaf_t *leaf = Mod_PointInLeaf (currententity->origin, cl.worldmodel);
-               if (leaf->dlightframe == r_dlightframecount)
-                       for (i = 0;i < 8;i++)
-                               modeldlightbits[i] = leaf->dlightbits[i];
-               else
-                       for (i = 0;i < 8;i++)
-                               modeldlightbits[i] = 0;
-       }
-
-       // get lighting information
-
-       if (currententity->model->flags & EF_FULLBRIGHT || currententity->effects & EF_FULLBRIGHT)
-       {
-               shadecolor[0] = currententity->colormod[0] * 256;
-               shadecolor[1] = currententity->colormod[1] * 256;
-               shadecolor[2] = currententity->colormod[2] * 256;
-       }
-       else
-       {
-               R_LightPoint (shadecolor, currententity->origin);
-
-               // HACK HACK HACK -- no fullbright colors, so make torches full light
-               if (!strcmp (currententity->model->name, "progs/flame2.mdl") || !strcmp (currententity->model->name, "progs/flame.mdl") )
-                       shadecolor[0] = shadecolor[1] = shadecolor[2] = 128;
-
-               shadecolor[0] *= currententity->colormod[0];
-               shadecolor[1] *= currententity->colormod[1];
-               shadecolor[2] *= currententity->colormod[2];
-       }
-
-       // locate the proper data
-       if (clmodel->aliastype == ALIASTYPE_MD2)
-       {
-               pheader = (void *)Mod_Extradata (currententity->model);
-               c_alias_polys += pheader->num_tris;
-       }
-       else
-       {
-               paliashdr = (void *)Mod_Extradata (currententity->model);
-               c_alias_polys += paliashdr->numtris;
-       }
-
-       // draw all the triangles
-
-       if (clmodel->aliastype == ALIASTYPE_MD2)
-       {
-               if (currententity->skinnum < 0 || currententity->skinnum >= pheader->num_skins)
-               {
-                       currententity->skinnum = 0;
-                       Con_DPrintf("invalid skin number %d for model %s\n", currententity->skinnum, clmodel->name);
-               }
-               glBindTexture(GL_TEXTURE_2D, pheader->gl_texturenum[currententity->skinnum]);
-       }
-       else
-       {
-               if (currententity->skinnum < 0 || currententity->skinnum >= paliashdr->numskins)
-               {
-                       currententity->skinnum = 0;
-                       Con_DPrintf("invalid skin number %d for model %s\n", currententity->skinnum, clmodel->name);
-               }
-               anim = (int)(cl.time*10) & 3;
-           glBindTexture(GL_TEXTURE_2D, paliashdr->gl_texturenum[currententity->skinnum][anim]);
-       }
-       glDisable(GL_ALPHA_TEST);
-       glEnable (GL_TEXTURE_2D);
-
-       // we can't dynamically colormap textures, so they are cached
-       // seperately for the players.  Heads are just uncolored.
-       if (currententity->colormap != 0 /*vid.colormap*/ /* && !gl_nocolors.value*/)
-       {
-               i = currententity - cl_entities;
-               if (i >= 1 && i<=cl.maxclients /* && !strcmp (currententity->model->name, "progs/player.mdl") */)
-                       glBindTexture(GL_TEXTURE_2D, playertextures - 1 + i);
-       }
-
-//     if (gl_affinemodels.value)
-//             glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
-       if (clmodel->aliastype == ALIASTYPE_MD2)
-               R_DrawQ2AliasFrame (pheader);
-       else
-               R_DrawAliasFrame (paliashdr);
-
-       glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
-}
-
 //==================================================================================
 
 void R_DrawBrushModel (entity_t *e);
@@ -1235,7 +492,7 @@ void R_DrawEntitiesOnList2 (void)
                switch (currententity->model->type)
                {
                case mod_alias:
-                       R_DrawAliasModel (currententity, true);
+                       R_DrawAliasModel (currententity, true, modelalpha, currententity->model, currententity->frame, currententity->skinnum, currententity->origin, currententity->effects, currententity->model->flags, currententity->colormap);
                        break;
 
                case mod_sprite:
@@ -1266,7 +523,7 @@ void R_DrawViewModel (void)
 
        // hack the depth range to prevent view model from poking into walls
        glDepthRange (gldepthmin, gldepthmin + 0.3*(gldepthmax-gldepthmin));
-       R_DrawAliasModel (currententity, FALSE);
+       R_DrawAliasModel (currententity, FALSE, modelalpha, currententity->model, currententity->frame, currententity->skinnum, currententity->origin, currententity->effects, currententity->model->flags, currententity->colormap);
        glDepthRange (gldepthmin, gldepthmax);
 }
 
index ab7573c..99ff6ec 100644 (file)
@@ -125,21 +125,25 @@ void R_Envmap_f (void)
 
 void R_InitParticles (void);
 
+void gl_misc_start()
+{
+}
+
+void gl_misc_shutdown()
+{
+}
+
 /*
 ===============
 R_Init
 ===============
 */
-void R_Init (void)
+void GL_Misc_Init (void)
 {      
-//     extern cvar_t gl_finish;
-
        Cmd_AddCommand ("timerefresh", R_TimeRefresh_f);        
        Cmd_AddCommand ("envmap", R_Envmap_f);  
        Cmd_AddCommand ("pointfile", R_ReadPointFile_f);        
 
-//     Cvar_RegisterVariable (&r_norefresh);
-//     Cvar_RegisterVariable (&r_lightmap);
        Cvar_RegisterVariable (&r_drawentities);
        Cvar_RegisterVariable (&r_drawviewmodel);
        Cvar_RegisterVariable (&r_shadows);
@@ -149,175 +153,11 @@ void R_Init (void)
        Cvar_RegisterVariable (&r_speeds);
        Cvar_RegisterVariable (&r_waterripple); // LordHavoc: added waterripple
 
-//     Cvar_RegisterVariable (&gl_cull);
-//     Cvar_RegisterVariable (&gl_affinemodels);
-//     Cvar_RegisterVariable (&gl_polyblend);
-       Cvar_RegisterVariable (&gl_playermip);
-//     Cvar_RegisterVariable (&gl_nocolors);
-
-//     Cvar_RegisterVariable (&gl_keeptjunctions);
-//     Cvar_RegisterVariable (&gl_reporttjunctions);
-
-       R_InitParticles ();
-
-       playertextures = texture_extension_number;
-       texture_extension_number += 64; // LordHavoc: increased number of players from 16 to 64
+       R_RegisterModule("GL_Misc", gl_misc_start, gl_misc_shutdown);
 }
 
-qboolean VID_Is8bit(void);
-void GL_Upload8_EXT (byte *data, int width, int height,  qboolean mipmap, qboolean alpha);
-
-/*
-===============
-R_TranslatePlayerSkin
-
-Translates a skin texture by the per-player color lookup
-===============
-*/
-void R_TranslatePlayerSkin (int playernum)
-{
-       int             top, bottom;
-       byte    translate[256];
-       unsigned        translate32[256];
-       int             i, j, s;
-       model_t *model;
-       aliashdr_t *paliashdr;
-       byte    *original;
-       unsigned        pixels[512*256], *out;
-       unsigned        scaled_width, scaled_height;
-       int                     inwidth, inheight;
-       byte            *inrow;
-       unsigned        frac, fracstep;
-
-       top = cl.scores[playernum].colors & 0xf0;
-       bottom = (cl.scores[playernum].colors &15)<<4;
-
-       for (i=0 ; i<256 ; i++)
-               translate[i] = i;
-
-       for (i=0 ; i<16 ; i++)
-       {
-               // LordHavoc: corrected color ranges
-               if (top < 128 || (top >= 224 && top < 240))     // the artists made some backwards ranges.  sigh.
-                       translate[TOP_RANGE+i] = top+i;
-               else
-                       translate[TOP_RANGE+i] = top+15-i;
-
-               // LordHavoc: corrected color ranges
-               if (bottom < 128 || (bottom >= 224 && bottom < 240))
-                       translate[BOTTOM_RANGE+i] = bottom+i;
-               else
-                       translate[BOTTOM_RANGE+i] = bottom+15-i;
-       }
-
-       //
-       // locate the original skin pixels
-       //
-       currententity = &cl_entities[1+playernum];
-       model = currententity->model;
-       if (!model)
-               return;         // player doesn't have a model yet
-       if (model->type != mod_alias)
-               return; // only translate skins on alias models
-
-       paliashdr = (aliashdr_t *)Mod_Extradata (model);
-       s = paliashdr->skinwidth * paliashdr->skinheight;
-       if (currententity->skinnum < 0 || currententity->skinnum >= paliashdr->numskins)
-       {
-               Con_Printf("(%d): Invalid player skin #%d\n", playernum, currententity->skinnum);
-               original = (byte *)paliashdr + paliashdr->texels[0];
-       }
-       else
-               original = (byte *)paliashdr + paliashdr->texels[currententity->skinnum];
-       if (s & 3)
-               Sys_Error ("R_TranslateSkin: s&3");
-
-       inwidth = paliashdr->skinwidth;
-       inheight = paliashdr->skinheight;
-
-       // because this happens during gameplay, do it fast
-       // instead of sending it through gl_upload 8
-    glBindTexture(GL_TEXTURE_2D, playertextures + playernum);
-
-#if 0
-       byte    translated[320*200];
-
-       for (i=0 ; i<s ; i+=4)
-       {
-               translated[i] = translate[original[i]];
-               translated[i+1] = translate[original[i+1]];
-               translated[i+2] = translate[original[i+2]];
-               translated[i+3] = translate[original[i+3]];
-       }
-
-
-       // don't mipmap these, because it takes too long
-       GL_Upload8 (translated, paliashdr->skinwidth, paliashdr->skinheight, false, false, true);
-#else
-       scaled_width = gl_max_size.value < 512 ? gl_max_size.value : 512;
-       scaled_height = gl_max_size.value < 256 ? gl_max_size.value : 256;
-
-       // allow users to crunch sizes down even more if they want
-       scaled_width >>= (int)gl_playermip.value;
-       scaled_height >>= (int)gl_playermip.value;
-
-       if (VID_Is8bit())
-       { // 8bit texture upload
-               byte *out2;
-
-               out2 = (byte *)pixels;
-               memset(pixels, 0, sizeof(pixels));
-               fracstep = inwidth*0x10000/scaled_width;
-               for (i=0 ; i<scaled_height ; i++, out2 += scaled_width)
-               {
-                       inrow = original + inwidth*(i*inheight/scaled_height);
-                       frac = fracstep >> 1;
-                       for (j=0 ; j<scaled_width ; j+=4)
-                       {
-                               out2[j] = translate[inrow[frac>>16]];
-                               frac += fracstep;
-                               out2[j+1] = translate[inrow[frac>>16]];
-                               frac += fracstep;
-                               out2[j+2] = translate[inrow[frac>>16]];
-                               frac += fracstep;
-                               out2[j+3] = translate[inrow[frac>>16]];
-                               frac += fracstep;
-                       }
-               }
-
-               GL_Upload8_EXT ((byte *)pixels, scaled_width, scaled_height, false, false);
-               return;
-       }
-
-       for (i=0 ; i<256 ; i++)
-               translate32[i] = d_8to24table[translate[i]];
-
-       out = pixels;
-       fracstep = inwidth*0x10000/scaled_width;
-       for (i=0 ; i<scaled_height ; i++, out += scaled_width)
-       {
-               inrow = original + inwidth*(i*inheight/scaled_height);
-               frac = fracstep >> 1;
-               for (j=0 ; j<scaled_width ; j+=4)
-               {
-                       out[j] = translate32[inrow[frac>>16]];
-                       frac += fracstep;
-                       out[j+1] = translate32[inrow[frac>>16]];
-                       frac += fracstep;
-                       out[j+2] = translate32[inrow[frac>>16]];
-                       frac += fracstep;
-                       out[j+3] = translate32[inrow[frac>>16]];
-                       frac += fracstep;
-               }
-       }
-       glTexImage2D (GL_TEXTURE_2D, 0, gl_solid_format, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
-
-       glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-       glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-       glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-#endif
-
-}
+//qboolean VID_Is8bit(void);
+//void GL_Upload8_EXT (byte *data, int width, int height,  qboolean mipmap, qboolean alpha);
 
 void R_ClearParticles (void);
 void GL_BuildLightmaps (void);
index fe5bb6c..be07117 100644 (file)
@@ -51,15 +51,22 @@ cvar_t gl_vertex = {"gl_vertex", "0"};
 cvar_t gl_texsort = {"gl_texsort", "1"};
 //cvar_t gl_funnywalls = {"gl_funnywalls", "0"}; // LordHavoc: see BuildSurfaceDisplayList
 
-qboolean lightmaprgba, nosubimagefragments, nosubimage;
+qboolean lightmaprgba, nosubimagefragments, nosubimage, skyisvisible;
 int lightmapbytes;
 
-qboolean skyisvisible;
 extern qboolean gl_arrays;
 
 extern int r_dlightframecount;
 
-void glrsurf_init()
+void gl_surf_start()
+{
+}
+
+void gl_surf_shutdown()
+{
+}
+
+void GL_Surf_Init()
 {
        int i;
        for (i = 0;i < MAX_LIGHTMAPS;i++)
@@ -80,6 +87,8 @@ void glrsurf_init()
 //             Cvar_SetValue("gl_nosubimage", 1);
                Cvar_SetValue("gl_lightmode", 0);
        }
+
+       R_RegisterModule("GL_Surf", gl_surf_start, gl_surf_shutdown);
 }
 
 extern qboolean lighthalf;
@@ -303,12 +312,9 @@ extern     int             solidskytexture;
 extern int             alphaskytexture;
 extern float   speedscale;             // for top sky and bottom sky
 
-qboolean mtexenabled = false;
-
 extern char skyname[];
 
 void R_DynamicLightPoint(vec3_t color, vec3_t org, int *dlightbits);
-//extern cvar_t r_dynamicwater;
 float  turbsin[256] =
 {
        #include "gl_warp_sin.h"
@@ -347,7 +353,9 @@ void UploadLightmaps()
        }
 }
 
-void R_SkySurf(msurface_t *s, qboolean transform)
+float  wvert[1024*6]; // used by the following functions
+
+void RSurf_DrawSky(msurface_t *s, int transform)
 {
        glpoly_t *p;
        int i;
@@ -379,11 +387,11 @@ void R_SkySurf(msurface_t *s, qboolean transform)
        }
 }
 
-void R_LightSurface(int *dlightbits, glpoly_t *polys, float *wvert)
+int RSurf_Light(int *dlightbits, glpoly_t *polys)
 {
        float           cr, cg, cb, radius, radius2, f, *v, *wv;
-       int                     i, a, b;
-       unsigned int c;
+       int                     i, a, b, lit = false;
+       unsigned int c, d;
        dlight_t        *light;
        vec_t           *lightorigin;
        glpoly_t        *p;
@@ -391,18 +399,18 @@ void R_LightSurface(int *dlightbits, glpoly_t *polys, float *wvert)
        {
                if ((c = dlightbits[a]))
                {
-                       for (b = 0;c && b < 32;b++)
+                       for (b = 0, d = 1;c;b++, d <<= 1)
                        {
-                               if (c & (1 << b))
+                               if (c & d)
                                {
-                                       c -= (1 << b);
+                                       c -= d;
                                        light = &cl_dlights[a * 32 + b];
                                        lightorigin = light->origin;
                                        cr = light->color[0];
                                        cg = light->color[1];
                                        cb = light->color[2];
-                                       radius = light->radius*light->radius*16.0f;
-                                       radius2 = radius * 16.0f;
+                                       radius = light->radius*light->radius*LIGHTSCALE;
+                                       radius2 = radius * (256.0f / LIGHTSCALE);
                                        wv = wvert;
                                        for (p = polys;p;p = p->next)
                                        {
@@ -411,28 +419,28 @@ void R_LightSurface(int *dlightbits, glpoly_t *polys, float *wvert)
                                                        f = VectorDistance2(wv, lightorigin);
                                                        if (f < radius)
                                                        {
-                                                               f = radius2 / (f + 65536.0f);
+                                                               f = radius2 / (f + LIGHTOFFSET);
                                                                wv[3] += cr * f;
                                                                wv[4] += cg * f;
                                                                wv[5] += cb * f;
+                                                               lit = true;
                                                        }
                                                        wv += 6;
                                                }
                                        }
                                }
-                               c >>= 1;
-                               b++;
                        }
                }
        }
+       return lit;
 }
 
-void R_WaterSurf(msurface_t *s, texture_t *t, qboolean transform, int alpha)
+void RSurf_DrawWater(msurface_t *s, texture_t *t, int transform, int alpha)
 {
        int             i;
        float   os = turbsin[(int)(realtime * TURBSCALE) & 255], ot = turbsin[(int)(realtime * TURBSCALE + 96.0) & 255];
        glpoly_t *p;
-       float   wvert[1024*6], *wv, *v;
+       float   *wv, *v;
        wv = wvert;
        for (p = s->polys;p;p = p->next)
        {
@@ -449,7 +457,7 @@ void R_WaterSurf(msurface_t *s, texture_t *t, qboolean transform, int alpha)
                }
        }
        if (s->dlightframe == r_dlightframecount && r_dynamic.value)
-               R_LightSurface(s->dlightbits, s->polys, wvert);
+               RSurf_Light(s->dlightbits, s->polys);
        wv = wvert;
        // FIXME: make fog texture if water texture is transparent?
        for (p=s->polys ; p ; p=p->next)
@@ -461,12 +469,8 @@ void R_WaterSurf(msurface_t *s, texture_t *t, qboolean transform, int alpha)
        }
 }
 
-void R_WallSurf(msurface_t *s, texture_t *t, qboolean transform)
+void RSurf_CheckLightmap(msurface_t *s)
 {
-       int                     i;
-       glpoly_t        *p;
-       float           wvert[64*6], *wv, *v;
-       // check for lightmap modification
        if (r_dynamic.value)
        {
                if (r_ambient.value != s->cached_ambient || lighthalf != s->cached_lighthalf
@@ -476,8 +480,13 @@ void R_WallSurf(msurface_t *s, texture_t *t, qboolean transform)
                || (s->styles[3] != 255 && d_lightstylevalue[s->styles[3]] != s->cached_light[3]))
                        R_UpdateLightmap(s, s->lightmaptexturenum);
        }
-       wv = wvert;
-       for (p = s->polys;p;p = p->next)
+}
+
+void RSurf_Transform(glpoly_t *p, int transform)
+{
+       int             i;
+       float   *v, *wv = wvert;
+       for (;p;p = p->next)
        {
                for (i = 0, v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
                {
@@ -489,77 +498,112 @@ void R_WallSurf(msurface_t *s, texture_t *t, qboolean transform)
                        wv += 6;
                }
        }
-       if (s->dlightframe == r_dlightframecount && r_dynamic.value)
-               R_LightSurface(s->dlightbits, s->polys, wvert);
-       wv = wvert;
-       for (p = s->polys;p;p = p->next)
+}
+
+void RSurf_EmitWallpolys(int lightmap, glpoly_t *p, texture_t *t, int lit)
+{
+       int             i;
+       float   *v, *wv = wvert;
+       wallpoly_t *wp = &wallpoly[currentwallpoly];
+       wallvert_t *out = &wallvert[currentwallvert];
+       for (;p;p = p->next)
        {
                if (currentwallpoly >= MAX_WALLPOLYS)
                        break;
+               if (currentwallvert+p->numverts > MAX_WALLVERTS)
+                       break;
                v = p->verts[0];
-               wallpoly[currentwallpoly].texnum = (unsigned short) t->gl_texturenum;
-               wallpoly[currentwallpoly].lighttexnum = (unsigned short) lightmap_textures + s->lightmaptexturenum;
-               wallpoly[currentwallpoly].glowtexnum = (unsigned short) t->gl_glowtexturenum;
-               wallpoly[currentwallpoly].firstvert = currentwallvert;
-               wallpoly[currentwallpoly].numverts = p->numverts;
-               wallpoly[currentwallpoly++].lit = true;
-               for (i = 0;i<p->numverts;i++, v += VERTEXSIZE)
+               wp->texnum = (unsigned short) t->gl_texturenum;
+               wp->lighttexnum = (unsigned short) lightmap;
+               wp->glowtexnum = (unsigned short) t->gl_glowtexturenum;
+               wp->firstvert = currentwallvert;
+               wp->numverts = p->numverts;
+               wp->lit = lit;
+               wp++;
+               currentwallpoly++;
+               currentwallvert += p->numverts;
+               for (i = 0;i < p->numverts;i++, v += VERTEXSIZE, wv += 6, out++)
                {
-                       if (lighthalf)
-                       {
-                               wallvert[currentwallvert].r = (byte) (bound(0, (int) wv[3] >> 1, 255));
-                               wallvert[currentwallvert].g = (byte) (bound(0, (int) wv[4] >> 1, 255));
-                               wallvert[currentwallvert].b = (byte) (bound(0, (int) wv[5] >> 1, 255));
-                               wallvert[currentwallvert].a = 255;
-                       }
-                       else
+                       if (lit)
                        {
-                               wallvert[currentwallvert].r = (byte) (bound(0, (int) wv[3], 255));
-                               wallvert[currentwallvert].g = (byte) (bound(0, (int) wv[4], 255));
-                               wallvert[currentwallvert].b = (byte) (bound(0, (int) wv[5], 255));
-                               wallvert[currentwallvert].a = 255;
+                               if (lighthalf)
+                               {
+                                       out->r = (byte) (bound(0, (int) wv[3] >> 1, 255));
+                                       out->g = (byte) (bound(0, (int) wv[4] >> 1, 255));
+                                       out->b = (byte) (bound(0, (int) wv[5] >> 1, 255));
+                                       out->a = 255;
+                               }
+                               else
+                               {
+                                       out->r = (byte) (bound(0, (int) wv[3], 255));
+                                       out->g = (byte) (bound(0, (int) wv[4], 255));
+                                       out->b = (byte) (bound(0, (int) wv[5], 255));
+                                       out->a = 255;
+                               }
                        }
-                       wallvert[currentwallvert].vert[0] = wv[0];
-                       wallvert[currentwallvert].vert[1] = wv[1];
-                       wallvert[currentwallvert].vert[2] = wv[2];
-                       wallvert[currentwallvert].s = v[3];
-                       wallvert[currentwallvert].t = v[4];
-                       wallvert[currentwallvert].u = v[5];
-                       wallvert[currentwallvert++].v = v[6];
-                       wv += 6;
+                       out->vert[0] = wv[0];
+                       out->vert[1] = wv[1];
+                       out->vert[2] = wv[2];
+                       out->s = v[3];
+                       out->t = v[4];
+                       out->u = v[5];
+                       out->v = v[6];
                }
        }
 }
 
+void RSurf_DrawWall(msurface_t *s, texture_t *t, int transform)
+{
+       int                     lit = false;
+       // check for lightmap modification
+       RSurf_CheckLightmap(s);
+       RSurf_Transform(s->polys, transform);
+       if (s->dlightframe == r_dlightframecount && r_dynamic.value)
+               lit = RSurf_Light(s->dlightbits, s->polys);
+       RSurf_EmitWallpolys(lightmap_textures + s->lightmaptexturenum, s->polys, t, lit);
+}
+
 // LordHavoc: transparent brush models
 extern int r_dlightframecount;
 extern float modelalpha;
-//extern vec3_t shadecolor;
-//qboolean R_CullBox (vec3_t mins, vec3_t maxs);
-//void R_DynamicLightPoint(vec3_t color, vec3_t org, int *dlightbits);
-//void R_DynamicLightPointNoMask(vec3_t color, vec3_t org);
-//void EmitWaterPolys (msurface_t *fa);
 
-void R_WallSurfVertex(msurface_t *s, texture_t *t, qboolean transform, qboolean isbmodel)
+void RSurf_EmitWallVertex(glpoly_t *p, texture_t *t, int modulate, int alpha)
 {
-       int                     i, alpha;
+       int i;
+       float *v, *wv = wvert;
+       if (modulate)
+       {
+               for (;p;p = p->next)
+               {
+                       v = p->verts[0];
+                       transpolybegin(t->gl_texturenum, t->gl_glowtexturenum, 0, currententity->effects & EF_ADDITIVE ? TPOLYTYPE_ADD : TPOLYTYPE_ALPHA);
+                       for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE, wv += 6)
+                               transpolyvert(wv[0], wv[1], wv[2], v[3], v[4], wv[3] * currententity->colormod[0], wv[4] * currententity->colormod[1], wv[5] * currententity->colormod[2], alpha);
+                       transpolyend();
+               }
+       }
+       else
+       {
+               for (;p;p = p->next)
+               {
+                       v = p->verts[0];
+                       transpolybegin(t->gl_texturenum, t->gl_glowtexturenum, 0, currententity->effects & EF_ADDITIVE ? TPOLYTYPE_ADD : TPOLYTYPE_ALPHA);
+                       for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE, wv += 6)
+                               transpolyvert(wv[0], wv[1], wv[2], v[3], v[4], wv[3], wv[4], wv[5], alpha);
+                       transpolyend();
+               }
+       }
+}
+
+void RSurf_WallVertexTransform(msurface_t *s, texture_t *t, int transform)
+{
+       int                     i;
        glpoly_t        *p;
-       float           wvert[64*6], *wv, *v;
+       float           *wv, *v;
        int                     size3;
        float           scale;
        byte            *lm;
        size3 = ((s->extents[0]>>4)+1)*((s->extents[1]>>4)+1)*3; // *3 for colored lighting
-       alpha = (int) (modelalpha * 255.0f);
-       // check for lightmap modification
-       if (r_dynamic.value)
-       {
-               if (r_ambient.value != s->cached_ambient || lighthalf != s->cached_lighthalf
-               || (s->styles[0] != 255 && d_lightstylevalue[s->styles[0]] != s->cached_light[0])
-               || (s->styles[1] != 255 && d_lightstylevalue[s->styles[1]] != s->cached_light[1])
-               || (s->styles[2] != 255 && d_lightstylevalue[s->styles[2]] != s->cached_light[2])
-               || (s->styles[3] != 255 && d_lightstylevalue[s->styles[3]] != s->cached_light[3]))
-                       R_UpdateLightmap(s, s->lightmaptexturenum);
-       }
        wv = wvert;
        for (p = s->polys;p;p = p->next)
        {
@@ -590,31 +634,14 @@ void R_WallSurfVertex(msurface_t *s, texture_t *t, qboolean transform, qboolean
                        wv += 6;
                }
        }
+}
+
+void RSurf_DrawWallVertex(msurface_t *s, texture_t *t, int transform, int isbmodel)
+{
+       RSurf_WallVertexTransform(s, t, transform);
        if (s->dlightframe == r_dlightframecount && r_dynamic.value)
-               R_LightSurface(s->dlightbits, s->polys, wvert);
-       wv = wvert;
-       if (isbmodel && (currententity->colormod[0] != 1 || currententity->colormod[1] != 1 || currententity->colormod[2] != 1))
-       {
-               for (p = s->polys;p;p = p->next)
-               {
-                       v = p->verts[0];
-                       transpolybegin(t->gl_texturenum, t->gl_glowtexturenum, 0, currententity->effects & EF_ADDITIVE ? TPOLYTYPE_ADD : TPOLYTYPE_ALPHA);
-                       for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE, wv += 6)
-                               transpolyvert(wv[0], wv[1], wv[2], v[3], v[4], wv[3] * currententity->colormod[0], wv[4] * currententity->colormod[1], wv[5] * currententity->colormod[2], alpha);
-                       transpolyend();
-               }
-       }
-       else
-       {
-               for (p = s->polys;p;p = p->next)
-               {
-                       v = p->verts[0];
-                       transpolybegin(t->gl_texturenum, t->gl_glowtexturenum, 0, currententity->effects & EF_ADDITIVE ? TPOLYTYPE_ADD : TPOLYTYPE_ALPHA);
-                       for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE, wv += 6)
-                               transpolyvert(wv[0], wv[1], wv[2], v[3], v[4], wv[3], wv[4], wv[5], alpha);
-                       transpolyend();
-               }
-       }
+               RSurf_Light(s->dlightbits, s->polys);
+       RSurf_EmitWallVertex(s->polys, t, isbmodel && (currententity->colormod[0] != 1 || currententity->colormod[1] != 1 || currententity->colormod[2] != 1), (int) (modelalpha * 255.0f));
 }
 
 /*
@@ -624,27 +651,26 @@ DrawTextureChains
 */
 extern qboolean hlbsp;
 extern char skyname[];
-//extern qboolean SV_TestLine (hull_t *hull, int num, vec3_t p1, vec3_t p2);
-void R_DrawSurf(msurface_t *s, qboolean isbmodel, qboolean vertexlit)
+void R_DrawSurf(msurface_t *s, int isbmodel, int vertexlit)
 {
        texture_t *t;
        if (s->flags & SURF_DRAWSKY)
        {
                skyisvisible = true;
                if (!hlbsp) // LordHavoc: HalfLife maps have freaky skypolys...
-                       R_SkySurf(s, false);
+                       RSurf_DrawSky(s, false);
                return;
        }
        t = R_TextureAnimation (s->texinfo->texture);
        if (s->flags & SURF_DRAWTURB)
        {
-               R_WaterSurf(s, t, false, s->flags & SURF_DRAWNOALPHA ? 255 : r_wateralpha.value*255.0f);
+               RSurf_DrawWater(s, t, false, s->flags & SURF_DRAWNOALPHA ? 255 : r_wateralpha.value*255.0f);
                return;
        }
        if (vertexlit)
-               R_WallSurfVertex(s, t, false, false);
+               RSurf_DrawWallVertex(s, t, false, false);
        else
-               R_WallSurf(s, t, false);
+               RSurf_DrawWall(s, t, false);
 }
 
 void DrawTextureChains (void)
@@ -667,7 +693,7 @@ void DrawTextureChains (void)
                        skyisvisible = true;
                        if (!hlbsp) // LordHavoc: HalfLife maps have freaky skypolys...
                                for (;s;s = s->texturechain)
-                                       R_SkySurf(s, false);
+                                       RSurf_DrawSky(s, false);
                        continue;
                }
                t = R_TextureAnimation (cl.worldmodel->textures[n]);
@@ -676,15 +702,15 @@ void DrawTextureChains (void)
                {
                        int alpha = s->flags & SURF_DRAWNOALPHA ? 255 : r_wateralpha.value*255.0f;
                        for (;s;s = s->texturechain)
-                               R_WaterSurf(s, t, false, alpha);
+                               RSurf_DrawWater(s, t, false, alpha);
                        continue;
                }
                if (gl_vertex.value)
                        for (;s;s = s->texturechain)
-                               R_WallSurfVertex(s, t, false, false);
+                               RSurf_DrawWallVertex(s, t, false, false);
                else
                        for (;s;s = s->texturechain)
-                               R_WallSurf(s, t, false);
+                               RSurf_DrawWall(s, t, false);
        }
 }
 
@@ -701,7 +727,7 @@ void R_DrawBrushModel (entity_t *e)
        vec3_t          mins, maxs;
        msurface_t      *s;
        model_t         *clmodel;
-       qboolean        rotated, vertexlit = false;
+       int     rotated, vertexlit = false;
        texture_t       *t;
        vec3_t          org;
 
@@ -767,19 +793,19 @@ e->angles[0] = -e->angles[0];     // stupid quake bug
 //                     R_DrawSurf(s, true, vertexlit || s->texinfo->texture->transparent);
                        if (s->flags & SURF_DRAWSKY)
                        {
-                               R_SkySurf(s, true);
+                               RSurf_DrawSky(s, true);
                                continue;
                        }
                        t = R_TextureAnimation (s->texinfo->texture);
                        if (s->flags & SURF_DRAWTURB)
                        {
-                               R_WaterSurf(s, t, true, s->flags & SURF_DRAWNOALPHA ? 255 : r_wateralpha.value*255.0f);
+                               RSurf_DrawWater(s, t, true, s->flags & SURF_DRAWNOALPHA ? 255 : r_wateralpha.value*255.0f);
                                continue;
                        }
                        if (vertexlit || s->texinfo->texture->transparent)
-                               R_WallSurfVertex(s, t, true, true);
+                               RSurf_DrawWallVertex(s, t, true, true);
                        else
-                               R_WallSurf(s, t, true);
+                               RSurf_DrawWall(s, t, true);
                }
        }
        UploadLightmaps();
index 43923c6..e2a35ff 100644 (file)
@@ -369,12 +369,23 @@ void SCR_SizeDown_f (void)
 
 //============================================================================
 
+void gl_screen_start()
+{
+       scr_ram = Draw_PicFromWad ("ram");
+       scr_net = Draw_PicFromWad ("net");
+       scr_turtle = Draw_PicFromWad ("turtle");
+}
+
+void gl_screen_shutdown()
+{
+}
+
 /*
 ==================
 SCR_Init
 ==================
 */
-void SCR_Init (void)
+void GL_Screen_Init (void)
 {
 
        Cvar_RegisterVariable (&scr_fov);
@@ -394,11 +405,9 @@ void SCR_Init (void)
        Cmd_AddCommand ("sizeup",SCR_SizeUp_f);
        Cmd_AddCommand ("sizedown",SCR_SizeDown_f);
 
-       scr_ram = Draw_PicFromWad ("ram");
-       scr_net = Draw_PicFromWad ("net");
-       scr_turtle = Draw_PicFromWad ("turtle");
-
        scr_initialized = true;
+
+       R_RegisterModule("GL_Screen", gl_screen_start, gl_screen_shutdown);
 }
 
 
@@ -780,9 +789,9 @@ void SCR_BringDownConsole (void)
                SCR_UpdateScreen ();
 
        cl.cshifts[0].percent = 0;              // no area contents palette on next frame
-       VID_SetPalette (host_basepal);
 }
 
+void DrawCrosshair(int num);
 void GL_Set2D (void);
 
 extern void SHOWLMP_drawall();
@@ -892,7 +901,7 @@ void SCR_UpdateScreen (void)
        if (vid.recalc_refdef)
                SCR_CalcRefdef ();
 
-       glClearColor(1,0,0,0);
+       glClearColor(0,0,0,0);
        glClear (GL_COLOR_BUFFER_BIT); // LordHavoc: clear the screen (around the view as well)
 
 //
@@ -928,7 +937,7 @@ void SCR_UpdateScreen (void)
        else
        {
                if (crosshair.value)
-                       Draw_Character (r_refdef.vrect.x + r_refdef.vrect.width/2, r_refdef.vrect.y + r_refdef.vrect.height/2, '+');
+                       DrawCrosshair(crosshair.value);
                
                SCR_DrawRam ();
                SCR_DrawNet ();
diff --git a/gl_textures.c b/gl_textures.c
new file mode 100644 (file)
index 0000000..7534ab4
--- /dev/null
@@ -0,0 +1,924 @@
+#include "quakedef.h"
+
+cvar_t         gl_max_size = {"gl_max_size", "1024"};
+cvar_t         gl_picmip = {"gl_picmip", "0"};
+cvar_t         gl_lerpimages = {"gl_lerpimages", "1"};
+
+int            gl_filter_min = GL_LINEAR_MIPMAP_LINEAR; //NEAREST;
+int            gl_filter_max = GL_LINEAR;
+
+
+int            texels;
+
+// 4096x4096
+#define MAXMIPS 12
+
+typedef struct
+{
+       int             texnum;
+       byte    *texels[MAXMIPS];
+       unsigned short texelsize[MAXMIPS][2];
+       char    identifier[64];
+       short   width, height;
+// LordHavoc: CRC to identify cache mismatchs
+       unsigned short crc;
+       char    mipmap;
+       char    alpha;
+       char    bytesperpixel;
+       char    lerped; // whether this texture was uploaded with or without interpolation
+} gltexture_t;
+
+#define        MAX_GLTEXTURES  4096
+gltexture_t    gltextures[MAX_GLTEXTURES];
+int                    numgltextures;
+
+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)
+               {
+                       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);
+               }
+       }
+}
+
+extern int buildnumber;
+
+char engineversion[40];
+
+void GL_UploadTexture (gltexture_t *glt);
+void gl_textures_start()
+{
+       int i;
+       gltexture_t *glt;
+       for (i=0, glt=gltextures ; i<numgltextures ; i++, glt++)
+               GL_UploadTexture(glt);
+}
+
+void gl_textures_shutdown()
+{
+}
+
+void GL_Textures_Init (void)
+{
+       Cvar_RegisterVariable (&gl_max_size);
+       Cvar_RegisterVariable (&gl_picmip);
+       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);
+
+       R_RegisterModule("GL_Textures", gl_textures_start, gl_textures_shutdown);
+}
+
+/*
+================
+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;
+}
+
+extern byte qgamma[];
+
+// LordHavoc: gamma correction and improved resampling
+void GL_ResampleTextureLerpLine (byte *in, byte *out, int inwidth, int outwidth)
+{
+       int             j, xi, oldx = 0, f, fstep, l1, l2, endx;
+       fstep = (int) (inwidth*65536.0f/outwidth);
+       endx = (inwidth-1);
+       for (j = 0,f = 0;j < outwidth;j++, f += fstep)
+       {
+               xi = (int) f >> 16;
+               if (xi != oldx)
+               {
+                       in += (xi - oldx) * 4;
+                       oldx = xi;
+               }
+               if (xi < endx)
+               {
+                       l2 = f & 0xFFFF;
+                       l1 = 0x10000 - l2;
+                       *out++ = qgamma[(byte) ((in[0] * l1 + in[4] * l2) >> 16)];
+                       *out++ = qgamma[(byte) ((in[1] * l1 + in[5] * l2) >> 16)];
+                       *out++ = qgamma[(byte) ((in[2] * l1 + in[6] * l2) >> 16)];
+                       *out++ =        (byte) ((in[3] * l1 + in[7] * l2) >> 16) ;
+               }
+               else // last pixel of the line has no pixel to lerp to
+               {
+                       *out++ = qgamma[in[0]];
+                       *out++ = qgamma[in[1]];
+                       *out++ = qgamma[in[2]];
+                       *out++ =        in[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, f, fstep, l1, l2, endy = (inheight-1);
+               byte    *inrow, *out, *row1, *row2;
+               out = outdata;
+               fstep = (int) (inheight*65536.0f/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)
+               {
+                       yi = f >> 16;
+                       if (yi != oldy)
+                       {
+                               inrow = (byte *)indata + inwidth*4*yi;
+                               if (yi == oldy+1)
+                                       memcpy(row1, row2, outwidth*4);
+                               else
+                                       GL_ResampleTextureLerpLine (inrow, row1, inwidth, outwidth);
+                               if (yi < endy)
+                                       GL_ResampleTextureLerpLine (inrow + inwidth*4, row2, inwidth, outwidth);
+                               else
+                                       memcpy(row2, row1, outwidth*4);
+                               oldy = yi;
+                       }
+                       if (yi < endy)
+                       {
+                               l2 = f & 0xFFFF;
+                               l1 = 0x10000 - l2;
+                               for (j = 0;j < outwidth;j++)
+                               {
+                                       *out++ = (byte) ((*row1++ * l1 + *row2++ * l2) >> 16);
+                                       *out++ = (byte) ((*row1++ * l1 + *row2++ * l2) >> 16);
+                                       *out++ = (byte) ((*row1++ * l1 + *row2++ * l2) >> 16);
+                                       *out++ = (byte) ((*row1++ * l1 + *row2++ * l2) >> 16);
+                               }
+                               row1 -= outwidth*4;
+                               row2 -= outwidth*4;
+                       }
+                       else // last line has no pixels to lerp to
+                       {
+                               for (j = 0;j < outwidth;j++)
+                               {
+                                       *out++ = *row1++;
+                                       *out++ = *row1++;
+                                       *out++ = *row1++;
+                                       *out++ = *row1++;
+                               }
+                               row1 -= outwidth*4;
+                       }
+               }
+               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)
+                       {
+                               inpix = inrow + ((frac >> 14) & ~3);*out++ = qgamma[*inpix++];*out++ = qgamma[*inpix++];*out++ = qgamma[*inpix++];*out++ =       *inpix++ ;frac += fracstep;
+                               inpix = inrow + ((frac >> 14) & ~3);*out++ = qgamma[*inpix++];*out++ = qgamma[*inpix++];*out++ = qgamma[*inpix++];*out++ =       *inpix++ ;frac += fracstep;
+                               inpix = inrow + ((frac >> 14) & ~3);*out++ = qgamma[*inpix++];*out++ = qgamma[*inpix++];*out++ = qgamma[*inpix++];*out++ =       *inpix++ ;frac += fracstep;
+                               inpix = inrow + ((frac >> 14) & ~3);*out++ = qgamma[*inpix++];*out++ = qgamma[*inpix++];*out++ = qgamma[*inpix++];*out++ =       *inpix++ ;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;
+       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;
+
+       if (alpha)
+       {
+               alpha = false;
+               in = data;
+               for (i = 3;i < width*height*4;i += 4)
+                       if (in[i] != 255)
+                       {
+                               alpha = true;
+                               break;
+                       }
+       }
+
+       samples = alpha ? gl_alpha_format : gl_solid_format;
+
+       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++ = qgamma[*in++];
+                       *out++ = qgamma[*in++];
+                       *out++ = qgamma[*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);
+               }
+       }
+
+       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 = NULL;
+
+       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);
+}
+*/
+
+extern 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
+                       {
+                               trans[i] = 0; // force to black
+                               noalpha = false;
+                       }
+               }
+
+               if (noalpha)
+               {
+                       if (VID_Is8bit() && (data!=scrap_texels[0]))
+                       {
+                               GL_Upload8_EXT (data, width, height, mipmap);
+                               free(trans);
+                               return;
+                       }
+                       alpha = false;
+               }
+       }
+       else
+       {
+               // LordHavoc: dodge the copy if it will be uploaded as 8bit
+               if (VID_Is8bit() && (data!=scrap_texels[0]))
+               {
+                       GL_Upload8_EXT (data, width, height, mipmap);
+                       free(trans);
+                       return;
+               }
+               //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);
+}
+*/
+
+void GL_AllocTexels(gltexture_t *glt, int width, int height, int mipmapped)
+{
+       int i, w, h, size, done;
+       if (glt->texels[0])
+               free(glt->texels[0]);
+       glt->texelsize[0][0] = width;
+       glt->texelsize[0][1] = height;
+       if (mipmapped)
+       {
+               size = 0;
+               w = width;h = height;
+               i = 0;
+               done = false;
+               for (i = 0;i < MAXMIPS;i++)
+               {
+                       glt->texelsize[i][0] = w;
+                       glt->texelsize[i][1] = h;
+                       glt->texels[i] = (void *)size;
+                       size += w*h*4;
+                       if (w > 1)
+                       {
+                               w >>= 1;
+                               if (h > 1)
+                                       h >>= 1;
+                       }
+                       else if (h > 1)
+                               h >>= 1;
+                       else
+                       {
+                               i++;
+                               break;
+                       }
+               }
+               while (i < MAXMIPS)
+                       glt->texels[i++] = NULL;
+               glt->texels[0] = malloc(size);
+               for (i = 1;i < MAXMIPS && glt->texels[i];i++)
+                       glt->texels[i] += (int) glt->texels[0];
+       }
+       else
+       {
+               glt->texels[0] = malloc(width*height*4);
+               for (i = 1;i < MAXMIPS;i++)
+                       glt->texels[i] = NULL;
+       }
+       if (!glt->texels[0])
+               Sys_Error("GL_AllocTexels: out of memory\n");
+}
+
+// in can be the same as out
+void GL_MipReduce(byte *in, byte *out, int width, int height, int destwidth, int destheight)
+{
+       int x, y, width2, height2, nextrow;
+       if (width > destwidth)
+       {
+               if (height > destheight)
+               {
+                       // reduce both
+                       width2 = width >> 1;
+                       height2 = height >> 1;
+                       nextrow = width << 2;
+                       for (y = 0;y < height2;y++)
+                       {
+                               for (x = 0;x < width2;x++)
+                               {
+                                       out[0] = (byte) ((in[0] + in[4] + in[nextrow  ] + in[nextrow+4]) >> 2);
+                                       out[1] = (byte) ((in[1] + in[5] + in[nextrow+1] + in[nextrow+5]) >> 2);
+                                       out[2] = (byte) ((in[2] + in[6] + in[nextrow+2] + in[nextrow+6]) >> 2);
+                                       out[3] = (byte) ((in[3] + in[7] + in[nextrow+3] + in[nextrow+7]) >> 2);
+                                       out += 4;
+                                       in += 8;
+                               }
+                               in += nextrow; // skip a line
+                       }
+               }
+               else
+               {
+                       // reduce width
+                       width2 = width >> 1;
+                       for (y = 0;y < height;y++)
+                       {
+                               for (x = 0;x < width2;x++)
+                               {
+                                       out[0] = (byte) ((in[0] + in[4]) >> 1);
+                                       out[1] = (byte) ((in[1] + in[5]) >> 1);
+                                       out[2] = (byte) ((in[2] + in[6]) >> 1);
+                                       out[3] = (byte) ((in[3] + in[7]) >> 1);
+                                       out += 4;
+                                       in += 8;
+                               }
+                       }
+               }
+       }
+       else
+       {
+               if (height > destheight)
+               {
+                       // reduce height
+                       height2 = height >> 1;
+                       nextrow = width << 2;
+                       for (y = 0;y < height2;y++)
+                       {
+                               for (x = 0;x < width;x++)
+                               {
+                                       out[0] = (byte) ((in[0] + in[nextrow  ]) >> 1);
+                                       out[1] = (byte) ((in[1] + in[nextrow+1]) >> 1);
+                                       out[2] = (byte) ((in[2] + in[nextrow+2]) >> 1);
+                                       out[3] = (byte) ((in[3] + in[nextrow+3]) >> 1);
+                                       out += 4;
+                                       in += 4;
+                               }
+                               in += nextrow; // skip a line
+                       }
+               }
+               else
+                       Sys_Error("GL_MipReduce: desired size already achieved\n");
+       }
+}
+
+void GL_UploadTexture (gltexture_t *glt)
+{
+       int mip, width, height;
+       glBindTexture(GL_TEXTURE_2D, glt->texnum);
+       width = glt->width;
+       height = glt->height;
+       for (mip = 0;mip < MAXMIPS && glt->texels[mip];mip++)
+               glTexImage2D(GL_TEXTURE_2D, mip, glt->alpha ? 4 : 3, glt->texelsize[mip][0], glt->texelsize[mip][1], 0, GL_RGBA, GL_UNSIGNED_BYTE, glt->texels[mip]);
+       if (glt->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);
+       }
+       glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+}
+
+/*
+================
+GL_LoadTexture
+================
+*/
+int GL_LoadTexture (char *identifier, int width, int height, byte *data, qboolean mipmap, qboolean alpha, int bytesperpixel)
+{
+       unsigned short  crc;
+       int                             i, width2, height2, width3, height3, w, h, mip;
+       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 (!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;
+                       }
+               }
+       }
+       // 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:
+       // calculate power of 2 size
+       width2 = 1;while (width2 < width) width2 <<= 1;
+       height2 = 1;while (height2 < height) height2 <<= 1;
+       // calculate final size (mipmapped downward to this)
+       width3 = width2 >> (int) gl_picmip.value;
+       height3 = height2 >> (int) gl_picmip.value;
+       while (width3 > (int) gl_max_size.value) width3 >>= 1;
+       while (height3 > (int) gl_max_size.value) height3 >>= 1;
+       if (width3 < 1) width3 = 1;
+       if (height3 < 1) height3 = 1;
+
+       // final storage
+       GL_AllocTexels(glt, width3, height3, mipmap);
+       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;
+       glt->alpha = false; // updated later
+       if (width == width3 && height == height3) // perfect match
+       {
+               if (bytesperpixel == 1) // 8bit
+                       Image_Copy8bitRGBA(data, glt->texels[0], width*height, d_8to24table);
+               else
+                       Image_CopyRGBAGamma(data, glt->texels[0], width*height);
+       }
+       else if (width == width2 && height == height2) // perfect match for top level, but needs to be reduced
+       {
+               byte *temptexels2;
+               temptexels2 = malloc(width2*height2*4); // scaleup buffer
+               if (bytesperpixel == 1) // 8bit
+                       Image_Copy8bitRGBA(data, temptexels2, width*height, d_8to24table);
+               else
+                       Image_CopyRGBAGamma(data, temptexels2, width*height);
+               while (width2 > width3 || height2 > height3)
+               {
+                       w = width2;h = height2;
+                       if (width2 > width3) width2 >>= 1;
+                       if (height2 > height3) height2 >>= 1;
+                       if (width2 <= width3 && height2 <= height3) // size achieved
+                               GL_MipReduce(temptexels2, glt->texels[0], w, h, width3, height3);
+                       else
+                               GL_MipReduce(temptexels2, temptexels2, w, h, width3, height3);
+               }
+               free(temptexels2);
+       }
+       else // scaling...
+       {
+               byte *temptexels;
+               // pre-scaleup buffer
+               temptexels = malloc(width*height*4);
+               if (bytesperpixel == 1) // 8bit
+                       Image_Copy8bitRGBA(data, temptexels, width*height, d_8to24table);
+               else
+                       Image_CopyRGBAGamma(data, temptexels, width*height);
+               if (width2 != width3 || height2 != height3) // reduced by gl_pic_mip or gl_max_size
+               {
+                       byte *temptexels2;
+                       temptexels2 = malloc(width2*height2*4); // scaleup buffer
+                       GL_ResampleTexture(temptexels, width, height, temptexels2, width2, height2);
+                       while (width2 > width3 || height2 > height3)
+                       {
+                               w = width2;h = height2;
+                               if (width2 > width3) width2 >>= 1;
+                               if (height2 > height3) height2 >>= 1;
+                               if (width2 <= width3 && height2 <= height3) // size achieved
+                                       GL_MipReduce(temptexels2, glt->texels[0], w, h, width3, height3);
+                               else
+                                       GL_MipReduce(temptexels2, temptexels2, w, h, width3, height3);
+                       }
+                       free(temptexels2);
+               }
+               else // copy directly
+                       GL_ResampleTexture(temptexels, width, height, glt->texels[0], width2, height2);
+               free(temptexels);
+       }
+       if (alpha)
+       {
+               byte    *in = glt->texels[0] + 3;
+               for (i = 0;i < width*height;i++, in += 4)
+                       if (*in < 255)
+                       {
+                               glt->alpha = true;
+                               break;
+                       }
+       }
+       // this loop is skipped if there are no mipmaps to generate
+       for (mip = 1;mip < MAXMIPS && glt->texels[mip];mip++)
+               GL_MipReduce(glt->texels[mip-1], glt->texels[mip], glt->texelsize[mip-1][0], glt->texelsize[mip-1][1], 1, 1);
+       GL_UploadTexture(glt);
+
+//     if (bytesperpixel == 1) // 8bit
+//             GL_Upload8 (data, width, height, mipmap, alpha);
+//     else // 32bit
+//             GL_Upload32 (data, width, height, mipmap, true);
+
+       return glt->texnum;
+}
+
+/*
+================
+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;
+}
index 5bf52b3..812b82a 100644 (file)
--- a/gl_warp.c
+++ b/gl_warp.c
@@ -178,7 +178,7 @@ void GL_SubdivideSurface (msurface_t *fa)
 
 extern qboolean lighthalf;
 
-#define        SKY_TEX         4000
+int skyboxside[6];
 
 char skyname[256];
 
@@ -201,7 +201,6 @@ void R_LoadSkyBox (void)
 
        for (i=0 ; i<6 ; i++)
        {
-               glBindTexture(GL_TEXTURE_2D, SKY_TEX + i);
                sprintf (name, "env/%s%s", skyname, suf[i]);
                if (!(image_rgba = loadimagepixels(name, FALSE, 0, 0)))
                {
@@ -212,10 +211,8 @@ void R_LoadSkyBox (void)
                                continue;
                        }
                }
-               glTexImage2D (GL_TEXTURE_2D, 0, gl_solid_format, image_width, image_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image_rgba);
+               skyboxside[i] = GL_LoadTexture(va("skyboxside%d", i), image_width, image_height, image_rgba, false, false, 4);
                free (image_rgba);
-               glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-               glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        }
 }
 
@@ -260,42 +257,42 @@ void R_SkyBox()
                glColor3f(0.5,0.5,0.5);
        else
                glColor3f(1,1,1);
-       glBindTexture(GL_TEXTURE_2D, SKY_TEX + 3); // front
+       glBindTexture(GL_TEXTURE_2D, skyboxside[3]); // front
        glBegin(GL_QUADS);
        R_SkyBoxPolyVec(1, 0,  1, -1,  1);
        R_SkyBoxPolyVec(1, 1,  1, -1, -1);
        R_SkyBoxPolyVec(0, 1,  1,  1, -1);
        R_SkyBoxPolyVec(0, 0,  1,  1,  1);
        glEnd();
-       glBindTexture(GL_TEXTURE_2D, SKY_TEX + 1); // back
+       glBindTexture(GL_TEXTURE_2D, skyboxside[1]); // back
        glBegin(GL_QUADS);
        R_SkyBoxPolyVec(1, 0, -1,  1,  1);
        R_SkyBoxPolyVec(1, 1, -1,  1, -1);
        R_SkyBoxPolyVec(0, 1, -1, -1, -1);
        R_SkyBoxPolyVec(0, 0, -1, -1,  1);
        glEnd();
-       glBindTexture(GL_TEXTURE_2D, SKY_TEX + 0); // right
+       glBindTexture(GL_TEXTURE_2D, skyboxside[0]); // right
        glBegin(GL_QUADS);
        R_SkyBoxPolyVec(1, 0,  1,  1,  1);
        R_SkyBoxPolyVec(1, 1,  1,  1, -1);
        R_SkyBoxPolyVec(0, 1, -1,  1, -1);
        R_SkyBoxPolyVec(0, 0, -1,  1,  1);
        glEnd();
-       glBindTexture(GL_TEXTURE_2D, SKY_TEX + 2); // left
+       glBindTexture(GL_TEXTURE_2D, skyboxside[2]); // left
        glBegin(GL_QUADS);
        R_SkyBoxPolyVec(1, 0, -1, -1,  1);
        R_SkyBoxPolyVec(1, 1, -1, -1, -1);
        R_SkyBoxPolyVec(0, 1,  1, -1, -1);
        R_SkyBoxPolyVec(0, 0,  1, -1,  1);
        glEnd();
-       glBindTexture(GL_TEXTURE_2D, SKY_TEX + 4); // up
+       glBindTexture(GL_TEXTURE_2D, skyboxside[4]); // up
        glBegin(GL_QUADS);
        R_SkyBoxPolyVec(1, 0,  1, -1,  1);
        R_SkyBoxPolyVec(1, 1,  1,  1,  1);
        R_SkyBoxPolyVec(0, 1, -1,  1,  1);
        R_SkyBoxPolyVec(0, 0, -1, -1,  1);
        glEnd();
-       glBindTexture(GL_TEXTURE_2D, SKY_TEX + 5); // down
+       glBindTexture(GL_TEXTURE_2D, skyboxside[5]); // down
        glBegin(GL_QUADS);
        R_SkyBoxPolyVec(1, 0,  1,  1, -1);
        R_SkyBoxPolyVec(1, 1,  1, -1, -1);
@@ -430,18 +427,14 @@ R_InitSky
 A sky texture is 256*128, with the right side being a masked overlay
 ==============
 */
-// LordHavoc: changed this for GLQuake
-void R_InitSky (byte *src, int bytesperpixel) //texture_t *mt)
+void R_InitSky (byte *src, int bytesperpixel)
 {
        int                     i, j, p;
-//     byte            *src;
        unsigned        trans[128*128];
        unsigned        transpix;
        int                     r, g, b;
        unsigned        *rgba;
 
-//     src = (byte *)mt + mt->offsets[0];
-
        if (bytesperpixel == 4)
        {
                for (i = 0;i < 128;i++)
@@ -470,16 +463,7 @@ void R_InitSky (byte *src, int bytesperpixel) //texture_t *mt)
                ((byte *)&transpix)[3] = 0;
        }
 
-       if (!solidskytexture)
-               solidskytexture = texture_extension_number++;
-       if (!isDedicated)
-       {
-               glBindTexture(GL_TEXTURE_2D, solidskytexture );
-               glTexImage2D (GL_TEXTURE_2D, 0, gl_solid_format, 128, 128, 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);
-       }
-
+       solidskytexture = GL_LoadTexture ("sky_solidtexture", 128, 128, (byte *) trans, false, false, 4);
 
        if (bytesperpixel == 4)
        {
@@ -500,14 +484,6 @@ void R_InitSky (byte *src, int bytesperpixel) //texture_t *mt)
                        }
        }
 
-       if (!alphaskytexture)
-               alphaskytexture = texture_extension_number++;
-       if (!isDedicated)
-       {
-               glBindTexture(GL_TEXTURE_2D, alphaskytexture);
-               glTexImage2D (GL_TEXTURE_2D, 0, gl_alpha_format, 128, 128, 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);
-       }
+       alphaskytexture = GL_LoadTexture ("sky_alphatexture", 128, 128, (byte *) trans, false, true, 4);
 }
 
index bed1e18..bab055b 100644 (file)
--- a/glquake.h
+++ b/glquake.h
@@ -37,17 +37,17 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #include <GL/gl.h>
 //#include <GL/glu.h>
 
-void GL_BeginRendering (int *x, int *y, int *width, int *height);
-void GL_EndRendering (void);
+extern void GL_BeginRendering (int *x, int *y, int *width, int *height);
+extern void GL_EndRendering (void);
 
 extern int texture_extension_number;
 
 extern float   gldepthmin, gldepthmax;
 
-void GL_Upload32 (void *data, int width, int height,  qboolean mipmap, qboolean alpha);
-void GL_Upload8 (byte *data, int width, int height,  qboolean mipmap, qboolean alpha);
-int GL_LoadTexture (char *identifier, int width, int height, byte *data, qboolean mipmap, qboolean alpha, int bytesperpixel);
-int GL_FindTexture (char *identifier);
+extern void GL_Upload32 (void *data, int width, int height,  qboolean mipmap, qboolean alpha);
+extern void GL_Upload8 (byte *data, int width, int height,  qboolean mipmap, qboolean alpha);
+extern int GL_LoadTexture (char *identifier, int width, int height, byte *data, qboolean mipmap, qboolean alpha, int bytesperpixel);
+extern int GL_FindTexture (char *identifier);
 
 typedef struct
 {
@@ -70,8 +70,8 @@ extern        int glx, gly, glwidth, glheight;
 #define BACKFACE_EPSILON       0.01
 
 
-void R_TimeRefresh_f (void);
-void R_ReadPointFile_f (void);
+extern void R_TimeRefresh_f (void);
+extern void R_ReadPointFile_f (void);
 
 //====================================================
 
@@ -103,39 +103,20 @@ extern    texture_t       *r_notexture_mip;
 extern int             d_lightstylevalue[256]; // 8.8 fraction of base light value
 
 extern qboolean        envmap;
-extern int     cnttextures[2];
-// LordHavoc: moved all code relating to particles into r_part.c
-//extern       int     particletexture;
-extern int     playertextures;
 
 extern int     skytexturenum;          // index in cl.loadmodel, not gl texture object
 
-//extern       cvar_t  r_norefresh;
 extern cvar_t  r_drawentities;
-//extern       cvar_t  r_drawworld;
 extern cvar_t  r_drawviewmodel;
 extern cvar_t  r_speeds;
-//extern       cvar_t  r_waterwarp;
 extern cvar_t  r_fullbright;
-//extern       cvar_t  r_lightmap;
 extern cvar_t  r_shadows;
 extern cvar_t  r_wateralpha;
 extern cvar_t  r_dynamic;
 extern cvar_t  r_novis;
 extern cvar_t  r_waterripple;
 
-//extern       cvar_t  gl_cull;
-//extern       cvar_t  gl_poly;
-//extern       cvar_t  gl_smoothmodels;
-//extern       cvar_t  gl_affinemodels;
-//extern       cvar_t  gl_polyblend;
-//extern       cvar_t  gl_keeptjunctions;
-//extern       cvar_t  gl_reporttjunctions;
-//extern       cvar_t  gl_nocolors;
-//extern       cvar_t  gl_doubleeyes;
-
 extern cvar_t  gl_max_size;
-extern cvar_t  gl_playermip;
 
 extern float   r_world_matrix[16];
 
@@ -144,8 +125,6 @@ extern      const char *gl_renderer;
 extern const char *gl_version;
 extern const char *gl_extensions;
 
-void R_TranslatePlayerSkin (int playernum);
-
 // Multitexture
 #define    TEXTURE0_SGIS                               0x835E
 #define    TEXTURE1_SGIS                               0x835F
@@ -259,3 +238,7 @@ extern vec_t fogdensity;
 //#define calcfog(v) (exp(-(fogdensity*fogdensity*(((v)[0] - r_refdef.vieworg[0]) * vpn[0] + ((v)[1] - r_refdef.vieworg[1]) * vpn[1] + ((v)[2] - r_refdef.vieworg[2]) * vpn[2])*(((v)[0] - r_refdef.vieworg[0]) * vpn[0] + ((v)[1] - r_refdef.vieworg[1]) * vpn[1] + ((v)[2] - r_refdef.vieworg[2]) * vpn[2]))))
 #define calcfog(v) (exp(-(fogdensity*fogdensity*(((v)[0] - r_refdef.vieworg[0])*((v)[0] - r_refdef.vieworg[0])+((v)[1] - r_refdef.vieworg[1])*((v)[1] - r_refdef.vieworg[1])+((v)[2] - r_refdef.vieworg[2])*((v)[2] - r_refdef.vieworg[2])))))
 #define calcfogbyte(v) ((byte) (bound(0, ((int) ((float) (calcfog((v)) * 255.0f))), 255)))
+
+#include "r_modules.h"
+
+extern void R_DrawAliasModel (entity_t *ent, int cull, float alpha, model_t *clmodel, int frame, int skin, vec3_t org, int effects, int flags, int colormap);
diff --git a/host.c b/host.c
index e9c697e..15ee313 100644 (file)
--- a/host.c
+++ b/host.c
@@ -53,7 +53,6 @@ client_t      *host_client;                   // current client
 jmp_buf        host_abortserver;
 
 byte           *host_basepal;
-//byte         *host_colormap;
 
 cvar_t host_framerate = {"host_framerate","0"};        // set for slow motion
 cvar_t host_speeds = {"host_speeds","0"};                      // set for running times
@@ -557,74 +556,6 @@ Host_ServerFrame
 
 ==================
 */
-#ifdef FPS_20
-
-void _Host_ServerFrame (void)
-{
-// run the world state 
-       pr_global_struct->frametime = host_frametime;
-
-// read client messages
-       SV_RunClients ();
-       
-// move things around and think
-// always pause in single player if in console or menus
-       if (!sv.paused && (svs.maxclients > 1 || key_dest == key_game) )
-               SV_Physics ();
-}
-
-void Host_ServerFrame (void)
-{
-       float   save_host_frametime;
-       float   temp_host_frametime;
-       static float    host_serverframe_timevalue;
-
-// run the world state 
-       pr_global_struct->frametime = host_frametime;
-
-// set the time and clear the general datagram
-       SV_ClearDatagram ();
-               
-// check for new clients
-       SV_CheckForNewClients ();
-
-       temp_host_frametime = save_host_frametime = host_frametime;
-       // LordHavoc: the results of my attempts to mangle this code to process no more than sys_ticrate, 
-       // when I found that was too choppy, I changed it back to processing at least 20fps,
-       // I consider it a bit of a failure...  because I felt a little out of control in singleplayer
-       // (sliding around)
-       //if (host_serverframe_timevalue < -0.2) // don't let it get way out of range
-       //      host_serverframe_timevalue = -0.2;
-       //host_serverframe_timevalue += host_frametime;
-       // process frames (several if rendering is too slow to run well as a server)
-       while(temp_host_frametime > 0.0)
-       {
-               host_frametime = temp_host_frametime;
-               if (host_frametime > 0.05)
-                       host_frametime = 0.05;
-               temp_host_frametime -= host_frametime;
-       //      host_serverframe_timevalue -= host_frametime;
-               _Host_ServerFrame ();
-       }
-       host_frametime = save_host_frametime;
-
-// send all messages to the clients
-       SV_SendClientMessages ();
-// LordHavoc: sadly, this didn't look good to the person running the server in listen mode
-       /*
-// wait until enough time has built up when the framerate exceeds sys_ticrate
-       if (host_serverframe_timevalue >= sys_ticrate.value)
-       //{
-       //      while(host_serverframe_timevalue >= sys_ticrate.value)
-       //              host_serverframe_timevalue -= sys_ticrate.value;
-// send all messages to the clients
-               SV_SendClientMessages ();
-       }
-       */
-}
-
-#else
-
 double frametimetotal = 0, lastservertime = 0;
 void Host_ServerFrame (void)
 {
@@ -655,8 +586,6 @@ void Host_ServerFrame (void)
        SV_SendClientMessages ();
 }
 
-#endif
-
 
 /*
 ==================
@@ -862,6 +791,8 @@ void Host_InitVCR (quakeparms_t *parms)
        
 }
 
+void Render_Init();
+
 /*
 ====================
 Host_Init
@@ -914,18 +845,13 @@ void Host_Init (quakeparms_t *parms)
                if (!host_basepal)
                        Sys_Error ("Couldn't load gfx/palette.lmp");
                host_basepal[765] = host_basepal[766] = host_basepal[767] = 0; // LordHavoc: force the transparent color to black
-//             host_colormap = (byte *)COM_LoadHunkFile ("gfx/colormap.lmp", false);
-//             if (!host_colormap)
-//                     Sys_Error ("Couldn't load gfx/colormap.lmp");
 
 #ifndef _WIN32 // on non win32, mouse comes before video for security reasons
                IN_Init ();
 #endif
                VID_Init (host_basepal);
 
-               Draw_Init ();
-               SCR_Init ();
-               R_Init ();
+               Render_Init();
                S_Init ();
                CDAudio_Init ();
                Sbar_Init ();
@@ -977,6 +903,7 @@ void Host_Shutdown(void)
 
        if (cls.state != ca_dedicated)
        {
+               R_ShutdownModules();
                VID_Shutdown();
        }
 }
index c08e921..1e18df9 100644 (file)
@@ -1469,15 +1469,15 @@ void Host_Viewframe_f (void)
 
 void PrintFrameName (model_t *m, int frame)
 {
-       aliashdr_t                      *hdr;
-       maliasframedesc_t       *pframedesc;
+       maliashdr_t     *mheader;
+       maliasframe_t   *frameinfo;
 
-       hdr = (aliashdr_t *)Mod_Extradata (m);
-       if (!hdr)
+       mheader = (maliashdr_t *)Mod_Extradata (m);
+       if (!mheader)
                return;
-       pframedesc = &hdr->frames[frame];
+       frameinfo = &((maliasframe_t *)(mheader->framedata + (int) mheader))[frame];
        
-       Con_Printf ("frame %i: %s\n", frame, pframedesc->name);
+       Con_Printf ("frame %i: %s\n", frame, frameinfo->name);
 }
 
 /*
diff --git a/image.c b/image.c
index d48bee4..6740dac 100644 (file)
--- a/image.c
+++ b/image.c
@@ -4,6 +4,59 @@
 int            image_width;
 int            image_height;
 
+// note: pal must be 32bit color
+void Image_Copy8bitRGBA(byte *in, byte *out, int pixels, int *pal)
+{
+       int *iout = (void *)out;
+       while (pixels >= 8)
+       {
+               iout[0] = pal[in[0]];
+               iout[1] = pal[in[1]];
+               iout[2] = pal[in[2]];
+               iout[3] = pal[in[3]];
+               iout[4] = pal[in[4]];
+               iout[5] = pal[in[5]];
+               iout[6] = pal[in[6]];
+               iout[7] = pal[in[7]];
+               in += 8;
+               iout += 8;
+               pixels -= 8;
+       }
+       if (pixels & 4)
+       {
+               iout[0] = pal[in[0]];
+               iout[1] = pal[in[1]];
+               iout[2] = pal[in[2]];
+               iout[3] = pal[in[3]];
+               in += 4;
+               iout += 4;
+       }
+       if (pixels & 2)
+       {
+               iout[0] = pal[in[0]];
+               iout[1] = pal[in[1]];
+               in += 2;
+               iout += 2;
+       }
+       if (pixels & 1)
+               iout[0] = pal[in[0]];
+}
+
+extern byte qgamma[];
+void Image_CopyRGBAGamma(byte *in, byte *out, int pixels)
+{
+       while (pixels--)
+       {
+               out[0] = qgamma[in[0]];
+               out[1] = qgamma[in[1]];
+               out[2] = qgamma[in[2]];
+               out[3] =        in[3] ;
+               in += 4;
+               out += 4;
+       }
+}
+
+
 /*
 =================================================================
 
@@ -101,6 +154,7 @@ byte* LoadPCX (FILE *f, int matchwidth, int matchheight)
                        }
                }
        }
+       fclose(f);
        image_width = pcx->xmax+1;
        image_height = pcx->ymax+1;
        return image_rgba;
@@ -184,7 +238,7 @@ byte* LoadTGA (FILE *fin, int matchwidth, int matchheight)
 
        if (targa_header.colormap_type !=0 
                || (targa_header.pixel_size!=32 && targa_header.pixel_size!=24))
-               Host_Error ("Texture_LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n");
+               Host_Error ("LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n");
 
        columns = targa_header.width;
        rows = targa_header.height;
@@ -309,12 +363,50 @@ byte* LoadTGA (FILE *fin, int matchwidth, int matchheight)
        return image_rgba;
 }
 
+/*
+============
+LoadLMP
+============
+*/
+byte* LoadLMP (FILE *f, int matchwidth, int matchheight)
+{
+       byte    *image_rgba;
+       int             width, height;
+
+       // parse the very complicated header *chuckle*
+       width = fgetLittleLong(f);
+       height = fgetLittleLong(f);
+       if ((unsigned) width > 4096 || (unsigned) height > 4096)
+               Host_Error("LoadLMP: invalid size\n");
+       if (matchwidth && width != matchwidth)
+               return NULL;
+       if (matchheight && height != matchheight)
+               return NULL;
+
+       image_rgba = malloc(width*height*4);
+       fread(image_rgba + width*height*3, 1, width*height, f);
+       fclose(f);
+
+       Image_Copy8bitRGBA(image_rgba + width*height*3, image_rgba, width*height, d_8to24table);
+       image_width = width;
+       image_height = height;
+       return image_rgba;
+}
+
 byte* loadimagepixels (char* filename, qboolean complain, int matchwidth, int matchheight)
 {
        FILE    *f;
        char    basename[128], name[128];
-       byte    *image_rgba;
+       byte    *image_rgba, *c;
        COM_StripExtension(filename, basename); // strip the extension to allow TGA skins on Q2 models despite the .pcx in the skin name
+       // replace *'s with +, so commandline utils don't get confused when dealing with the external files
+       c = basename;
+       while (*c)
+       {
+               if (*c == '*')
+                       *c = '+';
+               c++;
+       }
        sprintf (name, "textures/%s.tga", basename);
        COM_FOpenFile (name, &f, true);
        if (f)
@@ -331,6 +423,13 @@ byte* loadimagepixels (char* filename, qboolean complain, int matchwidth, int ma
        COM_FOpenFile (name, &f, true);
        if (f)
                return LoadPCX (f, matchwidth, matchheight);
+       sprintf (name, "%s.lmp", basename);
+       COM_FOpenFile (name, &f, true);
+       if (f)
+               return LoadLMP (f, matchwidth, matchheight);
+       if ((image_rgba = W_GetTexture(basename, matchwidth, matchheight)))
+               return image_rgba;
+       COM_StripExtension(filename, basename); // do it again with a * this time
        if ((image_rgba = W_GetTexture(basename, matchwidth, matchheight)))
                return image_rgba;
        if (complain)
@@ -338,22 +437,28 @@ byte* loadimagepixels (char* filename, qboolean complain, int matchwidth, int ma
        return NULL;
 }
 
-int loadtextureimage (int texnum, char* filename, qboolean complain, int matchwidth, int matchheight)
+int loadtextureimage (char* filename, int matchwidth, int matchheight, qboolean complain, qboolean mipmap)
 {
+       int texnum;
        byte *data;
        if (!(data = loadimagepixels (filename, complain, matchwidth, matchheight)))
                return 0;
+       texnum = GL_LoadTexture (filename, image_width, image_height, data, mipmap, true, 4);
+       free(data);
+       return texnum;
+       /*
        if (texnum >= 0) // specific texnum, not cached
        {
                glBindTexture(GL_TEXTURE_2D, texnum);
-               GL_Upload32 (data, image_width, image_height, true, true);
+               GL_Upload32 (data, image_width, image_height, mipmap, true);
                free(data);
                return texnum;
        }
        else // any texnum, cached
        {
-               texnum = GL_LoadTexture (filename, image_width, image_height, data, true, true, 4);
+               texnum = GL_LoadTexture (filename, image_width, image_height, data, mipmap, true, 4);
                free(data);
                return texnum;
        }
+       */
 }
diff --git a/image.h b/image.h
new file mode 100644 (file)
index 0000000..375f511
--- /dev/null
+++ b/image.h
@@ -0,0 +1,3 @@
+
+extern void Image_Copy8bitRGBA(byte *in, byte *out, int pixels, int *pal);
+extern void Image_CopyRGBAGamma(byte *in, byte *out, int pixels);
index d290c4b..2f7b5f2 100644 (file)
@@ -29,14 +29,14 @@ void Mod_AliasInit (void)
 {
 }
 
-aliashdr_t     *pheader;
-
-typedef struct
-{
-       int v[3];
-       vec3_t normal;
-} temptris_t;
-temptris_t *temptris;
+//aliashdr_t   *pheader;
+
+//typedef struct
+//{
+//     int v[3];
+//     vec3_t normal;
+//} temptris_t;
+//temptris_t *temptris;
 //stvert_t     stverts[MAXALIASVERTS];
 //mtriangle_t  triangles[MAXALIASTRIS];
 
@@ -50,16 +50,23 @@ byte                *player_8bit_texels;
 
 float          aliasbboxmin[3], aliasbboxmax[3]; // LordHavoc: proper bounding box considerations
 
-// LordHavoc: changed to use the normals from the model data itself
+#define MAXVERTS 8192
+float vertst[MAXVERTS][2];
+int vertusage[MAXVERTS];
+int vertonseam[MAXVERTS];
+int vertremap[MAXVERTS];
+unsigned short temptris[MAXVERTS][3];
+
 #define NUMVERTEXNORMALS       162
 extern float   r_avertexnormals[NUMVERTEXNORMALS][3];
-void Mod_ConvertAliasVerts (int numverts, int numtris, vec3_t scale, vec3_t translate, trivertx_t *v, trivert2 *out)
+void Mod_ConvertAliasVerts (int inverts, vec3_t scale, vec3_t translate, trivertx_t *v, trivert2 *out)
 {
-       int i;
+       int i, j;
        vec3_t temp;
-       for (i = 0;i < numverts;i++)
+       for (i = 0;i < inverts;i++)
        {
-               VectorCopy(v[i].v, out[i].v);
+               if (vertremap[i] < 0 && vertremap[i+inverts] < 0) // only used vertices need apply...
+                       continue;
                temp[0] = v[i].v[0] * scale[0] + translate[0];
                temp[1] = v[i].v[1] * scale[1] + translate[1];
                temp[2] = v[i].v[2] * scale[2] + translate[2];
@@ -70,62 +77,23 @@ void Mod_ConvertAliasVerts (int numverts, int numtris, vec3_t scale, vec3_t tran
                if (temp[0] > aliasbboxmax[0]) aliasbboxmax[0] = temp[0];
                if (temp[1] > aliasbboxmax[1]) aliasbboxmax[1] = temp[1];
                if (temp[2] > aliasbboxmax[2]) aliasbboxmax[2] = temp[2];
-               out[i].n[0] = (signed char) (r_avertexnormals[v[i].lightnormalindex][0] * 127.0);
-               out[i].n[1] = (signed char) (r_avertexnormals[v[i].lightnormalindex][1] * 127.0);
-               out[i].n[2] = (signed char) (r_avertexnormals[v[i].lightnormalindex][2] * 127.0);
-       }               
-       /*
-       int i, j;
-       vec3_t t1, t2;
-       struct
-       {
-               vec3_t v;
-               vec3_t normal;
-               int count;
-       } tempvert[MD2MAX_VERTS];
-       temptris_t *tris;
-       // decompress vertices
-       for (i = 0;i < numverts;i++)
-       {
-               VectorCopy(v[i].v, out[i].v);
-               tempvert[i].v[0] = v[i].v[0] * scale[0] + translate[0];
-               tempvert[i].v[1] = v[i].v[1] * scale[1] + translate[1];
-               tempvert[i].v[2] = v[i].v[2] * scale[2] + translate[2];
-               tempvert[i].normal[0] = tempvert[i].normal[1] = tempvert[i].normal[2] = 0;
-               tempvert[i].count = 0;
-               // update bounding box
-               if (tempvert[i].v[0] < aliasbboxmin[0]) aliasbboxmin[0] = tempvert[i].v[0];
-               if (tempvert[i].v[1] < aliasbboxmin[1]) aliasbboxmin[1] = tempvert[i].v[1];
-               if (tempvert[i].v[2] < aliasbboxmin[2]) aliasbboxmin[2] = tempvert[i].v[2];
-               if (tempvert[i].v[0] > aliasbboxmax[0]) aliasbboxmax[0] = tempvert[i].v[0];
-               if (tempvert[i].v[1] > aliasbboxmax[1]) aliasbboxmax[1] = tempvert[i].v[1];
-               if (tempvert[i].v[2] > aliasbboxmax[2]) aliasbboxmax[2] = tempvert[i].v[2];
-       }
-       // calculate surface normals
-       tris = temptris;
-       for (i = 0;i < numtris;i++)
-       {
-               VectorSubtract(tempvert[tris->v[0]].v, tempvert[tris->v[1]].v, t1);
-               VectorSubtract(tempvert[tris->v[2]].v, tempvert[tris->v[1]].v, t2);
-               CrossProduct(t1, t2, tris->normal);
-               VectorNormalize(tris->normal);
-               // add surface normal to vertices
-               for (j = 0;j < 3;j++)
+               j = vertremap[i]; // not onseam
+               if (j >= 0)
                {
-                       VectorAdd(tris->normal, tempvert[tris->v[j]].normal, tempvert[tris->v[j]].normal);
-                       tempvert[tris->v[j]].count++;
+                       VectorCopy(v[i].v, out[j].v);
+                       out[j].n[0] = (signed char) (r_avertexnormals[v[i].lightnormalindex][0] * 127.0);
+                       out[j].n[1] = (signed char) (r_avertexnormals[v[i].lightnormalindex][1] * 127.0);
+                       out[j].n[2] = (signed char) (r_avertexnormals[v[i].lightnormalindex][2] * 127.0);
+               }
+               j = vertremap[i+inverts]; // onseam
+               if (j >= 0)
+               {
+                       VectorCopy(v[i].v, out[j].v);
+                       out[j].n[0] = (signed char) (r_avertexnormals[v[i].lightnormalindex][0] * 127.0);
+                       out[j].n[1] = (signed char) (r_avertexnormals[v[i].lightnormalindex][1] * 127.0);
+                       out[j].n[2] = (signed char) (r_avertexnormals[v[i].lightnormalindex][2] * 127.0);
                }
-               tris++;
-       }
-       // average normals and write out 1.7bit format
-       for (i = 0;i < pheader->numtris;i++)
-       {
-               VectorNormalize(tempvert[i].normal);
-               out[i].n[0] = (signed char) (tempvert[i].normal[0] * 127.0);
-               out[i].n[1] = (signed char) (tempvert[i].normal[1] * 127.0);
-               out[i].n[2] = (signed char) (tempvert[i].normal[2] * 127.0);
        }
-       */
 }
 
 /*
@@ -133,35 +101,25 @@ void Mod_ConvertAliasVerts (int numverts, int numtris, vec3_t scale, vec3_t tran
 Mod_LoadAliasFrame
 =================
 */
-void * Mod_LoadAliasFrame (void * pin, maliasframedesc_t *frame)
+void * Mod_LoadAliasFrame (void *pin, maliasframe_t *frame, maliashdr_t *mheader, int inverts, int outverts, trivert2 **posevert)
 {
        trivertx_t              *pinframe;
-       int                             i;
        daliasframe_t   *pdaliasframe;
        
        pdaliasframe = (daliasframe_t *)pin;
 
-       strcpy (frame->name, pdaliasframe->name);
-       frame->firstpose = posenum;
-       frame->numposes = 1;
-
-       for (i=0 ; i<3 ; i++)
-       {
-       // these are byte values, so we don't have to worry about
-       // endianness
-               frame->bboxmin.v[i] = pdaliasframe->bboxmin.v[i];
-               frame->bboxmax.v[i] = pdaliasframe->bboxmax.v[i]; // LordHavoc: was setting bboxmin a second time (bug)
-       }
+       strcpy(frame->name, pdaliasframe->name);
+       frame->start = posenum;
+       frame->length = 1;
+       frame->rate = 10.0f; // unnecessary but...
 
        pinframe = (trivertx_t *)(pdaliasframe + 1);
 
-//     poseverts[posenum] = pinframe;
-       Mod_ConvertAliasVerts(pheader->numverts, pheader->numtris, pheader->scale, pheader->scale_origin, pinframe, (void *)((int) pheader + pheader->posedata + sizeof(trivert2) * pheader->numverts * posenum));
-//     // LordHavoc: copy the frame data
-//     memcpy((void *)((int) pheader + pheader->posedata + sizeof(trivertx_t) * pheader->numverts * posenum), pinframe, sizeof(trivertx_t) * pheader->numverts);
+       Mod_ConvertAliasVerts(inverts, mheader->scale, mheader->scale_origin, pinframe, *posevert);
+       *posevert += outverts;
        posenum++;
 
-       pinframe += pheader->numverts;
+       pinframe += inverts;
 
        return (void *)pinframe;
 }
@@ -172,44 +130,31 @@ void * Mod_LoadAliasFrame (void * pin, maliasframedesc_t *frame)
 Mod_LoadAliasGroup
 =================
 */
-void *Mod_LoadAliasGroup (void * pin,  maliasframedesc_t *frame)
+void *Mod_LoadAliasGroup (void *pin, maliasframe_t *frame, maliashdr_t *mheader, int inverts, int outverts, trivert2 **posevert)
 {
-       daliasgroup_t           *pingroup;
-       int                                     i, numframes;
-       daliasinterval_t        *pin_intervals;
-       void                            *ptemp;
+       int             i, numframes;
+       void    *ptemp;
+       float   interval;
        
-       pingroup = (daliasgroup_t *)pin;
-
-       numframes = LittleLong (pingroup->numframes);
-
-       frame->firstpose = posenum;
-       frame->numposes = numframes;
-
-       for (i=0 ; i<3 ; i++)
-       {
-       // these are byte values, so we don't have to worry about endianness
-               frame->bboxmin.v[i] = pingroup->bboxmin.v[i];
-               frame->bboxmax.v[i] = pingroup->bboxmax.v[i]; // LordHavoc: was setting bboxmin a second time (bug)
-       }
-
-       pin_intervals = (daliasinterval_t *)(pingroup + 1);
+       numframes = LittleLong (((daliasgroup_t *)pin)->numframes);
 
-       frame->interval = LittleFloat (pin_intervals->interval);
+       strcpy(frame->name, "group");
+       frame->start = posenum;
+       frame->length = numframes;
+       interval = LittleFloat (((daliasinterval_t *)(((daliasgroup_t *)pin) + 1))->interval); // FIXME: support variable framerate groups?
+       if (interval < 0.01f)
+               Host_Error("Mod_LoadAliasGroup: invalid interval");
+       frame->rate = 1.0f / interval;
 
-       pin_intervals += numframes;
-
-       ptemp = (void *)pin_intervals;
+       ptemp = (void *)(((daliasinterval_t *)(((daliasgroup_t *)pin) + 1)) + numframes);
 
        for (i=0 ; i<numframes ; i++)
        {
-//             poseverts[posenum] = (trivertx_t *)((daliasframe_t *)ptemp + 1);
-               Mod_ConvertAliasVerts(pheader->numverts, pheader->numtris, pheader->scale, pheader->scale_origin, (void *)((daliasframe_t *)ptemp + 1), (void *)((int) pheader + pheader->posedata + sizeof(trivert2) * pheader->numverts * posenum));
-//             // LordHavoc: copy the frame data
-//             memcpy((void *)((int) pheader + pheader->posedata + sizeof(trivertx_t) * pheader->numverts * posenum), (void *)((daliasframe_t *)ptemp + 1), sizeof(trivertx_t) * pheader->numverts);
+               ((daliasframe_t *)ptemp)++;
+               Mod_ConvertAliasVerts(inverts, mheader->scale, mheader->scale_origin, ptemp, *posevert);
+               *posevert += outverts;
                posenum++;
-
-               ptemp = (trivertx_t *)((daliasframe_t *)ptemp + 1) + pheader->numverts;
+               ptemp = (trivertx_t *)ptemp + inverts;
        }
 
        return ptemp;
@@ -293,84 +238,179 @@ void Mod_FloodFillSkin( byte *skin, int skinwidth, int skinheight )
        }
 }
 
+int GL_SkinSplitShirt(byte *in, byte *out, int width, int height, unsigned short bits, char *name)
+{
+       int i, pixels, passed;
+       byte pixeltest[16];
+       for (i = 0;i < 16;i++)
+               pixeltest[i] = (bits & (1 << i)) != 0;
+       pixels = width*height;
+       passed = 0;
+       while(pixels--)
+       {
+               if (pixeltest[*in >> 4] && *in != 0 && *in != 255)
+               {
+                       passed++;
+                       // turn to white while copying
+                       if (*in >= 128 && *in < 224) // backwards ranges
+                               *out = (*in & 15) ^ 15;
+                       else
+                               *out = *in & 15;
+               }
+               else
+                       *out = 0;
+               in++;
+               out++;
+       }
+       if (passed)
+               return GL_LoadTexture (name, width, height, out - width*height, true, false, 1);
+       else
+               return 0;
+}
+
+int GL_SkinSplit(byte *in, byte *out, int width, int height, unsigned short bits, char *name)
+{
+       int i, pixels, passed;
+       byte pixeltest[16];
+       for (i = 0;i < 16;i++)
+               pixeltest[i] = (bits & (1 << i)) != 0;
+       pixels = width*height;
+       passed = 0;
+       while(pixels--)
+       {
+               if (pixeltest[*in >> 4] && *in != 0 && *in != 255)
+               {
+                       passed++;
+                       *out = *in;
+               }
+               else
+                       *out = 0;
+               in++;
+               out++;
+       }
+       if (passed)
+               return GL_LoadTexture (name, width, height, out - width*height, true, false, 1);
+       else
+               return 0;
+}
+
 /*
 ===============
 Mod_LoadAllSkins
 ===============
 */
-void *Mod_LoadAllSkins (int numskins, daliasskintype_t *pskintype, int bytesperpixel)
+void *Mod_LoadAllSkins (int numskins, daliasskintype_t *pskintype, int width, int height)
 {
-       int             i, j, k;
+       int             i, j;
        char    name[32];
        int             s;
        byte    *skin;
-       byte    *texels;
        daliasskingroup_t               *pinskingroup;
        int             groupskins;
        daliasskininterval_t    *pinskinintervals;
+       int             skinranges, skincount, *skintexnum, *skinrange, skinnum;
+       void    *temp;
+       byte    *skintemp = NULL;
        
        skin = (byte *)(pskintype + 1);
 
        if (numskins < 1 || numskins > MAX_SKINS)
                Host_Error ("Mod_LoadAliasModel: Invalid # of skins: %d\n", numskins);
 
-       s = pheader->skinwidth * pheader->skinheight;
+       s = width * height;
+       skintemp = malloc(s);
 
+       // LordHavoc: skim the data, measure the number of skins and number of groups
+       skinranges = numskins;
+       skincount = 0;
+       temp = pskintype;
+       for (i = 0;i < numskins;i++)
+       {
+               pskintype++;
+               if (pskintype[-1].type == ALIAS_SKIN_SINGLE)
+               {
+                       skincount++;
+                       (byte *)pskintype += s;
+               }
+               else
+               {
+                       groupskins = LittleLong (((daliasskingroup_t *)pskintype)->numskins);
+                       skincount += groupskins;
+                       (byte *)pskintype += (s + sizeof(daliasskininterval_t)) * groupskins + sizeof(daliasskingroup_t);
+               }
+       }
+       pskintype = temp;
+
+       skinrange = loadmodel->skinanimrange;
+       skintexnum = loadmodel->skinanim;
+//     skinrange = Hunk_AllocName (sizeof(int) * (skinranges + skincount), loadname);  
+//     skintexnum = skinrange + skinranges * 2;
+//     loadmodel->skinanimrange = (int) skinrange - (int) pheader;
+//     loadmodel->skinanim = (int) skintexnum - (int) pheader;
+       skinnum = 0;
        for (i = 0;i < numskins;i++)
        {
-               if (pskintype->type == ALIAS_SKIN_SINGLE)
+               *skinrange++ = skinnum; // start of the range
+               pskintype++;
+               if (pskintype[-1].type == ALIAS_SKIN_SINGLE)
                {
-                       if (bytesperpixel == 1)
-                               Mod_FloodFillSkin( skin, pheader->skinwidth, pheader->skinheight );
-
-                       // save 8 bit texels for the player model to remap
-       //              if (!strcmp(loadmodel->name,"progs/player.mdl")) {
-                               texels = Hunk_AllocName(s, loadname);
-                               pheader->texels[i] = texels - (byte *)pheader;
-                               memcpy (texels, (byte *)(pskintype + 1), s);
-       //              }
+                       *skinrange++ = 1; // single skin
+                       skinnum++;
                        sprintf (name, "%s_%i", loadmodel->name, i);
-                       pheader->gl_texturenum[i][0] =
-                       pheader->gl_texturenum[i][1] =
-                       pheader->gl_texturenum[i][2] =
-                       pheader->gl_texturenum[i][3] =
-                               GL_LoadTexture (name, pheader->skinwidth, pheader->skinheight, (byte *)(pskintype + 1), true, false, bytesperpixel);
-                       pskintype = (daliasskintype_t *)((byte *)(pskintype+1) + s);
+
+                       Mod_FloodFillSkin( skin, width, height );
+                       *skintexnum++ = GL_SkinSplit((byte *)pskintype, skintemp, width, height, 0x3FBD, va("%s_normal", name)); // normal (no special colors)
+                       *skintexnum++ = GL_SkinSplitShirt((byte *)pskintype, skintemp, width, height, 0x0040, va("%s_pants",  name)); // pants
+                       *skintexnum++ = GL_SkinSplitShirt((byte *)pskintype, skintemp, width, height, 0x0002, va("%s_shirt",  name)); // shirt
+                       *skintexnum++ = GL_SkinSplit((byte *)pskintype, skintemp, width, height, 0xC000, va("%s_glow",   name)); // glow
+                       *skintexnum++ = GL_SkinSplit((byte *)pskintype, skintemp, width, height, 0x3FFF, va("%s_body",   name)); // body (normal + pants + shirt, but not glow)
+                       pskintype = (daliasskintype_t *)((byte *)(pskintype) + s);
                }
                else
                {
                        // animating skin group.  yuck.
-                       pskintype++;
                        pinskingroup = (daliasskingroup_t *)pskintype;
                        groupskins = LittleLong (pinskingroup->numskins);
                        pinskinintervals = (daliasskininterval_t *)(pinskingroup + 1);
 
                        pskintype = (void *)(pinskinintervals + groupskins);
 
+                       *skinrange++ = groupskins; // number of skins
+                       skinnum += groupskins;
                        for (j = 0;j < groupskins;j++)
                        {
-                                       if (bytesperpixel == 1)
-                                               Mod_FloodFillSkin( skin, pheader->skinwidth, pheader->skinheight );
-                                       if (j == 0)
-                                       {
-                                               texels = Hunk_AllocName(s, loadname);
-                                               pheader->texels[i] = texels - (byte *)pheader;
-                                               memcpy (texels, (byte *)(pskintype), s);
-                                       }
-                                       sprintf (name, "%s_%i_%i", loadmodel->name, i,j);
-                                       pheader->gl_texturenum[i][j&3] = 
-                                               GL_LoadTexture (name, pheader->skinwidth, pheader->skinheight, (byte *)(pskintype), true, false, bytesperpixel);
-                                       pskintype = (daliasskintype_t *)((byte *)(pskintype) + s);
+                               sprintf (name, "%s_%i_%i", loadmodel->name, i,j);
+
+                               Mod_FloodFillSkin( skin, width, height );
+                               *skintexnum++ = GL_SkinSplit((byte *)pskintype, skintemp, width, height, 0x3FBD, va("%s_normal", name)); // normal (no special colors)
+                               *skintexnum++ = GL_SkinSplitShirt((byte *)pskintype, skintemp, width, height, 0x0040, va("%s_pants",  name)); // pants
+                               *skintexnum++ = GL_SkinSplitShirt((byte *)pskintype, skintemp, width, height, 0x0002, va("%s_shirt",  name)); // shirt
+                               *skintexnum++ = GL_SkinSplit((byte *)pskintype, skintemp, width, height, 0xC000, va("%s_glow",   name)); // glow
+                               *skintexnum++ = GL_SkinSplit((byte *)pskintype, skintemp, width, height, 0x3FFF, va("%s_body",   name)); // body (normal + pants + shirt, but not glow)
+                               pskintype = (daliasskintype_t *)((byte *)(pskintype) + s);
                        }
-                       k = j;
-                       for (;j < 4;j++)
-                               pheader->gl_texturenum[i][j&3] = pheader->gl_texturenum[i][j - k]; 
                }
        }
+       loadmodel->numskins = numskins;
+       free(skintemp);
 
        return (void *)pskintype;
 }
 
+void *Mod_SkipAllSkins (int numskins, daliasskintype_t *pskintype, int skinsize)
+{
+       int             i;
+       for (i = 0;i < numskins;i++)
+       {
+               pskintype++;
+               if (pskintype[-1].type == ALIAS_SKIN_SINGLE)
+                       (byte *)pskintype += skinsize;
+               else
+                       (byte *)pskintype += (skinsize + sizeof(daliasskininterval_t)) * LittleLong (((daliasskingroup_t *)pskintype)->numskins) + sizeof(daliasskingroup_t);
+       }
+       return pskintype;
+}
+
 //=========================================================================
 
 //void GL_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr);
@@ -384,164 +424,164 @@ Mod_LoadAliasModel
 #define BOUNDF(VALUE,MIN,MAX) if (VALUE < MIN || VALUE >= MAX) Host_Error("model %s has an invalid VALUE (%f exceeds %f - %f)\n", mod->name, VALUE, MIN, MAX);
 void Mod_LoadAliasModel (model_t *mod, void *buffer)
 {
-       int                                     i, j, version, numframes, size, start, end, total;
+       int                                     i, j, version, numframes, start, end, total, numverts, numtris, numposes, numskins, skinwidth, skinheight, f, totalverts;
        mdl_t                           *pinmodel;
        stvert_t                        *pinstverts;
        dtriangle_t                     *pintriangles;
        daliasframetype_t       *pframetype;
        daliasskintype_t        *pskintype;
-       // LordHavoc: 32bit textures
-       int                                     bytesperpixel;
-       unsigned short          *poutvertindices;
        float                           *pouttexcoords, scales, scalet;
-       temptris_t                      *tris;
+       maliashdr_t                     *mheader;
+       unsigned short          *pouttris;
+       maliasframe_t           *frame;
+       trivert2                        *posevert;
 
        start = Hunk_LowMark ();
 
-       if (!temptris)
-               temptris = malloc(sizeof(temptris_t) * MD2MAX_TRIANGLES);
-
        pinmodel = (mdl_t *)buffer;
 
        version = LittleLong (pinmodel->version);
-       if (version != ALIAS_VERSION && version != ALIAS32_VERSION)
-               Host_Error ("%s has wrong version number (%i should be %i or %i)",
-                                mod->name, version, ALIAS_VERSION, ALIAS32_VERSION);
+       if (version != ALIAS_VERSION)
+               Host_Error ("%s has wrong version number (%i should be %i)",
+                                mod->name, version, ALIAS_VERSION);
 
        mod->type = ALIASTYPE_MDL;
 
-//
-// allocate space for a working header, plus all the data except the frames,
-// skin and group info
-//
-//     size = sizeof (aliashdr_t) + (LittleLong (pinmodel->numframes) - 1) * sizeof (pinmodel->frames[0]));
-       size = sizeof (aliashdr_t);
-       size += LittleLong (pinmodel->numverts) * sizeof(float[2][2]);
-       size += LittleLong (pinmodel->numtris) * sizeof(unsigned short[3]);
-       size += LittleLong (pinmodel->numframes) * (sizeof(trivert2) * LittleLong (pinmodel->numverts) + sizeof(maliasframedesc_t));
-       BOUNDI(size,256,4194304);
-       pheader = Hunk_AllocName (size, loadname);
+       numframes = LittleLong(pinmodel->numframes);
+       BOUNDI(numframes,0,65536);
+       numverts = LittleLong(pinmodel->numverts);
+       BOUNDI(numverts,0,MAXALIASVERTS);
+       numtris = LittleLong(pinmodel->numtris);
+       BOUNDI(numtris,0,65536);
+       numskins = LittleLong(pinmodel->numskins);
+       BOUNDI(numskins,0,256);
+       skinwidth = LittleLong (pinmodel->skinwidth);
+       BOUNDI(skinwidth,0,4096);
+       skinheight = LittleLong (pinmodel->skinheight);
+       BOUNDI(skinheight,0,1024);
        
+       pskintype = (daliasskintype_t *)&pinmodel[1];
+       pinstverts = (stvert_t *)Mod_SkipAllSkins (numskins, pskintype, skinwidth * skinheight);
+       pintriangles = (dtriangle_t *)&pinstverts[numverts];
+       pframetype = (daliasframetype_t *)&pintriangles[numtris];
+
+       numposes = 0;
+       for (i=0 ; i<numframes ; i++)
+       {
+               if ((aliasframetype_t) LittleLong (pframetype->type) == ALIAS_SINGLE)
+               {
+                       numposes++;
+                       pframetype = (daliasframetype_t *)((int)pframetype + sizeof(daliasframetype_t)                         + (sizeof(daliasframe_t)                            + sizeof(trivertx_t) * numverts)    );
+               }
+               else
+               {
+                       f = LittleLong (((daliasgroup_t *)((int)pframetype + sizeof(daliasframetype_t)))->numframes);
+                       numposes += f;
+                       pframetype = (daliasframetype_t *)((int)pframetype + sizeof(daliasframetype_t) + sizeof(daliasgroup_t) + (sizeof(daliasframe_t) + sizeof(daliasinterval_t) + sizeof(trivertx_t) * numverts) * f);
+               }
+       }
+
+       // rebuild the model
+       mheader = Hunk_AllocName (sizeof(maliashdr_t), loadname);
        mod->flags = LittleLong (pinmodel->flags);
        mod->type = mod_alias;
-
 // endian-adjust and copy the data, starting with the alias model header
-       pheader->boundingradius = LittleFloat (pinmodel->boundingradius);
-       BOUNDF(pheader->boundingradius,0,65536);
-       pheader->numskins = LittleLong (pinmodel->numskins);
-       BOUNDI(pheader->numskins,0,256);
-       pheader->skinwidth = LittleLong (pinmodel->skinwidth);
-       BOUNDI(pheader->skinwidth,0,4096);
-       pheader->skinheight = LittleLong (pinmodel->skinheight);
-       BOUNDI(pheader->skinheight,0,1024);
-//LordHavoc: 32bit textures
-       bytesperpixel = version == ALIAS32_VERSION ? 4 : 1;
-
-//     if (pheader->skinheight > MAX_LBM_HEIGHT)
-//             Host_Error ("model %s has a skin taller than %d", mod->name, MAX_LBM_HEIGHT);
-
-       pheader->numverts = LittleLong (pinmodel->numverts);
-       BOUNDI(pheader->numverts,0,MAXALIASVERTS);
-       /*
-       if (pheader->numverts <= 0)
-               Host_Error ("model %s has no vertices", mod->name);
-       if (pheader->numverts > MAXALIASVERTS)
-               Host_Error ("model %s has too many vertices", mod->name);
-       */
-
-       pheader->numtris = LittleLong (pinmodel->numtris);
-       BOUNDI(pheader->numtris,0,65536);
-//     if (pheader->numtris <= 0)
-//             Host_Error ("model %s has no triangles", mod->name);
-
-       pheader->numframes = LittleLong (pinmodel->numframes);
-       BOUNDI(pheader->numframes,0,65536);
-       numframes = pheader->numframes;
-//     if (numframes < 1)
-//             Host_Error ("Mod_LoadAliasModel: Invalid # of frames: %d\n", numframes);
-
-       pheader->size = LittleFloat (pinmodel->size) * ALIAS_BASE_SIZE_RATIO;
-       BOUNDF(pheader->size,0,65536);
+       mheader->numverts = numverts;
+       mod->numtris = mheader->numtris = numtris;
+       mod->numframes = mheader->numframes = numframes;
        mod->synctype = LittleLong (pinmodel->synctype);
-       BOUNDI(pheader->synctype,0,2);
-       mod->numframes = pheader->numframes;
+       BOUNDI(mod->synctype,0,2);
 
        for (i=0 ; i<3 ; i++)
        {
-               pheader->scale[i] = LittleFloat (pinmodel->scale[i]);
-               BOUNDF(pheader->scale[i],0,65536);
-               pheader->scale_origin[i] = LittleFloat (pinmodel->scale_origin[i]);
-               BOUNDF(pheader->scale_origin[i],-65536,65536);
-               pheader->eyeposition[i] = LittleFloat (pinmodel->eyeposition[i]);
-               BOUNDF(pheader->eyeposition[i],-65536,65536);
+               mheader->scale[i] = LittleFloat (pinmodel->scale[i]);
+               BOUNDF(mheader->scale[i],0,65536);
+               mheader->scale_origin[i] = LittleFloat (pinmodel->scale_origin[i]);
+               BOUNDF(mheader->scale_origin[i],-65536,65536);
        }
 
-// load the skins
+       // load the skins
        pskintype = (daliasskintype_t *)&pinmodel[1];
-       pskintype = Mod_LoadAllSkins (pheader->numskins, pskintype, bytesperpixel);
+       pskintype = Mod_LoadAllSkins(numskins, pskintype, skinwidth, skinheight);
 
-// load base s and t vertices
+       // store texture coordinates into temporary array, they will be stored after usage is determined (triangle data)
        pinstverts = (stvert_t *)pskintype;
-       pouttexcoords = (float *)&pheader->frames[numframes];
-       pheader->texcoords = (int) pouttexcoords - (int) pheader;
 
        // LordHavoc: byteswap and convert stvert data
-       scales = 1.0 / pheader->skinwidth;
-       scalet = 1.0 / pheader->skinheight;
-       for (i = 0;i < pheader->numverts;i++)
+       scales = 1.0 / skinwidth;
+       scalet = 1.0 / skinheight;
+       for (i = 0;i < numverts;i++)
        {
-               pouttexcoords[i*2] = LittleLong (pinstverts[i].s) * scales;
-               pouttexcoords[i*2+1] = LittleLong (pinstverts[i].t) * scalet;
-               pouttexcoords[(i+pheader->numverts)*2] = LittleLong (pinstverts[i].s) * scales + 0.5;
-               pouttexcoords[(i+pheader->numverts)*2+1] = LittleLong (pinstverts[i].t) * scalet;
-               if (pouttexcoords[i*2] >= 0.5) // already a back side coordinate
-               {
-                       pouttexcoords[i*2] -= 0.5;
-                       pouttexcoords[(i+pheader->numverts)*2] -= 0.5;
-               }
-               // LordHavoc: CTF's v_star.mdl failed these checks
-//             BOUNDF(pouttexcoords[i*2],0.0,1.0);
-//             BOUNDF(pouttexcoords[i*2+1],0.0,1.0);
-//             BOUNDF(pouttexcoords[(i+pheader->numverts)*2],0.0,1.0);
-//             BOUNDF(pouttexcoords[(i+pheader->numverts)*2+1],0.0,1.0);
+               vertonseam[i] = LittleLong(pinstverts[i].onseam);
+               vertst[i][0] = LittleLong(pinstverts[i].s) * scales;
+               vertst[i][1] = LittleLong(pinstverts[i].t) * scalet;
+               vertst[i+numverts][0] = vertst[i][0] + 0.5;
+               vertst[i+numverts][1] = vertst[i][1];
+               vertusage[i] = 0;
+               vertusage[i+numverts] = 0;
        }
 
 // load triangle data
-       pintriangles = (dtriangle_t *)&pinstverts[pheader->numverts];
-       poutvertindices = (unsigned short *)&pouttexcoords[pheader->numverts*4];
-       pheader->vertindices = (int) poutvertindices - (int) pheader;
-       // LordHavoc: sort triangles into front and back lists
-       // so they can be drawn refering to different texture coordinate arrays,
-       // but sharing vertex data
-       pheader->frontfaces = 0;
-       pheader->backfaces = 0;
-       tris = temptris;
-       for (i=0 ; i<pheader->numtris ; i++)
+       pouttris = Hunk_AllocName(sizeof(unsigned short[3]) * numtris, loadname);
+       mheader->tridata = (int) pouttris - (int) mheader;
+       pintriangles = (dtriangle_t *)&pinstverts[mheader->numverts];
+
+       // count the vertices used
+       for (i = 0;i < numverts*2;i++)
+               vertusage[i] = 0;
+       for (i = 0;i < numtris;i++)
        {
-               if (LittleLong(pintriangles[i].facesfront))
+               temptris[i][0] = LittleLong(pintriangles[i].vertindex[0]);
+               temptris[i][1] = LittleLong(pintriangles[i].vertindex[1]);
+               temptris[i][2] = LittleLong(pintriangles[i].vertindex[2]);
+               if (!LittleLong(pintriangles[i].facesfront)) // backface
                {
-                       pheader->frontfaces++;
-                       for (j=0 ; j<3 ; j++)
-                               *poutvertindices++ = LittleLong (pintriangles[i].vertindex[j]);
+                       if (vertonseam[temptris[i][0]]) temptris[i][0] += numverts;
+                       if (vertonseam[temptris[i][1]]) temptris[i][1] += numverts;
+                       if (vertonseam[temptris[i][2]]) temptris[i][2] += numverts;
                }
-               for (j=0 ; j<3 ; j++)
-                       tris->v[j] = LittleLong (pintriangles[i].vertindex[j]);
-               tris++;
+               vertusage[temptris[i][0]]++;
+               vertusage[temptris[i][1]]++;
+               vertusage[temptris[i][2]]++;
        }
-       for (i=0 ; i<pheader->numtris ; i++)
+       // build remapping table and compact array
+       totalverts = 0;
+       for (i = 0;i < numverts*2;i++)
        {
-               if (!LittleLong(pintriangles[i].facesfront))
+               if (vertusage[i])
                {
-                       pheader->backfaces++;
-                       for (j=0 ; j<3 ; j++)
-                               *poutvertindices++ = LittleLong (pintriangles[i].vertindex[j]);
+                       vertremap[i] = totalverts;
+                       vertst[totalverts][0] = vertst[i][0];
+                       vertst[totalverts][1] = vertst[i][1];
+                       totalverts++;
                }
+               else
+                       vertremap[i] = -1; // not used at all
+       }
+       mheader->numverts = totalverts;
+       // remap the triangle references
+       for (i = 0;i < numtris;i++)
+       {
+               *pouttris++ = vertremap[temptris[i][0]];
+               *pouttris++ = vertremap[temptris[i][1]];
+               *pouttris++ = vertremap[temptris[i][2]];
+       }
+       // store the texture coordinates
+       pouttexcoords = Hunk_AllocName(sizeof(float[2]) * totalverts, loadname);
+       mheader->texdata = (int) pouttexcoords - (int) mheader;
+       for (i = 0;i < totalverts;i++)
+       {
+               *pouttexcoords++ = vertst[i][0];
+               *pouttexcoords++ = vertst[i][1];
        }
 
 // load the frames
        posenum = 0;
-       pheader->posedata = (int) poutvertindices - (int) pheader;
-       pframetype = (daliasframetype_t *)&pintriangles[pheader->numtris];
+       frame = Hunk_AllocName(sizeof(maliasframe_t) * numframes, loadname);
+       mheader->framedata = (int) frame - (int) mheader;
+       posevert = Hunk_AllocName(sizeof(trivert2) * numposes * totalverts, loadname);
+       mheader->posedata = (int) posevert - (int) mheader;
+       pframetype = (daliasframetype_t *)&pintriangles[numtris];
 
        // LordHavoc: doing proper bbox for model
        aliasbboxmin[0] = aliasbboxmin[1] = aliasbboxmin[2] = 1000000000;
@@ -549,18 +589,12 @@ void Mod_LoadAliasModel (model_t *mod, void *buffer)
 
        for (i=0 ; i<numframes ; i++)
        {
-               aliasframetype_t        frametype;
-
-               frametype = LittleLong (pframetype->type);
-
-               if (frametype == ALIAS_SINGLE)
-                       pframetype = (daliasframetype_t *) Mod_LoadAliasFrame (pframetype + 1, &pheader->frames[i]);
+               if ((aliasframetype_t) LittleLong (pframetype->type) == ALIAS_SINGLE)
+                       pframetype = (daliasframetype_t *) Mod_LoadAliasFrame (pframetype + 1, frame++, mheader, numverts, totalverts, &posevert);
                else
-                       pframetype = (daliasframetype_t *) Mod_LoadAliasGroup (pframetype + 1, &pheader->frames[i]);
+                       pframetype = (daliasframetype_t *) Mod_LoadAliasGroup (pframetype + 1, frame++, mheader, numverts, totalverts, &posevert);
        }
 
-       pheader->numposes = posenum;
-
        // LordHavoc: fixed model bbox - was //FIXME: do this right
        //mod->mins[0] = mod->mins[1] = mod->mins[2] = -16;
        //mod->maxs[0] = mod->maxs[1] = mod->maxs[2] = 16;
@@ -577,17 +611,91 @@ void Mod_LoadAliasModel (model_t *mod, void *buffer)
        Cache_Alloc (&mod->cache, total, loadname);
        if (!mod->cache.data)
                return;
-       memcpy (mod->cache.data, pheader, total);
+       memcpy (mod->cache.data, mheader, total);
 
        Hunk_FreeToLowMark (start);
 }
 
+void Mod_ConvertQ2AliasVerts (int numverts, vec3_t scale, vec3_t translate, trivertx_t *v, trivert2 *out)
+{
+       int i;
+       vec3_t temp;
+       for (i = 0;i < numverts;i++)
+       {
+               VectorCopy(v[i].v, out[i].v);
+               temp[0] = v[i].v[0] * scale[0] + translate[0];
+               temp[1] = v[i].v[1] * scale[1] + translate[1];
+               temp[2] = v[i].v[2] * scale[2] + translate[2];
+               // update bounding box
+               if (temp[0] < aliasbboxmin[0]) aliasbboxmin[0] = temp[0];
+               if (temp[1] < aliasbboxmin[1]) aliasbboxmin[1] = temp[1];
+               if (temp[2] < aliasbboxmin[2]) aliasbboxmin[2] = temp[2];
+               if (temp[0] > aliasbboxmax[0]) aliasbboxmax[0] = temp[0];
+               if (temp[1] > aliasbboxmax[1]) aliasbboxmax[1] = temp[1];
+               if (temp[2] > aliasbboxmax[2]) aliasbboxmax[2] = temp[2];
+               out[i].n[0] = (signed char) (r_avertexnormals[v[i].lightnormalindex][0] * 127.0);
+               out[i].n[1] = (signed char) (r_avertexnormals[v[i].lightnormalindex][1] * 127.0);
+               out[i].n[2] = (signed char) (r_avertexnormals[v[i].lightnormalindex][2] * 127.0);
+       }               
+       /*
+       int i, j;
+       vec3_t t1, t2;
+       struct
+       {
+               vec3_t v;
+               vec3_t normal;
+               int count;
+       } tempvert[MD2MAX_VERTS];
+       temptris_t *tris;
+       // decompress vertices
+       for (i = 0;i < numverts;i++)
+       {
+               VectorCopy(v[i].v, out[i].v);
+               tempvert[i].v[0] = v[i].v[0] * scale[0] + translate[0];
+               tempvert[i].v[1] = v[i].v[1] * scale[1] + translate[1];
+               tempvert[i].v[2] = v[i].v[2] * scale[2] + translate[2];
+               tempvert[i].normal[0] = tempvert[i].normal[1] = tempvert[i].normal[2] = 0;
+               tempvert[i].count = 0;
+               // update bounding box
+               if (tempvert[i].v[0] < aliasbboxmin[0]) aliasbboxmin[0] = tempvert[i].v[0];
+               if (tempvert[i].v[1] < aliasbboxmin[1]) aliasbboxmin[1] = tempvert[i].v[1];
+               if (tempvert[i].v[2] < aliasbboxmin[2]) aliasbboxmin[2] = tempvert[i].v[2];
+               if (tempvert[i].v[0] > aliasbboxmax[0]) aliasbboxmax[0] = tempvert[i].v[0];
+               if (tempvert[i].v[1] > aliasbboxmax[1]) aliasbboxmax[1] = tempvert[i].v[1];
+               if (tempvert[i].v[2] > aliasbboxmax[2]) aliasbboxmax[2] = tempvert[i].v[2];
+       }
+       // calculate surface normals
+       tris = temptris;
+       for (i = 0;i < numtris;i++)
+       {
+               VectorSubtract(tempvert[tris->v[0]].v, tempvert[tris->v[1]].v, t1);
+               VectorSubtract(tempvert[tris->v[2]].v, tempvert[tris->v[1]].v, t2);
+               CrossProduct(t1, t2, tris->normal);
+               VectorNormalize(tris->normal);
+               // add surface normal to vertices
+               for (j = 0;j < 3;j++)
+               {
+                       VectorAdd(tris->normal, tempvert[tris->v[j]].normal, tempvert[tris->v[j]].normal);
+                       tempvert[tris->v[j]].count++;
+               }
+               tris++;
+       }
+       // average normals and write out 1.7bit format
+       for (i = 0;i < pheader->numtris;i++)
+       {
+               VectorNormalize(tempvert[i].normal);
+               out[i].n[0] = (signed char) (tempvert[i].normal[0] * 127.0);
+               out[i].n[1] = (signed char) (tempvert[i].normal[1] * 127.0);
+               out[i].n[2] = (signed char) (tempvert[i].normal[2] * 127.0);
+       }
+       */
+}
+
 /*
 =================
 Mod_LoadQ2AliasModel
 =================
 */
-int loadtextureimage (int texnum, char* filename, qboolean complain, int matchwidth, int matchheight);
 void Mod_LoadQ2AliasModel (model_t *mod, void *buffer)
 {
        int                                     i, j, version, size, *pinglcmd, *poutglcmd, start, end, total, framesize;
@@ -597,12 +705,12 @@ void Mod_LoadQ2AliasModel (model_t *mod, void *buffer)
        md2frame_t                      *pinframe;
        md2memframe_t           *poutframe;
        char                            *pinskins;
-       temptris_t                      *tris;
+//     temptris_t                      *tris;
 
        start = Hunk_LowMark ();
 
-       if (!temptris)
-               temptris = malloc(sizeof(temptris_t) * MD2MAX_TRIANGLES);
+//     if (!temptris)
+//             temptris = malloc(sizeof(temptris_t) * MD2MAX_TRIANGLES);
 
        pinmodel = (md2_t *)buffer;
 
@@ -628,6 +736,7 @@ void Mod_LoadQ2AliasModel (model_t *mod, void *buffer)
        mod->flags = 0; // there are no MD2 flags
        mod->numframes = LittleLong(pinmodel->num_frames);
        mod->synctype = ST_RAND;
+       mod->numtris = LittleLong(pinmodel->num_tris); // LordHavoc: to simplify renderer decisions
 
        if (LittleLong(pinmodel->num_skins) >= 1 && (LittleLong(pinmodel->ofs_skins <= 0) || LittleLong(pinmodel->ofs_skins) >= LittleLong(pinmodel->ofs_end)))
                Host_Error ("%s is not a valid model", mod->name);
@@ -644,7 +753,7 @@ void Mod_LoadQ2AliasModel (model_t *mod, void *buffer)
                Host_Error ("%s has invalid number of triangles: %i", mod->name, LittleLong(pinmodel->num_tris));
        if (LittleLong(pinmodel->num_xyz < 1) || LittleLong(pinmodel->num_xyz) > MD2MAX_VERTS)
                Host_Error ("%s has invalid number of vertices: %i", mod->name, LittleLong(pinmodel->num_xyz));
-       if (LittleLong(pinmodel->num_frames < 1) || LittleLong(pinmodel->num_frames) > 256) //MD2MAX_FRAMES)
+       if (LittleLong(pinmodel->num_frames < 1) || LittleLong(pinmodel->num_frames) > MD2MAX_FRAMES)
                Host_Error ("%s has invalid number of frames: %i", mod->name, LittleLong(pinmodel->num_frames));
        if (LittleLong(pinmodel->num_skins < 0) || LittleLong(pinmodel->num_skins) > MD2MAX_SKINS)
                Host_Error ("%s has invalid number of skins: %i", mod->name, LittleLong(pinmodel->num_skins));
@@ -660,25 +769,39 @@ void Mod_LoadQ2AliasModel (model_t *mod, void *buffer)
 // load the skins
        if (pheader->num_skins)
        {
+               int *skin, *skinrange;
+               skinrange = loadmodel->skinanimrange;
+               skin = loadmodel->skinanim;
+//             skinrange = Hunk_AllocName (sizeof(int) * (pheader->num_skins * 2), loadname);  
+//             skin = skinrange + pheader->num_skins * 2;
+//             loadmodel->skinanimrange = (int) skinrange - (int) pheader;
+//             loadmodel->skinanim = (int) skin - (int) pheader;
                pinskins = (void*)((int) pinmodel + LittleLong(pinmodel->ofs_skins));
                for (i = 0;i < pheader->num_skins;i++)
                {
-                       pheader->gl_texturenum[i] = loadtextureimage (-1, pinskins, TRUE, 0, 0);
+                       *skinrange++ = i;
+                       *skinrange++ = 1;
+                       *skin++ = loadtextureimage (pinskins, 0, 0, true, true);
+                       *skin++ = 0; // the extra 4 layers are currently unused
+                       *skin++ = 0;
+                       *skin++ = 0;
+                       *skin++ = 0;
                        pinskins += MD2MAX_SKINNAME;
                }
        }
+       loadmodel->numskins = pheader->num_skins;
 
 // load triangles
        pintriangles = (void*)((int) pinmodel + LittleLong(pinmodel->ofs_tris));
        pouttriangles = (void*)&pheader[1];
        pheader->ofs_tris = (int) pouttriangles - (int) pheader;
-       tris = temptris;
+//     tris = temptris;
        // swap the triangle list
        for (i=0 ; i<pheader->num_tris ; i++)
        {
                for (j=0 ; j<3 ; j++)
                {
-                       tris->v[j] = pouttriangles->index_xyz[j] = LittleShort (pintriangles->index_xyz[j]);
+                       temptris[i][j] = pouttriangles->index_xyz[j] = LittleShort (pintriangles->index_xyz[j]);
                        pouttriangles->index_st[j] = LittleShort (pintriangles->index_st[j]);
                        if (pouttriangles->index_xyz[j] >= pheader->num_xyz)
                                Host_Error ("%s has invalid vertex indices", mod->name);
@@ -687,7 +810,6 @@ void Mod_LoadQ2AliasModel (model_t *mod, void *buffer)
                }
                pintriangles++;
                pouttriangles++;
-               tris++;
        }
 
        // LordHavoc: doing proper bbox for model
@@ -705,7 +827,7 @@ void Mod_LoadQ2AliasModel (model_t *mod, void *buffer)
                        poutframe->scale[j] = LittleFloat(pinframe->scale[j]);
                        poutframe->translate[j] = LittleFloat(pinframe->translate[j]);
                }
-               Mod_ConvertAliasVerts (pheader->num_xyz, pheader->num_tris, poutframe->scale, poutframe->translate, &pinframe->verts[0], &poutframe->verts[0]);
+               Mod_ConvertQ2AliasVerts (pheader->num_xyz, poutframe->scale, poutframe->translate, &pinframe->verts[0], &poutframe->verts[0]);
                pinframe = (void*) &pinframe->verts[j];
                poutframe = (void*) &poutframe->verts[j];
        }
index a00d41e..aafcb33 100644 (file)
@@ -29,6 +29,7 @@ Alias models are position independent, so the cache manager can move them.
 
 #include "modelgen.h"
 
+/*
 typedef struct
 {
        int                                     firstpose;
@@ -54,11 +55,11 @@ typedef struct
        maliasgroupframedesc_t  frames[1];
 } maliasgroup_t;
 
-// !!! if this is changed, it must be changed in asm_draw.h too !!!
 typedef struct mtriangle_s {
        int                                     facesfront;
        int                                     vertindex[3];
 } mtriangle_t;
+*/
 
 // LordHavoc: new vertex format
 typedef struct {
@@ -83,30 +84,34 @@ typedef struct {
        synctype_t      synctype;
        int                     flags;
        float           size;
+} daliashdr_t;
 
-       int                                     numposes;
-       int                                     posedata;       // LordHavoc: numposes*numverts*trivert2
-       int                                     frontfaces; // LordHavoc: how many front faces
-       int                                     backfaces; // LordHavoc: how many back faces
-//     int                                     poseverts;
-//     int                                     posedata;       // numposes*poseverts trivert_t
-//     int                                     commands;       // gl command list with embedded s/t
-       int                                     texcoords;      // LordHavoc: texture coordinates
-       int                                     vertindices;    // LordHavoc: vertex numbers
-       int                                     gl_texturenum[MAX_SKINS][4];
-       int                                     texels[MAX_SKINS];      // only for player skins
-       maliasframedesc_t       frames[1];      // variable sized
-} aliashdr_t;
+typedef struct
+{
+       char name[16]; // LordHavoc: only kept this for reasons of viewthing support
+       unsigned short start;
+       unsigned short length;
+       float rate; // in poses per second
+} maliasframe_t;
+
+typedef struct
+{
+       vec3_t          scale;
+       vec3_t          scale_origin;
+       int                     numverts;
+       int                     numtris;
+       int                     numframes;
+       int                     numposes;
+       int                     framedata; // LordHavoc: unsigned short start
+       int                     texdata; // LordHavoc: texture coordinate array
+       int                     posedata; // LordHavoc: vertex data for all the poses
+       int                     tridata; // LordHavoc: vertex indices for the triangles
+} maliashdr_t;
 
 #define        MAXALIASVERTS   4096
 #define        MAXALIASFRAMES  1024
 #define        MAXALIASTRIS    4096
 
-extern aliashdr_t      *pheader;
-//extern       stvert_t        stverts[MAXALIASVERTS];
-//extern       mtriangle_t     triangles[MAXALIASTRIS];
-//extern       trivertx_t      *poseverts[MAXALIASFRAMES];
-
 /*
 ========================================================================
 
@@ -146,7 +151,7 @@ typedef struct
        float           scale[3];       // multiply byte verts by this
        float           translate[3];   // then add this
        char            name[16];       // frame name from grabbing
-       trivertx_t      verts[0];       // variable sized
+       trivertx_t      verts[];        // variable sized
 } md2frame_t;
 
 // LordHavoc: memory representation is different than disk
@@ -154,7 +159,7 @@ typedef struct
 {
        float           scale[3];       // multiply byte verts by this
        float           translate[3];   // then add this
-       trivert2        verts[0];       // variable sized
+       trivert2        verts[];        // variable sized
 } md2memframe_t;
 
 
@@ -205,8 +210,6 @@ typedef struct
        int                     ofs_tris;               // offset for dtriangles
        int                     ofs_frames;             // offset for first frame
        int                     ofs_glcmds;     
-
-       int                     gl_texturenum[MAX_SKINS];
 } md2mem_t;
 
 #define ALIASTYPE_MDL 1
index 03f9dc9..913e9b3 100644 (file)
@@ -867,29 +867,70 @@ void Mod_LoadClipnodes (lump_t *l)
        loadmodel->clipnodes = out;
        loadmodel->numclipnodes = count;
 
-       hull = &loadmodel->hulls[1];
-       hull->clipnodes = out;
-       hull->firstclipnode = 0;
-       hull->lastclipnode = count-1;
-       hull->planes = loadmodel->planes;
-       hull->clip_mins[0] = -16;
-       hull->clip_mins[1] = -16;
-       hull->clip_mins[2] = -24;
-       hull->clip_maxs[0] = 16;
-       hull->clip_maxs[1] = 16;
-       hull->clip_maxs[2] = 32;
-
-       hull = &loadmodel->hulls[2];
-       hull->clipnodes = out;
-       hull->firstclipnode = 0;
-       hull->lastclipnode = count-1;
-       hull->planes = loadmodel->planes;
-       hull->clip_mins[0] = -32;
-       hull->clip_mins[1] = -32;
-       hull->clip_mins[2] = -24;
-       hull->clip_maxs[0] = 32;
-       hull->clip_maxs[1] = 32;
-       hull->clip_maxs[2] = 64;
+       if (hlbsp)
+       {
+               hull = &loadmodel->hulls[1];
+               hull->clipnodes = out;
+               hull->firstclipnode = 0;
+               hull->lastclipnode = count-1;
+               hull->planes = loadmodel->planes;
+               hull->clip_mins[0] = -16;
+               hull->clip_mins[1] = -16;
+               hull->clip_mins[2] = -36;
+               hull->clip_maxs[0] = 16;
+               hull->clip_maxs[1] = 16;
+               hull->clip_maxs[2] = 36;
+
+               hull = &loadmodel->hulls[2];
+               hull->clipnodes = out;
+               hull->firstclipnode = 0;
+               hull->lastclipnode = count-1;
+               hull->planes = loadmodel->planes;
+               hull->clip_mins[0] = -32;
+               hull->clip_mins[1] = -32;
+               hull->clip_mins[2] = -32;
+               hull->clip_maxs[0] = 32;
+               hull->clip_maxs[1] = 32;
+               hull->clip_maxs[2] = 32;
+
+               hull = &loadmodel->hulls[3];
+               hull->clipnodes = out;
+               hull->firstclipnode = 0;
+               hull->lastclipnode = count-1;
+               hull->planes = loadmodel->planes;
+               hull->clip_mins[0] = -16;
+               hull->clip_mins[1] = -16;
+               hull->clip_mins[2] = -18;
+               hull->clip_maxs[0] = 16;
+               hull->clip_maxs[1] = 16;
+               hull->clip_maxs[2] = 18;
+       }
+       else
+       {
+               hull = &loadmodel->hulls[1];
+               hull->clipnodes = out;
+               hull->firstclipnode = 0;
+               hull->lastclipnode = count-1;
+               hull->planes = loadmodel->planes;
+               hull->clip_mins[0] = -16;
+               hull->clip_mins[1] = -16;
+               hull->clip_mins[2] = -24;
+               hull->clip_maxs[0] = 16;
+               hull->clip_maxs[1] = 16;
+               hull->clip_maxs[2] = 32;
+
+               hull = &loadmodel->hulls[2];
+               hull->clipnodes = out;
+               hull->firstclipnode = 0;
+               hull->lastclipnode = count-1;
+               hull->planes = loadmodel->planes;
+               hull->clip_mins[0] = -32;
+               hull->clip_mins[1] = -32;
+               hull->clip_mins[2] = -24;
+               hull->clip_maxs[0] = 32;
+               hull->clip_maxs[1] = 32;
+               hull->clip_maxs[2] = 64;
+       }
 
        for (i=0 ; i<count ; i++, out++, in++)
        {
index ea85c58..ecfe872 100644 (file)
@@ -153,7 +153,7 @@ model_t *Mod_LoadModel (model_t *mod, qboolean crash)
 {
        void    *d;
        unsigned *buf;
-       byte    stackbuf[1024];         // avoid dirtying the cache heap
+//     byte    stackbuf[1024];         // avoid dirtying the cache heap
 
        if (!mod->needload)
        {
@@ -168,7 +168,8 @@ model_t *Mod_LoadModel (model_t *mod, qboolean crash)
        }
 
 // load the file
-       buf = (unsigned *)COM_LoadStackFile (mod->name, stackbuf, sizeof(stackbuf), false);
+       buf = (unsigned *)COM_LoadMallocFile (mod->name, false);
+//     buf = (unsigned *)COM_LoadStackFile (mod->name, stackbuf, sizeof(stackbuf), false);
        if (!buf)
        {
                if (crash)
@@ -202,6 +203,7 @@ model_t *Mod_LoadModel (model_t *mod, qboolean crash)
                Mod_LoadBrushModel (mod, buf);
                break;
        }
+       free(buf);
 
        return mod;
 }
index 865ef39..d3a701a 100644 (file)
@@ -105,6 +105,12 @@ typedef struct model_s
        byte            *lightdata;
        char            *entities;
 
+       // LordHavoc: useful for sprites and models
+       int                     numtris;
+       int                     numskins;
+       int                     skinanimrange[1024]; // array of start and length pairs, note: offset from ->cache.data
+       int                     skinanim[1024*5]; // texture numbers for each frame (indexed by animrange), note: offset from ->cache.data, second note: normal pants shirt glow body (normal contains no shirt/pants/glow colors and body is normal + pants + shirt, but not glow)
+
 // additional model data
        cache_user_t    cache;          // only access through Mod_Extradata
 
index b8b75dd..4169107 100644 (file)
@@ -28,7 +28,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 // *********************************************************
 
 #define ALIAS_VERSION  6
-#define ALIAS32_VERSION        7
 
 #define ALIAS_ONSEAM                           0x0020
 
index 3c5a773..0d5265e 100644 (file)
@@ -129,7 +129,7 @@ int WINS_Init (void)
        
        if (hInst == NULL)
        {
-               Con_SafePrintf ("Failed to load winsock.dll\n");
+               Con_SafePrintf ("Failed to load wsock32.dll\n");
                winsock_lib_initialized = false;
                return -1;
        }
@@ -156,7 +156,7 @@ int WINS_Init (void)
                !pgethostname || !pgethostbyname || !pgethostbyaddr ||
                !pgetsockname)
        {
-               Con_SafePrintf ("Couldn't GetProcAddress from winsock.dll\n");
+               Con_SafePrintf ("Couldn't GetProcAddress from wsock32.dll\n");
                return -1;
        }
 
index 4dd41a9..a608a07 100644 (file)
--- a/pr_exec.c
+++ b/pr_exec.c
@@ -358,318 +358,6 @@ int PR_LeaveFunction (void)
 PR_ExecuteProgram
 ====================
 */
-/*
-void PR_ExecuteProgram (func_t fnum)
-{
-       eval_t  *a, *b, *c;
-       int                     s;
-       dstatement_t    *st;
-       dfunction_t     *f, *newf;
-       int             runaway;
-       int             i;
-       edict_t *ed;
-       int             exitdepth;
-       eval_t  *ptr;
-
-       if (!fnum || fnum >= progs->numfunctions)
-       {
-               if (pr_global_struct->self)
-                       ED_Print (PROG_TO_EDICT(pr_global_struct->self));
-               Host_Error ("PR_ExecuteProgram: NULL function");
-       }
-       
-       f = &pr_functions[fnum];
-
-       runaway = 100000;
-       pr_trace = false;
-
-// make a stack frame
-       exitdepth = pr_depth;
-
-       s = PR_EnterFunction (f);
-       
-while (1)
-{
-       s++;    // next statement
-
-       st = &pr_statements[s];
-       // LordHavoc: fix for 32768 QC def limit (just added unsigned short typecast)
-       a = (eval_t *)&pr_globals[(unsigned short) st->a];
-       b = (eval_t *)&pr_globals[(unsigned short) st->b];
-       c = (eval_t *)&pr_globals[(unsigned short) st->c];
-       
-       if (!--runaway)
-               PR_RunError ("runaway loop error");
-               
-       pr_xfunction->profile++;
-       pr_xstatement = s;
-       
-       if (pr_trace)
-               PR_PrintStatement (st);
-               
-       switch (st->op)
-       {
-       case OP_ADD_F:
-               c->_float = a->_float + b->_float;
-               break;
-       case OP_ADD_V:
-               c->vector[0] = a->vector[0] + b->vector[0];
-               c->vector[1] = a->vector[1] + b->vector[1];
-               c->vector[2] = a->vector[2] + b->vector[2];
-               break;
-               
-       case OP_SUB_F:
-               c->_float = a->_float - b->_float;
-               break;
-       case OP_SUB_V:
-               c->vector[0] = a->vector[0] - b->vector[0];
-               c->vector[1] = a->vector[1] - b->vector[1];
-               c->vector[2] = a->vector[2] - b->vector[2];
-               break;
-
-       case OP_MUL_F:
-               c->_float = a->_float * b->_float;
-               break;
-       case OP_MUL_V:
-               c->_float = a->vector[0]*b->vector[0]
-                               + a->vector[1]*b->vector[1]
-                               + a->vector[2]*b->vector[2];
-               break;
-       case OP_MUL_FV:
-               c->vector[0] = a->_float * b->vector[0];
-               c->vector[1] = a->_float * b->vector[1];
-               c->vector[2] = a->_float * b->vector[2];
-               break;
-       case OP_MUL_VF:
-               c->vector[0] = b->_float * a->vector[0];
-               c->vector[1] = b->_float * a->vector[1];
-               c->vector[2] = b->_float * a->vector[2];
-               break;
-
-       case OP_DIV_F:
-               c->_float = a->_float / b->_float;
-               break;
-       
-       case OP_BITAND:
-               c->_float = (int)a->_float & (int)b->_float;
-               break;
-       
-       case OP_BITOR:
-               c->_float = (int)a->_float | (int)b->_float;
-               break;
-       
-               
-       case OP_GE:
-               c->_float = a->_float >= b->_float;
-               break;
-       case OP_LE:
-               c->_float = a->_float <= b->_float;
-               break;
-       case OP_GT:
-               c->_float = a->_float > b->_float;
-               break;
-       case OP_LT:
-               c->_float = a->_float < b->_float;
-               break;
-       case OP_AND:
-               c->_float = a->_float && b->_float;
-               break;
-       case OP_OR:
-               c->_float = a->_float || b->_float;
-               break;
-               
-       case OP_NOT_F:
-               c->_float = !a->_float;
-               break;
-       case OP_NOT_V:
-               c->_float = !a->vector[0] && !a->vector[1] && !a->vector[2];
-               break;
-       case OP_NOT_S:
-               c->_float = !a->string || !pr_strings[a->string];
-               break;
-       case OP_NOT_FNC:
-               c->_float = !a->function;
-               break;
-       case OP_NOT_ENT:
-               c->_float = (PROG_TO_EDICT(a->edict) == sv.edicts);
-               break;
-
-       case OP_EQ_F:
-               c->_float = a->_float == b->_float;
-               break;
-       case OP_EQ_V:
-               c->_float = (a->vector[0] == b->vector[0]) &&
-                                       (a->vector[1] == b->vector[1]) &&
-                                       (a->vector[2] == b->vector[2]);
-               break;
-       case OP_EQ_S:
-               c->_float = !strcmp(pr_strings+a->string,pr_strings+b->string);
-               break;
-       case OP_EQ_E:
-               c->_float = a->_int == b->_int;
-               break;
-       case OP_EQ_FNC:
-               c->_float = a->function == b->function;
-               break;
-
-
-       case OP_NE_F:
-               c->_float = a->_float != b->_float;
-               break;
-       case OP_NE_V:
-               c->_float = (a->vector[0] != b->vector[0]) ||
-                                       (a->vector[1] != b->vector[1]) ||
-                                       (a->vector[2] != b->vector[2]);
-               break;
-       case OP_NE_S:
-               c->_float = strcmp(pr_strings+a->string,pr_strings+b->string);
-               break;
-       case OP_NE_E:
-               c->_float = a->_int != b->_int;
-               break;
-       case OP_NE_FNC:
-               c->_float = a->function != b->function;
-               break;
-
-//==================
-       case OP_STORE_F:
-       case OP_STORE_ENT:
-       case OP_STORE_FLD:              // integers
-       case OP_STORE_S:
-       case OP_STORE_FNC:              // pointers
-               b->_int = a->_int;
-               break;
-       case OP_STORE_V:
-               b->vector[0] = a->vector[0];
-               b->vector[1] = a->vector[1];
-               b->vector[2] = a->vector[2];
-               break;
-               
-       case OP_STOREP_F:
-       case OP_STOREP_ENT:
-       case OP_STOREP_FLD:             // integers
-       case OP_STOREP_S:
-       case OP_STOREP_FNC:             // pointers
-               ptr = (eval_t *)((byte *)sv.edicts + b->_int);
-               ptr->_int = a->_int;
-               break;
-       case OP_STOREP_V:
-               ptr = (eval_t *)((byte *)sv.edicts + b->_int);
-               ptr->vector[0] = a->vector[0];
-               ptr->vector[1] = a->vector[1];
-               ptr->vector[2] = a->vector[2];
-               break;
-               
-       case OP_ADDRESS:
-               ed = PROG_TO_EDICT(a->edict);
-#ifdef PARANOID
-               NUM_FOR_EDICT(ed);              // make sure it's in range
-#endif
-               if (ed == (edict_t *)sv.edicts && sv.state == ss_active)
-                       PR_RunError ("assignment to world entity");
-               c->_int = (b