]> de.git.xonotic.org Git - xonotic/darkplaces.git/commitdiff
rewrote memory system entirely (hunk, cache, and zone are gone, memory pools replaced...
authorlordhavoc <lordhavoc@d7cf8633-e32d-0410-b094-e92efae38249>
Wed, 16 Jan 2002 06:16:58 +0000 (06:16 +0000)
committerlordhavoc <lordhavoc@d7cf8633-e32d-0410-b094-e92efae38249>
Wed, 16 Jan 2002 06:16:58 +0000 (06:16 +0000)
models can be reloaded at any time (Mod_CheckLoaded, etc)
entire renderer can be restarted using r_restart command
batch triangle mesh rendering system (gl_backend.c)
most rendering code does not touch GL anymore
gl_textures now supports procedural textures, and fragment textures (small textures combined into larger images)
lightmaps can now be mipmapped (r_miplightmaps)
broke up r_part.c and r_decals.c into cl_particles.c, r_particles.c, cl_decals.c, and r_decals.c to improve renderer/client separation, but explosions are still renderer
moved CL_NextDemo from cl_main.c to cl_demo.c
cleaned up demo stop/disconnect code
removed render modules stuff from all cl_ files
renderer uses separate light array, and recalculates radius for lights based on color, and calculates subtract value to give it a soft edge at the radius perimeter
small surfaces do not use lightmaps (unfortunately they still look slightly different in dynamic lighting)
items can now bob according to cl_itembob* cvars
moved CL_SignonReply from cl_main.c to cl_parse.c
monster movement interpolation is now done clientside instead of serverside, Nehahra movie should look better now
cvars now have a .integer field containing the integer value of their string (nearly all .value accesses have been changed to .integer for speed reasons)
pmodel is now only available in Nehahra mode (pmodel was a bad hack)
r_farclip cvar removed, farclip now dynamically adjusts to level as you explore it
parsing of wad names out of HL maps is now in renderer code
changed isworldmodel stuff in model loading
cleaned up CL_ParseUpdate a bit (related to clientside monster interpolation)
renamed r_glowinglightning to cl_glowinglightning
moved FindNonSolidLocation to bmodel code
lightning beam models are now only looked up once
entity_t now contains an entity_persistent_t which holds data persistent from frame to frame (interpolation mainly), entity_render_t is wiped every frame
marked a lot more things as static
increased command buffer (script execution buffer) from 8k to 32k
COM_LoadMallocFile has been renamed to COM_LoadFile, and all other variants are gone
rounding on MSG_Read/Write stuff has been changed to fix negative rounding (C rounds toward zero, old code assumed it always rounded down)
improved cachepic (menu images) system to load from wad
statusbar now uses cachepic system
cachepics are cleared when renderer is restarted
fixed fog on transparent objects, should always look correct now
moved R_TimeRefresh_f from gl_rmisc.c to gl_rmain.c
moved R_NewMap from gl_rmisc.c to gl_rmain.c
deleted gl_rmisc.c
removed support for glfog
masked sky rendering is now done by first rendering the sky scene, clearing the depthbuffer, rendering invisible depth polys over it, then rendering the scene, this is for more flexibility
C-code based shader system (not scripted)
deleted hcompress.c
due to more thorough memory corruption detection, a (harmless with old zone system) buffer overflow bug in the client name command was fixed
untested (and quite possibly broken) quaternion math stuff added to mathlib.h
removed support for colormod entity effect (massive mess to support it everywhere)
improved QC PR_RunError reports
moved QC opcode execution loop into pr_execprogram.h, included multiple times
fairly major sbar cleanup
rearranged GL extension detection again
added EXT_texture_env_combine support

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

103 files changed:
buildnumber.c
chase.c
cl_decals.c [new file with mode: 0644]
cl_demo.c
cl_light.c
cl_light.h
cl_main.c
cl_parse.c
cl_particles.c [new file with mode: 0644]
cl_tent.c
client.h
cmd.c
cmd.h
common.c
common.h
console.c
cvar.c
cvar.h
draw.h
fractalnoise.c
gl_backend.c [new file with mode: 0644]
gl_backend.h [new file with mode: 0644]
gl_draw.c
gl_models.c
gl_rmain.c
gl_rmisc.c [deleted file]
gl_rsurf.c
gl_screen.c
gl_textures.c
glquake.h
hcompress.c [deleted file]
host.c
host_cmd.c
image.c
image.h
in_svgalib.c
in_win.c
makefile
mathlib.c
mathlib.h
menu.c
model_alias.c
model_alias.h
model_brush.c
model_brush.h
model_shared.c
model_shared.h
model_sprite.c
model_sprite.h
modelgen.h
net_main.c
palette.c
palette.h
portals.c
pr_cmds.c
pr_edict.c
pr_exec.c
pr_execprogram.h [new file with mode: 0644]
progs.h
protocol.c
protocol.h
quakedef.h
quakeio.c
r_clip.c
r_crosshairs.c
r_decals.c
r_explosion.c
r_lerpanim.c
r_light.c
r_light.h
r_modules.c
r_part.c [deleted file]
r_particles.c [new file with mode: 0644]
r_sky.c [new file with mode: 0644]
r_sprites.c
r_textures.h
render.h
sbar.c
snd_dma.c
snd_mem.c
sound.h
spritegn.h
sv_light.c
sv_main.c
sv_phys.c
sv_user.c
sys_linux.c
sys_shared.c
sys_win.c
transform.c
transform.h
ui.c
vid_3dfxsvga.c
vid_glx.c
vid_shared.c
vid_wgl.c
view.c
wad.c
wad.h
world.c
world.h
zone.c
zone.h

index 8ec24a4ee823310f3a1a334dd4d0171c1593c7d5..2d3037b3fe32b0599dfb88aa9151b5a2d2099521 100644 (file)
@@ -1,4 +1,4 @@
 
-#define BUILDNUMBER 256
+#define BUILDNUMBER 604
 
 int buildnumber = BUILDNUMBER;
diff --git a/chase.c b/chase.c
index f4ee5b9611c5c2d6230969cf0670bcea873c0278..1b6e78ed2bb57337b5d653ed31938fcc49d33597 100644 (file)
--- a/chase.c
+++ b/chase.c
@@ -44,6 +44,11 @@ float TraceLine (vec3_t start, vec3_t end, vec3_t impact, vec3_t normal, int con
 {
        trace_t trace;
 
+// FIXME: broken, fix it
+//     if (impact == NULL && normal == NULL && contents == 0)
+//             return SV_TestLine (cl.worldmodel->hulls, 0, start, end);
+
+       Mod_CheckLoaded(cl.worldmodel);
        memset (&trace, 0, sizeof(trace));
        VectorCopy (end, trace.endpos);
        trace.fraction = 1;
diff --git a/cl_decals.c b/cl_decals.c
new file mode 100644 (file)
index 0000000..0a071c5
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+#include "quakedef.h"
+
+#define MAX_DECALS 2048
+
+typedef struct decal_s
+{
+       entity_render_t *ent;
+       int tex;
+       model_t *model;
+       int surface;
+       float scale;
+       vec3_t org;
+       vec3_t dir;
+       float color[4];
+}
+decal_t;
+
+static decal_t *cl_decals;
+static int cl_currentdecal; // wraps around in decal array, replacing old ones when a new one is needed
+
+static renderdecal_t *cl_renderdecals;
+
+static mempool_t *cl_decal_mempool;
+
+void CL_Decals_Clear(void)
+{
+       memset(cl_decals, 0, MAX_DECALS * sizeof(decal_t));
+       cl_currentdecal = 0;
+}
+
+void CL_Decals_Init(void)
+{
+       cl_decal_mempool = Mem_AllocPool("CL_Decals");
+       cl_decals = (decal_t *) Mem_Alloc(cl_decal_mempool, MAX_DECALS * sizeof(decal_t));
+       memset(cl_decals, 0, MAX_DECALS * sizeof(decal_t));
+       cl_currentdecal = 0;
+
+       // FIXME: r_refdef stuff should be allocated somewhere else?
+       r_refdef.decals = cl_renderdecals = Mem_Alloc(cl_decal_mempool, MAX_DECALS * sizeof(renderdecal_t));
+}
+
+
+// these are static globals only to avoid putting unnecessary things on the stack
+static vec3_t decalorg, decalbestorg;
+static float decalbestdist;
+static msurface_t *decalbestsurf;
+static entity_render_t *decalbestent, *decalent;
+static model_t *decalmodel;
+void CL_RecursiveDecalSurface (mnode_t *node)
+{
+       // these are static because only one occurance of them need exist at once, so avoid putting them on the stack
+       static float ndist, dist;
+       static msurface_t *surf, *endsurf;
+       static vec3_t impact;
+       static int ds, dt;
+
+loc0:
+       if (node->contents < 0)
+               return;
+
+       ndist = PlaneDiff(decalorg, node->plane);
+
+       if (ndist > 16)
+       {
+               node = node->children[0];
+               goto loc0;
+       }
+       if (ndist < -16)
+       {
+               node = node->children[1];
+               goto loc0;
+       }
+
+// mark the polygons
+       surf = decalmodel->surfaces + node->firstsurface;
+       endsurf = surf + node->numsurfaces;
+       for (;surf < endsurf;surf++)
+       {
+               if (!(surf->flags & SURF_LIGHTMAP))
+                       continue;
+
+               dist = PlaneDiff(decalorg, surf->plane);
+               if (surf->flags & SURF_PLANEBACK)
+                       dist = -dist;
+               if (dist < -1)
+                       continue;
+               if (dist >= decalbestdist)
+                       continue;
+
+               impact[0] = decalorg[0] - surf->plane->normal[0] * dist;
+               impact[1] = decalorg[1] - surf->plane->normal[1] * dist;
+               impact[2] = decalorg[2] - surf->plane->normal[2] * dist;
+
+               ds = (int) (DotProduct(impact, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]) - surf->texturemins[0];
+               dt = (int) (DotProduct(impact, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3]) - surf->texturemins[1];
+
+               if (ds < 0 || dt < 0 || ds > surf->extents[0] || dt > surf->extents[1])
+                       continue;
+
+               VectorCopy(decalorg, decalbestorg);
+               decalbestent = decalent;
+               decalbestsurf = surf;
+               decalbestdist = dist;
+       }
+
+       if (node->children[0]->contents >= 0)
+       {
+               if (node->children[1]->contents >= 0)
+               {
+                       CL_RecursiveDecalSurface (node->children[0]);
+                       node = node->children[1];
+                       goto loc0;
+               }
+               else
+               {
+                       node = node->children[0];
+                       goto loc0;
+               }
+       }
+       else if (node->children[1]->contents >= 0)
+       {
+               node = node->children[1];
+               goto loc0;
+       }
+}
+
+void CL_Decal(vec3_t origin, int tex, float scale, float red, float green, float blue, float alpha)
+{
+       int i;
+       decal_t *decal;
+
+       if (alpha < (1.0f / 255.0f))
+               return;
+
+       // find the best surface to place the decal on
+       decalbestent = NULL;
+       decalbestsurf = NULL;
+       decalbestdist = 16;
+
+       decalent = NULL;
+       decalmodel = cl.worldmodel;
+       Mod_CheckLoaded(decalmodel);
+       VectorCopy(origin, decalorg);
+       CL_RecursiveDecalSurface (decalmodel->nodes);
+
+       for (i = 1;i < MAX_EDICTS;i++)
+       {
+               decalent = &cl_entities[i].render;
+               decalmodel = decalent->model;
+               if (decalmodel && decalmodel->name[0])
+               {
+                       Mod_CheckLoaded(decalmodel);
+                       if (decalmodel->type == mod_brush)
+                       {
+                               softwaretransformforentity(decalent);
+                               softwareuntransform(origin, decalorg);
+                               CL_RecursiveDecalSurface (decalmodel->nodes);
+                       }
+               }
+       }
+
+       // abort if no suitable surface was found
+       if (decalbestsurf == NULL)
+               return;
+
+       // grab a decal from the array and advance to the next decal to replace, wrapping to replace an old decal if necessary
+       decal = &cl_decals[cl_currentdecal++];
+       if (cl_currentdecal >= MAX_DECALS)
+               cl_currentdecal = 0;
+       memset(decal, 0, sizeof(*decal));
+
+       decal->ent = decalbestent;
+       if (decal->ent)
+               decal->model = decal->ent->model;
+       else
+               decal->model = cl.worldmodel;
+
+       decal->tex = tex + 1; // our texture numbers are +1 to make 0 mean invisible
+       VectorNegate(decalbestsurf->plane->normal, decal->dir);
+       if (decalbestsurf->flags & SURF_PLANEBACK)
+               VectorNegate(decal->dir, decal->dir);
+       // 0.25 to push it off the surface a bit
+       decalbestdist -= 0.25f;
+       decal->org[0] = decalbestorg[0] + decal->dir[0] * decalbestdist;
+       decal->org[1] = decalbestorg[1] + decal->dir[1] * decalbestdist;
+       decal->org[2] = decalbestorg[2] + decal->dir[2] * decalbestdist;
+       decal->scale = scale * 0.5f;
+       // store the color
+       decal->color[0] = red;
+       decal->color[1] = green;
+       decal->color[2] = blue;
+       decal->color[3] = alpha;
+       // store the surface information
+       decal->surface = decalbestsurf - decal->model->surfaces;
+}
+
+void CL_UpdateDecals (void)
+{
+       int i;
+       decal_t *p;
+       renderdecal_t *r;
+
+       for (i = 0, p = cl_decals, r = r_refdef.decals;i < MAX_DECALS;i++, p++)
+       {
+               if (p->tex == 0)
+                       continue;
+
+               if (p->ent && p->ent->visframe == r_framecount && p->ent->model != p->model)
+               {
+                       p->tex = 0;
+                       continue;
+               }
+
+               r->ent = p->ent;
+               r->tex = p->tex - 1; // our texture numbers are +1 to make 0 mean invisible
+               r->surface = p->surface;
+               r->scale = p->scale;
+               VectorCopy(p->org, r->org);
+               VectorCopy(p->dir, r->dir);
+               VectorCopy4(p->color, r->color);
+               r++;
+       }
+       r_refdef.numdecals = r - r_refdef.decals;
+}
+
index ee61e500b9e818090291908d7c31a2a84c78fec8..780b1f1c9b5355cd3a3170eed4405fba941ab2fd 100644 (file)
--- a/cl_demo.c
+++ b/cl_demo.c
@@ -35,6 +35,38 @@ read from the demo file.
 ==============================================================================
 */
 
+/*
+=====================
+CL_NextDemo
+
+Called to play the next demo in the demo loop
+=====================
+*/
+void CL_NextDemo (void)
+{
+       char    str[1024];
+
+       if (cls.demonum == -1)
+               return;         // don't play demos
+
+//     SCR_BeginLoadingPlaque ();
+
+       if (!cls.demos[cls.demonum][0] || cls.demonum == MAX_DEMOS)
+       {
+               cls.demonum = 0;
+               if (!cls.demos[cls.demonum][0])
+               {
+                       Con_Printf ("No demos listed with startdemos\n");
+                       cls.demonum = -1;
+                       return;
+               }
+       }
+
+       sprintf (str,"playdemo %s\n", cls.demos[cls.demonum]);
+       Cbuf_InsertText (str);
+       cls.demonum++;
+}
+
 /*
 ==============
 CL_StopPlayback
@@ -42,6 +74,7 @@ CL_StopPlayback
 Called when a demo file runs out, or the user starts a game
 ==============
 */
+// LordHavoc: now called only by CL_Disconnect
 void CL_StopPlayback (void)
 {
        if (!cls.demoplayback)
@@ -50,7 +83,6 @@ void CL_StopPlayback (void)
        Qclose (cls.demofile);
        cls.demoplayback = false;
        cls.demofile = NULL;
-       cls.state = ca_disconnected;
 
        if (cls.timedemo)
                CL_FinishTimeDemo ();
@@ -134,7 +166,7 @@ int CL_GetMessage (void)
                r = Qread (cls.demofile, net_message.data, net_message.cursize);
                if (r != net_message.cursize)
                {
-                       CL_StopPlayback ();
+                       CL_Disconnect ();
                        return 0;
                }
        
index e4b9d4bb0108019fdbc45cbcce5e02efcb8d5bd6..be8ab869cfbfd6bdf679c99e231e18253df778cf 100644 (file)
@@ -2,24 +2,6 @@
 
 dlight_t cl_dlights[MAX_DLIGHTS];
 
-void cl_light_start(void)
-{
-}
-
-void cl_light_shutdown(void)
-{
-}
-
-void cl_light_newmap(void)
-{
-       memset (cl_dlights, 0, sizeof(cl_dlights));
-}
-
-void CL_Light_Init(void)
-{
-       R_RegisterModule("CL_Light", cl_light_start, cl_light_shutdown, cl_light_newmap);
-}
-
 /*
 ===============
 CL_AllocDlight
@@ -76,7 +58,6 @@ void CL_DecayLights (void)
 
        time = cl.time - cl.oldtime;
 
-       c_dlights = 0;
        dl = cl_dlights;
        for (i=0 ; i<MAX_DLIGHTS ; i++, dl++)
        {
@@ -88,8 +69,6 @@ void CL_DecayLights (void)
                        continue;
                }
 
-               c_dlights++; // count every dlight in use
-
                dl->radius -= time*dl->decay;
                if (dl->radius < 0)
                        dl->radius = 0;
index 384306558e83019e05d3128300a2b1a06673b3ea..f29c25bff904a97c47f439c8c4262462f60a4f3b 100644 (file)
@@ -3,19 +3,25 @@
 #define        MAX_DLIGHTS             256
 typedef struct
 {
+       // location
        vec3_t  origin;
+       // stop lighting after this time
+       float   die;
+       // color of light
+       vec3_t  color;
+       // brightness (not really radius anymore)
        float   radius;
-       float   die;                    // stop lighting after this time
-       float   decay;                  // drop this each second
-       entity_render_t *ent;   // the entity that spawned this light (can be NULL if it will never be replaced)
-       vec3_t  color;                  // LordHavoc: colored lighting
-} dlight_t;
+       // drop this each second
+       float   decay;
+       // the entity that spawned this light (can be NULL if it will never be replaced)
+       entity_render_t *ent;
+}
+dlight_t;
 
 // LordHavoc: this affects the lighting scale of the whole game
-#define LIGHTOFFSET 4096.0f
+#define LIGHTOFFSET 1024.0f
 
-extern dlight_t                cl_dlights[MAX_DLIGHTS];
+extern dlight_t cl_dlights[MAX_DLIGHTS];
 
 extern void CL_AllocDlight (entity_render_t *ent, vec3_t org, float radius, float red, float green, float blue, float decay, float lifetime);
 extern void CL_DecayLights (void);
-
index 26b78cff7477b0dd6927ececb3c16b28c3cc1b91..73d7adc7ec3c6740d603a70f8ee8131a3ed1fc81 100644 (file)
--- a/cl_main.c
+++ b/cl_main.c
@@ -25,24 +25,31 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 // references them even when on a unix system.
 
 // these two are not intended to be set directly
-cvar_t cl_name = {CVAR_SAVE, "_cl_name", "player"};
-cvar_t cl_color = {CVAR_SAVE, "_cl_color", "0"};
-cvar_t cl_pmodel = {CVAR_SAVE, "_cl_pmodel", "0"};
+cvar_t cl_name = {CVAR_SAVE, "_cl_name", "player"};
+cvar_t cl_color = {CVAR_SAVE, "_cl_color", "0"};
+cvar_t cl_pmodel = {CVAR_SAVE, "_cl_pmodel", "0"};
 
-cvar_t cl_shownet = {0, "cl_shownet","0"};
-cvar_t cl_nolerp = {0, "cl_nolerp", "0"};
+cvar_t cl_shownet = {0, "cl_shownet","0"};
+cvar_t cl_nolerp = {0, "cl_nolerp", "0"};
 
-cvar_t lookspring = {CVAR_SAVE, "lookspring","0"};
-cvar_t lookstrafe = {CVAR_SAVE, "lookstrafe","0"};
-cvar_t sensitivity = {CVAR_SAVE, "sensitivity","3", 1, 30};
+cvar_t cl_itembobheight = {0, "cl_itembobheight", "8"};
+cvar_t cl_itembobspeed = {0, "cl_itembobspeed", "0.5"};
 
-cvar_t m_pitch = {CVAR_SAVE, "m_pitch","0.022"};
-cvar_t m_yaw = {CVAR_SAVE, "m_yaw","0.022"};
-cvar_t m_forward = {CVAR_SAVE, "m_forward","1"};
-cvar_t m_side = {CVAR_SAVE, "m_side","0.8"};
+cvar_t lookspring = {CVAR_SAVE, "lookspring","0"};
+cvar_t lookstrafe = {CVAR_SAVE, "lookstrafe","0"};
+cvar_t sensitivity = {CVAR_SAVE, "sensitivity","3", 1, 30};
+
+cvar_t m_pitch = {CVAR_SAVE, "m_pitch","0.022"};
+cvar_t m_yaw = {CVAR_SAVE, "m_yaw","0.022"};
+cvar_t m_forward = {CVAR_SAVE, "m_forward","1"};
+cvar_t m_side = {CVAR_SAVE, "m_side","0.8"};
 
 cvar_t freelook = {CVAR_SAVE, "freelook", "1"};
 
+cvar_t cl_draweffects = {0, "cl_draweffects", "1"};
+
+mempool_t *cl_scores_mempool;
+
 client_static_t        cls;
 client_state_t cl;
 // FIXME: put these on hunk?
@@ -53,6 +60,27 @@ lightstyle_t cl_lightstyle[MAX_LIGHTSTYLES];
 int                            cl_numvisedicts;
 entity_t               *cl_visedicts[MAX_VISEDICTS];
 
+typedef struct effect_s
+{
+       int active;
+       vec3_t origin;
+       float starttime;
+       float framerate;
+       int modelindex;
+       int startframe;
+       int endframe;
+       // these are for interpolation
+       int frame;
+       double frame1time;
+       double frame2time;
+}
+cl_effect_t;
+
+#define MAX_EFFECTS 256
+
+static cl_effect_t cl_effect[MAX_EFFECTS];
+
+
 /*
 =====================
 CL_ClearState
@@ -66,16 +94,22 @@ void CL_ClearState (void)
        if (!sv.active)
                Host_ClearMemory ();
 
+       Mem_EmptyPool(cl_scores_mempool);
+
 // wipe the entire cl structure
        memset (&cl, 0, sizeof(cl));
 
        SZ_Clear (&cls.message);
 
 // clear other arrays
-       memset (cl_entities, 0, sizeof(cl_entities));
-       memset (cl_lightstyle, 0, sizeof(cl_lightstyle));
-       memset (cl_temp_entities, 0, sizeof(cl_temp_entities));
-       memset (cl_beams, 0, sizeof(cl_beams));
+       memset(cl_entities, 0, sizeof(cl_entities));
+       memset(cl_lightstyle, 0, sizeof(cl_lightstyle));
+       memset(cl_temp_entities, 0, sizeof(cl_temp_entities));
+       memset(cl_beams, 0, sizeof(cl_beams));
+       memset(cl_dlights, 0, sizeof(cl_dlights));
+       memset(cl_effect, 0, sizeof(cl_effect));
+       CL_Particles_Clear();
+       CL_Decals_Clear();
        // LordHavoc: have to set up the baseline info for alpha and other stuff
        for (i = 0;i < MAX_EDICTS;i++)
        {
@@ -142,7 +176,8 @@ void CL_Disconnect (void)
        cl.cshifts[2].percent = 0;
        cl.cshifts[3].percent = 0;
 
-// if running a local server, shut it down
+       cl.worldmodel = NULL;
+
        if (cls.demoplayback)
                CL_StopPlayback ();
        else if (cls.state == ca_connected)
@@ -156,11 +191,11 @@ void CL_Disconnect (void)
                NET_SendUnreliableMessage (cls.netcon, &cls.message);
                SZ_Clear (&cls.message);
                NET_Close (cls.netcon);
-
-               cls.state = ca_disconnected;
+               // if running a local server, shut it down
                if (sv.active)
                        Host_ShutdownServer(false);
        }
+       cls.state = ca_disconnected;
 
        cls.demoplayback = cls.timedemo = false;
        cls.signon = 0;
@@ -197,106 +232,23 @@ void CL_EstablishConnection (char *host)
        if (!cls.netcon)
                Host_Error ("CL_Connect: connect failed\n");
        Con_DPrintf ("CL_EstablishConnection: connected to %s\n", host);
-       
+
        cls.demonum = -1;                       // not in the demo loop now
        cls.state = ca_connected;
        cls.signon = 0;                         // need all the signon messages before playing
 }
 
-/*
-=====================
-CL_SignonReply
-
-An svc_signonnum has been received, perform a client side setup
-=====================
-*/
-void CL_SignonReply (void)
-{
-       char    str[8192];
-
-Con_DPrintf ("CL_SignonReply: %i\n", cls.signon);
-
-       switch (cls.signon)
-       {
-       case 1:
-               MSG_WriteByte (&cls.message, clc_stringcmd);
-               MSG_WriteString (&cls.message, "prespawn");
-               break;
-
-       case 2:
-               MSG_WriteByte (&cls.message, clc_stringcmd);
-               MSG_WriteString (&cls.message, va("name \"%s\"\n", cl_name.string));
-
-               MSG_WriteByte (&cls.message, clc_stringcmd);
-               MSG_WriteString (&cls.message, va("color %i %i\n", ((int)cl_color.value)>>4, ((int)cl_color.value)&15));
-       
-               if (cl_pmodel.value)
-               {
-                       MSG_WriteByte (&cls.message, clc_stringcmd);
-                       MSG_WriteString (&cls.message, va("pmodel %f\n", cl_pmodel.value));
-               }
-
-               MSG_WriteByte (&cls.message, clc_stringcmd);
-               sprintf (str, "spawn %s", cls.spawnparms);
-               MSG_WriteString (&cls.message, str);
-               break;
-               
-       case 3: 
-               MSG_WriteByte (&cls.message, clc_stringcmd);
-               MSG_WriteString (&cls.message, "begin");
-               Cache_Report ();                // print remaining memory
-               break;
-               
-       case 4:
-//             SCR_EndLoadingPlaque ();                // allow normal screen updates
-               Con_ClearNotify();
-               break;
-       }
-}
-
-/*
-=====================
-CL_NextDemo
-
-Called to play the next demo in the demo loop
-=====================
-*/
-void CL_NextDemo (void)
-{
-       char    str[1024];
-
-       if (cls.demonum == -1)
-               return;         // don't play demos
-
-//     SCR_BeginLoadingPlaque ();
-
-       if (!cls.demos[cls.demonum][0] || cls.demonum == MAX_DEMOS)
-       {
-               cls.demonum = 0;
-               if (!cls.demos[cls.demonum][0])
-               {
-                       Con_Printf ("No demos listed with startdemos\n");
-                       cls.demonum = -1;
-                       return;
-               }
-       }
-
-       sprintf (str,"playdemo %s\n", cls.demos[cls.demonum]);
-       Cbuf_InsertText (str);
-       cls.demonum++;
-}
-
 /*
 ==============
 CL_PrintEntities_f
 ==============
 */
-void CL_PrintEntities_f (void)
+static void CL_PrintEntities_f (void)
 {
        entity_t        *ent;
        int                     i, j;
        char            name[32];
-       
+
        for (i = 0, ent = cl_entities;i < MAX_EDICTS /*cl.num_entities*/;i++, ent++)
        {
                if (!ent->state_current.active)
@@ -327,19 +279,19 @@ Determines the fraction between the last two messages that the objects
 should be put at.
 ===============
 */
-float  CL_LerpPoint (void)
+static float CL_LerpPoint (void)
 {
        float   f, frac;
 
        f = cl.mtime[0] - cl.mtime[1];
 
        // LordHavoc: lerp in listen games as the server is being capped below the client (usually)
-       if (!f || cl_nolerp.value || cls.timedemo || (sv.active && svs.maxclients == 1))
+       if (!f || cl_nolerp.integer || cls.timedemo || (sv.active && svs.maxclients == 1))
        {
                cl.time = cl.mtime[0];
                return 1;
        }
-               
+
        if (f > 0.1)
        {       // dropped packet, or start of demo
                cl.mtime[1] = cl.mtime[0] - 0.1;
@@ -365,35 +317,18 @@ float     CL_LerpPoint (void)
                }
                frac = 1;
        }
-               
-       return frac;
-}
-
-float CL_EntityLerpPoint (entity_t *ent)
-{
-       float   f;
-
-       if (cl_nolerp.value || cls.timedemo || (sv.active && svs.maxclients == 1))
-               return 1;
-
-       f = ent->state_current.time - ent->state_previous.time;
-//     Con_Printf(" %g-%g=%g", ent->state_current.time, ent->state_previous.time, f);
 
-       if (f <= 0)
-               return 1;
-       if (f >= 0.1)
-               f = 0.1;
-
-//     Con_Printf(" %g-%g/%g=%f", cl.time, ent->state_previous.time, f, (cl.time - ent->state_previous.time) / f);
-       f = (cl.time - ent->state_previous.time) / f;
-       return bound(0, f, 1);
+       return frac;
 }
 
-void CL_RelinkStaticEntities(void)
+static void CL_RelinkStaticEntities(void)
 {
        int i;
        for (i = 0;i < cl.num_statics && cl_numvisedicts < MAX_VISEDICTS;i++)
+       {
+               Mod_CheckLoaded(cl_static_entities[i].render.model);
                cl_visedicts[cl_numvisedicts++] = &cl_static_entities[i];
+       }
 }
 
 /*
@@ -401,16 +336,18 @@ void CL_RelinkStaticEntities(void)
 CL_RelinkEntities
 ===============
 */
-void R_RocketTrail2 (vec3_t start, vec3_t end, int color, entity_t *ent);
-void CL_RelinkNetworkEntities()
+static void CL_RelinkNetworkEntities()
 {
        entity_t        *ent;
-       int                     i, j, glowcolor, effects;
-       float           f, d, bobjrotate/*, bobjoffset*/, dlightradius, glowsize;
+       int                     i, glowcolor, effects;
+       float           f, d, bobjrotate, bobjoffset, dlightradius, glowsize, lerp;
        vec3_t          oldorg, neworg, delta, dlightcolor;
 
        bobjrotate = ANGLEMOD(100*cl.time);
-//     bobjoffset = cos(180 * cl.time * M_PI / 180) * 4.0f + 4.0f;
+       if (cl_itembobheight.value)
+               bobjoffset = (cos(cl.time * cl_itembobspeed.value * (2.0 * M_PI)) + 1.0) * 0.5 * cl_itembobheight.value;
+       else
+               bobjoffset = 0;
 
        CL_RelinkStaticEntities();
 
@@ -426,19 +363,84 @@ void CL_RelinkNetworkEntities()
                if (!ent->state_previous.active)
                {
                        // only one state available
+                       lerp = 1;
+                       VectorCopy (ent->state_current.origin, oldorg); // skip trails
                        VectorCopy (ent->state_current.origin, neworg);
                        VectorCopy (ent->state_current.angles, ent->render.angles);
+
+                       /*
+                       // monster interpolation
+                       ent->persistent.steplerptime = 0;
+                       VectorCopy(ent->state_current.origin, ent->persistent.stepoldorigin);
+                       VectorCopy(ent->state_current.angles, ent->persistent.stepoldangles);
+                       VectorCopy(ent->state_current.origin, ent->persistent.steporigin);
+                       VectorCopy(ent->state_current.angles, ent->persistent.stepangles);
+                       */
+               }
+               /*
+               else if ((ent->state_current.flags & ent->state_previous.flags) & ENTFLAG_STEP)
+               {
+                       if (ent->state_current.origin[0] != ent->persistent.steporigin[0]
+                        || ent->state_current.origin[1] != ent->persistent.steporigin[1]
+                        || ent->state_current.origin[2] != ent->persistent.steporigin[2]
+                        || ent->state_current.angles[0] != ent->persistent.stepangles[0]
+                        || ent->state_current.angles[1] != ent->persistent.stepangles[1]
+                        || ent->state_current.angles[2] != ent->persistent.stepangles[2])
+                       {
+                               // update lerp positions
+                               ent->clientpersistent.steplerptime = sv.time;
+                               VectorCopy(ent->steporigin, ent->stepoldorigin);
+                               VectorCopy(ent->stepangles, ent->stepoldangles);
+                               VectorCopy(ent->v.origin, ent->steporigin);
+                               VectorCopy(ent->v.angles, ent->stepangles);
+                       }
+                       lerp = (cl.time - ent->persistent.steplerptime) * 10.0;
+                       if (lerp < 1)
+                       {
+                               // origin
+                               VectorSubtract(ent->persistent.steporigin, ent->persistent.stepoldorigin, delta);
+                               VectorMA(ent->persistent.stepoldorigin, lerp, delta, neworg);
+
+                               // angles
+                               VectorSubtract(ent->persistent.stepangles, ent->persistent.stepoldangles, delta);
+                               // choose shortest rotate (to avoid 'spin around' situations)
+                               if (delta[0] < -180) delta[0] += 360;else if (delta[0] >= 180) delta[0] -= 360;
+                               if (delta[1] < -180) delta[1] += 360;else if (delta[1] >= 180) delta[1] -= 360;
+                               if (delta[2] < -180) delta[2] += 360;else if (delta[2] >= 180) delta[2] -= 360;
+                               VectorMA(ent->stepoldangles, lerp, delta, ent->render.angles);
+                       }
+                       else
+                       {
+                               VectorCopy(ent->persistent.steporigin, neworg);
+                               VectorCopy(ent->persistent.stepangles, ent->render.angles);
+                       }
                }
+               */
                else
                {
+                       /*
+                       // monster interpolation
+                       ent->persistent.steplerptime = 0;
+                       VectorCopy(ent->state_current.origin, ent->persistent.stepoldorigin);
+                       VectorCopy(ent->state_current.angles, ent->persistent.stepoldangles);
+                       VectorCopy(ent->state_current.origin, ent->persistent.steporigin);
+                       VectorCopy(ent->state_current.angles, ent->persistent.stepangles);
+                       */
+
                        // if the delta is large, assume a teleport and don't lerp
                        VectorSubtract(ent->state_current.origin, ent->state_previous.origin, delta);
                        // LordHavoc: increased tolerance from 100 to 200
-                       if (DotProduct(delta, delta) > 200*200)
-                               f = 1;
+                       if ((sv.active && svs.maxclients == 1 && !(ent->state_current.flags & RENDER_STEP)) || cls.timedemo || DotProduct(delta, delta) > 200*200 || cl_nolerp.integer)
+                               lerp = 1;
                        else
-                               f = CL_EntityLerpPoint(ent);
-                       if (f >= 1)
+                       {
+                               f = ent->state_current.time - ent->state_previous.time;
+                               if (f > 0)
+                                       lerp = (cl.time - ent->state_previous.time) / f;
+                               else
+                                       lerp = 1;
+                       }
+                       if (lerp >= 1)
                        {
                                // no interpolation
                                VectorCopy (ent->state_current.origin, neworg);
@@ -447,29 +449,25 @@ void CL_RelinkNetworkEntities()
                        else
                        {
                                // interpolate the origin and angles
-                               for (j = 0;j < 3;j++)
-                               {
-                                       neworg[j] = ent->state_previous.origin[j] + f*delta[j];
-
-                                       d = ent->state_current.angles[j] - ent->state_previous.angles[j];
-                                       if (d > 180)
-                                               d -= 360;
-                                       else if (d < -180)
-                                               d += 360;
-                                       ent->render.angles[j] = ent->state_previous.angles[j] + f*d;
-                               }
+                               VectorMA(ent->state_previous.origin, lerp, delta, neworg);
+                               VectorSubtract(ent->state_current.angles, ent->state_previous.angles, delta);
+                               if (delta[0] < -180) delta[0] += 360;else if (delta[0] >= 180) delta[0] -= 360;
+                               if (delta[1] < -180) delta[1] += 360;else if (delta[1] >= 180) delta[1] -= 360;
+                               if (delta[2] < -180) delta[2] += 360;else if (delta[2] >= 180) delta[2] -= 360;
+                               VectorMA(ent->state_previous.angles, lerp, delta, ent->render.angles);
                        }
                }
 
                VectorCopy (neworg, ent->persistent.trail_origin);
                // persistent.modelindex will be updated by CL_LerpUpdate
-               if (ent->state_current.modelindex != ent->persistent.modelindex)
+               if (ent->state_current.modelindex != ent->persistent.modelindex || !ent->state_previous.active)
                        VectorCopy(neworg, oldorg);
 
                VectorCopy (neworg, ent->render.origin);
                ent->render.flags = ent->state_current.flags;
                ent->render.effects = effects = ent->state_current.effects;
                ent->render.model = cl.model_precache[ent->state_current.modelindex];
+               Mod_CheckLoaded(ent->render.model);
                ent->render.frame = ent->state_current.frame;
                if (cl.scores == NULL || !ent->state_current.colormap)
                        ent->render.colormap = -1; // no special coloring
@@ -480,9 +478,6 @@ void CL_RelinkNetworkEntities()
                ent->render.scale = ent->state_current.scale * (1.0f / 16.0f); // FIXME: interpolate?
                glowsize = ent->state_current.glowsize * 4.0f; // FIXME: interpolate?
                glowcolor = ent->state_current.glowcolor;
-               ent->render.colormod[0] = (float) ((ent->state_current.colormod >> 5) & 7) * (1.0f / 7.0f);
-               ent->render.colormod[1] = (float) ((ent->state_current.colormod >> 2) & 7) * (1.0f / 7.0f);
-               ent->render.colormod[2] = (float) (ent->state_current.colormod & 3) * (1.0f / 3.0f);
 
                // update interpolation info
                CL_LerpUpdate(ent, ent->state_current.frame, ent->state_current.modelindex);
@@ -497,7 +492,7 @@ void CL_RelinkNetworkEntities()
                if (effects)
                {
                        if (effects & EF_BRIGHTFIELD)
-                               R_EntityParticles (ent);
+                               CL_EntityParticles (ent);
                        if (effects & EF_MUZZLEFLASH)
                        {
                                vec3_t v, v2;
@@ -559,7 +554,7 @@ void CL_RelinkNetworkEntities()
                                        }
                                        // how many flames to make
                                        temp = (int) (cl.time * 300) - (int) (cl.oldtime * 300);
-                                       R_FlameCube(mins, maxs, temp);
+                                       CL_FlameCube(mins, maxs, temp);
                                }
                                d = lhrandom(200, 250);
                                dlightcolor[0] += d * 1.0f;
@@ -574,22 +569,22 @@ void CL_RelinkNetworkEntities()
                        if (ent->render.model->flags & EF_ROTATE)
                        {
                                ent->render.angles[1] = bobjrotate;
-//                             ent->render.origin[2] += bobjoffset;
+                               ent->render.origin[2] += bobjoffset;
                        }
                        // only do trails if present in the previous frame as well
                        if (ent->state_previous.active)
                        {
                                if (ent->render.model->flags & EF_GIB)
-                                       R_RocketTrail (oldorg, neworg, 2, ent);
+                                       CL_RocketTrail (oldorg, neworg, 2, ent);
                                else if (ent->render.model->flags & EF_ZOMGIB)
-                                       R_RocketTrail (oldorg, neworg, 4, ent);
+                                       CL_RocketTrail (oldorg, neworg, 4, ent);
                                else if (ent->render.model->flags & EF_TRACER)
-                                       R_RocketTrail (oldorg, neworg, 3, ent);
+                                       CL_RocketTrail (oldorg, neworg, 3, ent);
                                else if (ent->render.model->flags & EF_TRACER2)
-                                       R_RocketTrail (oldorg, neworg, 5, ent);
+                                       CL_RocketTrail (oldorg, neworg, 5, ent);
                                else if (ent->render.model->flags & EF_ROCKET)
                                {
-                                       R_RocketTrail (oldorg, ent->render.origin, 0, ent);
+                                       CL_RocketTrail (oldorg, ent->render.origin, 0, ent);
                                        dlightcolor[0] += 200.0f;
                                        dlightcolor[1] += 160.0f;
                                        dlightcolor[2] +=  80.0f;
@@ -597,12 +592,12 @@ void CL_RelinkNetworkEntities()
                                else if (ent->render.model->flags & EF_GRENADE)
                                {
                                        if (ent->render.alpha == -1) // LordHavoc: Nehahra dem compatibility
-                                               R_RocketTrail (oldorg, neworg, 7, ent);
+                                               CL_RocketTrail (oldorg, neworg, 7, ent);
                                        else
-                                               R_RocketTrail (oldorg, neworg, 1, ent);
+                                               CL_RocketTrail (oldorg, neworg, 1, ent);
                                }
                                else if (ent->render.model->flags & EF_TRACER3)
-                                       R_RocketTrail (oldorg, neworg, 6, ent);
+                                       CL_RocketTrail (oldorg, neworg, 6, ent);
                        }
                }
                // LordHavoc: customizable glow
@@ -615,7 +610,7 @@ void CL_RelinkNetworkEntities()
                }
                // LordHavoc: customizable trail
                if (ent->render.flags & RENDER_GLOWTRAIL)
-                       R_RocketTrail2 (oldorg, neworg, glowcolor, ent);
+                       CL_RocketTrail2 (oldorg, neworg, glowcolor, ent);
 
                if (dlightcolor[0] || dlightcolor[1] || dlightcolor[2])
                {
@@ -624,12 +619,12 @@ void CL_RelinkNetworkEntities()
                        d = 1.0f / dlightradius;
                        VectorCopy(neworg, vec);
                        // hack to make glowing player light shine on their gun
-                       if (i == cl.viewentity && !chase_active.value)
+                       if (i == cl.viewentity && !chase_active.integer)
                                vec[2] += 30;
                        CL_AllocDlight (&ent->render, vec, dlightradius, dlightcolor[0] * d, dlightcolor[1] * d, dlightcolor[2] * d, 0, 0);
                }
 
-               if (chase_active.value)
+               if (chase_active.integer)
                {
                        if (ent->render.flags & RENDER_VIEWMODEL)
                                continue;
@@ -649,7 +644,7 @@ void CL_RelinkNetworkEntities()
        }
 }
 
-void CL_LerpPlayerVelocity (void)
+static void CL_LerpPlayerVelocity (void)
 {
        int i;
        float frac, d;
@@ -675,12 +670,90 @@ void CL_LerpPlayerVelocity (void)
        }
 }
 
+void CL_Effect(vec3_t org, int modelindex, int startframe, int framecount, float framerate)
+{
+       int i;
+       cl_effect_t *e;
+       if (!modelindex) // sanity check
+               return;
+       for (i = 0, e = cl_effect;i < MAX_EFFECTS;i++, e++)
+       {
+               if (e->active)
+                       continue;
+               e->active = true;
+               VectorCopy(org, e->origin);
+               e->modelindex = modelindex;
+               e->starttime = cl.time;
+               e->startframe = startframe;
+               e->endframe = startframe + framecount;
+               e->framerate = framerate;
+
+               e->frame = 0;
+               e->frame1time = cl.time;
+               e->frame2time = cl.time;
+               break;
+       }
+}
+
+static void CL_RelinkEffects()
+{
+       int i, intframe;
+       cl_effect_t *e;
+       entity_t *vis;
+       float frame;
+
+       for (i = 0, e = cl_effect;i < MAX_EFFECTS;i++, e++)
+       {
+               if (e->active)
+               {
+                       frame = (cl.time - e->starttime) * e->framerate + e->startframe;
+                       intframe = frame;
+                       if (intframe < 0 || intframe >= e->endframe)
+                       {
+                               e->active = false;
+                               memset(e, 0, sizeof(*e));
+                               continue;
+                       }
+
+                       if (intframe != e->frame)
+                       {
+                               e->frame = intframe;
+                               e->frame1time = e->frame2time;
+                               e->frame2time = cl.time;
+                       }
+
+                       if ((vis = CL_NewTempEntity()))
+                       {
+                               // interpolation stuff
+                               vis->render.frame1 = intframe;
+                               vis->render.frame2 = intframe + 1;
+                               if (vis->render.frame2 >= e->endframe)
+                                       vis->render.frame2 = -1; // disappear
+                               vis->render.framelerp = frame - intframe;
+                               vis->render.frame1time = e->frame1time;
+                               vis->render.frame2time = e->frame2time;
+
+                               // normal stuff
+                               VectorCopy(e->origin, vis->render.origin);
+                               vis->render.model = cl.model_precache[e->modelindex];
+                               vis->render.frame = vis->render.frame2;
+                               vis->render.colormap = -1; // no special coloring
+                               vis->render.scale = 1;
+                               vis->render.alpha = 1;
+                       }
+               }
+       }
+}
+
 void CL_RelinkEntities (void)
 {
        cl_numvisedicts = 0;
 
        CL_LerpPlayerVelocity();
        CL_RelinkNetworkEntities();
+       CL_RelinkEffects();
+       CL_MoveParticles();
+       CL_UpdateDecals();
 }
 
 
@@ -697,7 +770,7 @@ int CL_ReadFromServer (void)
 
        cl.oldtime = cl.time;
        cl.time += cl.frametime;
-       
+
        netshown = false;
        do
        {
@@ -706,22 +779,21 @@ int CL_ReadFromServer (void)
                        Host_Error ("CL_ReadFromServer: lost server connection");
                if (!ret)
                        break;
-               
+
                cl.last_received_message = realtime;
 
-               if (cl_shownet.value)
+               if (cl_shownet.integer)
                        netshown = true;
 
                CL_ParseServerMessage ();
        }
        while (ret && cls.state == ca_connected);
-       
+
        if (netshown)
                Con_Printf ("\n");
 
        CL_RelinkEntities ();
        CL_UpdateTEnts ();
-       CL_DoEffects ();
 
 //
 // bring the links up to date
@@ -748,7 +820,7 @@ void CL_SendCmd (void)
 
        // allow mice or other external controllers to add to the move
                IN_Move (&cmd);
-       
+
        // send the unreliable message
                CL_SendMove (&cmd);
        }
@@ -758,11 +830,11 @@ void CL_SendCmd (void)
                SZ_Clear (&cls.message);
                return;
        }
-       
+
 // send the reliable message
        if (!cls.message.cursize)
                return;         // no message at all
-       
+
        if (!NET_CanSendMessage (cls.netcon))
        {
                Con_DPrintf ("CL_WriteToServer: can't send\n");
@@ -776,7 +848,7 @@ void CL_SendCmd (void)
 }
 
 // LordHavoc: pausedemo command
-void CL_PauseDemo_f (void)
+static void CL_PauseDemo_f (void)
 {
        cls.demopaused = !cls.demopaused;
        if (cls.demopaused)
@@ -791,7 +863,7 @@ CL_PModel_f
 LordHavoc: Intended for Nehahra, I personally think this is dumb, but Mindcrime won't listen.
 ======================
 */
-void CL_PModel_f (void)
+static void CL_PModel_f (void)
 {
        int i;
        eval_t *val;
@@ -805,7 +877,7 @@ void CL_PModel_f (void)
 
        if (cmd_source == src_command)
        {
-               if (cl_pmodel.value == i)
+               if (cl_pmodel.integer == i)
                        return;
                Cvar_SetValue ("_cl_pmodel", i);
                if (cls.state == ca_connected)
@@ -823,7 +895,7 @@ void CL_PModel_f (void)
 CL_Fog_f
 ======================
 */
-void CL_Fog_f (void)
+static void CL_Fog_f (void)
 {
        if (Cmd_Argc () == 1)
        {
@@ -842,18 +914,19 @@ CL_Init
 =================
 */
 void CL_Init (void)
-{      
-       SZ_Alloc (&cls.message, 1024);
+{
+       SZ_Alloc (&cls.message, 1024, "cls.message");
 
        CL_InitInput ();
        CL_InitTEnts ();
-       
+
 //
 // register our commands
 //
        Cvar_RegisterVariable (&cl_name);
        Cvar_RegisterVariable (&cl_color);
-       Cvar_RegisterVariable (&cl_pmodel);
+       if (gamemode == GAME_NEHAHRA)
+               Cvar_RegisterVariable (&cl_pmodel);
        Cvar_RegisterVariable (&cl_upspeed);
        Cvar_RegisterVariable (&cl_forwardspeed);
        Cvar_RegisterVariable (&cl_backspeed);
@@ -874,8 +947,9 @@ void CL_Init (void)
        Cvar_RegisterVariable (&m_forward);
        Cvar_RegisterVariable (&m_side);
 
-//     Cvar_RegisterVariable (&cl_autofire);
-       
+       Cvar_RegisterVariable (&cl_itembobspeed);
+       Cvar_RegisterVariable (&cl_itembobheight);
+
        Cmd_AddCommand ("entities", CL_PrintEntities_f);
        Cmd_AddCommand ("bitprofile", CL_BitProfile_f);
        Cmd_AddCommand ("disconnect", CL_Disconnect_f);
@@ -888,8 +962,14 @@ void CL_Init (void)
 
        // LordHavoc: added pausedemo
        Cmd_AddCommand ("pausedemo", CL_PauseDemo_f);
-       // LordHavoc: added pmodel command (like name, etc, only intended for Nehahra)
-       Cmd_AddCommand ("pmodel", CL_PModel_f);
+       if (gamemode == GAME_NEHAHRA)
+               Cmd_AddCommand ("pmodel", CL_PModel_f);
+
+       cl_scores_mempool = Mem_AllocPool("client player info");
+
+       Cvar_RegisterVariable(&cl_draweffects);
 
        CL_Parse_Init();
+       CL_Particles_Init();
+       CL_Decals_Init();
 }
index ec3d3d597f712a80c4c521b3797f1cb155575044..9a06ee434a8aa17c2aadb19c9e81d219473e016f 100644 (file)
@@ -8,7 +8,7 @@ of the License, or (at your option) any later version.
 
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 See the GNU General Public License for more details.
 
@@ -273,19 +273,17 @@ void CL_ParseEntityLump(char *entdata)
 {
        char *data;
        char key[128], value[4096];
-       char wadname[128];
        char targetnamebuffer[65536];
        char *targetname[8192], *target[MAX_STATICLIGHTS], light_target[256];
        vec3_t targetnameorigin[8192], targetnametemporigin, v;
        int targets, targetnames, targetnamebufferpos, targetnameorigintofillin;
-       int i, j, k, n;
+       int i, j, n;
        float f1, f2, f3, f4;
        float ambientlight, ambientcolor[3], sunlight, sunlightdirection[3], sunlightcolor[3];
        int light_fadetype, light_style, hlight, tyrlite, light_enable;
        float light_origin[3], light_light, light_distancescale, light_lightcolor[3], light_color[3], light_direction[3], light_cone, light_lightradius;
        FOG_clear(); // LordHavoc: no fog until set
        R_SetSkyBox(""); // LordHavoc: no environment mapped sky until set
-       r_farclip.value = 6144; // LordHavoc: default farclip distance
        r_sunlightenabled = false;
        staticlights = 0;
        data = entdata;
@@ -335,12 +333,6 @@ void CL_ParseEntityLump(char *entdata)
                        R_SetSkyBox(value);
                else if (!strcmp("qlsky", key)) // non-standard, introduced by QuakeLives (EEK)
                        R_SetSkyBox(value);
-               else if (!strcmp("farclip", key))
-               {
-                       r_farclip.value = atof(value);
-                       if (r_farclip.value < 64)
-                               r_farclip.value = 64;
-               }
                else if (!strcmp("fog", key))
                        scanf(value, "%f %f %f %f", &fog_density, &fog_red, &fog_green, &fog_blue);
                else if (!strcmp("fog_density", key))
@@ -351,36 +343,6 @@ void CL_ParseEntityLump(char *entdata)
                        fog_green = atof(value);
                else if (!strcmp("fog_blue", key))
                        fog_blue = atof(value);
-               else if (!strcmp("wad", key)) // for HalfLife maps
-               {
-                       if (hlbsp)
-                       {
-                               j = 0;
-                               for (i = 0;i < 4096;i++)
-                                       if (value[i] != ';' && value[i] != '\\' && value[i] != '/' && value[i] != ':')
-                                               break;
-                               if (value[i])
-                               {
-                                       for (;i < 4096;i++)
-                                       {
-                                               // ignore path - the \\ check is for HalfLife... stupid windoze 'programmers'...
-                                               if (value[i] == '\\' || value[i] == '/' || value[i] == ':')
-                                                       j = i+1;
-                                               else if (value[i] == ';' || value[i] == 0)
-                                               {
-                                                       k = value[i];
-                                                       value[i] = 0;
-                                                       strcpy(wadname, "textures/");
-                                                       strcat(wadname, &value[j]);
-                                                       W_LoadTextureWadFile (wadname, false);
-                                                       j = i+1;
-                                                       if (!k)
-                                                               break;
-                                               }
-                                       }
-                               }
-                       }
-               }
                else if (!strcmp("light", key))
                        ambientlight = atof(value);
                else if (!strcmp("sunlight", key))
@@ -590,7 +552,7 @@ void CL_ParseEntityLump(char *entdata)
                        staticlights++;
                }
        }
-       if (hlbsp)
+       if (cl.worldmodel->ishlbsp)
                n = LIGHTFADE_LDIVX2;
        else if (tyrlite)
                n = LIGHTFADE_LMINUSX;
@@ -620,6 +582,56 @@ void CL_ParseEntityLump(char *entdata)
        }
 }
 
+/*
+=====================
+CL_SignonReply
+
+An svc_signonnum has been received, perform a client side setup
+=====================
+*/
+static void CL_SignonReply (void)
+{
+       char    str[8192];
+
+Con_DPrintf ("CL_SignonReply: %i\n", cls.signon);
+
+       switch (cls.signon)
+       {
+       case 1:
+               MSG_WriteByte (&cls.message, clc_stringcmd);
+               MSG_WriteString (&cls.message, "prespawn");
+               break;
+
+       case 2:
+               MSG_WriteByte (&cls.message, clc_stringcmd);
+               MSG_WriteString (&cls.message, va("name \"%s\"\n", cl_name.string));
+
+               MSG_WriteByte (&cls.message, clc_stringcmd);
+               MSG_WriteString (&cls.message, va("color %i %i\n", cl_color.integer >> 4, cl_color.integer & 15));
+
+               if (cl_pmodel.integer)
+               {
+                       MSG_WriteByte (&cls.message, clc_stringcmd);
+                       MSG_WriteString (&cls.message, va("pmodel %i\n", cl_pmodel.integer));
+               }
+
+               MSG_WriteByte (&cls.message, clc_stringcmd);
+               sprintf (str, "spawn %s", cls.spawnparms);
+               MSG_WriteString (&cls.message, str);
+               break;
+
+       case 3:
+               MSG_WriteByte (&cls.message, clc_stringcmd);
+               MSG_WriteString (&cls.message, "begin");
+               break;
+
+       case 4:
+//             SCR_EndLoadingPlaque ();                // allow normal screen updates
+               Con_ClearNotify();
+               break;
+       }
+}
+
 /*
 ==================
 CL_ParseServerInfo
@@ -649,7 +661,7 @@ void CL_ParseServerInfo (void)
        Nehahrademcompatibility = false;
        if (i == 250)
                Nehahrademcompatibility = true;
-       if (cls.demoplayback && demo_nehahra.value)
+       if (cls.demoplayback && demo_nehahra.integer)
                Nehahrademcompatibility = true;
        dpprotocol = i == DPPROTOCOL_VERSION;
 
@@ -660,7 +672,7 @@ void CL_ParseServerInfo (void)
                Con_Printf("Bad maxclients (%u) from server\n", cl.maxclients);
                return;
        }
-       cl.scores = Hunk_AllocName (cl.maxclients*sizeof(*cl.scores), "scores");
+       cl.scores = Mem_Alloc(cl_scores_mempool, cl.maxclients*sizeof(*cl.scores));
 
 // parse gametype
        cl.gametype = MSG_ReadByte ();
@@ -682,7 +694,11 @@ void CL_ParseServerInfo (void)
 // needlessly purge it
 //
 
-       Hunk_Check ();
+       Mem_CheckSentinelsGlobal();
+
+       Mod_ClearUsed();
+
+       Mem_CheckSentinelsGlobal();
 
 // precache models
        memset (cl.model_precache, 0, sizeof(cl.model_precache));
@@ -700,9 +716,6 @@ void CL_ParseServerInfo (void)
                        Host_Error ("Server sent a precache name of %i characters (max %i)", strlen(str), MAX_QPATH - 1);
                strcpy (model_precache[nummodels], str);
                Mod_TouchModel (str);
-
-//             Hunk_Check ();
-
        }
 
 // precache sounds
@@ -723,18 +736,20 @@ void CL_ParseServerInfo (void)
                S_TouchSound (str);
        }
 
+       Mem_CheckSentinelsGlobal();
+
+       Mod_PurgeUnused();
+
 //
 // now we try to load everything else until a cache allocation fails
 //
 
-       Hunk_Check ();
+       Mem_CheckSentinelsGlobal();
 
        for (i=1 ; i<nummodels ; i++)
        {
-               isworldmodel = i == 1; // LordHavoc: first model is the world model
-               cl.model_precache[i] = Mod_ForName (model_precache[i], false);
-
-//             Hunk_Check ();
+               // LordHavoc: i == 1 means the first model is the world model
+               cl.model_precache[i] = Mod_ForName (model_precache[i], false, true, i == 1);
 
                if (cl.model_precache[i] == NULL)
                {
@@ -744,7 +759,7 @@ void CL_ParseServerInfo (void)
                CL_KeepaliveMessage ();
        }
 
-       Hunk_Check ();
+       Mem_CheckSentinelsGlobal();
 
        S_BeginPrecaching ();
        for (i=1 ; i<numsounds ; i++)
@@ -754,15 +769,14 @@ void CL_ParseServerInfo (void)
        }
        S_EndPrecaching ();
 
-
 // local state
        cl_entities[0].render.model = cl.worldmodel = cl.model_precache[1];
-
-//     Hunk_Check ();
+       cl_entities[0].render.scale = 1;
+       cl_entities[0].render.alpha = 1;
 
        R_NewMap ();
 
-       Hunk_Check ();          // make sure nothing is hurt
+       Mem_CheckSentinelsGlobal();
 
        noclip_anglehack = false;               // noclip is turned off at start
 }
@@ -782,14 +796,15 @@ void CL_ValidateState(entity_state_t *s)
                Host_Error ("CL_ValidateState: colormap (%i) > cl.maxclients (%i)", s->colormap, cl.maxclients);
 
        model = cl.model_precache[s->modelindex];
+       Mod_CheckLoaded(model);
        if (model && s->frame >= model->numframes)
        {
-               Con_DPrintf("CL_ValidateState: no such frame %i in \"%s\"\n", s->frame, model->name);
+               Con_Printf("CL_ValidateState: no such frame %i in \"%s\"\n", s->frame, model->name);
                s->frame = 0;
        }
-       if (model && s->skin >= model->numskins)
+       if (model && s->skin > 0 && s->skin >= model->numskins)
        {
-               Con_DPrintf("CL_ValidateState: no such skin %i in \"%s\"\n", s->skin, model->name);
+               Con_Printf("CL_ValidateState: no such skin %i in \"%s\"\n", s->skin, model->name);
                s->skin = 0;
        }
 }
@@ -809,6 +824,7 @@ void CL_ParseUpdate (int bits)
 {
        int i, num, deltadie;
        entity_t *ent;
+       entity_state_t new;
 
        if (cls.signon == SIGNONS - 1)
        {       // first update is the final signon stage
@@ -825,7 +841,7 @@ void CL_ParseUpdate (int bits)
                        bits |= MSG_ReadByte() << 24;
        }
 
-       if (bits & U_LONGENTITY)        
+       if (bits & U_LONGENTITY)
                num = (unsigned) MSG_ReadShort ();
        else
                num = (unsigned) MSG_ReadByte ();
@@ -845,43 +861,48 @@ void CL_ParseUpdate (int bits)
                        bitprofile[i]++;
        bitprofilecount++;
 
-       ent->state_previous = ent->state_current;
        deltadie = false;
        if (bits & U_DELTA)
        {
-               if (!ent->state_current.active)
+               new = ent->state_current;
+               if (!new.active)
                        deltadie = true; // was not present in previous frame, leave hidden until next full update
        }
        else
-               ent->state_current = ent->state_baseline;
-
-       ent->state_current.time = cl.mtime[0];
-
-       ent->state_current.flags = 0;
-       ent->state_current.active = true;
-       if (bits & U_MODEL)             ent->state_current.modelindex = (ent->state_current.modelindex & 0xFF00) | MSG_ReadByte();
-       if (bits & U_FRAME)             ent->state_current.frame = (ent->state_current.frame & 0xFF00) | MSG_ReadByte();
-       if (bits & U_COLORMAP)  ent->state_current.colormap = MSG_ReadByte();
-       if (bits & U_SKIN)              ent->state_current.skin = MSG_ReadByte();
-       if (bits & U_EFFECTS)   ent->state_current.effects = (ent->state_current.effects & 0xFF00) | MSG_ReadByte();
-       if (bits & U_ORIGIN1)   ent->state_current.origin[0] = MSG_ReadCoord();
-       if (bits & U_ANGLE1)    ent->state_current.angles[0] = MSG_ReadAngle();
-       if (bits & U_ORIGIN2)   ent->state_current.origin[1] = MSG_ReadCoord();
-       if (bits & U_ANGLE2)    ent->state_current.angles[1] = MSG_ReadAngle();
-       if (bits & U_ORIGIN3)   ent->state_current.origin[2] = MSG_ReadCoord();
-       if (bits & U_ANGLE3)    ent->state_current.angles[2] = MSG_ReadAngle();
-       if (bits & U_STEP)              ent->state_current.flags |= RENDER_STEP;
-       if (bits & U_ALPHA)             ent->state_current.alpha = MSG_ReadByte();
-       if (bits & U_SCALE)             ent->state_current.scale = MSG_ReadByte();
-       if (bits & U_EFFECTS2)  ent->state_current.effects = (ent->state_current.effects & 0x00FF) | (MSG_ReadByte() << 8);
-       if (bits & U_GLOWSIZE)  ent->state_current.glowsize = MSG_ReadByte();
-       if (bits & U_GLOWCOLOR) ent->state_current.glowcolor = MSG_ReadByte();
-       if (bits & U_GLOWTRAIL) ent->state_current.flags |= RENDER_GLOWTRAIL;
-       if (bits & U_COLORMOD)  ent->state_current.colormod = MSG_ReadByte();
-       if (bits & U_FRAME2)    ent->state_current.frame = (ent->state_current.frame & 0x00FF) | (MSG_ReadByte() << 8);
-       if (bits & U_MODEL2)    ent->state_current.modelindex = (ent->state_current.modelindex & 0x00FF) | (MSG_ReadByte() << 8);
-       if (bits & U_VIEWMODEL) ent->state_current.flags |= RENDER_VIEWMODEL;
-       if (bits & U_EXTERIORMODEL)     ent->state_current.flags |= RENDER_EXTERIORMODEL;
+               new = ent->state_baseline;
+
+       new.time = cl.mtime[0];
+
+       new.flags = 0;
+       new.active = true;
+       if (bits & U_MODEL)             new.modelindex = (new.modelindex & 0xFF00) | MSG_ReadByte();
+       if (bits & U_FRAME)             new.frame = (new.frame & 0xFF00) | MSG_ReadByte();
+       if (bits & U_COLORMAP)  new.colormap = MSG_ReadByte();
+       if (bits & U_SKIN)              new.skin = MSG_ReadByte();
+       if (bits & U_EFFECTS)   new.effects = (new.effects & 0xFF00) | MSG_ReadByte();
+       if (bits & U_ORIGIN1)   new.origin[0] = MSG_ReadCoord();
+       if (bits & U_ANGLE1)    new.angles[0] = MSG_ReadAngle();
+       if (bits & U_ORIGIN2)   new.origin[1] = MSG_ReadCoord();
+       if (bits & U_ANGLE2)    new.angles[1] = MSG_ReadAngle();
+       if (bits & U_ORIGIN3)   new.origin[2] = MSG_ReadCoord();
+       if (bits & U_ANGLE3)    new.angles[2] = MSG_ReadAngle();
+       if (bits & U_STEP)              new.flags |= RENDER_STEP;
+       if (bits & U_ALPHA)             new.alpha = MSG_ReadByte();
+       if (bits & U_SCALE)             new.scale = MSG_ReadByte();
+       if (bits & U_EFFECTS2)  new.effects = (new.effects & 0x00FF) | (MSG_ReadByte() << 8);
+       if (bits & U_GLOWSIZE)  new.glowsize = MSG_ReadByte();
+       if (bits & U_GLOWCOLOR) new.glowcolor = MSG_ReadByte();
+#if 0
+       if (bits & U_COLORMOD)  {int i = MSG_ReadByte();float r = (((int) i >> 5) & 7) * 1.0 / 7, g = (((int) i >> 2) & 7) * 1.0 / 7, b = ((int) i & 3) * 1.0 / 3;Con_Printf("warning: U_COLORMOD %i (%1.2f %1.2f %1.2f) ignored\n", i, r, g, b);}
+#else
+       // apparently the dpcrush demo uses this (unintended, and it uses white anyway)
+       if (bits & U_COLORMOD)  MSG_ReadByte();
+#endif
+       if (bits & U_GLOWTRAIL) new.flags |= RENDER_GLOWTRAIL;
+       if (bits & U_FRAME2)    new.frame = (new.frame & 0x00FF) | (MSG_ReadByte() << 8);
+       if (bits & U_MODEL2)    new.modelindex = (new.modelindex & 0x00FF) | (MSG_ReadByte() << 8);
+       if (bits & U_VIEWMODEL) new.flags |= RENDER_VIEWMODEL;
+       if (bits & U_EXTERIORMODEL)     new.flags |= RENDER_EXTERIORMODEL;
 
        // LordHavoc: to allow playback of the Nehahra movie
        if (Nehahrademcompatibility && (bits & U_EXTEND1))
@@ -892,44 +913,42 @@ void CL_ParseUpdate (int bits)
                if (i == 2)
                {
                        if (MSG_ReadFloat())
-                               ent->state_current.effects |= EF_FULLBRIGHT;
+                               new.effects |= EF_FULLBRIGHT;
                }
                if (j < 0)
-                       ent->state_current.alpha = 0;
+                       new.alpha = 0;
                else if (j == 0 || j >= 255)
-                       ent->state_current.alpha = 255;
+                       new.alpha = 255;
                else
-                       ent->state_current.alpha = j;
+                       new.alpha = j;
        }
 
        if (deltadie)
        {
                // hide the entity
-               ent->state_current.active = false;
+               new.active = false;
        }
        else
-       {
-               CL_ValidateState(&ent->state_current);
+               CL_ValidateState(&new);
 
-               /*
-               if (!ent->state_current.active)
+       if (new.flags & RENDER_STEP) // FIXME: rename this flag?
+       {
+               // make time identical for memcmp
+               new.time = ent->state_current.time;
+               if (memcmp(&new, &ent->state_current, sizeof(entity_state_t)))
                {
-                       if (bits & U_DELTA)
-                       {
-                               if (bits & U_MODEL)
-                                       Con_Printf("CL_ParseUpdate: delta NULL model on %i: %i %i\n", num, ent->state_previous.modelindex, ent->state_current.modelindex);
-                               else
-                                       Con_Printf("CL_ParseUpdate: delta NULL model on %i: %i\n", num, ent->state_previous.modelindex);
-                       }
-                       else
-                       {
-                               if (bits & U_MODEL)
-                                       Con_Printf("CL_ParseUpdate:       NULL model on %i: %i %i\n", num, ent->state_baseline.modelindex, ent->state_current.modelindex);
-                               else
-                                       Con_Printf("CL_ParseUpdate:       NULL model on %i: %i\n", num, ent->state_baseline.modelindex);
-                       }
+                       // state has changed
+                       ent->state_previous = ent->state_current;
+                       ent->state_current = new;
+                       // assume 10fps animation
+                       ent->state_previous.time = cl.mtime[0];
+                       ent->state_current.time = cl.mtime[0] + 0.1; //ent->state_previous.time + 0.1;
                }
-               */
+       }
+       else
+       {
+               ent->state_previous = ent->state_current;
+               ent->state_current = new;
        }
 }
 
@@ -957,7 +976,7 @@ char *bitprofilenames[32] =
        "U_EFFECTS2",
        "U_GLOWSIZE",
        "U_GLOWCOLOR",
-       "U_COLORMOD",
+       "obsolete U_COLORMOD",
        "U_EXTEND2",
        "U_GLOWTRAIL",
        "U_VIEWMODEL",
@@ -1028,7 +1047,6 @@ void CL_ParseBaseline (entity_t *ent, int large)
        ent->state_baseline.scale = 16;
        ent->state_baseline.glowsize = 0;
        ent->state_baseline.glowcolor = 254;
-       ent->state_baseline.colormod = 255;
        ent->state_previous = ent->state_current = ent->state_baseline;
 
        CL_ValidateState(&ent->state_baseline);
@@ -1141,7 +1159,6 @@ void CL_ParseStatic (int large)
        ent->render.alpha = 1;
        ent->render.scale = 1;
        ent->render.alpha = 1;
-       ent->render.colormod[0] = ent->render.colormod[1] = ent->render.colormod[2] = 1;
 
        VectorCopy (ent->state_baseline.origin, ent->render.origin);
        VectorCopy (ent->state_baseline.angles, ent->render.angles);    
@@ -1197,7 +1214,7 @@ void CL_ParseEffect2 (void)
 }
 
 
-#define SHOWNET(x) if(cl_shownet.value==2)Con_Printf ("%3i:%s\n", msg_readcount-1, x);
+#define SHOWNET(x) if(cl_shownet.integer==2)Con_Printf ("%3i:%s\n", msg_readcount-1, x);
 
 /*
 =====================
@@ -1215,9 +1232,9 @@ void CL_ParseServerMessage (void)
 //
 // if recording demos, copy the message out
 //
-       if (cl_shownet.value == 1)
+       if (cl_shownet.integer == 1)
                Con_Printf ("%i ",net_message.cursize);
-       else if (cl_shownet.value == 2)
+       else if (cl_shownet.integer == 2)
                Con_Printf ("------------------\n");
        
        cl.onground = false;    // unless the server says otherwise     
@@ -1303,7 +1320,7 @@ void CL_ParseServerMessage (void)
                        cl.mtime[1] = cl.mtime[0];
                        cl.mtime[0] = MSG_ReadFloat ();                 
                        break;
-                       
+
                case svc_clientdata:
                        i = MSG_ReadShort ();
                        CL_ParseClientdata (i);
@@ -1316,7 +1333,7 @@ void CL_ParseServerMessage (void)
                        Nehahrademcompatibility = false;
                        if (i == 250)
                                Nehahrademcompatibility = true;
-                       if (cls.demoplayback && demo_nehahra.value)
+                       if (cls.demoplayback && demo_nehahra.integer)
                                Nehahrademcompatibility = true;
                        dpprotocol = i == DPPROTOCOL_VERSION;
                        break;
@@ -1335,11 +1352,11 @@ void CL_ParseServerMessage (void)
                case svc_stufftext:
                        Cbuf_AddText (MSG_ReadString ());
                        break;
-                       
+
                case svc_damage:
                        V_ParseDamage ();
                        break;
-                       
+
                case svc_serverinfo:
                        CL_ParseServerInfo ();
 //                     vid.recalc_refdef = true;       // leave intermission full screen
@@ -1375,7 +1392,7 @@ void CL_ParseServerMessage (void)
                        i = MSG_ReadShort();
                        S_StopSound(i>>3, i&7);
                        break;
-               
+
                case svc_updatename:
                        i = MSG_ReadByte ();
                        if (i >= cl.maxclients)
@@ -1398,7 +1415,7 @@ void CL_ParseServerMessage (void)
                        break;
                        
                case svc_particle:
-                       R_ParseParticleEffect ();
+                       CL_ParseParticleEffect ();
                        break;
 
                case svc_effect:
@@ -1487,7 +1504,7 @@ void CL_ParseServerMessage (void)
                        cl.intermission = 2;
                        cl.completed_time = cl.time;
 //                     vid.recalc_refdef = true;       // go to full screen
-                       SCR_CenterPrint (MSG_ReadString ());                    
+                       SCR_CenterPrint (MSG_ReadString ());
                        break;
 
                case svc_cutscene:
diff --git a/cl_particles.c b/cl_particles.c
new file mode 100644 (file)
index 0000000..12fe619
--- /dev/null
@@ -0,0 +1,1181 @@
+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+#include "quakedef.h"
+
+#define MAX_PARTICLES                  16384   // default max # of particles at one time
+#define ABSOLUTE_MIN_PARTICLES 512             // no fewer than this no matter what's on the command line
+
+typedef enum
+{
+       pt_static, pt_grav, pt_blob, pt_blob2, pt_bulletsmoke, pt_smoke, pt_snow, pt_rain, pt_spark, pt_bubble, pt_fade, pt_steam, pt_splash, pt_splashpuff, pt_flame, pt_blood, pt_oneframe, pt_lavasplash, pt_raindropsplash, pt_underwaterspark, pt_explosionsplash
+}
+ptype_t;
+
+typedef struct particle_s
+{
+       ptype_t         type;
+       vec3_t          org;
+       vec3_t          vel;
+       int                     tex;
+       float           die;
+       float           scale;
+       float           alpha; // 0-255
+       float           time2; // used for various things (snow fluttering, for example)
+       float           bounce; // how much bounce-back from a surface the particle hits (0 = no physics, 1 = stop and slide, 2 = keep bouncing forever, 1.5 is typical)
+       vec3_t          oldorg;
+       vec3_t          vel2; // used for snow fluttering (base velocity, wind for instance)
+       float           friction; // how much air friction affects this object (objects with a low mass/size ratio tend to get more air friction)
+       float           pressure; // if non-zero, apply pressure to other particles
+       int                     dynlight; // if set the particle will be dynamically lit (if cl_dynamicparticles is on), used for smoke and blood
+       byte            color[4];
+}
+particle_t;
+
+static int particlepalette[256] =
+{
+       0x000000,0x0f0f0f,0x1f1f1f,0x2f2f2f,0x3f3f3f,0x4b4b4b,0x5b5b5b,0x6b6b6b,
+       0x7b7b7b,0x8b8b8b,0x9b9b9b,0xababab,0xbbbbbb,0xcbcbcb,0xdbdbdb,0xebebeb,
+       0x0f0b07,0x170f0b,0x1f170b,0x271b0f,0x2f2313,0x372b17,0x3f2f17,0x4b371b,
+       0x533b1b,0x5b431f,0x634b1f,0x6b531f,0x73571f,0x7b5f23,0x836723,0x8f6f23,
+       0x0b0b0f,0x13131b,0x1b1b27,0x272733,0x2f2f3f,0x37374b,0x3f3f57,0x474767,
+       0x4f4f73,0x5b5b7f,0x63638b,0x6b6b97,0x7373a3,0x7b7baf,0x8383bb,0x8b8bcb,
+       0x000000,0x070700,0x0b0b00,0x131300,0x1b1b00,0x232300,0x2b2b07,0x2f2f07,
+       0x373707,0x3f3f07,0x474707,0x4b4b0b,0x53530b,0x5b5b0b,0x63630b,0x6b6b0f,
+       0x070000,0x0f0000,0x170000,0x1f0000,0x270000,0x2f0000,0x370000,0x3f0000,
+       0x470000,0x4f0000,0x570000,0x5f0000,0x670000,0x6f0000,0x770000,0x7f0000,
+       0x131300,0x1b1b00,0x232300,0x2f2b00,0x372f00,0x433700,0x4b3b07,0x574307,
+       0x5f4707,0x6b4b0b,0x77530f,0x835713,0x8b5b13,0x975f1b,0xa3631f,0xaf6723,
+       0x231307,0x2f170b,0x3b1f0f,0x4b2313,0x572b17,0x632f1f,0x733723,0x7f3b2b,
+       0x8f4333,0x9f4f33,0xaf632f,0xbf772f,0xcf8f2b,0xdfab27,0xefcb1f,0xfff31b,
+       0x0b0700,0x1b1300,0x2b230f,0x372b13,0x47331b,0x533723,0x633f2b,0x6f4733,
+       0x7f533f,0x8b5f47,0x9b6b53,0xa77b5f,0xb7876b,0xc3937b,0xd3a38b,0xe3b397,
+       0xab8ba3,0x9f7f97,0x937387,0x8b677b,0x7f5b6f,0x775363,0x6b4b57,0x5f3f4b,
+       0x573743,0x4b2f37,0x43272f,0x371f23,0x2b171b,0x231313,0x170b0b,0x0f0707,
+       0xbb739f,0xaf6b8f,0xa35f83,0x975777,0x8b4f6b,0x7f4b5f,0x734353,0x6b3b4b,
+       0x5f333f,0x532b37,0x47232b,0x3b1f23,0x2f171b,0x231313,0x170b0b,0x0f0707,
+       0xdbc3bb,0xcbb3a7,0xbfa39b,0xaf978b,0xa3877b,0x977b6f,0x876f5f,0x7b6353,
+       0x6b5747,0x5f4b3b,0x533f33,0x433327,0x372b1f,0x271f17,0x1b130f,0x0f0b07,
+       0x6f837b,0x677b6f,0x5f7367,0x576b5f,0x4f6357,0x475b4f,0x3f5347,0x374b3f,
+       0x2f4337,0x2b3b2f,0x233327,0x1f2b1f,0x172317,0x0f1b13,0x0b130b,0x070b07,
+       0xfff31b,0xefdf17,0xdbcb13,0xcbb70f,0xbba70f,0xab970b,0x9b8307,0x8b7307,
+       0x7b6307,0x6b5300,0x5b4700,0x4b3700,0x3b2b00,0x2b1f00,0x1b0f00,0x0b0700,
+       0x0000ff,0x0b0bef,0x1313df,0x1b1bcf,0x2323bf,0x2b2baf,0x2f2f9f,0x2f2f8f,
+       0x2f2f7f,0x2f2f6f,0x2f2f5f,0x2b2b4f,0x23233f,0x1b1b2f,0x13131f,0x0b0b0f,
+       0x2b0000,0x3b0000,0x4b0700,0x5f0700,0x6f0f00,0x7f1707,0x931f07,0xa3270b,
+       0xb7330f,0xc34b1b,0xcf632b,0xdb7f3b,0xe3974f,0xe7ab5f,0xefbf77,0xf7d38b,
+       0xa77b3b,0xb79b37,0xc7c337,0xe7e357,0x7fbfff,0xabe7ff,0xd7ffff,0x670000,
+       0x8b0000,0xb30000,0xd70000,0xff0000,0xfff393,0xfff7c7,0xffffff,0x9f5b53
+};
+
+static int explosparkramp[8] = {0x4b0700, 0x6f0f00, 0x931f07, 0xb7330f, 0xcf632b, 0xe3974f, 0xffe7b5, 0xffffff};
+//static int explounderwatersparkramp[8] = {0x00074b, 0x000f6f, 0x071f93, 0x0f33b7, 0x2b63cf, 0x4f97e3, 0xb5e7ff, 0xffffff};
+
+// these must match r_part.c's textures
+static const int tex_smoke[8] = {0, 1, 2, 3, 4, 5, 6, 7};
+static const int tex_bullethole[8] = {8, 9, 10, 11, 12, 13, 14, 15};
+static const int tex_rainsplash[16] = {16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
+static const int tex_particle = 32;
+static const int tex_rain = 33;
+static const int tex_bubble = 34;
+static const int tex_rocketglow = 35;
+
+static int                     cl_maxparticles;
+static int                     cl_numparticles;
+static particle_t      *particles;
+static particle_t      **freeparticles; // list used only in compacting particles array
+static renderparticle_t        *cl_renderparticles;
+
+static cvar_t cl_particles = {CVAR_SAVE, "cl_particles", "1"};
+static cvar_t cl_particles_size = {CVAR_SAVE, "cl_particles_size", "1"};
+static cvar_t cl_particles_bloodshowers = {CVAR_SAVE, "cl_particles_bloodshowers", "1"};
+static cvar_t cl_particles_blood = {CVAR_SAVE, "cl_particles_blood", "1"};
+static cvar_t cl_particles_smoke = {CVAR_SAVE, "cl_particles_smoke", "1"};
+static cvar_t cl_particles_sparks = {CVAR_SAVE, "cl_particles_sparks", "1"};
+static cvar_t cl_particles_bubbles = {CVAR_SAVE, "cl_particles_bubbles", "1"};
+static cvar_t cl_particles_explosions = {CVAR_SAVE, "cl_particles_explosions", "0"};
+
+static mempool_t *cl_part_mempool;
+
+void CL_Particles_Clear(void)
+{
+       cl_numparticles = 0;
+}
+
+/*
+===============
+CL_InitParticles
+===============
+*/
+void CL_ReadPointFile_f (void);
+void CL_Particles_Init (void)
+{
+       int             i;
+
+       i = COM_CheckParm ("-particles");
+
+       if (i)
+       {
+               cl_maxparticles = (int)(atoi(com_argv[i+1]));
+               if (cl_maxparticles < ABSOLUTE_MIN_PARTICLES)
+                       cl_maxparticles = ABSOLUTE_MIN_PARTICLES;
+       }
+       else
+               cl_maxparticles = MAX_PARTICLES;
+
+       Cmd_AddCommand ("pointfile", CL_ReadPointFile_f);
+
+       Cvar_RegisterVariable (&cl_particles);
+       Cvar_RegisterVariable (&cl_particles_size);
+       Cvar_RegisterVariable (&cl_particles_bloodshowers);
+       Cvar_RegisterVariable (&cl_particles_blood);
+       Cvar_RegisterVariable (&cl_particles_smoke);
+       Cvar_RegisterVariable (&cl_particles_sparks);
+       Cvar_RegisterVariable (&cl_particles_bubbles);
+       Cvar_RegisterVariable (&cl_particles_explosions);
+
+       cl_part_mempool = Mem_AllocPool("CL_Part");
+       particles = (particle_t *) Mem_Alloc(cl_part_mempool, cl_maxparticles * sizeof(particle_t));
+       freeparticles = (void *) Mem_Alloc(cl_part_mempool, cl_maxparticles * sizeof(particle_t *));
+       cl_numparticles = 0;
+
+       // FIXME: r_refdef stuff should be allocated somewhere else?
+       r_refdef.particles = cl_renderparticles = Mem_Alloc(cl_part_mempool, cl_maxparticles * sizeof(renderparticle_t));
+}
+
+#define particle(ptype, pcolor, ptex, plight, pscale, palpha, ptime, pbounce, px, py, pz, pvx, pvy, pvz, ptime2, pvx2, pvy2, pvz2, pfriction, ppressure)\
+{\
+       particle_t      *part;\
+       int tempcolor;\
+       if (cl_numparticles >= cl_maxparticles)\
+               return;\
+       part = &particles[cl_numparticles++];\
+       part->type = (ptype);\
+       tempcolor = (pcolor);\
+       part->color[0] = ((tempcolor) >> 16) & 0xFF;\
+       part->color[1] = ((tempcolor) >> 8) & 0xFF;\
+       part->color[2] = (tempcolor) & 0xFF;\
+       part->color[3] = 0xFF;\
+       part->tex = (ptex);\
+       part->dynlight = (plight);\
+       part->scale = (pscale);\
+       part->alpha = (palpha);\
+       part->die = cl.time + (ptime);\
+       part->bounce = (pbounce);\
+       part->org[0] = (px);\
+       part->org[1] = (py);\
+       part->org[2] = (pz);\
+       part->vel[0] = (pvx);\
+       part->vel[1] = (pvy);\
+       part->vel[2] = (pvz);\
+       part->time2 = (ptime2);\
+       part->vel2[0] = (pvx2);\
+       part->vel2[1] = (pvy2);\
+       part->vel2[2] = (pvz2);\
+       part->friction = (pfriction);\
+       part->pressure = (ppressure);\
+}
+
+/*
+===============
+CL_EntityParticles
+===============
+*/
+void CL_EntityParticles (entity_t *ent)
+{
+       int                     i;
+       float           angle;
+       float           sp, sy, cp, cy;
+       vec3_t          forward;
+       float           dist;
+       float           beamlength;
+       static vec3_t avelocities[NUMVERTEXNORMALS];
+       if (!cl_particles.integer) return;
+
+       dist = 64;
+       beamlength = 16;
+
+       if (!avelocities[0][0])
+               for (i=0 ; i<NUMVERTEXNORMALS*3 ; i++)
+                       avelocities[0][i] = (rand()&255) * 0.01;
+
+       for (i=0 ; i<NUMVERTEXNORMALS ; i++)
+       {
+               angle = cl.time * avelocities[i][0];
+               sy = sin(angle);
+               cy = cos(angle);
+               angle = cl.time * avelocities[i][1];
+               sp = sin(angle);
+               cp = cos(angle);
+
+               forward[0] = cp*cy;
+               forward[1] = cp*sy;
+               forward[2] = -sp;
+
+               particle(pt_oneframe, particlepalette[0x6f], tex_particle, false, 2, 255, 9999, 0, ent->render.origin[0] + m_bytenormals[i][0]*dist + forward[0]*beamlength, ent->render.origin[1] + m_bytenormals[i][1]*dist + forward[1]*beamlength, ent->render.origin[2] + m_bytenormals[i][2]*dist + forward[2]*beamlength, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+       }
+}
+
+
+void CL_ReadPointFile_f (void)
+{
+       vec3_t  org;
+       int             r, c;
+       char    *pointfile, *pointfilepos, *t, tchar;
+
+       pointfile = COM_LoadFile(va("maps/%s.pts", sv.name), true);
+       if (!pointfile)
+       {
+               Con_Printf ("couldn't open %s.pts\n", sv.name);
+               return;
+       }
+
+       Con_Printf ("Reading %s.pts...\n", sv.name);
+       c = 0;
+       pointfilepos = pointfile;
+       while (*pointfilepos)
+       {
+               while (*pointfilepos == '\n' || *pointfilepos == '\r')
+                       pointfilepos++;
+               if (!*pointfilepos)
+                       break;
+               t = pointfilepos;
+               while (*t && *t != '\n' && *t != '\r')
+                       t++;
+               tchar = *t;
+               *t = 0;
+               r = sscanf (pointfilepos,"%f %f %f", &org[0], &org[1], &org[2]);
+               *t = tchar;
+               pointfilepos = t;
+               if (r != 3)
+                       break;
+               c++;
+
+               if (cl_numparticles >= cl_maxparticles)
+               {
+                       Con_Printf ("Not enough free particles\n");
+                       break;
+               }
+               particle(pt_static, particlepalette[(-c)&15], tex_particle, false, 2, 255, 99999, 0, org[0], org[1], org[2], 0, 0, 0, 0, 0, 0, 0, 0, 0);
+       }
+
+       Mem_Free(pointfile);
+       Con_Printf ("%i points read\n", c);
+}
+
+/*
+===============
+CL_ParseParticleEffect
+
+Parse an effect out of the server message
+===============
+*/
+void CL_ParseParticleEffect (void)
+{
+       vec3_t          org, dir;
+       int                     i, count, msgcount, color;
+
+       for (i=0 ; i<3 ; i++)
+               org[i] = MSG_ReadCoord ();
+       for (i=0 ; i<3 ; i++)
+               dir[i] = MSG_ReadChar () * (1.0/16);
+       msgcount = MSG_ReadByte ();
+       color = MSG_ReadByte ();
+
+       if (msgcount == 255)
+               count = 1024;
+       else
+               count = msgcount;
+
+       CL_RunParticleEffect (org, dir, color, count);
+}
+
+/*
+===============
+CL_ParticleExplosion
+
+===============
+*/
+void CL_ParticleExplosion (vec3_t org, int smoke)
+{
+       int i, j;
+       float f;
+       vec3_t v, end, ang;
+       byte noise1[32*32], noise2[32*32];
+
+       if (cl_particles.integer && cl_particles_explosions.integer)
+       {
+               i = Mod_PointInLeaf(org, cl.worldmodel)->contents;
+               if (i == CONTENTS_SLIME || i == CONTENTS_WATER)
+               {
+                       for (i = 0;i < 128;i++)
+                               particle(pt_bubble, 0xFFFFFF, tex_bubble, false, lhrandom(1, 2), 255, 9999, 1.5, org[0] + lhrandom(-16, 16), org[1] + lhrandom(-16, 16), org[2] + lhrandom(-16, 16), lhrandom(-96, 96), lhrandom(-96, 96), lhrandom(-96, 96), 0, 0, 0, 0, 0, 0);
+
+                       ang[2] = lhrandom(0, 360);
+                       fractalnoise(noise1, 32, 4);
+                       fractalnoise(noise2, 32, 8);
+                       for (i = 0;i < 32;i++)
+                       {
+                               for (j = 0;j < 32;j++)
+                               {
+                                       VectorRandom(v);
+                                       VectorMA(org, 16, v, v);
+                                       TraceLine(org, v, end, NULL, 0);
+                                       ang[0] = (j + 0.5f) * (360.0f / 32.0f);
+                                       ang[1] = (i + 0.5f) * (360.0f / 32.0f);
+                                       AngleVectors(ang, v, NULL, NULL);
+                                       f = noise1[j*32+i] * 1.5f;
+                                       VectorScale(v, f, v);
+                                       particle(pt_underwaterspark, noise2[j*32+i] * 0x010101, tex_smoke[rand()&7], false, 10, lhrandom(128, 255), 9999, 1.5, end[0], end[1], end[2], v[0], v[1], v[2], 512.0f, 0, 0, 0, 2, 0);
+                                       VectorScale(v, 0.75, v);
+                                       particle(pt_underwaterspark, explosparkramp[(noise2[j*32+i] >> 5)], tex_particle, false, 10, lhrandom(128, 255), 9999, 1.5, end[0], end[1], end[2], v[0], v[1], v[2], 512.0f, 0, 0, 0, 2, 0);
+                               }
+                       }
+               }
+               else
+               {
+                       ang[2] = lhrandom(0, 360);
+                       fractalnoise(noise1, 32, 4);
+                       fractalnoise(noise2, 32, 8);
+                       for (i = 0;i < 32;i++)
+                       {
+                               for (j = 0;j < 32;j++)
+                               {
+                                       VectorRandom(v);
+                                       VectorMA(org, 16, v, v);
+                                       TraceLine(org, v, end, NULL, 0);
+                                       ang[0] = (j + 0.5f) * (360.0f / 32.0f);
+                                       ang[1] = (i + 0.5f) * (360.0f / 32.0f);
+                                       AngleVectors(ang, v, NULL, NULL);
+                                       f = noise1[j*32+i] * 1.5f;
+                                       VectorScale(v, f, v);
+                                       particle(pt_spark, noise2[j*32+i] * 0x010101, tex_smoke[random()&7], false, 10, lhrandom(128, 255), 9999, 1.5, end[0], end[1], end[2], v[0], v[1], v[2] + 160.0f, 512.0f, 0, 0, 0, 2, 0);
+                                       VectorScale(v, 0.75, v);
+                                       particle(pt_spark, explosparkramp[(noise2[j*32+i] >> 5)], tex_particle, false, 10, lhrandom(128, 255), 9999, 1.5, end[0], end[1], end[2], v[0], v[1], v[2] + 160.0f, 512.0f, 0, 0, 0, 2, 0);
+                               //      VectorRandom(v);
+                               //      VectorScale(v, 384, v);
+                               //      particle(pt_spark, explosparkramp[rand()&7], tex_particle, false, 2, lhrandom(16, 255), 9999, 1.5, end[0], end[1], end[2], v[0], v[1], v[2] + 160.0f, 512.0f, 0, 0, 0, 2, 0);
+                               }
+                       }
+               }
+       }
+       else
+       {
+               R_NewExplosion(org);
+
+               for (i = 0;i < 256;i++)
+               {
+                       VectorRandom(v);
+                       particle(pt_spark, explosparkramp[rand()&7], tex_particle, false, 2, lhrandom(16, 255), 9999, 1.5, end[0], end[1], end[2], v[0] * 384.0f, v[1] * 384.0f, v[2] * 384.0f + 160.0f, 512.0f, 0, 0, 0, 2, 0);
+               }
+       }
+}
+
+/*
+===============
+CL_ParticleExplosion2
+
+===============
+*/
+void CL_ParticleExplosion2 (vec3_t org, int colorStart, int colorLength)
+{
+       int                     i;
+       if (!cl_particles.integer) return;
+
+       for (i = 0;i < 512;i++)
+               particle(pt_fade, particlepalette[colorStart + (i % colorLength)], tex_particle, false, 1.5, 255, 0.3, 0, org[0] + lhrandom(-8, 8), org[1] + lhrandom(-8, 8), org[2] + lhrandom(-8, 8), lhrandom(-192, 192), lhrandom(-192, 192), lhrandom(-192, 192), 0, 0, 0, 0, 0.1f, 0);
+}
+
+/*
+===============
+CL_BlobExplosion
+
+===============
+*/
+void CL_BlobExplosion (vec3_t org)
+{
+       int                     i;
+       if (!cl_particles.integer) return;
+
+       for (i = 0;i < 256;i++)
+               particle(pt_blob , particlepalette[ 66+(rand()%6)], tex_particle, false, 4, 255, 9999, 0, org[0] + lhrandom(-16, 16), org[1] + lhrandom(-16, 16), org[2] + lhrandom(-16, 16), lhrandom(-4, 4), lhrandom(-4, 4), lhrandom(-128, 128), 0, 0, 0, 0, 0, 0);
+       for (i = 0;i < 256;i++)
+               particle(pt_blob2, particlepalette[150+(rand()%6)], tex_particle, false, 4, 255, 9999, 0, org[0] + lhrandom(-16, 16), org[1] + lhrandom(-16, 16), org[2] + lhrandom(-16, 16), lhrandom(-4, 4), lhrandom(-4, 4), lhrandom(-128, 128), 0, 0, 0, 0, 0, 0);
+}
+
+/*
+===============
+CL_RunParticleEffect
+
+===============
+*/
+void CL_RunParticleEffect (vec3_t org, vec3_t dir, int color, int count)
+{
+       if (!cl_particles.integer) return;
+
+       if (count == 1024)
+       {
+               CL_ParticleExplosion(org, false);
+               return;
+       }
+       while (count--)
+               particle(pt_fade, particlepalette[color + (rand()&7)], tex_particle, false, 1, 128, 9999, 0, org[0] + lhrandom(-8, 8), org[1] + lhrandom(-8, 8), org[2] + lhrandom(-8, 8), lhrandom(-15, 15), lhrandom(-15, 15), lhrandom(-15, 15), 0, 0, 0, 0, 0, 0);
+}
+
+// LordHavoc: added this for spawning sparks/dust (which have strong gravity)
+/*
+===============
+CL_SparkShower
+===============
+*/
+void CL_SparkShower (vec3_t org, vec3_t dir, int count)
+{
+       if (!cl_particles.integer) return;
+
+       CL_Decal(org, tex_bullethole[rand()&7], 16 * cl_particles_size.value, 0, 0, 0, 1);
+
+       // smoke puff
+       if (cl_particles_smoke.integer)
+               particle(pt_bulletsmoke, 0xA0A0A0, tex_smoke[rand()&7], true, 5, 255, 9999, 0, org[0], org[1], org[2], lhrandom(-8, 8), lhrandom(-8, 8), lhrandom(0, 16), 0, 0, 0, 0, 0, 0);
+
+       if (cl_particles_sparks.integer)
+       {
+               // sparks
+               while(count--)
+                       particle(pt_spark, particlepalette[0x68 + (rand() & 7)], tex_particle, false, 1, lhrandom(0, 255), 9999, 1.5, org[0], org[1], org[2], lhrandom(-64, 64), lhrandom(-64, 64), lhrandom(0, 128), 512.0f, 0, 0, 0, 0.2f, 0);
+       }
+}
+
+void CL_BloodPuff (vec3_t org, vec3_t vel, int count)
+{
+       // bloodcount is used to accumulate counts too small to cause a blood particle
+       static int bloodcount = 0;
+       if (!cl_particles.integer) return;
+       if (!cl_particles_blood.integer) return;
+
+       if (count > 100)
+               count = 100;
+       bloodcount += count;
+       while(bloodcount >= 10)
+       {
+               particle(pt_blood, 0x300000, tex_smoke[rand()&7], true, 24, 255, 9999, -1, org[0], org[1], org[2], vel[0] + lhrandom(-64, 64), vel[1] + lhrandom(-64, 64), vel[2] + lhrandom(-64, 64), 0, 0, 0, 0, 1.0f, 0);
+               bloodcount -= 10;
+       }
+}
+
+void CL_BloodShower (vec3_t mins, vec3_t maxs, float velspeed, int count)
+{
+       vec3_t diff, center, velscale;
+       if (!cl_particles.integer) return;
+       if (!cl_particles_bloodshowers.integer) return;
+       if (!cl_particles_blood.integer) return;
+
+       VectorSubtract(maxs, mins, diff);
+       center[0] = (mins[0] + maxs[0]) * 0.5;
+       center[1] = (mins[1] + maxs[1]) * 0.5;
+       center[2] = (mins[2] + maxs[2]) * 0.5;
+       // FIXME: change velspeed back to 2.0x after fixing mod
+       velscale[0] = velspeed * 2.0 / diff[0];
+       velscale[1] = velspeed * 2.0 / diff[1];
+       velscale[2] = velspeed * 2.0 / diff[2];
+
+       while (count--)
+       {
+               vec3_t org, vel;
+               org[0] = lhrandom(mins[0], maxs[0]);
+               org[1] = lhrandom(mins[1], maxs[1]);
+               org[2] = lhrandom(mins[2], maxs[2]);
+               vel[0] = (org[0] - center[0]) * velscale[0];
+               vel[1] = (org[1] - center[1]) * velscale[1];
+               vel[2] = (org[2] - center[2]) * velscale[2];
+               particle(pt_blood, 0x300000, tex_smoke[rand()&7], true, 24, 255, 9999, -1, org[0], org[1], org[2], vel[0], vel[1], vel[2], 0, 0, 0, 0, 1.0f, 0);
+       }
+}
+
+void CL_ParticleCube (vec3_t mins, vec3_t maxs, vec3_t dir, int count, int colorbase, int gravity, int randomvel)
+{
+       float           t;
+       if (!cl_particles.integer) return;
+       if (maxs[0] <= mins[0]) {t = mins[0];mins[0] = maxs[0];maxs[0] = t;}
+       if (maxs[1] <= mins[1]) {t = mins[1];mins[1] = maxs[1];maxs[1] = t;}
+       if (maxs[2] <= mins[2]) {t = mins[2];mins[2] = maxs[2];maxs[2] = t;}
+
+       while (count--)
+               particle(gravity ? pt_grav : pt_static, particlepalette[colorbase + (rand()&3)], tex_particle, false, 2, 255, lhrandom(1, 2), 0, lhrandom(mins[0], maxs[0]), lhrandom(mins[1], maxs[1]), lhrandom(mins[2], maxs[2]), dir[0] + lhrandom(-randomvel, randomvel), dir[1] + lhrandom(-randomvel, randomvel), dir[2] + lhrandom(-randomvel, randomvel), 0, 0, 0, 0, 0, 0);
+}
+
+void CL_ParticleRain (vec3_t mins, vec3_t maxs, vec3_t dir, int count, int colorbase, int type)
+{
+       vec3_t          vel;
+       float           t, z;
+       if (!cl_particles.integer) return;
+       if (maxs[0] <= mins[0]) {t = mins[0];mins[0] = maxs[0];maxs[0] = t;}
+       if (maxs[1] <= mins[1]) {t = mins[1];mins[1] = maxs[1];maxs[1] = t;}
+       if (maxs[2] <= mins[2]) {t = mins[2];mins[2] = maxs[2];maxs[2] = t;}
+       if (dir[2] < 0) // falling
+       {
+               t = (maxs[2] - mins[2]) / -dir[2];
+               z = maxs[2];
+       }
+       else // rising??
+       {
+               t = (maxs[2] - mins[2]) / dir[2];
+               z = mins[2];
+       }
+       if (t < 0 || t > 2) // sanity check
+               t = 2;
+
+       switch(type)
+       {
+       case 0:
+               while(count--)
+               {
+                       vel[0] = dir[0] + lhrandom(-16, 16);
+                       vel[1] = dir[1] + lhrandom(-16, 16);
+                       vel[2] = dir[2] + lhrandom(-32, 32);
+                       particle(pt_rain, particlepalette[colorbase + (rand()&3)], tex_rain, true, 3, 255, t, 0, lhrandom(mins[0], maxs[0]), lhrandom(mins[1], maxs[1]), z, vel[0], vel[1], vel[2], 0, vel[0], vel[1], vel[2], 0, 0);
+               }
+               break;
+       case 1:
+               while(count--)
+               {
+                       vel[0] = dir[0] + lhrandom(-16, 16);
+                       vel[1] = dir[1] + lhrandom(-16, 16);
+                       vel[2] = dir[2] + lhrandom(-32, 32);
+                       particle(pt_snow, particlepalette[colorbase + (rand()&3)], tex_particle, false, 2, 255, t, 0, lhrandom(mins[0], maxs[0]), lhrandom(mins[1], maxs[1]), z, vel[0], vel[1], vel[2], 0, vel[0], vel[1], vel[2], 0, 0);
+               }
+               break;
+       default:
+               Host_Error("CL_ParticleRain: unknown type %i (0 = rain, 1 = snow)\n", type);
+       }
+}
+
+void CL_FlameCube (vec3_t mins, vec3_t maxs, int count)
+{
+       float           t;
+       if (!cl_particles.integer) return;
+       if (maxs[0] <= mins[0]) {t = mins[0];mins[0] = maxs[0];maxs[0] = t;}
+       if (maxs[1] <= mins[1]) {t = mins[1];mins[1] = maxs[1];maxs[1] = t;}
+       if (maxs[2] <= mins[2]) {t = mins[2];mins[2] = maxs[2];maxs[2] = t;}
+
+       while (count--)
+               particle(pt_flame, particlepalette[224 + (rand()&15)], tex_particle, false, 8, 255, 9999, 1.1, lhrandom(mins[0], maxs[0]), lhrandom(mins[1], maxs[1]), lhrandom(mins[2], maxs[2]), lhrandom(-32, 32), lhrandom(-32, 32), lhrandom(-32, 64), 0, 0, 0, 0, 0.1f, 0);
+}
+
+void CL_Flames (vec3_t org, vec3_t vel, int count)
+{
+       if (!cl_particles.integer) return;
+
+       while (count--)
+               particle(pt_flame, particlepalette[224 + (rand()&15)], tex_particle, false, 8, 255, 9999, 1.1, org[0], org[1], org[2], vel[0] + lhrandom(-128, 128), vel[1] + lhrandom(-128, 128), vel[2] + lhrandom(-128, 128), 0, 0, 0, 0, 0.1f, 0);
+}
+
+
+
+/*
+===============
+CL_LavaSplash
+
+===============
+*/
+void CL_LavaSplash (vec3_t origin)
+{
+       int                     i, j;
+       float           vel;
+       vec3_t          dir, org;
+       if (!cl_particles.integer) return;
+
+       for (i=-128 ; i<128 ; i+=16)
+       {
+               for (j=-128 ; j<128 ; j+=16)
+               {
+                       dir[0] = j + lhrandom(0, 8);
+                       dir[1] = i + lhrandom(0, 8);
+                       dir[2] = 256;
+                       org[0] = origin[0] + dir[0];
+                       org[1] = origin[1] + dir[1];
+                       org[2] = origin[2] + lhrandom(0, 64);
+                       vel = lhrandom(50, 120) / VectorLength(dir); // normalize and scale
+                       particle(pt_lavasplash, particlepalette[224 + (rand()&7)], tex_particle, false, 7, 255, 9999, 0, org[0], org[1], org[2], dir[0] * vel, dir[1] * vel, dir[2] * vel, 0, 0, 0, 0, 0, 0);
+               }
+       }
+}
+
+/*
+===============
+CL_TeleportSplash
+
+===============
+*/
+void CL_TeleportSplash (vec3_t org)
+{
+       int                     i, j, k;
+       if (!cl_particles.integer) return;
+
+       for (i=-16 ; i<16 ; i+=8)
+               for (j=-16 ; j<16 ; j+=8)
+                       for (k=-24 ; k<32 ; k+=8)
+                               particle(pt_fade, 0xFFFFFF, tex_particle, false, 1, lhrandom(64, 128), 9999, 0, org[0] + i + lhrandom(0, 8), org[1] + j + lhrandom(0, 8), org[2] + k + lhrandom(0, 8), i*2 + lhrandom(-12.5, 12.5), j*2 + lhrandom(-12.5, 12.5), k*2 + lhrandom(27.5, 52.5), 0, 0, 0, 0, 0.1f, -512.0f);
+}
+
+void CL_RocketTrail (vec3_t start, vec3_t end, int type, entity_t *ent)
+{
+       vec3_t          vec, dir, vel;
+       float           len, dec = 0, speed;
+       int                     contents, bubbles;
+       double          t;
+       if (!cl_particles.integer) return;
+
+       VectorSubtract(end, start, dir);
+       VectorNormalize(dir);
+
+       if (type == 0 && host_frametime != 0) // rocket glow
+               particle(pt_oneframe, 0xFFFFFF, tex_rocketglow, false, 24, 255, 9999, 0, end[0] - 12 * dir[0], end[1] - 12 * dir[1], end[2] - 12 * dir[2], 0, 0, 0, 0, 0, 0, 0, 0, 0);
+
+       t = ent->persistent.trail_time;
+       if (t >= cl.time)
+               return; // no particles to spawn this frame (sparse trail)
+
+       if (t < cl.oldtime)
+               t = cl.oldtime;
+
+       VectorSubtract (end, start, vec);
+       len = VectorNormalizeLength (vec);
+       if (len <= 0.01f)
+       {
+               // advance the trail time
+               ent->persistent.trail_time = cl.time;
+               return;
+       }
+       speed = len / (cl.time - cl.oldtime);
+       VectorScale(vec, speed, vel);
+
+       // advance into this frame to reach the first puff location
+       dec = t - cl.oldtime;
+       dec *= speed;
+       VectorMA(start, dec, vec, start);
+
+       contents = Mod_PointInLeaf(start, cl.worldmodel)->contents;
+       if (contents == CONTENTS_SKY || contents == CONTENTS_LAVA)
+       {
+               // advance the trail time
+               ent->persistent.trail_time = cl.time;
+               return;
+       }
+
+       bubbles = (contents == CONTENTS_WATER || contents == CONTENTS_SLIME);
+
+       while (t < cl.time)
+       {
+               switch (type)
+               {
+                       case 0: // rocket trail
+                               if (!cl_particles_smoke.integer)
+                                       dec = cl.time - t;
+                               else if (bubbles && cl_particles_bubbles.integer)
+                               {
+                                       dec = 0.005f;
+                                       particle(pt_bubble, 0xFFFFFF, tex_bubble, false, lhrandom(1, 2), 255, 9999, 1.5, start[0], start[1], start[2], lhrandom(-16, 16), lhrandom(-16, 16), lhrandom(-16, 16), 0, 0, 0, 0, 0, 0);
+                                       particle(pt_bubble, 0xFFFFFF, tex_bubble, false, lhrandom(1, 2), 255, 9999, 1.5, start[0], start[1], start[2], lhrandom(-16, 16), lhrandom(-16, 16), lhrandom(-16, 16), 0, 0, 0, 0, 0, 0);
+                                       particle(pt_smoke, 0xFFFFFF, tex_smoke[rand()&7], false, 2, 160, 9999, 0, start[0], start[1], start[2], 0, 0, 0, 0, 0, 0, 0, 0, 0);
+                               }
+                               else
+                               {
+                                       dec = 0.005f;
+                                       particle(pt_smoke, 0xC0C0C0, tex_smoke[rand()&7], true, 2, 160, 9999, 0, start[0], start[1], start[2], 0, 0, 0, 0, 0, 0, 0, 0, 0);
+                                       //particle(pt_spark, particlepalette[0x68 + (rand() & 7)], tex_particle, false, 1, lhrandom(128, 255), 9999, 1.5, start[0], start[1], start[2], lhrandom(-64, 64) - vel[0] * 0.0625, lhrandom(-64, 64) - vel[1] * 0.0625, lhrandom(-64, 64) - vel[2] * 0.0625, 512.0f, 0, 0, 0, 0.1f, 0);
+                                       //particle(pt_spark, particlepalette[0x68 + (rand() & 7)], tex_particle, false, 1, lhrandom(128, 255), 9999, 1.5, start[0], start[1], start[2], lhrandom(-64, 64) - vel[0] * 0.0625, lhrandom(-64, 64) - vel[1] * 0.0625, lhrandom(-64, 64) - vel[2] * 0.0625, 512.0f, 0, 0, 0, 0.1f, 0);
+                                       //particle(pt_spark, particlepalette[0x68 + (rand() & 7)], tex_particle, false, 1, lhrandom(128, 255), 9999, 1.5, start[0], start[1], start[2], lhrandom(-64, 64) - vel[0] * 0.0625, lhrandom(-64, 64) - vel[1] * 0.0625, lhrandom(-64, 64) - vel[2] * 0.0625, 512.0f, 0, 0, 0, 0.1f, 0);
+                                       //particle(pt_spark, particlepalette[0x68 + (rand() & 7)], tex_particle, false, 1, lhrandom(128, 255), 9999, 1.5, start[0], start[1], start[2], lhrandom(-64, 64) - vel[0] * 0.0625, lhrandom(-64, 64) - vel[1] * 0.0625, lhrandom(-64, 64) - vel[2] * 0.0625, 512.0f, 0, 0, 0, 0.1f, 0);
+                               }
+                               break;
+
+                       case 1: // grenade trail
+                               // FIXME: make it gradually stop smoking
+                               if (!cl_particles_smoke.integer)
+                                       dec = cl.time - t;
+                               else if (bubbles && cl_particles_bubbles.integer)
+                               {
+                                       dec = 0.02f;
+                                       particle(pt_bubble, 0xFFFFFF, tex_bubble, false, lhrandom(1, 2), 255, 9999, 1.5, start[0], start[1], start[2], lhrandom(-16, 16), lhrandom(-16, 16), lhrandom(-16, 16), 0, 0, 0, 0, 0, 0);
+                                       particle(pt_bubble, 0xFFFFFF, tex_bubble, false, lhrandom(1, 2), 255, 9999, 1.5, start[0], start[1], start[2], lhrandom(-16, 16), lhrandom(-16, 16), lhrandom(-16, 16), 0, 0, 0, 0, 0, 0);
+                                       particle(pt_smoke, 0xFFFFFF, tex_smoke[rand()&7], false, 2, 160, 9999, 0, start[0], start[1], start[2], 0, 0, 0, 0, 0, 0, 0, 0, 0);
+                               }
+                               else
+                               {
+                                       dec = 0.02f;
+                                       particle(pt_smoke, 0x808080, tex_smoke[rand()&7], true, 2, 160, 9999, 0, start[0], start[1], start[2], 0, 0, 0, 0, 0, 0, 0, 0, 0);
+                               }
+                               break;
+
+
+                       case 2: // blood
+                               if (!cl_particles_blood.integer)
+                                       dec = cl.time - t;
+                               else
+                               {
+                                       dec = 0.1f;
+                                       particle(pt_blood, 0x300000, tex_smoke[rand()&7], true, 24, 255, 9999, -1, start[0], start[1], start[2], vel[0] + lhrandom(-64, 64), vel[1] + lhrandom(-64, 64), vel[2] + lhrandom(-64, 64), 0, 0, 0, 0, 1.0f, 0);
+                               }
+                               break;
+
+                       case 4: // slight blood
+                               if (!cl_particles_blood.integer)
+                                       dec = cl.time - t;
+                               else
+                               {
+                                       dec = 0.15f;
+                                       particle(pt_blood, 0x300000, tex_smoke[rand()&7], true, 24, 255, 9999, -1, start[0], start[1], start[2], vel[0] + lhrandom(-64, 64), vel[1] + lhrandom(-64, 64), vel[2] + lhrandom(-64, 64), 0, 0, 0, 0, 1.0f, 0);
+                               }
+                               break;
+
+                       case 3: // green tracer
+                               dec = 0.02f;
+                               particle(pt_fade, 0x373707, tex_smoke[rand()&7], false, 4, 255, 9999, 0, start[0], start[1], start[2], 0, 0, 0, 0, 0, 0, 0, 0, 0);
+                               break;
+
+                       case 5: // flame tracer
+                               dec = 0.02f;
+                               particle(pt_fade, 0xCF632B, tex_smoke[rand()&7], false, 4, 255, 9999, 0, start[0], start[1], start[2], 0, 0, 0, 0, 0, 0, 0, 0, 0);
+                               break;
+
+                       case 6: // voor trail
+                               dec = 0.05f; // sparse trail
+                               particle(pt_fade, 0x47232B, tex_smoke[rand()&7], false, 4, 255, 9999, 0, start[0], start[1], start[2], 0, 0, 0, 0, 0, 0, 0, 0, 0);
+                               break;
+
+                       case 7: // Nehahra smoke tracer
+                               if (!cl_particles_smoke.integer)
+                                       dec = cl.time - t;
+                               else
+                               {
+                                       dec = 0.14f;
+                                       particle(pt_smoke, 0xC0C0C0, tex_smoke[rand()&7], true, 10, 64, 9999, 0, start[0], start[1], start[2], 0, 0, 0, 0, 0, 0, 0, 0, 0);
+                               }
+                               break;
+               }
+
+               // advance to next time and position
+               t += dec;
+               dec *= speed;
+               VectorMA (start, dec, vec, start);
+       }
+       ent->persistent.trail_time = t;
+}
+
+void CL_RocketTrail2 (vec3_t start, vec3_t end, int color, entity_t *ent)
+{
+       vec3_t          vec;
+       int                     len;
+       if (!cl_particles.integer) return;
+       if (!cl_particles_smoke.integer) return;
+
+       VectorSubtract (end, start, vec);
+       len = (int) (VectorNormalizeLength (vec) * (1.0f / 3.0f));
+       VectorScale(vec, 3, vec);
+       color = particlepalette[color];
+       while (len--)
+       {
+               particle(pt_smoke, color, tex_particle, false, 8, 192, 9999, 0, start[0], start[1], start[2], 0, 0, 0, 0, 0, 0, 0, 0, 0);
+               VectorAdd (start, vec, start);
+       }
+}
+
+
+/*
+===============
+CL_MoveParticles
+===============
+*/
+void CL_MoveParticles (void)
+{
+       particle_t *p;
+       renderparticle_t *r;
+       int i, activeparticles, maxparticle, j, a, b, pressureused = false;
+       float gravity, dvel, frametime, f, dist, normal[3], v[3], org[3], o[3];
+
+       // LordHavoc: early out condition
+       if (!cl_numparticles)
+               return;
+
+       frametime = cl.time - cl.oldtime;
+       if (!frametime)
+               return; // if absolutely still, don't update particles
+       gravity = frametime * sv_gravity.value;
+       dvel = 1+4*frametime;
+
+       activeparticles = 0;
+       maxparticle = -1;
+       j = 0;
+       for (i = 0, p = particles, r = r_refdef.particles;i < cl_numparticles;i++, p++)
+       {
+               if (p->die < cl.time)
+               {
+                       freeparticles[j++] = p;
+                       continue;
+               }
+
+               VectorCopy(p->org, p->oldorg);
+               VectorMA(p->org, frametime, p->vel, p->org);
+               if (p->friction)
+               {
+                       f = 1.0f - (p->friction * frametime);
+                       VectorScale(p->vel, f, p->vel);
+               }
+               VectorCopy(p->org, org);
+               if (p->bounce)
+               {
+                       if (TraceLine(p->oldorg, p->org, v, normal, 0) < 1)
+                       {
+                               VectorCopy(v, p->org);
+                               if (p->bounce < 0)
+                               {
+                                       CL_Decal(v, p->tex, p->scale * cl_particles_size.value, p->color[0] * (1.0f / 255.0f), p->color[1] * (1.0f / 255.0f), p->color[2] * (1.0f / 255.0f), p->alpha * (1.0f / 255.0f));
+                                       p->die = -1;
+                                       freeparticles[j++] = p;
+                                       continue;
+                               }
+                               else
+                               {
+                                       dist = DotProduct(p->vel, normal) * -p->bounce;
+                                       VectorMA(p->vel, dist, normal, p->vel);
+                                       if (DotProduct(p->vel, p->vel) < 0.03)
+                                               VectorClear(p->vel);
+                               }
+                       }
+               }
+
+               switch (p->type)
+               {
+               case pt_static:
+                       break;
+
+                       // LordHavoc: drop-through because of shared code
+               case pt_blob:
+                       p->vel[2] *= dvel;
+               case pt_blob2:
+                       p->vel[0] *= dvel;
+                       p->vel[1] *= dvel;
+                       p->alpha -= frametime * 256;
+                       if (p->alpha < 1)
+                               p->die = -1;
+                       break;
+
+               case pt_grav:
+                       p->vel[2] -= gravity;
+                       break;
+               case pt_lavasplash:
+                       p->vel[2] -= gravity * 0.05;
+                       p->alpha -= frametime * 192;
+                       if (p->alpha < 1)
+                               p->die = -1;
+                       break;
+               case pt_snow:
+                       if (cl.time > p->time2)
+                       {
+                               p->time2 = cl.time + (rand() & 3) * 0.1;
+                               p->vel[0] = (rand()&63)-32 + p->vel2[0];
+                               p->vel[1] = (rand()&63)-32 + p->vel2[1];
+                               p->vel[2] = (rand()&63)-32 + p->vel2[2];
+                       }
+                       a = Mod_PointInLeaf(p->org, cl.worldmodel)->contents;
+                       if (a != CONTENTS_EMPTY && a != CONTENTS_SKY)
+                       {
+                               vec3_t normal;
+                               if (a == CONTENTS_SOLID && Mod_PointInLeaf(p->oldorg, cl.worldmodel)->contents == CONTENTS_SOLID)
+                                       break; // still in solid
+                               p->die = cl.time + 1000;
+                               p->vel[0] = p->vel[1] = p->vel[2] = 0;
+                               switch (a)
+                               {
+                               case CONTENTS_LAVA:
+                               case CONTENTS_SLIME:
+                                       p->tex = tex_smoke[rand()&7];
+                                       p->type = pt_steam;
+                                       p->alpha = 96;
+                                       p->scale = 5;
+                                       p->vel[2] = 96;
+                                       break;
+                               case CONTENTS_WATER:
+                                       p->tex = tex_smoke[rand()&7];
+                                       p->type = pt_splash;
+                                       p->alpha = 96;
+                                       p->scale = 5;
+                                       p->vel[2] = 96;
+                                       break;
+                               default: // CONTENTS_SOLID and any others
+                                       TraceLine(p->oldorg, p->org, v, normal, 0);
+                                       VectorCopy(v, p->org);
+                                       p->tex = tex_smoke[rand()&7];
+                                       p->type = pt_fade;
+                                       VectorClear(p->vel);
+                                       break;
+                               }
+                       }
+                       break;
+               case pt_blood:
+                       p->friction = 1;
+                       a = Mod_PointInLeaf(p->org, cl.worldmodel)->contents;
+                       if (a != CONTENTS_EMPTY)
+                       {
+                               if (a == CONTENTS_WATER || a == CONTENTS_SLIME)
+                               {
+                                       p->friction = 5;
+                                       p->scale += frametime * 32.0f;
+                                       p->alpha -= frametime * 128.0f;
+                                       p->vel[2] += gravity * 0.125f;
+                                       if (p->alpha < 1)
+                                               p->die = -1;
+                                       break;
+                               }
+                               else
+                               {
+                                       p->die = -1;
+                                       break;
+                               }
+                       }
+                       p->vel[2] -= gravity * 0.5;
+                       break;
+               case pt_spark:
+                       p->alpha -= frametime * p->time2;
+                       p->vel[2] -= gravity;
+                       if (p->alpha < 1)
+                               p->die = -1;
+                       else if (Mod_PointInLeaf(p->org, cl.worldmodel)->contents != CONTENTS_EMPTY)
+                               p->type = pt_underwaterspark;
+                       break;
+               case pt_underwaterspark:
+                       if (Mod_PointInLeaf(p->org, cl.worldmodel)->contents == CONTENTS_EMPTY)
+                       {
+                               p->tex = tex_smoke[rand()&7];
+                               p->color[0] = p->color[1] = p->color[2] = 255;
+                               p->scale = 16;
+                               p->type = pt_explosionsplash;
+                       }
+                       else
+                               p->vel[2] += gravity * 0.5f;
+                       p->alpha -= frametime * p->time2;
+                       if (p->alpha < 1)
+                               p->die = -1;
+                       break;
+               case pt_explosionsplash:
+                       if (Mod_PointInLeaf(p->org, cl.worldmodel)->contents == CONTENTS_EMPTY)
+                               p->vel[2] -= gravity;
+                       else
+                               p->alpha = 0;
+                       p->scale += frametime * 64.0f;
+                       p->alpha -= frametime * 1024.0f;
+                       if (p->alpha < 1)
+                               p->die = -1;
+                       break;
+               case pt_fade:
+                       p->alpha -= frametime * 512;
+                       if (p->alpha < 1)
+                               p->die = -1;
+                       break;
+               case pt_bubble:
+                       a = Mod_PointInLeaf(p->org, cl.worldmodel)->contents;
+                       if (a != CONTENTS_WATER && a != CONTENTS_SLIME)
+                       {
+                               p->tex = tex_smoke[rand()&7];
+                               p->type = pt_splashpuff;
+                               p->scale = 4;
+                               p->vel[0] = p->vel[1] = p->vel[2] = 0;
+                               break;
+                       }
+                       p->vel[2] += gravity * 0.25;
+                       p->vel[0] *= (1 - (frametime * 0.0625));
+                       p->vel[1] *= (1 - (frametime * 0.0625));
+                       p->vel[2] *= (1 - (frametime * 0.0625));
+                       if (cl.time > p->time2)
+                       {
+                               p->time2 = cl.time + lhrandom(0, 0.5);
+                               p->vel[0] += lhrandom(-32,32);
+                               p->vel[1] += lhrandom(-32,32);
+                               p->vel[2] += lhrandom(-32,32);
+                       }
+                       p->alpha -= frametime * 256;
+                       if (p->alpha < 1)
+                               p->die = -1;
+                       break;
+               case pt_bulletsmoke:
+                       p->scale += frametime * 16;
+                       p->alpha -= frametime * 1024;
+                       p->vel[2] += gravity * 0.1;
+                       if (p->alpha < 1)
+                               p->die = -1;
+                       break;
+               case pt_smoke:
+                       p->scale += frametime * 24;
+                       p->alpha -= frametime * 256;
+                       p->vel[2] += gravity * 0.1;
+                       if (p->alpha < 1)
+                               p->die = -1;
+                       break;
+               case pt_steam:
+                       p->scale += frametime * 48;
+                       p->alpha -= frametime * 512;
+                       p->vel[2] += gravity * 0.05;
+                       if (p->alpha < 1)
+                               p->die = -1;
+                       break;
+               case pt_splashpuff:
+                       p->alpha -= frametime * 1024;
+                       if (p->alpha < 1)
+                               p->die = -1;
+                       break;
+               case pt_rain:
+                       f = 0;
+                       b = Mod_PointInLeaf(p->oldorg, cl.worldmodel)->contents;
+                       VectorCopy(p->oldorg, o);
+                       while (f < 1)
+                       {
+                               a = b;
+                               f = TraceLine(o, p->org, v, normal, a);
+                               b = traceline_endcontents;
+                               if (f < 1 && b != CONTENTS_EMPTY && b != CONTENTS_SKY)
+                               {
+                                       p->die = cl.time + 1000;
+                                       p->vel[0] = p->vel[1] = p->vel[2] = 0;
+                                       VectorCopy(v, p->org);
+                                       switch (b)
+                                       {
+                                       case CONTENTS_LAVA:
+                                       case CONTENTS_SLIME:
+                                               p->tex = tex_smoke[rand()&7];
+                                               p->type = pt_steam;
+                                               p->scale = 3;
+                                               p->vel[2] = 96;
+                                               break;
+                                       default: // water, solid, and anything else
+                                               p->tex = tex_rainsplash[0];
+                                               p->time2 = 0;
+                                               VectorCopy(normal, p->vel2);
+                                       //      VectorAdd(p->org, normal, p->org);
+                                               p->type = pt_raindropsplash;
+                                               p->scale = 8;
+                                               break;
+                                       }
+                               }
+                       }
+                       break;
+               case pt_raindropsplash:
+                       p->time2 += frametime * 64.0f;
+                       if (p->time2 >= 16.0f)
+                       {
+                               p->die = -1;
+                               break;
+                       }
+                       p->tex = tex_rainsplash[(int) p->time2];
+                       break;
+               case pt_flame:
+                       p->alpha -= frametime * 512;
+                       p->vel[2] += gravity;
+                       if (p->alpha < 16)
+                               p->die = -1;
+                       break;
+               case pt_oneframe:
+                       if (p->time2)
+                               p->die = -1;
+                       p->time2 = 1;
+                       break;
+               default:
+                       printf("unknown particle type %i\n", p->type);
+                       p->die = -1;
+                       break;
+               }
+
+               // LordHavoc: immediate removal of unnecessary particles (must be done to ensure compactor below operates properly in all cases)
+               if (p->die < cl.time)
+                       freeparticles[j++] = p;
+               else
+               {
+                       maxparticle = i;
+                       activeparticles++;
+                       if (p->pressure)
+                               pressureused = true;
+
+                       // build renderparticle for renderer to use
+                       if (p->type == pt_raindropsplash)
+                       {
+                               r->orientation = PARTICLE_ORIENTED_DOUBLESIDED;
+                               r->dir[0] = p->vel2[0];
+                               r->dir[1] = p->vel2[1];
+                               r->dir[2] = p->vel2[2];
+                       }
+                       else if (p->tex == tex_rain)
+                               r->orientation = PARTICLE_UPRIGHT_FACING;
+                       else
+                               r->orientation = PARTICLE_BILLBOARD;
+                       r->org[0] = p->org[0];
+                       r->org[1] = p->org[1];
+                       r->org[2] = p->org[2];
+                       r->tex = p->tex;
+                       r->scale = p->scale * 0.5f * cl_particles_size.value;
+                       r->dynlight = p->dynlight;
+                       r->color[0] = p->color[0] * (1.0f / 255.0f);
+                       r->color[1] = p->color[1] * (1.0f / 255.0f);
+                       r->color[2] = p->color[2] * (1.0f / 255.0f);
+                       r->color[3] = p->alpha * (1.0f / 255.0f);
+                       r++;
+               }
+       }
+       r_refdef.numparticles = r - r_refdef.particles;
+       // fill in gaps to compact the array
+       i = 0;
+       while (maxparticle >= activeparticles)
+       {
+               *freeparticles[i++] = particles[maxparticle--];
+               while (maxparticle >= activeparticles && particles[maxparticle].die < cl.time)
+                       maxparticle--;
+       }
+       cl_numparticles = activeparticles;
+
+       if (pressureused)
+       {
+               activeparticles = 0;
+               for (i = 0, p = particles;i < cl_numparticles;i++, p++)
+                       if (p->pressure)
+                               freeparticles[activeparticles++] = p;
+
+               if (activeparticles)
+               {
+                       for (i = 0, p = particles;i < cl_numparticles;i++, p++)
+                       {
+                               for (j = 0;j < activeparticles;j++)
+                               {
+                                       if (freeparticles[j] != p)
+                                       {
+                                               float dist, diff[3];
+                                               VectorSubtract(p->org, freeparticles[j]->org, diff);
+                                               dist = DotProduct(diff, diff);
+                                               if (dist < 4096 && dist >= 1)
+                                               {
+                                                       dist = freeparticles[j]->scale * 4.0f * frametime / sqrt(dist);
+                                                       VectorMA(p->vel, dist, diff, p->vel);
+                                                       //dist = freeparticles[j]->scale * 4.0f * frametime / dist;
+                                                       //VectorMA(p->vel, dist, freeparticles[j]->vel, p->vel);
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+}
index d441a61ec59a65b2ddc92189c6caca1d00407f29..d38ee2705302e708f7902778d315d78642c44c3b 100644 (file)
--- a/cl_tent.c
+++ b/cl_tent.c
@@ -21,19 +21,24 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 #include "quakedef.h"
 
-cvar_t r_glowinglightning = {CVAR_SAVE, "r_glowinglightning", "1"};
+cvar_t cl_glowinglightning = {CVAR_SAVE, "cl_glowinglightning", "1"};
 
 int                    num_temp_entities;
 entity_t       cl_temp_entities[MAX_TEMP_ENTITIES];
 beam_t         cl_beams[MAX_BEAMS];
 
-sfx_t                  *cl_sfx_wizhit;
-sfx_t                  *cl_sfx_knighthit;
-sfx_t                  *cl_sfx_tink1;
-sfx_t                  *cl_sfx_ric1;
-sfx_t                  *cl_sfx_ric2;
-sfx_t                  *cl_sfx_ric3;
-sfx_t                  *cl_sfx_r_exp3;
+model_t                *cl_model_bolt = NULL;
+model_t                *cl_model_bolt2 = NULL;
+model_t                *cl_model_bolt3 = NULL;
+model_t                *cl_model_beam = NULL;
+
+sfx_t          *cl_sfx_wizhit;
+sfx_t          *cl_sfx_knighthit;
+sfx_t          *cl_sfx_tink1;
+sfx_t          *cl_sfx_ric1;
+sfx_t          *cl_sfx_ric2;
+sfx_t          *cl_sfx_ric3;
+sfx_t          *cl_sfx_r_exp3;
 
 /*
 =================
@@ -42,7 +47,7 @@ CL_ParseTEnt
 */
 void CL_InitTEnts (void)
 {
-       Cvar_RegisterVariable(&r_glowinglightning);
+       Cvar_RegisterVariable(&cl_glowinglightning);
        cl_sfx_wizhit = S_PrecacheSound ("wizard/hit.wav");
        cl_sfx_knighthit = S_PrecacheSound ("hknight/hit.wav");
        cl_sfx_tink1 = S_PrecacheSound ("weapons/tink1.wav");
@@ -63,7 +68,7 @@ void CL_ParseBeam (model_t *m)
        vec3_t  start, end;
        beam_t  *b;
        int             i;
-       
+
        ent = MSG_ReadShort ();
        MSG_ReadVector(start);
        MSG_ReadVector(end);
@@ -96,25 +101,6 @@ void CL_ParseBeam (model_t *m)
        Con_Printf ("beam list overflow!\n");   
 }
 
-//void R_BlastParticles(vec3_t org, vec_t radius, vec_t power);
-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;
-}
 
 /*
 =================
@@ -138,21 +124,21 @@ void CL_ParseTEnt (void)
        {
        case TE_WIZSPIKE:                       // spike hitting wall
                MSG_ReadVector(pos);
-               R_RunParticleEffect (pos, vec3_origin, 20, 30);
+               CL_RunParticleEffect (pos, vec3_origin, 20, 30);
                S_StartSound (-1, 0, cl_sfx_wizhit, pos, 1, 1);
                break;
                
        case TE_KNIGHTSPIKE:                    // spike hitting wall
                MSG_ReadVector(pos);
-               R_RunParticleEffect (pos, vec3_origin, 226, 20);
+               CL_RunParticleEffect (pos, vec3_origin, 226, 20);
                S_StartSound (-1, 0, cl_sfx_knighthit, pos, 1, 1);
                break;
                
        case TE_SPIKE:                  // spike hitting wall
                MSG_ReadVector(pos);
                // LordHavoc: changed to spark shower
-               R_SparkShower(pos, vec3_origin, 15);
-               //R_RunParticleEffect (pos, vec3_origin, 0, 10);
+               CL_SparkShower(pos, vec3_origin, 15);
+               //CL_RunParticleEffect (pos, vec3_origin, 0, 10);
                if ( rand() % 5 )
                        S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1);
                else
@@ -169,8 +155,8 @@ void CL_ParseTEnt (void)
        case TE_SPIKEQUAD:                      // quad spike hitting wall
                MSG_ReadVector(pos);
                // LordHavoc: changed to spark shower
-               R_SparkShower(pos, vec3_origin, 15);
-               //R_RunParticleEffect (pos, vec3_origin, 0, 10);
+               CL_SparkShower(pos, vec3_origin, 15);
+               //CL_RunParticleEffect (pos, vec3_origin, 0, 10);
                CL_AllocDlight (NULL, pos, 200, 0.1f, 0.1f, 1.0f, 1000, 0.2);
                S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
                if ( rand() % 5 )
@@ -189,8 +175,8 @@ void CL_ParseTEnt (void)
        case TE_SUPERSPIKE:                     // super spike hitting wall
                MSG_ReadVector(pos);
                // LordHavoc: changed to dust shower
-               R_SparkShower(pos, vec3_origin, 30);
-               //R_RunParticleEffect (pos, vec3_origin, 0, 20);
+               CL_SparkShower(pos, vec3_origin, 30);
+               //CL_RunParticleEffect (pos, vec3_origin, 0, 20);
                if ( rand() % 5 )
                        S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1);
                else
@@ -207,8 +193,8 @@ void CL_ParseTEnt (void)
        case TE_SUPERSPIKEQUAD:                 // quad super spike hitting wall
                MSG_ReadVector(pos);
                // LordHavoc: changed to dust shower
-               R_SparkShower(pos, vec3_origin, 30);
-               //R_RunParticleEffect (pos, vec3_origin, 0, 20);
+               CL_SparkShower(pos, vec3_origin, 30);
+               //CL_RunParticleEffect (pos, vec3_origin, 0, 20);
                CL_AllocDlight (NULL, pos, 200, 0.1f, 0.1f, 1.0f, 1000, 0.2);
                if ( rand() % 5 )
                        S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1);
@@ -230,11 +216,11 @@ void CL_ParseTEnt (void)
                dir[1] = MSG_ReadChar ();
                dir[2] = MSG_ReadChar ();
                count = MSG_ReadByte (); // amount of particles
-               R_BloodPuff(pos, dir, count);
+               CL_BloodPuff(pos, dir, count);
                break;
        case TE_BLOOD2: // blood puff
                MSG_ReadVector(pos);
-               R_BloodPuff(pos, vec3_origin, 10);
+               CL_BloodPuff(pos, vec3_origin, 10);
                break;
        case TE_SPARK:  // spark shower
                MSG_ReadVector(pos);
@@ -242,7 +228,7 @@ void CL_ParseTEnt (void)
                dir[1] = MSG_ReadChar ();
                dir[2] = MSG_ReadChar ();
                count = MSG_ReadByte (); // amount of particles
-               R_SparkShower(pos, dir, count);
+               CL_SparkShower(pos, dir, count);
                break;
                // LordHavoc: added for improved gore
        case TE_BLOODSHOWER:    // vaporized body
@@ -250,7 +236,7 @@ void CL_ParseTEnt (void)
                MSG_ReadVector(pos2); // maxs
                velspeed = MSG_ReadCoord (); // speed
                count = MSG_ReadShort (); // number of particles
-               R_BloodShower(pos, pos2, velspeed, count);
+               CL_BloodShower(pos, pos2, velspeed, count);
                break;
        case TE_PARTICLECUBE:   // general purpose particle effect
                MSG_ReadVector(pos); // mins
@@ -260,7 +246,7 @@ void CL_ParseTEnt (void)
                colorStart = MSG_ReadByte (); // color
                colorLength = MSG_ReadByte (); // gravity (1 or 0)
                velspeed = MSG_ReadCoord (); // randomvel
-               R_ParticleCube(pos, pos2, dir, count, colorStart, colorLength, velspeed);
+               CL_ParticleCube(pos, pos2, dir, count, colorStart, colorLength, velspeed);
                break;
 
        case TE_PARTICLERAIN:   // general purpose particle effect
@@ -269,7 +255,7 @@ void CL_ParseTEnt (void)
                MSG_ReadVector(dir); // dir
                count = MSG_ReadShort (); // number of particles
                colorStart = MSG_ReadByte (); // color
-               R_ParticleRain(pos, pos2, dir, count, colorStart, 0);
+               CL_ParticleRain(pos, pos2, dir, count, colorStart, 0);
                break;
 
        case TE_PARTICLESNOW:   // general purpose particle effect
@@ -278,36 +264,36 @@ void CL_ParseTEnt (void)
                MSG_ReadVector(dir); // dir
                count = MSG_ReadShort (); // number of particles
                colorStart = MSG_ReadByte (); // color
-               R_ParticleRain(pos, pos2, dir, count, colorStart, 1);
+               CL_ParticleRain(pos, pos2, dir, count, colorStart, 1);
                break;
 
        case TE_GUNSHOT:                        // bullet hitting wall
                MSG_ReadVector(pos);
                // LordHavoc: changed to dust shower
-               R_SparkShower(pos, vec3_origin, 15);
-               //R_RunParticleEffect (pos, vec3_origin, 0, 20);
+               CL_SparkShower(pos, vec3_origin, 15);
+               //CL_RunParticleEffect (pos, vec3_origin, 0, 20);
                break;
 
        case TE_GUNSHOTQUAD:                    // quad bullet hitting wall
                MSG_ReadVector(pos);
-               R_SparkShower(pos, vec3_origin, 15);
+               CL_SparkShower(pos, vec3_origin, 15);
                CL_AllocDlight (NULL, pos, 200, 0.1f, 0.1f, 1.0f, 1000, 0.2);
                break;
 
        case TE_EXPLOSION:                      // rocket explosion
                MSG_ReadVector(pos);
-               FindNonSolidLocation(pos);
-               R_ParticleExplosion (pos, false);
-//             R_BlastParticles (pos, 120, 120);
+               Mod_FindNonSolidLocation(pos, cl.worldmodel);
+               CL_ParticleExplosion (pos, false);
+//             CL_BlastParticles (pos, 120, 120);
                CL_AllocDlight (NULL, pos, 350, 1.0f, 0.8f, 0.4f, 700, 0.5);
                S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
                break;
 
        case TE_EXPLOSIONQUAD:                  // quad rocket explosion
                MSG_ReadVector(pos);
-               FindNonSolidLocation(pos);
-               R_ParticleExplosion (pos, false);
-//             R_BlastParticles (pos, 120, 480);
+               Mod_FindNonSolidLocation(pos, cl.worldmodel);
+               CL_ParticleExplosion (pos, false);
+//             CL_BlastParticles (pos, 120, 480);
                CL_AllocDlight (NULL, pos, 600, 0.5f, 0.4f, 1.0f, 1200, 0.5);
                S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
                break;
@@ -315,8 +301,8 @@ void CL_ParseTEnt (void)
                /*
        case TE_SMOKEEXPLOSION:                 // rocket explosion with a cloud of smoke
                MSG_ReadVector(pos);
-               FindNonSolidLocation(pos);
-               R_ParticleExplosion (pos, true);
+               Mod_FindNonSolidLocation(pos, cl.worldmodel);
+               CL_ParticleExplosion (pos, true);
                CL_AllocDlight (NULL, pos, 350, 1.0f, 0.8f, 0.4f, 700, 0.5);
                S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
                break;
@@ -324,18 +310,18 @@ void CL_ParseTEnt (void)
 
        case TE_EXPLOSION3:                             // Nehahra movie colored lighting explosion
                MSG_ReadVector(pos);
-               FindNonSolidLocation(pos);
-               R_ParticleExplosion (pos, false);
-//             R_BlastParticles (pos, 120, 120);
+               Mod_FindNonSolidLocation(pos, cl.worldmodel);
+               CL_ParticleExplosion (pos, false);
+//             CL_BlastParticles (pos, 120, 120);
                CL_AllocDlight (NULL, pos, 350, MSG_ReadCoord(), MSG_ReadCoord(), MSG_ReadCoord(), 700, 0.5);
                S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
                break;
 
        case TE_EXPLOSIONRGB:                   // colored lighting explosion
                MSG_ReadVector(pos);
-               FindNonSolidLocation(pos);
-               R_ParticleExplosion (pos, false);
-//             R_BlastParticles (pos, 120, 120);
+               Mod_FindNonSolidLocation(pos, cl.worldmodel);
+               CL_ParticleExplosion (pos, false);
+//             CL_BlastParticles (pos, 120, 120);
                color[0] = MSG_ReadByte() * (1.0 / 255.0);
                color[1] = MSG_ReadByte() * (1.0 / 255.0);
                color[2] = MSG_ReadByte() * (1.0 / 255.0);
@@ -345,9 +331,9 @@ void CL_ParseTEnt (void)
 
        case TE_TAREXPLOSION:                   // tarbaby explosion
                MSG_ReadVector(pos);
-               FindNonSolidLocation(pos);
-               R_BlobExplosion (pos);
-//             R_BlastParticles (pos, 120, 120);
+               Mod_FindNonSolidLocation(pos, cl.worldmodel);
+               CL_BlobExplosion (pos);
+//             CL_BlastParticles (pos, 120, 120);
 
                S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
                CL_AllocDlight (NULL, pos, 600, 0.8f, 0.4f, 1.0f, 1200, 0.5);
@@ -356,13 +342,13 @@ void CL_ParseTEnt (void)
 
        case TE_SMALLFLASH:
                MSG_ReadVector(pos);
-               FindNonSolidLocation(pos);
+               Mod_FindNonSolidLocation(pos, cl.worldmodel);
                CL_AllocDlight (NULL, pos, 200, 1, 1, 1, 1000, 0.2);
                break;
 
        case TE_CUSTOMFLASH:
                MSG_ReadVector(pos);
-               FindNonSolidLocation(pos);
+               Mod_FindNonSolidLocation(pos, cl.worldmodel);
                radius = MSG_ReadByte() * 8;
                velspeed = (MSG_ReadByte() + 1) * (1.0 / 256.0);
                color[0] = MSG_ReadByte() * (1.0 / 255.0);
@@ -375,53 +361,61 @@ void CL_ParseTEnt (void)
                MSG_ReadVector(pos);
                MSG_ReadVector(dir);
                count = MSG_ReadByte();
-               R_Flames(pos, dir, count);
+               CL_Flames(pos, dir, count);
                break;
 
        case TE_LIGHTNING1:                             // lightning bolts
-               CL_ParseBeam (Mod_ForName("progs/bolt.mdl", true));
+               if (!cl_model_bolt)
+                       cl_model_bolt = Mod_ForName("progs/bolt.mdl", true, true, false);
+               CL_ParseBeam (cl_model_bolt);
                break;
 
        case TE_LIGHTNING2:                             // lightning bolts
-               CL_ParseBeam (Mod_ForName("progs/bolt2.mdl", true));
+               if (!cl_model_bolt2)
+                       cl_model_bolt2 = Mod_ForName("progs/bolt2.mdl", true, true, false);
+               CL_ParseBeam (cl_model_bolt2);
                break;
-       
+
        case TE_LIGHTNING3:                             // lightning bolts
-               CL_ParseBeam (Mod_ForName("progs/bolt3.mdl", true));
+               if (!cl_model_bolt3)
+                       cl_model_bolt3 = Mod_ForName("progs/bolt3.mdl", true, true, false);
+               CL_ParseBeam (cl_model_bolt3);
                break;
 
-// PGM 01/21/97 
+// PGM 01/21/97
        case TE_BEAM:                           // grappling hook beam
-               CL_ParseBeam (Mod_ForName("progs/beam.mdl", true));
+               if (!cl_model_beam)
+                       cl_model_beam = Mod_ForName("progs/beam.mdl", true, true, false);
+               CL_ParseBeam (cl_model_beam);
                break;
 // PGM 01/21/97
 
 // LordHavoc: for compatibility with the Nehahra movie...
        case TE_LIGHTNING4NEH:
-               CL_ParseBeam (Mod_ForName(MSG_ReadString(), true));
+               CL_ParseBeam (Mod_ForName(MSG_ReadString(), true, false, false));
                break;
 
        case TE_LAVASPLASH:     
                pos[0] = MSG_ReadCoord ();
                pos[1] = MSG_ReadCoord ();
                pos[2] = MSG_ReadCoord ();
-               R_LavaSplash (pos);
+               CL_LavaSplash (pos);
                break;
        
        case TE_TELEPORT:
                pos[0] = MSG_ReadCoord ();
                pos[1] = MSG_ReadCoord ();
                pos[2] = MSG_ReadCoord ();
-               R_TeleportSplash (pos);
+               CL_TeleportSplash (pos);
                break;
                
        case TE_EXPLOSION2:                             // color mapped explosion
                MSG_ReadVector(pos);
-               FindNonSolidLocation(pos);
+               Mod_FindNonSolidLocation(pos, cl.worldmodel);
                colorStart = MSG_ReadByte ();
                colorLength = MSG_ReadByte ();
-               R_ParticleExplosion2 (pos, colorStart, colorLength);
-//             R_BlastParticles (pos, 80, 80);
+               CL_ParticleExplosion2 (pos, colorStart, colorLength);
+//             CL_BlastParticles (pos, 80, 80);
                tempcolor = (byte *)&d_8to24table[(rand()%colorLength) + colorStart];
                CL_AllocDlight (NULL, pos, 350, tempcolor[0] * (1.0f / 255.0f), tempcolor[1] * (1.0f / 255.0f), tempcolor[2] * (1.0f / 255.0f), 700, 0.5);
                S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
@@ -453,7 +447,6 @@ entity_t *CL_NewTempEntity (void)
        ent->render.colormap = -1; // no special coloring
        ent->render.scale = 1;
        ent->render.alpha = 1;
-       ent->render.colormod[0] = ent->render.colormod[1] = ent->render.colormod[2] = 1;
        return ent;
 }
 
@@ -523,8 +516,8 @@ void CL_UpdateTEnts (void)
                        ent->render.angles[1] = yaw;
                        ent->render.angles[2] = rand()%360;
 
-                       if (r_glowinglightning.value > 0)
-                               CL_AllocDlight(&ent->render, ent->render.origin, lhrandom(100, 120), r_glowinglightning.value * 0.25f, r_glowinglightning.value * 0.25f, r_glowinglightning.value * 0.25f, 0, 0);
+                       if (cl_glowinglightning.value > 0)
+                               CL_AllocDlight(&ent->render, ent->render.origin, lhrandom(200, 240), cl_glowinglightning.value * 0.25f, cl_glowinglightning.value * 0.25f, cl_glowinglightning.value * 0.25f, 0, 0);
 
                        VectorMA(org, 30, dist, org);
                        d -= 30;
index 4b469bb30dd6d7dc568c5883affacef36bf72845..d9dbbe5b844a5538bbff17297015b01ac1a6afa8 100644 (file)
--- a/client.h
+++ b/client.h
@@ -8,7 +8,7 @@ of the License, or (at your option) any later version.
 
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 See the GNU General Public License for more details.
 
@@ -19,6 +19,70 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
 // client.h
 
+typedef struct frameblend_s
+{
+       int frame;
+       float lerp;
+}
+frameblend_t;
+
+// LordHavoc: nothing in this structure is persistant, it may be overwritten by the client every frame, for persistant data use entity_lerp_t.
+typedef struct entity_render_s
+{
+       vec3_t  origin;                 // location
+       vec3_t  angles;                 // orientation
+       float   alpha;                  // opacity (alpha) of the model
+       float   scale;                  // size the model is shown
+
+       model_t *model;                 // NULL = no model
+       int             frame;                  // current uninterpolated animation frame (for things which do not use interpolation)
+       int             colormap;               // entity shirt and pants colors
+       int             effects;                // light, particles, etc
+       int             skinnum;                // for Alias models
+       int             flags;                  // render flags
+
+       // these are copied from the persistent data
+       int             frame1;                 // frame that the model is interpolating from
+       int             frame2;                 // frame that the model is interpolating to
+       double  framelerp;              // interpolation factor, usually computed from frame2time
+       double  frame1time;             // time frame1 began playing (for framegroup animations)
+       double  frame2time;             // time frame2 began playing (for framegroup animations)
+
+       // calculated by the renderer (but not persistent)
+       int             visframe;               // if visframe == r_framecount, it is visible
+       vec3_t  mins, maxs;             // calculated during R_AddModelEntities
+       frameblend_t    frameblend[4]; // 4 frame numbers (-1 if not used) and their blending scalers (0-1), if interpolation is not desired, use frame instead
+}
+entity_render_t;
+
+typedef struct entity_persistent_s
+{
+       // particles
+       vec3_t  trail_origin;   // trail rendering
+       float   trail_time;             // trail rendering
+
+       // interpolated animation
+       int             modelindex;             // lerp resets when model changes
+       int             frame1;                 // frame that the model is interpolating from
+       int             frame2;                 // frame that the model is interpolating to
+       double  framelerp;              // interpolation factor, usually computed from frame2time
+       double  frame1time;             // time frame1 began playing (for framegroup animations)
+       double  frame2time;             // time frame2 began playing (for framegroup animations)
+}
+entity_persistent_t;
+
+typedef struct entity_s
+{
+       entity_state_t state_baseline;  // baseline state (default values)
+       entity_state_t state_previous;  // previous state (interpolating from this)
+       entity_state_t state_current;   // current state (interpolating to this)
+
+       entity_persistent_t persistent; // used for regenerating parts of render
+
+       entity_render_t render; // the only data the renderer should know about
+}
+entity_t;
+
 typedef struct
 {
        vec3_t  viewangles;
@@ -64,8 +128,6 @@ typedef struct
 
 #define        SIGNONS         4                       // signon messages to receive before connected
 
-#include "r_light.h"
-
 #define        MAX_BEAMS       24
 typedef struct
 {
@@ -96,7 +158,7 @@ typedef struct
 {
        cactive_t       state;
 
-// personalization data sent to server 
+// personalization data sent to server
        char            mapstring[MAX_QPATH];
        char            spawnparms[MAX_MAPSTRING];      // to restart a level
 
@@ -134,7 +196,7 @@ typedef struct
 {
        int                     movemessages;   // since connecting to this server
                                                                // throw out the first couple, so the player
-                                                               // doesn't accidentally do something the 
+                                                               // doesn't accidentally do something the
                                                                // first frame
        usercmd_t       cmd;                    // last command sent to the server
 
@@ -154,7 +216,7 @@ typedef struct
        vec3_t          mviewangles[2]; // during demo playback viewangles is lerped
                                                                // between these
        vec3_t          viewangles;
-       
+
        vec3_t          mvelocity[2];   // update by server, used for lean+bob
                                                                // (0 is newest)
        vec3_t          velocity;               // lerped between mvelocity[0] and [1]
@@ -179,7 +241,7 @@ typedef struct
        int                     intermission;   // don't change view angle, full screen, etc
        int                     completed_time; // latched at intermission start
 
-       double          mtime[2];               // the timestamp of last two messages   
+       double          mtime[2];               // the timestamp of last two messages
        double          time;                   // clients view of time, should be between
                                                                // servertime and oldservertime to generate
                                                                // a lerp point for other data
@@ -215,6 +277,7 @@ typedef struct
 }
 client_state_t;
 
+extern mempool_t *cl_scores_mempool;
 
 //
 // cvars
@@ -266,26 +329,22 @@ extern    lightstyle_t    cl_lightstyle[MAX_LIGHTSTYLES];
 extern entity_t                cl_temp_entities[MAX_TEMP_ENTITIES];
 extern beam_t                  cl_beams[MAX_BEAMS];
 
-//=============================================================================
-
 #include "cl_light.h"
 
+//=============================================================================
+
 //
 // cl_main
 //
 
-extern void CL_Init (void);
+void CL_Init (void);
 
-extern void CL_EstablishConnection (char *host);
-extern void CL_Signon1 (void);
-extern void CL_Signon2 (void);
-extern void CL_Signon3 (void);
-extern void CL_Signon4 (void);
+void CL_EstablishConnection (char *host);
 
-extern void CL_Disconnect (void);
-extern void CL_Disconnect_f (void);
-extern void CL_NextDemo (void);
+void CL_Disconnect (void);
+void CL_Disconnect_f (void);
 
+// LordHavoc: fixme: move this to r_refdef?
 // LordHavoc: raised this from 256 to the maximum possible number of entities visible
 #define MAX_VISEDICTS (MAX_EDICTS + MAX_STATIC_ENTITIES + MAX_TEMP_ENTITIES)
 extern int                     cl_numvisedicts;
@@ -305,62 +364,134 @@ extern   kbutton_t       in_mlook, in_klook;
 extern         kbutton_t       in_strafe;
 extern         kbutton_t       in_speed;
 
-extern void CL_InitInput (void);
-extern void CL_SendCmd (void);
-extern void CL_SendMove (usercmd_t *cmd);
+void CL_InitInput (void);
+void CL_SendCmd (void);
+void CL_SendMove (usercmd_t *cmd);
 
-extern void CL_ParseTEnt (void);
-extern void CL_UpdateTEnts (void);
-extern void CL_DoEffects (void);
+void CL_LerpUpdate(entity_t *e, int frame, int modelindex);
+void CL_ParseTEnt (void);
+void CL_UpdateTEnts (void);
 
-extern entity_t *CL_NewTempEntity (void);
+entity_t *CL_NewTempEntity (void);
 
-extern void CL_Effect(vec3_t org, int modelindex, int startframe, int framecount, float framerate);
+void CL_Effect(vec3_t org, int modelindex, int startframe, int framecount, float framerate);
 
-extern void CL_ClearState (void);
+void CL_ClearState (void);
 
 
-extern int  CL_ReadFromServer (void);
-extern void CL_WriteToServer (usercmd_t *cmd);
-extern void CL_BaseMove (usercmd_t *cmd);
+int  CL_ReadFromServer (void);
+void CL_WriteToServer (usercmd_t *cmd);
+void CL_BaseMove (usercmd_t *cmd);
 
 
-extern float CL_KeyState (kbutton_t *key);
-extern char *Key_KeynumToString (int keynum);
+float CL_KeyState (kbutton_t *key);
+char *Key_KeynumToString (int keynum);
 
 //
 // cl_demo.c
 //
-extern void CL_StopPlayback (void);
-extern int CL_GetMessage (void);
+void CL_StopPlayback (void);
+int CL_GetMessage (void);
 
-extern void CL_Stop_f (void);
-extern void CL_Record_f (void);
-extern void CL_PlayDemo_f (void);
-extern void CL_TimeDemo_f (void);
+void CL_NextDemo (void);
+void CL_Stop_f (void);
+void CL_Record_f (void);
+void CL_PlayDemo_f (void);
+void CL_TimeDemo_f (void);
 
 //
 // cl_parse.c
 //
-extern void CL_Parse_Init(void);
-extern void CL_ParseServerMessage(void);
-extern void CL_BitProfile_f(void);
+void CL_Parse_Init(void);
+void CL_ParseServerMessage(void);
+void CL_BitProfile_f(void);
 
 //
 // view
 //
-extern void V_StartPitchDrift (void);
-extern void V_StopPitchDrift (void);
+void V_StartPitchDrift (void);
+void V_StopPitchDrift (void);
 
-extern void V_RenderView (void);
-extern void V_UpdateBlends (void);
-extern void V_Register (void);
-extern void V_ParseDamage (void);
-extern void V_SetContentsColor (int contents);
+void V_RenderView (void);
+void V_UpdateBlends (void);
+void V_Register (void);
+void V_ParseDamage (void);
+void V_SetContentsColor (int contents);
 
 
 //
 // cl_tent
 //
-extern void CL_InitTEnts (void);
-extern void CL_SignonReply (void);
+void CL_InitTEnts (void);
+
+//
+// cl_part
+//
+
+#define PARTICLE_INVALID 0
+#define PARTICLE_BILLBOARD 1
+#define PARTICLE_UPRIGHT_FACING 2
+#define PARTICLE_ORIENTED_DOUBLESIDED 3
+
+typedef struct renderparticle_s
+{
+       int                     tex;
+       int                     orientation;
+       int                     dynlight;
+       float           scale;
+       float           org[3];
+       float           dir[3];
+       float           color[4];
+}
+renderparticle_t;
+
+void CL_Particles_Clear(void);
+void CL_Particles_Init(void);
+
+void CL_ParseParticleEffect (void);
+void CL_RunParticleEffect (vec3_t org, vec3_t dir, int color, int count);
+void CL_RocketTrail (vec3_t start, vec3_t end, int type, entity_t *ent);
+void CL_RocketTrail2 (vec3_t start, vec3_t end, int color, entity_t *ent);
+void CL_SparkShower (vec3_t org, vec3_t dir, int count);
+void CL_BloodPuff (vec3_t org, vec3_t vel, int count);
+void CL_FlameCube (vec3_t mins, vec3_t maxs, int count);
+void CL_Flames (vec3_t org, vec3_t vel, int count);
+void CL_BloodShower (vec3_t mins, vec3_t maxs, float velspeed, int count);
+void CL_ParticleCube (vec3_t mins, vec3_t maxs, vec3_t dir, int count, int colorbase, int gravity, int randomvel);
+void CL_ParticleRain (vec3_t mins, vec3_t maxs, vec3_t dir, int count, int colorbase, int type);
+void CL_EntityParticles (entity_t *ent);
+void CL_BlobExplosion (vec3_t org);
+void CL_ParticleExplosion (vec3_t org, int smoke);
+void CL_ParticleExplosion2 (vec3_t org, int colorStart, int colorLength);
+void CL_LavaSplash (vec3_t org);
+void CL_TeleportSplash (vec3_t org);
+void CL_MoveParticles(void);
+void CL_UpdateDecals(void);
+void R_MoveExplosions(void);
+void R_NewExplosion(vec3_t org);
+
+//
+// cl_decal
+//
+
+typedef struct renderdecal_s
+{
+       entity_render_t *ent;
+       int tex;
+       int surface;
+       float scale;
+       vec3_t org;
+       vec3_t dir;
+       float color[4];
+}
+renderdecal_t;
+
+void CL_Decals_Clear(void);
+void CL_Decals_Init(void);
+void CL_Decal(vec3_t origin, int tex, float scale, float red, float green, float blue, float alpha);
+
+// if contents is not zero, it will impact on content changes
+// (leafs matching contents are considered empty, others are solid)
+extern int traceline_endcontents; // set by TraceLine
+float TraceLine (vec3_t start, vec3_t end, vec3_t impact, vec3_t normal, int contents);
+
diff --git a/cmd.c b/cmd.c
index 71f476b7d2e1d7a7ae61d893466c019f52679546..293155d62de244a1eb3ffefcd2fc500b2cabc065 100644 (file)
--- a/cmd.c
+++ b/cmd.c
@@ -8,7 +8,7 @@ of the License, or (at your option) any later version.
 
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 See the GNU General Public License for more details.
 
@@ -21,8 +21,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 #include "quakedef.h"
 
-void Cmd_ForwardToServer (void);
-
 #define        MAX_ALIAS_NAME  32
 
 typedef struct cmdalias_s
@@ -32,12 +30,11 @@ typedef struct cmdalias_s
        char    *value;
 } cmdalias_t;
 
-cmdalias_t     *cmd_alias;
+static cmdalias_t *cmd_alias;
 
-int trashtest;
-int *trashspot;
+static qboolean cmd_wait;
 
-qboolean       cmd_wait;
+static mempool_t *cmd_mempool;
 
 //=============================================================================
 
@@ -50,7 +47,7 @@ next frame.  This allows commands like:
 bind g "impulse 5 ; +attack ; wait ; -attack ; impulse 2"
 ============
 */
-void Cmd_Wait_f (void)
+static void Cmd_Wait_f (void)
 {
        cmd_wait = true;
 }
@@ -63,7 +60,7 @@ void Cmd_Wait_f (void)
 =============================================================================
 */
 
-sizebuf_t      cmd_text;
+static sizebuf_t       cmd_text;
 
 /*
 ============
@@ -72,7 +69,8 @@ Cbuf_Init
 */
 void Cbuf_Init (void)
 {
-       SZ_Alloc (&cmd_text, 8192);             // space for commands and script files
+       // LordHavoc: inreased this from 8192 to 32768
+       SZ_Alloc (&cmd_text, 32768, "command buffer"); // space for commands and script files
 }
 
 
@@ -86,7 +84,7 @@ Adds command text at the end of the buffer
 void Cbuf_AddText (char *text)
 {
        int             l;
-       
+
        l = strlen (text);
 
        if (cmd_text.cursize + l >= cmd_text.maxsize)
@@ -123,10 +121,10 @@ void Cbuf_InsertText (char *text)
        }
        else
                temp = NULL;    // shut up compiler
-               
+
 // add the entire text of the file
        Cbuf_AddText (text);
-       
+
 // add the copied off data
        if (templen)
        {
@@ -146,7 +144,7 @@ void Cbuf_Execute (void)
        char    *text;
        char    line[1024];
        int             quotes;
-       
+
        while (cmd_text.cursize)
        {
 // find a \n or ; line break
@@ -162,11 +160,10 @@ void Cbuf_Execute (void)
                        if (text[i] == '\n')
                                break;
                }
-                       
-                               
+
                memcpy (line, text, i);
                line[i] = 0;
-               
+
 // delete the text from the command buffer and move remaining commands down
 // this is necessary because commands (exec, alias) can insert data at the
 // beginning of the text buffer
@@ -182,7 +179,7 @@ void Cbuf_Execute (void)
 
 // execute the command line
                Cmd_ExecuteString (line, src_command);
-               
+
                if (cmd_wait)
                {       // skip out while text still remains in buffer, leaving it
                        // for next frame
@@ -215,7 +212,7 @@ void Cmd_StuffCmds_f (void)
        int             i, j;
        int             s;
        char    *text, *build, c;
-               
+
        if (Cmd_Argc () != 1)
        {
                Con_Printf ("stuffcmds : execute command line parameters\n");
@@ -232,7 +229,7 @@ void Cmd_StuffCmds_f (void)
        }
        if (!s)
                return;
-               
+
        text = Z_Malloc (s+1);
        text[0] = 0;
        for (i=1 ; i<com_argc ; i++)
@@ -243,11 +240,11 @@ void Cmd_StuffCmds_f (void)
                if (i != com_argc-1)
                        strcat (text, " ");
        }
-       
+
 // pull out the commands
        build = Z_Malloc (s+1);
        build[0] = 0;
-       
+
        for (i=0 ; i<s-1 ; i++)
        {
                if (text[i] == '+')
@@ -259,17 +256,17 @@ void Cmd_StuffCmds_f (void)
 
                        c = text[j];
                        text[j] = 0;
-                       
+
                        strcat (build, text+i);
                        strcat (build, "\n");
                        text[j] = c;
                        i = j-1;
                }
        }
-       
+
        if (build[0])
                Cbuf_InsertText (build);
-       
+
        Z_Free (text);
        Z_Free (build);
 }
@@ -280,7 +277,7 @@ void Cmd_StuffCmds_f (void)
 Cmd_Exec_f
 ===============
 */
-void Cmd_Exec_f (void)
+static void Cmd_Exec_f (void)
 {
        char    *f;
 
@@ -290,16 +287,16 @@ void Cmd_Exec_f (void)
                return;
        }
 
-       f = (char *)COM_LoadMallocFile (Cmd_Argv(1), false);
+       f = (char *)COM_LoadFile (Cmd_Argv(1), false);
        if (!f)
        {
                Con_Printf ("couldn't exec %s\n",Cmd_Argv(1));
                return;
        }
        Con_Printf ("execing %s\n",Cmd_Argv(1));
-       
+
        Cbuf_InsertText (f);
-       qfree(f);
+       Mem_Free(f);
 }
 
 
@@ -310,10 +307,10 @@ Cmd_Echo_f
 Just prints the rest of the line to the console
 ===============
 */
-void Cmd_Echo_f (void)
+static void Cmd_Echo_f (void)
 {
        int             i;
-       
+
        for (i=1 ; i<Cmd_Argc() ; i++)
                Con_Printf ("%s ",Cmd_Argv(i));
        Con_Printf ("\n");
@@ -327,16 +324,16 @@ Creates a new command that executes a command string (possibly ; seperated)
 ===============
 */
 
-char *CopyString (char *in)
+static char *CopyString (char *in)
 {
        char    *out;
-       
+
        out = Z_Malloc (strlen(in)+1);
        strcpy (out, in);
        return out;
 }
 
-void Cmd_Alias_f (void)
+static void Cmd_Alias_f (void)
 {
        cmdalias_t      *a;
        char            cmd[1024];
@@ -374,7 +371,7 @@ void Cmd_Alias_f (void)
                a->next = cmd_alias;
                cmd_alias = a;
        }
-       strcpy (a->name, s);    
+       strcpy (a->name, s);
 
 // copy the rest of the command line
        cmd[0] = 0;             // start out with a null string
@@ -386,7 +383,7 @@ void Cmd_Alias_f (void)
                        strcat (cmd, " ");
        }
        strcat (cmd, "\n");
-       
+
        a->value = CopyString (cmd);
 }
 
@@ -408,15 +405,15 @@ typedef struct cmd_function_s
 
 #define        MAX_ARGS                80
 
-static int                     cmd_argc;
-static char            *cmd_argv[MAX_ARGS];
-static char            *cmd_null_string = "";
-static char            *cmd_args = NULL;
+static int cmd_argc;
+static char *cmd_argv[MAX_ARGS];
+static char *cmd_null_string = "";
+static char *cmd_args = NULL;
 
-cmd_source_t   cmd_source;
+cmd_source_t cmd_source;
 
 
-static cmd_function_t  *cmd_functions;         // possible commands to execute
+static cmd_function_t *cmd_functions;          // possible commands to execute
 
 /*
 ========
@@ -427,7 +424,7 @@ Cmd_List
 
 ========
 */
-void Cmd_List_f (void)
+static void Cmd_List_f (void)
 {
        cmd_function_t  *cmd;
        char                    *partial;
@@ -464,6 +461,8 @@ Cmd_Init
 */
 void Cmd_Init (void)
 {
+       cmd_mempool = Mem_AllocPool("commands");
+
 //
 // register our commands
 //
@@ -497,7 +496,7 @@ char        *Cmd_Argv (int arg)
 {
        if (arg >= cmd_argc )
                return cmd_null_string;
-       return cmd_argv[arg];   
+       return cmd_argv[arg];
 }
 
 /*
@@ -518,17 +517,17 @@ Cmd_TokenizeString
 Parses the given string into command line tokens.
 ============
 */
-void Cmd_TokenizeString (char *text)
+static void Cmd_TokenizeString (char *text)
 {
        int             i;
-       
+
 // clear the args from the last string
        for (i=0 ; i<cmd_argc ; i++)
                Z_Free (cmd_argv[i]);
-               
+
        cmd_argc = 0;
        cmd_args = NULL;
-       
+
        while (1)
        {
 // skip whitespace up to a /n
@@ -536,7 +535,7 @@ void Cmd_TokenizeString (char *text)
                {
                        text++;
                }
-               
+
                if (*text == '\n')
                {       // a newline seperates commands in the buffer
                        text++;
@@ -545,10 +544,10 @@ void Cmd_TokenizeString (char *text)
 
                if (!*text)
                        return;
-       
+
                if (cmd_argc == 1)
                         cmd_args = text;
-                       
+
                text = COM_Parse (text);
                if (!text)
                        return;
@@ -560,7 +559,7 @@ void Cmd_TokenizeString (char *text)
                        cmd_argc++;
                }
        }
-       
+
 }
 
 
@@ -572,17 +571,17 @@ Cmd_AddCommand
 void   Cmd_AddCommand (char *cmd_name, xcommand_t function)
 {
        cmd_function_t  *cmd;
-       
-       if (host_initialized)   // because hunk allocation would get stomped
-               Sys_Error ("Cmd_AddCommand after host_initialized");
-               
+
+//     if (host_initialized)   // because hunk allocation would get stomped
+//             Sys_Error ("Cmd_AddCommand after host_initialized");
+
 // fail if the command is a variable name
        if (Cvar_VariableString(cmd_name)[0])
        {
                Con_Printf ("Cmd_AddCommand: %s already defined as a var\n", cmd_name);
                return;
        }
-       
+
 // fail if the command already exists
        for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
        {
@@ -593,7 +592,7 @@ void        Cmd_AddCommand (char *cmd_name, xcommand_t function)
                }
        }
 
-       cmd = Hunk_AllocName (sizeof(cmd_function_t), "commands");
+       cmd = Mem_Alloc(cmd_mempool, sizeof(cmd_function_t));
        cmd->name = cmd_name;
        cmd->function = function;
        cmd->next = cmd_functions;
@@ -610,10 +609,8 @@ qboolean   Cmd_Exists (char *cmd_name)
        cmd_function_t  *cmd;
 
        for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
-       {
                if (!strcmp (cmd_name,cmd->name))
                        return true;
-       }
 
        return false;
 }
@@ -629,12 +626,12 @@ char *Cmd_CompleteCommand (char *partial)
 {
        cmd_function_t  *cmd;
        int                             len;
-       
+
        len = strlen(partial);
-       
+
        if (!len)
                return NULL;
-               
+
 // check functions
        for (cmd = cmd_functions; cmd; cmd = cmd->next)
                if (!strncmp(partial, cmd->name, len))
@@ -652,19 +649,18 @@ char *Cmd_CompleteCommand (char *partial)
        Thanks to taniwha
 
 */
-int
-Cmd_CompleteCountPossible (char *partial)
+int Cmd_CompleteCountPossible (char *partial)
 {
        cmd_function_t  *cmd;
        int                             len;
        int                             h;
-       
+
        h = 0;
        len = strlen(partial);
-       
+
        if (!len)
                return 0;
-       
+
        // Loop through the command list and count all partial matches
        for (cmd = cmd_functions; cmd; cmd = cmd->next)
                if (!strncasecmp(partial, cmd->name, len))
@@ -682,8 +678,7 @@ Cmd_CompleteCountPossible (char *partial)
        Thanks to taniwha
 
 */
-char   **
-Cmd_CompleteBuildList (char *partial)
+char **Cmd_CompleteBuildList (char *partial)
 {
        cmd_function_t  *cmd;
        int                             len = 0;
@@ -692,7 +687,7 @@ Cmd_CompleteBuildList (char *partial)
        char                    **buf;
 
        len = strlen(partial);
-       buf = qmalloc(sizeofbuf + sizeof (char *));
+       buf = Mem_Alloc(tempmempool, sizeofbuf + sizeof (char *));
        // Loop through the alias list and print all matches
        for (cmd = cmd_functions; cmd; cmd = cmd->next)
                if (!strncasecmp(partial, cmd->name, len))
@@ -711,8 +706,7 @@ Cmd_CompleteBuildList (char *partial)
        Thanks to taniwha
 
 */
-char
-*Cmd_CompleteAlias (char * partial)
+char *Cmd_CompleteAlias (char * partial)
 {
        cmdalias_t      *alias;
        int                     len;
@@ -739,8 +733,7 @@ char
        Thanks to taniwha
 
 */
-int
-Cmd_CompleteAliasCountPossible (char *partial)
+int Cmd_CompleteAliasCountPossible (char *partial)
 {
        cmdalias_t      *alias;
        int                     len;
@@ -770,8 +763,7 @@ Cmd_CompleteAliasCountPossible (char *partial)
        Thanks to taniwha
 
 */
-char   **
-Cmd_CompleteAliasBuildList (char *partial)
+char **Cmd_CompleteAliasBuildList (char *partial)
 {
        cmdalias_t      *alias;
        int                     len = 0;
@@ -780,7 +772,7 @@ Cmd_CompleteAliasBuildList (char *partial)
        char            **buf;
 
        len = strlen(partial);
-       buf = qmalloc(sizeofbuf + sizeof (char *));
+       buf = Mem_Alloc(tempmempool, sizeofbuf + sizeof (char *));
        // Loop through the alias list and print all matches
        for (alias = cmd_alias; alias; alias = alias->next)
                if (!strncasecmp(partial, alias->name, len))
@@ -799,13 +791,13 @@ FIXME: lookupnoadd the token to speed search?
 ============
 */
 void   Cmd_ExecuteString (char *text, cmd_source_t src)
-{      
+{
        cmd_function_t  *cmd;
        cmdalias_t              *a;
 
        cmd_source = src;
        Cmd_TokenizeString (text);
-                       
+
 // execute the command line
        if (!Cmd_Argc())
                return;         // no tokens
@@ -829,11 +821,10 @@ void      Cmd_ExecuteString (char *text, cmd_source_t src)
                        return;
                }
        }
-       
+
 // check cvars
        if (!Cvar_Command ())
                Con_Printf ("Unknown command \"%s\"\n", Cmd_Argv(0));
-       
 }
 
 
@@ -851,7 +842,7 @@ void Cmd_ForwardToServer (void)
                Con_Printf ("Can't \"%s\", not connected\n", Cmd_Argv(0));
                return;
        }
-       
+
        if (cls.demoplayback)
                return;         // not really connected
 
@@ -880,14 +871,14 @@ where the given parameter apears, or 0 if not present
 int Cmd_CheckParm (char *parm)
 {
        int i;
-       
+
        if (!parm)
                Sys_Error ("Cmd_CheckParm: NULL");
 
        for (i = 1; i < Cmd_Argc (); i++)
                if (!Q_strcasecmp (parm, Cmd_Argv (i)))
                        return i;
-                       
+
        return 0;
 }
 
diff --git a/cmd.h b/cmd.h
index ba2796e1a011ab4f8105374d0e4c1f28ce15bba5..640afc57a567b24efbc945e9053f443d1852558f 100644 (file)
--- a/cmd.h
+++ b/cmd.h
@@ -116,7 +116,7 @@ int Cmd_CheckParm (char *parm);
 // Returns the position (1 to argc-1) in the command's argument list
 // where the given parameter apears, or 0 if not present
 
-void Cmd_TokenizeString (char *text);
+//void Cmd_TokenizeString (char *text);
 // Takes a null terminated string.  Does not need to be /n terminated.
 // breaks the string up into arg tokens.
 
index 5c73c036c92cd4accd2f10aede6560ba84b40c4d..27112675c830b572a56a29fac0749925330a2000 100644 (file)
--- a/common.c
+++ b/common.c
@@ -31,32 +31,34 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 #define NUM_SAFE_ARGVS  7
 
-static char     *largv[MAX_NUM_ARGVS + NUM_SAFE_ARGVS + 1];
-static char     *argvdummy = " ";
+static char *largv[MAX_NUM_ARGVS + NUM_SAFE_ARGVS + 1];
+static char *argvdummy = " ";
 
-static char     *safeargvs[NUM_SAFE_ARGVS] =
+static char *safeargvs[NUM_SAFE_ARGVS] =
        {"-stdvid", "-nolan", "-nosound", "-nocdaudio", "-nojoy", "-nomouse", "-window"};
 
 cvar_t registered = {0, "registered","0"};
 cvar_t cmdline = {0, "cmdline","0"};
 
-qboolean        com_modified;   // set true if using non-id files
+mempool_t *pak_mempool;
 
-//qboolean             proghack;
+qboolean com_modified;   // set true if using non-id files
 
-//int             static_registered = 1;  // only for startup check, then set
+//qboolean proghack;
 
-qboolean               msg_suppress_1 = 0;
+//int static_registered = 1;  // only for startup check, then set
+
+qboolean msg_suppress_1 = 0;
 
 void COM_InitFilesystem (void);
 
-char   com_token[1024];
-int            com_argc;
-char   **com_argv;
+char com_token[1024];
+int com_argc;
+char **com_argv;
 
 // LordHavoc: made commandline 1024 characters instead of 256
 #define CMDLINE_LENGTH 1024
-char   com_cmdline[CMDLINE_LENGTH];
+char com_cmdline[CMDLINE_LENGTH];
 
 int gamemode;
 char *gamename;
@@ -192,7 +194,7 @@ int Q_strcmp (char *s1, char *s2)
                s1++;
                s2++;
        }
-       
+
        return -1;
 }
 
@@ -209,7 +211,7 @@ int Q_strncmp (char *s1, char *s2, int count)
                s1++;
                s2++;
        }
-       
+
        return -1;
 }
 */
@@ -224,7 +226,7 @@ int Q_strncasecmp (char *s1, char *s2, int n)
 
                if (!n--)
                        return 0;               // strings are equal until end point
-               
+
                if (c1 != c2)
                {
                        if (c1 >= 'a' && c1 <= 'z')
@@ -239,7 +241,7 @@ int Q_strncasecmp (char *s1, char *s2, int n)
 //              s1++;
 //              s2++;
        }
-       
+
        return -1;
 }
 
@@ -410,10 +412,12 @@ short   ShortSwap (short l)
        return (b1<<8) + b2;
 }
 
+#if !defined(ENDIAN_LITTLE) && !defined(ENDIAN_BIG)
 short   ShortNoSwap (short l)
 {
        return l;
 }
+#endif
 
 int    LongSwap (int l)
 {
@@ -427,10 +431,12 @@ int    LongSwap (int l)
        return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
 }
 
+#if !defined(ENDIAN_LITTLE) && !defined(ENDIAN_BIG)
 int     LongNoSwap (int l)
 {
        return l;
 }
+#endif
 
 float FloatSwap (float f)
 {
@@ -439,8 +445,8 @@ float FloatSwap (float f)
                float   f;
                byte    b[4];
        } dat1, dat2;
-       
-       
+
+
        dat1.f = f;
        dat2.b[0] = dat1.b[3];
        dat2.b[1] = dat1.b[2];
@@ -449,10 +455,12 @@ float FloatSwap (float f)
        return dat2.f;
 }
 
+#if !defined(ENDIAN_LITTLE) && !defined(ENDIAN_BIG)
 float FloatNoSwap (float f)
 {
        return f;
 }
+#endif
 
 /*
 ==============================================================================
@@ -496,7 +504,7 @@ void MSG_WriteByte (sizebuf_t *sb, int c)
 void MSG_WriteShort (sizebuf_t *sb, int c)
 {
        byte    *buf;
-       
+
 //#ifdef PARANOID
 //     if (c < ((short)0x8000) || c > (short)0x7fff)
 //             Sys_Error ("MSG_WriteShort: range error");
@@ -510,7 +518,7 @@ void MSG_WriteShort (sizebuf_t *sb, int c)
 void MSG_WriteLong (sizebuf_t *sb, int c)
 {
        byte    *buf;
-       
+
        buf = SZ_GetSpace (sb, 4);
        buf[0] = c&0xff;
        buf[1] = (c>>8)&0xff;
@@ -525,11 +533,11 @@ void MSG_WriteFloat (sizebuf_t *sb, float f)
                float   f;
                int     l;
        } dat;
-       
-       
+
+
        dat.f = f;
        dat.l = LittleLong (dat.l);
-       
+
        SZ_Write (sb, &dat.l, 4);
 }
 
@@ -556,18 +564,29 @@ void MSG_WriteCoord (sizebuf_t *sb, float f)
        if (dpprotocol)
                MSG_WriteFloat(sb, f);
        else
-               MSG_WriteShort (sb, (int)(f*8.0f + 0.5f));
+       {
+               if (f >= 0)
+                       MSG_WriteShort (sb, (int)(f*8.0f + 0.5f));
+               else
+                       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.0f) + 0.5f) & 65535);
+       if (f >= 0)
+               MSG_WriteShort (sb, (int)(f*(65536.0f/360.0f) + 0.5f) & 65535);
+       else
+               MSG_WriteShort (sb, (int)(f*(65536.0f/360.0f) - 0.5f) & 65535);
 }
 
-// LordHavoc: round to nearest value, rather than rounding down, fixes crosshair problem
+// LordHavoc: round to nearest value, rather than rounding toward zero, fixes crosshair problem
 void MSG_WriteAngle (sizebuf_t *sb, float f)
 {
-       MSG_WriteByte (sb, (int)(f*(256.0f/360.0f) + 0.5f) & 255);
+       if (f >= 0)
+               MSG_WriteByte (sb, (int)(f*(256.0f/360.0f) + 0.5f) & 255);
+       else
+               MSG_WriteByte (sb, (int)(f*(256.0f/360.0f) - 0.5f) & 255);
 }
 
 //
@@ -598,7 +617,7 @@ int MSG_ReadChar (void)
                
        c = (signed char)net_message.data[msg_readcount];
        msg_readcount++;
-       
+
        return c;
 }
 
@@ -613,7 +632,7 @@ int MSG_ReadByte (void)
                msg_badread = true;
                return -1;
        }
-               
+
        c = (unsigned char)net_message.data[msg_readcount];
        msg_readcount++;
        
@@ -624,7 +643,7 @@ int MSG_ReadByte (void)
 int MSG_ReadShort (void)
 {
        int     c;
-       
+
        if (msg_readcount+2 > net_message.cursize)
        {
                msg_badread = true;
@@ -737,11 +756,12 @@ float MSG_ReadPreciseAngle (void)
 
 //===========================================================================
 
-void SZ_Alloc (sizebuf_t *buf, int startsize)
+void SZ_Alloc (sizebuf_t *buf, int startsize, char *name)
 {
        if (startsize < 256)
                startsize = 256;
-       buf->data = Hunk_AllocName (startsize, "sizebuf");
+       buf->mempool = Mem_AllocPool(name);
+       buf->data = Mem_Alloc(buf->mempool, startsize);
        buf->maxsize = startsize;
        buf->cursize = 0;
 }
@@ -749,9 +769,9 @@ void SZ_Alloc (sizebuf_t *buf, int startsize)
 
 void SZ_Free (sizebuf_t *buf)
 {
-//      Z_Free (buf->data);
-//      buf->data = NULL;
-//      buf->maxsize = 0;
+       Mem_FreePool(&buf->mempool);
+       buf->data = NULL;
+       buf->maxsize = 0;
        buf->cursize = 0;
 }
 
@@ -763,18 +783,18 @@ void SZ_Clear (sizebuf_t *buf)
 void *SZ_GetSpace (sizebuf_t *buf, int length)
 {
        void    *data;
-       
+
        if (buf->cursize + length > buf->maxsize)
        {
                if (!buf->allowoverflow)
                        Host_Error ("SZ_GetSpace: overflow without allowoverflow set - use -zone on the commandline for more zone memory, default: 128k (quake original default was 48k)");
-               
+
                if (length > buf->maxsize)
                        Host_Error ("SZ_GetSpace: %i is > full buffer size", length);
-                       
+
                buf->overflowed = true;
                Con_Printf ("SZ_GetSpace: overflow");
-               SZ_Clear (buf); 
+               SZ_Clear (buf);
        }
 
        data = buf->data + buf->cursize;
@@ -813,7 +833,7 @@ COM_SkipPath
 char *COM_SkipPath (char *pathname)
 {
        char    *last;
-       
+
        last = pathname;
        while (*pathname)
        {
@@ -1056,7 +1076,7 @@ void COM_CheckRegistered (void)
 //                     Sys_Error ("You must have the registered version to use modified games");
                return;
        }
-       
+
 //     Cvar_Set ("cmdline", com_cmdline);
        Cvar_Set ("registered", "1");
 //     static_registered = 1;
@@ -1166,42 +1186,6 @@ void COM_InitArgv (int argc, char **argv)
 }
 
 
-unsigned int qmalloctotal_alloc, qmalloctotal_alloccount, qmalloctotal_free, qmalloctotal_freecount;
-
-void *qmalloc(unsigned int size)
-{
-       unsigned int *mem;
-       qmalloctotal_alloc += size;
-       qmalloctotal_alloccount++;
-       mem = malloc(size+sizeof(unsigned int));
-       if (!mem)
-               return mem;
-       *mem = size;
-       return (void *)(mem + 1);
-}
-
-void qfree(void *mem)
-{
-       unsigned int *m;
-       if (!mem)
-               return;
-       m = mem;
-       m--; // back up to size
-       qmalloctotal_free += *m; // size
-       qmalloctotal_freecount++;
-       free(m);
-}
-
-extern void GL_TextureStats_PrintTotal(void);
-extern int hunk_low_used, hunk_high_used, hunk_size;
-void COM_Memstats_f(void)
-{
-       Con_Printf("%i malloc calls totalling %i bytes (%.4gMB)\n%i free calls totalling %i bytes (%.4gMB)\n%i bytes (%.4gMB) currently allocated\n", qmalloctotal_alloccount, qmalloctotal_alloc, qmalloctotal_alloc / 1048576.0, qmalloctotal_freecount, qmalloctotal_free, qmalloctotal_free / 1048576.0, qmalloctotal_alloc - qmalloctotal_free, (qmalloctotal_alloc - qmalloctotal_free) / 1048576.0);
-       GL_TextureStats_PrintTotal();
-       Con_Printf ("%i bytes (%.4gMB) of %.4gMB hunk in use\n", hunk_low_used + hunk_high_used, (hunk_low_used + hunk_high_used) / 1048576.0, hunk_size / 1048576.0);
-}
-
-
 extern void Mathlib_Init(void);
 
 /*
@@ -1209,12 +1193,12 @@ extern void Mathlib_Init(void);
 COM_Init
 ================
 */
-void COM_Init (char *basedir)
+void COM_Init (void)
 {
 #if !defined(ENDIAN_LITTLE) && !defined(ENDIAN_BIG)
        byte    swaptest[2] = {1,0};
 
-// set the byte swapping variables in a portable manner 
+// set the byte swapping variables in a portable manner
        if ( *(short *)swaptest == 1)
        {
                BigShort = ShortSwap;
@@ -1235,10 +1219,11 @@ void COM_Init (char *basedir)
        }
 #endif
 
+       pak_mempool = Mem_AllocPool("paks");
+
        Cvar_RegisterVariable (&registered);
        Cvar_RegisterVariable (&cmdline);
        Cmd_AddCommand ("path", COM_Path_f);
-       Cmd_AddCommand ("memstats", COM_Memstats_f);
 
        Mathlib_Init();
 
@@ -1297,16 +1282,18 @@ int     com_filesize;
 
 typedef struct
 {
-       char    name[MAX_QPATH];
-       int             filepos, filelen;
+       char name[MAX_QPATH];
+       int filepos, filelen;
 } packfile_t;
 
 typedef struct pack_s
 {
-       char    filename[MAX_OSPATH];
-       int             handle;
-       int             numfiles;
-       packfile_t      *files;
+       char filename[MAX_OSPATH];
+       int handle;
+       int numfiles;
+       packfile_t *files;
+       mempool_t *mempool;
+       struct pack_s *next;
 } pack_t;
 
 //
@@ -1314,19 +1301,21 @@ typedef struct pack_s
 //
 typedef struct
 {
-       char    name[56];
-       int             filepos, filelen;
+       char name[56];
+       int filepos, filelen;
 } dpackfile_t;
 
 typedef struct
 {
-       char    id[4];
-       int             dirofs;
-       int             dirlen;
+       char id[4];
+       int dirofs;
+       int dirlen;
 } dpackheader_t;
 
-// LordHavoc: was 2048, increased to 16384 and changed info[MAX_PACK_FILES] to a temporary malloc to avoid stack overflows
-#define MAX_FILES_IN_PACK       16384
+// LordHavoc: was 2048, increased to 65536 and changed info[MAX_PACK_FILES] to a temporary alloc
+#define MAX_FILES_IN_PACK       65536
+
+pack_t *packlist = NULL;
 
 #if CACHEENABLE
 char   com_cachedir[MAX_OSPATH];
@@ -1335,8 +1324,8 @@ char      com_gamedir[MAX_OSPATH];
 
 typedef struct searchpath_s
 {
-       char    filename[MAX_OSPATH];
-       pack_t  *pack;          // only one of filename / pack will be used
+       char filename[MAX_OSPATH];
+       pack_t *pack;          // only one of filename / pack will be used
        struct searchpath_s *next;
 } searchpath_t;
 
@@ -1351,7 +1340,7 @@ COM_Path_f
 void COM_Path_f (void)
 {
        searchpath_t    *s;
-       
+
        Con_Printf ("Current search path:\n");
        for (s=com_searchpaths ; s ; s=s->next)
        {
@@ -1431,7 +1420,7 @@ void COM_CopyFile (char *netpath, char *cachepath)
        int             in, out;
        int             remaining, count;
        char    buf[4096];
-       
+
        remaining = Sys_FileOpenRead (netpath, &in);            
        COM_CreatePath (cachepath);     // create directories up to the cache file
        out = Sys_FileOpenWrite (cachepath);
@@ -1631,10 +1620,9 @@ Filename are reletive to the quake directory.
 Always appends a 0 byte.
 ============
 */
-cache_user_t   *loadcache;
 byte                   *loadbuf;
 int                            loadsize;
-byte *COM_LoadFile (char *path, int usehunk, qboolean quiet)
+byte *COM_LoadFile (char *path, qboolean quiet)
 {
        QFile             *h;
        byte    *buf;
@@ -1650,64 +1638,22 @@ byte *COM_LoadFile (char *path, int usehunk, qboolean quiet)
                return NULL;
 
        loadsize = len;
-       
+
 // extract the filename base name for hunk tag
        COM_FileBase (path, base);
-       
-       switch (usehunk)
-       {
-       case 1:
-               buf = Hunk_AllocName (len+1, va("%s (file)", path));
-               if (!buf)
-                       Sys_Error ("COM_LoadFile: not enough hunk space for %s (size %i)", path, len);
-               break;
-//     case 0:
-//             buf = Z_Malloc (len+1);
-//             if (!buf)
-//                     Sys_Error ("COM_LoadFile: not enough zone space for %s (size %i)", path, len);
-//             break;
-//     case 3:
-//             buf = Cache_Alloc (loadcache, len+1, base);
-//             if (!buf)
-//                     Sys_Error ("COM_LoadFile: not enough cache space for %s (size %i)", path, len);
-//             break;
-       case 5:
-               buf = qmalloc (len+1);
-               if (!buf)
-                       Sys_Error ("COM_LoadFile: not enough available memory for %s (size %i)", path, len);
-               break;
-       default:
-               Sys_Error ("COM_LoadFile: bad usehunk");
-               break;
-       }
+
+       buf = Mem_Alloc(tempmempool, len+1);
+       if (!buf)
+               Sys_Error ("COM_LoadFile: not enough available memory for %s (size %i)", path, len);
 
        ((byte *)buf)[len] = 0;
 
-       Qread (h, buf, len);                     
+       Qread (h, buf, len);
        Qclose (h);
 
        return buf;
 }
 
-byte *COM_LoadHunkFile (char *path, qboolean quiet)
-{
-       return COM_LoadFile (path, 1, quiet);
-}
-
-// LordHavoc: returns malloc'd memory
-byte *COM_LoadMallocFile (char *path, qboolean quiet)
-{
-       return COM_LoadFile (path, 5, quiet);
-}
-
-/*
-void COM_LoadCacheFile (char *path, struct cache_user_s *cu, qboolean quiet)
-{
-       loadcache = cu;
-       COM_LoadFile (path, 3, quiet);
-}
-*/
-
 /*
 =================
 COM_LoadPackFile
@@ -1722,51 +1668,54 @@ pack_t *COM_LoadPackFile (char *packfile)
 {
        dpackheader_t   header;
        int                             i;
-       packfile_t              *newfiles;
        int                             numpackfiles;
        pack_t                  *pack;
        int                             packhandle;
-       // LordHavoc: changed from stack array to temporary malloc, allowing huge pack directories
+       // LordHavoc: changed from stack array to temporary alloc, allowing huge pack directories
        dpackfile_t             *info;
 
        if (Sys_FileOpenRead (packfile, &packhandle) == -1)
        {
-//              Con_Printf ("Couldn't open %s\n", packfile);
+               //Con_Printf ("Couldn't open %s\n", packfile);
                return NULL;
        }
        Sys_FileRead (packhandle, (void *)&header, sizeof(header));
-       if (header.id[0] != 'P' || header.id[1] != 'A'
-       || header.id[2] != 'C' || header.id[3] != 'K')
+       if (memcmp(header.id, "PACK", 4))
                Sys_Error ("%s is not a packfile", packfile);
        header.dirofs = LittleLong (header.dirofs);
        header.dirlen = LittleLong (header.dirlen);
 
+       if (header.dirlen % sizeof(dpackfile_t))
+               Sys_Error ("%s has an invalid directory size", packfile);
+
        numpackfiles = header.dirlen / sizeof(dpackfile_t);
 
        if (numpackfiles > MAX_FILES_IN_PACK)
                Sys_Error ("%s has %i files", packfile, numpackfiles);
 
-       newfiles = Hunk_AllocName (numpackfiles * sizeof(packfile_t), "pack file-table");
+       pack = Mem_Alloc(pak_mempool, sizeof (pack_t));
+       strcpy (pack->filename, packfile);
+       pack->handle = packhandle;
+       pack->numfiles = numpackfiles;
+       pack->mempool = Mem_AllocPool(packfile);
+       pack->files = Mem_Alloc(pack->mempool, numpackfiles * sizeof(packfile_t));
+       pack->next = packlist;
+       packlist = pack;
 
-       info = qmalloc(sizeof(*info)*MAX_FILES_IN_PACK);
+       info = Mem_Alloc(tempmempool, sizeof(*info) * numpackfiles);
        Sys_FileSeek (packhandle, header.dirofs);
        Sys_FileRead (packhandle, (void *)info, header.dirlen);
 
 // parse the directory
-       for (i=0 ; i<numpackfiles ; i++)
+       for (i = 0;i < numpackfiles;i++)
        {
-               strcpy (newfiles[i].name, info[i].name);
-               newfiles[i].filepos = LittleLong(info[i].filepos);
-               newfiles[i].filelen = LittleLong(info[i].filelen);
+               strcpy (pack->files[i].name, info[i].name);
+               pack->files[i].filepos = LittleLong(info[i].filepos);
+               pack->files[i].filelen = LittleLong(info[i].filelen);
        }
-       qfree(info);
 
-       pack = Hunk_AllocName (sizeof (pack_t), packfile);
-       strcpy (pack->filename, packfile);
-       pack->handle = packhandle;
-       pack->numfiles = numpackfiles;
-       pack->files = newfiles;
-       
+       Mem_Free(info);
+
        Con_Printf ("Added packfile %s (%i files)\n", packfile, numpackfiles);
        return pack;
 }
@@ -1777,7 +1726,7 @@ pack_t *COM_LoadPackFile (char *packfile)
 COM_AddGameDirectory
 
 Sets com_gamedir, adds the directory to the head of the path,
-then loads and adds pak1.pak pak2.pak ... 
+then loads and adds pak1.pak pak2.pak ...
 ================
 */
 void COM_AddGameDirectory (char *dir)
@@ -1792,7 +1741,7 @@ void COM_AddGameDirectory (char *dir)
 //
 // add the directory to the search path
 //
-       search = Hunk_AllocName (sizeof(searchpath_t), "pack info");
+       search = Mem_Alloc(pak_mempool, sizeof(searchpath_t));
        strcpy (search->filename, dir);
        search->next = com_searchpaths;
        com_searchpaths = search;
@@ -1806,7 +1755,7 @@ void COM_AddGameDirectory (char *dir)
                pak = COM_LoadPackFile (pakfile);
                if (!pak)
                        break;
-               search = Hunk_AllocName (sizeof(searchpath_t), "pack info");
+               search = Mem_Alloc(pak_mempool, sizeof(searchpath_t));
                search->pack = pak;
                search->next = com_searchpaths;
                com_searchpaths = search;
@@ -1919,7 +1868,7 @@ void COM_InitFilesystem (void)
                        if (!com_argv[i] || com_argv[i][0] == '+' || com_argv[i][0] == '-')
                                break;
 
-                       search = Hunk_AllocName (sizeof(searchpath_t), "pack info");
+                       search = Mem_Alloc(pak_mempool, sizeof(searchpath_t));
                        if ( !strcmp(COM_FileExtension(com_argv[i]), "pak") )
                        {
                                search->pack = COM_LoadPackFile (com_argv[i]);
index c7a0be34ac525a6b95bdeb4565e94d2fce4c547f..7d084f47f3fbc55ab44e16fd9bb2bb52ec9d6e73 100644 (file)
--- a/common.h
+++ b/common.h
@@ -19,18 +19,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
 // comndef.h  -- general definitions
 
-#if !defined BYTE_DEFINED
-typedef unsigned char          byte;
-#define BYTE_DEFINED 1
-#endif
-
-#undef true
-#undef false
-
-typedef enum {false, true}     qboolean;
-
-#include "quakeio.h"
-
 // LordHavoc: MSVC has a different name for snprintf
 #ifdef WIN32
 #define snprintf _snprintf
@@ -38,33 +26,23 @@ typedef enum {false, true}  qboolean;
 
 //============================================================================
 
-extern void *qmalloc(unsigned int size);
-extern void qfree(void *mem);
-
-//============================================================================
-
 typedef struct sizebuf_s
 {
        qboolean        allowoverflow;  // if false, do a Sys_Error
        qboolean        overflowed;             // set to true if the buffer size failed
-       byte    *data;
-       int             maxsize;
-       int             cursize;
+       byte            *data;
+       mempool_t       *mempool;
+       int                     maxsize;
+       int                     cursize;
 } sizebuf_t;
 
-void SZ_Alloc (sizebuf_t *buf, int startsize);
+void SZ_Alloc (sizebuf_t *buf, int startsize, char *name);
 void SZ_Free (sizebuf_t *buf);
 void SZ_Clear (sizebuf_t *buf);
 void *SZ_GetSpace (sizebuf_t *buf, int length);
 void SZ_Write (sizebuf_t *buf, void *data, int length);
 void SZ_Print (sizebuf_t *buf, char *data);    // strcats onto the sizebuf
 
-//============================================================================
-
-#ifndef NULL
-#define NULL ((void *)0)
-#endif
-
 //============================================================================
 #if !defined(ENDIAN_LITTLE) && !defined(ENDIAN_BIG)
 #if  defined(__i386__) || defined(__ia64__) || defined(WIN32) || (defined(__alpha__) || defined(__alpha)) || defined(__arm__) || (defined(__mips__) && defined(__MIPSEL__)) || defined(__LITTLE_ENDIAN__)
@@ -179,7 +157,7 @@ extern      int             com_argc;
 extern char    **com_argv;
 
 int COM_CheckParm (char *parm);
-void COM_Init (char *path);
+void COM_Init (void);
 void COM_InitArgv (int argc, char **argv);
 
 char *COM_SkipPath (char *pathname);
@@ -194,7 +172,6 @@ char        *va(char *format, ...);
 //============================================================================
 
 extern int com_filesize;
-struct cache_user_s;
 
 extern char    com_gamedir[MAX_OSPATH];
 
@@ -203,11 +180,7 @@ int COM_FOpenFile (char *filename, QFile **file, qboolean quiet, qboolean zip);
 
 // set by COM_LoadFile functions
 extern int loadsize;
-byte *COM_LoadHunkFile (char *path, qboolean quiet);
-byte *COM_LoadMallocFile (char *path, qboolean quiet);
-//void COM_LoadCacheFile (char *path, struct cache_user_s *cu, qboolean quiet);
-
-byte *COM_LoadFile (char *path, int usehunk, qboolean quiet);
+byte *COM_LoadFile (char *path, qboolean quiet);
 
 int COM_FileExists(char *filename);
 
index 69b093d9c6f8a20e8cba0d7c73b440f88162bf4c..d8654f31b4e62e8b3cb5e102a5a890557330e817 100644 (file)
--- a/console.c
+++ b/console.c
@@ -8,7 +8,7 @@ of the License, or (at your option) any later version.
 
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 See the GNU General Public License for more details.
 
@@ -63,10 +63,12 @@ extern      char    key_lines[32][MAXCMDLINE];
 extern int             edit_line;
 extern int             key_linepos;
 extern int             key_insert;
-               
+
 
 qboolean       con_initialized;
 
+mempool_t      *console_mempool;
+
 int            con_notifylines;                // scan lines to clear for notify lines
 
 extern void M_Menu_Main_f (void);
@@ -230,10 +232,11 @@ void Con_Init (void)
                        sprintf (temp, "%s%s", com_gamedir, t2);
                        unlink (temp);
                }
-               logfile.value = 1;
+               logfile.integer = 1;
        }
 
-       con_text = Hunk_AllocName (CON_TEXTSIZE, "context");
+       console_mempool = Mem_AllocPool("console");
+       con_text = Mem_Alloc(console_mempool, CON_TEXTSIZE);
        memset (con_text, ' ', CON_TEXTSIZE);
        con_linewidth = -1;
        Con_CheckResize ();
@@ -439,7 +442,7 @@ void Con_DPrintf (char *fmt, ...)
        va_list         argptr;
        char            msg[MAXPRINTMSG];
                
-       if (!developer.value)
+       if (!developer.integer)
                return;                 // don't confuse non-developers with techie stuff...
 
        va_start (argptr,fmt);
@@ -798,6 +801,6 @@ Con_CompleteCommandLine (void)
        }
        for (i = 0; i < 3; i++)
                if (list[i])
-                       qfree (list[i]);
+                       Mem_Free(list[i]);
 }
 
diff --git a/cvar.c b/cvar.c
index d38c5ba9eeda565bf22dc6b3c351e0521855c5d5..bee89d929f1aeaf6b7992ed7ac190cbbd846d9f1 100644 (file)
--- a/cvar.c
+++ b/cvar.c
@@ -144,7 +144,7 @@ Cvar_CompleteBuildList (char *partial)
        char    **buf;
 
        len = strlen(partial);
-       buf = qmalloc(sizeofbuf + sizeof (char *));
+       buf = Mem_Alloc(tempmempool, sizeofbuf + sizeof (char *));
        // Loop through the alias list and print all matches
        for (cvar = cvar_vars; cvar; cvar = cvar->next)
                if (!strncasecmp(partial, cvar->name, len))
@@ -178,6 +178,7 @@ void Cvar_Set (char *var_name, char *value)
        var->string = Z_Malloc (strlen(value)+1);
        strcpy (var->string, value);
        var->value = atof (var->string);
+       var->integer = (int) var->value;
        if ((var->flags & CVAR_NOTIFY) && changed)
        {
                if (sv.active)
@@ -229,6 +230,7 @@ void Cvar_RegisterVariable (cvar_t *variable)
        variable->string = Z_Malloc (strlen(variable->string)+1);
        strcpy (variable->string, oldstr);
        variable->value = atof (variable->string);
+       variable->integer = (int) variable->value;
 
 // link the variable in
        variable->next = cvar_vars;
diff --git a/cvar.h b/cvar.h
index 61871b68afda2303f853cef1ea65cbe090ef011b..0751a2da486cb7716d3c81e81bcd4c8a9e8b637c 100644 (file)
--- a/cvar.h
+++ b/cvar.h
@@ -97,7 +97,7 @@ typedef struct cvar_s
        char                    *string;
 //     qboolean                archive;                // set to true to cause it to be saved to vars.rc
 //     qboolean                server;         // notifies players when changed
-       int                             intvalue;
+       int                             integer;
        float                   value;
        float                   vector[3];
        menucvar_t              menuinfo;
diff --git a/draw.h b/draw.h
index 80ba2d18920dd96b6d27719f11a14da82c22a11e..b8b6ea3a4feb346ce99b40ad40c26f8988c8a63f 100644 (file)
--- a/draw.h
+++ b/draw.h
@@ -21,8 +21,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 // draw.h -- these are the only functions outside the refresh allowed
 // to touch the vid buffer
 
-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 (rtexture_t *tex, float red, float green, float blue, float alpha, int x, int y, int width, int height);
index 3425daf84dca34e94bb7881c1d1939d109176214..31b140d518972459b866a85687df6722d056efa3 100644 (file)
@@ -18,7 +18,7 @@ void fractalnoise(byte *noise, int size, int startgrid)
        startgrid = bound(0, startgrid, size);
 
        amplitude = 0xFFFF; // this gets halved before use
-       noisebuf = qmalloc(size*size*sizeof(int));
+       noisebuf = Mem_Alloc(tempmempool, size*size*sizeof(int));
        memset(noisebuf, 0, size*size*sizeof(int));
 
        for (g2 = startgrid;g2;g2 >>= 1)
@@ -60,6 +60,6 @@ void fractalnoise(byte *noise, int size, int startgrid)
        for (y = 0;y < size;y++)
                for (x = 0;x < size;x++)
                        *noise++ = (byte) (((n(x,y) - min) * 256) / max);
-       qfree(noisebuf);
+       Mem_Free(noisebuf);
 #undef n
 }
diff --git a/gl_backend.c b/gl_backend.c
new file mode 100644 (file)
index 0000000..adb0fcc
--- /dev/null
@@ -0,0 +1,979 @@
+
+#include "quakedef.h"
+
+static int max_meshs;
+static int max_batch;
+static int max_verts; // always max_meshs * 3
+#define TRANSDEPTHRES 4096
+
+static cvar_t gl_mesh_maxtriangles = {0, "gl_mesh_maxtriangles", "21760"};
+static cvar_t gl_mesh_batchtriangles = {0, "gl_mesh_batchtriangles", "1024"};
+static cvar_t gl_mesh_merge = {0, "gl_mesh_merge", "1"};
+static cvar_t gl_mesh_floatcolors = {0, "gl_mesh_floatcolors", "1"};
+
+typedef struct buf_mesh_s
+{
+       struct buf_mesh_s *next;
+       int depthmask;
+       int blendfunc1, blendfunc2;
+       int textures[MAX_TEXTUREUNITS];
+       float texturergbscale[MAX_TEXTUREUNITS];
+       int firsttriangle;
+       int triangles;
+}
+buf_mesh_t;
+
+typedef struct buf_transtri_s
+{
+       struct buf_transtri_s *next;
+       buf_mesh_t *mesh;
+       int index[3];
+}
+buf_transtri_t;
+
+typedef struct buf_tri_s
+{
+       int index[3];
+}
+buf_tri_t;
+
+typedef struct
+{
+       float v[4];
+}
+buf_vertex_t;
+
+typedef struct
+{
+       float c[4];
+}
+buf_fcolor_t;
+
+typedef struct
+{
+       byte c[4];
+}
+buf_bcolor_t;
+
+typedef struct
+{
+       float t[2];
+}
+buf_texcoord_t;
+
+static float meshfarclip;
+static int currentmesh, currenttriangle, currentvertex, backendunits, backendactive, meshmerge, floatcolors, transranout;
+static buf_mesh_t *buf_mesh;
+static buf_tri_t *buf_tri;
+static buf_vertex_t *buf_vertex;
+static buf_fcolor_t *buf_fcolor;
+static buf_bcolor_t *buf_bcolor;
+static buf_texcoord_t *buf_texcoord[MAX_TEXTUREUNITS];
+
+static int currenttransmesh, currenttransvertex, currenttranstriangle;
+static buf_mesh_t *buf_transmesh;
+static buf_transtri_t *buf_transtri;
+static buf_transtri_t **buf_transtri_list;
+static buf_vertex_t *buf_transvertex;
+static buf_fcolor_t *buf_transfcolor;
+static buf_bcolor_t *buf_transbcolor;
+static buf_texcoord_t *buf_transtexcoord[MAX_TEXTUREUNITS];
+
+static mempool_t *gl_backend_mempool;
+
+static void gl_backend_start(void)
+{
+       int i;
+
+       max_verts = max_meshs * 3;
+
+       gl_backend_mempool = Mem_AllocPool("GL_Backend");
+
+#define BACKENDALLOC(var, count, sizeofstruct)\
+       {\
+               var = Mem_Alloc(gl_backend_mempool, count * sizeof(sizeofstruct));\
+               if (var == NULL)\
+                       Sys_Error("gl_backend_start: unable to allocate memory\n");\
+               memset(var, 0, count * sizeof(sizeofstruct));\
+       }
+
+       BACKENDALLOC(buf_mesh, max_meshs, buf_mesh_t)
+       BACKENDALLOC(buf_tri, max_meshs, buf_tri_t)
+       BACKENDALLOC(buf_vertex, max_verts, buf_vertex_t)
+       BACKENDALLOC(buf_fcolor, max_verts, buf_fcolor_t)
+       BACKENDALLOC(buf_bcolor, max_verts, buf_bcolor_t)
+
+       BACKENDALLOC(buf_transmesh, max_meshs, buf_mesh_t)
+       BACKENDALLOC(buf_transtri, max_meshs, buf_transtri_t)
+       BACKENDALLOC(buf_transtri_list, TRANSDEPTHRES, buf_transtri_t *)
+       BACKENDALLOC(buf_transvertex, max_verts, buf_vertex_t)
+       BACKENDALLOC(buf_transfcolor, max_verts, buf_fcolor_t)
+       BACKENDALLOC(buf_transbcolor, max_verts, buf_bcolor_t)
+
+       for (i = 0;i < MAX_TEXTUREUNITS;i++)
+       {
+               // only allocate as many texcoord arrays as we need
+               if (i < gl_textureunits)
+               {
+                       BACKENDALLOC(buf_texcoord[i], max_verts, buf_texcoord_t)
+                       BACKENDALLOC(buf_transtexcoord[i], max_verts, buf_texcoord_t)
+               }
+               else
+               {
+                       buf_texcoord[i] = NULL;
+                       buf_transtexcoord[i] = NULL;
+               }
+       }
+       backendunits = min(MAX_TEXTUREUNITS, gl_textureunits);
+       backendactive = true;
+}
+
+static void gl_backend_shutdown(void)
+{
+       int i;
+       /*
+#define BACKENDFREE(var)\
+       if (var)\
+       {\
+               Mem_Free(var);\
+               var = NULL;\
+       }
+       */
+#define BACKENDFREE(var) var = NULL;
+
+       BACKENDFREE(buf_mesh)
+       BACKENDFREE(buf_tri)
+       BACKENDFREE(buf_vertex)
+       BACKENDFREE(buf_fcolor)
+       BACKENDFREE(buf_bcolor)
+
+       BACKENDFREE(buf_transmesh)
+       BACKENDFREE(buf_transtri)
+       BACKENDFREE(buf_transtri_list)
+       BACKENDFREE(buf_transvertex)
+       BACKENDFREE(buf_transfcolor)
+       BACKENDFREE(buf_transbcolor)
+
+       for (i = 0;i < MAX_TEXTUREUNITS;i++)
+       {
+               BACKENDFREE(buf_texcoord[i])
+               BACKENDFREE(buf_transtexcoord[i])
+       }
+
+       Mem_FreePool(&gl_backend_mempool);
+
+       backendunits = 0;
+       backendactive = false;
+}
+
+static void gl_backend_bufferchanges(int init)
+{
+       // 21760 is (65536 / 3) rounded off to a multiple of 128
+       if (gl_mesh_maxtriangles.integer < 256)
+               Cvar_SetValue("gl_mesh_maxtriangles", 256);
+       if (gl_mesh_maxtriangles.integer > 21760)
+               Cvar_SetValue("gl_mesh_maxtriangles", 21760);
+
+       if (gl_mesh_batchtriangles.integer < 0)
+               Cvar_SetValue("gl_mesh_batchtriangles", 0);
+       if (gl_mesh_batchtriangles.integer > gl_mesh_maxtriangles.integer)
+               Cvar_SetValue("gl_mesh_batchtriangles", gl_mesh_maxtriangles.integer);
+
+       max_batch = gl_mesh_batchtriangles.integer;
+
+       if (max_meshs != gl_mesh_maxtriangles.integer)
+       {
+               max_meshs = gl_mesh_maxtriangles.integer;
+
+               if (!init)
+               {
+                       gl_backend_shutdown();
+                       gl_backend_start();
+               }
+       }
+}
+
+float r_farclip, r_newfarclip;
+
+static void gl_backend_newmap(void)
+{
+       r_farclip = r_newfarclip = 2048.0f;
+}
+
+int polyindexarray[768];
+
+void gl_backend_init(void)
+{
+       int i;
+       Cvar_RegisterVariable(&gl_mesh_maxtriangles);
+       Cvar_RegisterVariable(&gl_mesh_batchtriangles);
+       Cvar_RegisterVariable(&gl_mesh_merge);
+       Cvar_RegisterVariable(&gl_mesh_floatcolors);
+       R_RegisterModule("GL_Backend", gl_backend_start, gl_backend_shutdown, gl_backend_newmap);
+       gl_backend_bufferchanges(true);
+       for (i = 0;i < 256;i++)
+       {
+               polyindexarray[i*3+0] = 0;
+               polyindexarray[i*3+1] = i + 1;
+               polyindexarray[i*3+2] = i + 2;
+       }
+}
+
+static float viewdist;
+
+int c_meshtris;
+
+// called at beginning of frame
+void R_Mesh_Clear(void)
+{
+       if (!backendactive)
+               Sys_Error("R_Mesh_Clear: called when backend is not active\n");
+
+       gl_backend_bufferchanges(false);
+
+       currentmesh = 0;
+       currenttriangle = 0;
+       currentvertex = 0;
+       currenttransmesh = 0;
+       currenttranstriangle = 0;
+       currenttransvertex = 0;
+       meshfarclip = 0;
+       meshmerge = gl_mesh_merge.integer;
+       floatcolors = gl_mesh_floatcolors.integer;
+       transranout = false;
+       viewdist = DotProduct(r_origin, vpn);
+
+       c_meshtris = 0;
+}
+
+#ifdef DEBUGGL
+void GL_PrintError(int errornumber, char *filename, int linenumber)
+{
+       switch(errornumber)
+       {
+       case GL_INVALID_ENUM:
+               Con_Printf("GL_INVALID_ENUM at %s:%i\n", filename, linenumber);
+               break;
+       case GL_INVALID_VALUE:
+               Con_Printf("GL_INVALID_VALUE at %s:%i\n", filename, linenumber);
+               break;
+       case GL_INVALID_OPERATION:
+               Con_Printf("GL_INVALID_OPERATION at %s:%i\n", filename, linenumber);
+               break;
+       case GL_STACK_OVERFLOW:
+               Con_Printf("GL_STACK_OVERFLOW at %s:%i\n", filename, linenumber);
+               break;
+       case GL_STACK_UNDERFLOW:
+               Con_Printf("GL_STACK_UNDERFLOW at %s:%i\n", filename, linenumber);
+               break;
+       case GL_OUT_OF_MEMORY:
+               Con_Printf("GL_OUT_OF_MEMORY at %s:%i\n", filename, linenumber);
+               break;
+       case GL_TABLE_TOO_LARGE:
+               Con_Printf("GL_TABLE_TOO_LARGE at %s:%i\n", filename, linenumber);
+               break;
+       default:
+               Con_Printf("GL UNKNOWN (%i) at %s:%i\n", errornumber, filename, linenumber);
+               break;
+       }
+}
+
+int errornumber = 0;
+#endif
+
+// renders mesh buffers, called to flush buffers when full
+void R_Mesh_Render(void)
+{
+       int i, k, blendfunc1, blendfunc2, blend, depthmask, unit = 0, clientunit = 0, firsttriangle, triangles, texture[MAX_TEXTUREUNITS];
+       float farclip, texturergbscale[MAX_TEXTUREUNITS];
+       buf_mesh_t *mesh;
+       if (!backendactive)
+               Sys_Error("R_Mesh_Render: called when backend is not active\n");
+       if (!currentmesh)
+               return;
+
+CHECKGLERROR
+
+       farclip = meshfarclip + 256.0f - viewdist; // + 256 just to be safe
+
+       // push out farclip for next frame
+       if (farclip > r_newfarclip)
+               r_newfarclip = ceil((farclip + 255) / 256) * 256 + 256;
+
+       for (i = 0;i < backendunits;i++)
+               texturergbscale[i] = 1;
+
+       glEnable(GL_CULL_FACE);
+CHECKGLERROR
+       glCullFace(GL_FRONT);
+CHECKGLERROR
+       glEnable(GL_DEPTH_TEST);
+CHECKGLERROR
+       blendfunc1 = GL_ONE;
+       blendfunc2 = GL_ZERO;
+       glBlendFunc(blendfunc1, blendfunc2);
+CHECKGLERROR
+       blend = 0;
+       glDisable(GL_BLEND);
+CHECKGLERROR
+       depthmask = 1;
+       glDepthMask(depthmask);
+CHECKGLERROR
+
+CHECKGLERROR
+       glVertexPointer(3, GL_FLOAT, sizeof(buf_vertex_t), buf_vertex);
+CHECKGLERROR
+       glEnableClientState(GL_VERTEX_ARRAY);
+CHECKGLERROR
+       if (floatcolors)
+       {
+               glColorPointer(4, GL_FLOAT, sizeof(buf_fcolor_t), buf_fcolor);
+CHECKGLERROR
+       }
+       else
+       {
+               glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(buf_bcolor_t), buf_bcolor);
+CHECKGLERROR
+       }
+       glEnableClientState(GL_COLOR_ARRAY);
+CHECKGLERROR
+
+       if (backendunits > 1)
+       {
+               for (i = 0;i < backendunits;i++)
+               {
+                       glActiveTextureARB(GL_TEXTURE0_ARB + (unit = i));
+CHECKGLERROR
+                       glBindTexture(GL_TEXTURE_2D, (texture[i] = 0));
+CHECKGLERROR
+                       glDisable(GL_TEXTURE_2D);
+CHECKGLERROR
+                       if (gl_combine.integer)
+                       {
+                               glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
+CHECKGLERROR
+                               glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
+CHECKGLERROR
+                               glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
+CHECKGLERROR
+                               glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB);
+CHECKGLERROR
+                               glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_ARB, GL_CONSTANT_ARB);
+CHECKGLERROR
+                               glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
+CHECKGLERROR
+                               glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
+CHECKGLERROR
+                               glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_ARB, GL_SRC_ALPHA);
+CHECKGLERROR
+                               glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_MODULATE);
+CHECKGLERROR
+                               glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
+CHECKGLERROR
+                               glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, GL_PREVIOUS_ARB);
+CHECKGLERROR
+                               glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_ARB, GL_CONSTANT_ARB);
+CHECKGLERROR
+                               glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
+CHECKGLERROR
+                               glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_ARB, GL_SRC_ALPHA);
+CHECKGLERROR
+                               glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_ARB, GL_SRC_ALPHA);
+CHECKGLERROR
+                               glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1.0f);
+CHECKGLERROR
+                               glTexEnvf(GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1.0f);
+CHECKGLERROR
+                       }
+                       else
+                       {
+                               glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+CHECKGLERROR
+                       }
+
+                       glClientActiveTextureARB(GL_TEXTURE0_ARB + (clientunit = i));
+CHECKGLERROR
+                       glTexCoordPointer(2, GL_FLOAT, sizeof(buf_texcoord_t), buf_texcoord[i]);
+CHECKGLERROR
+                       glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+CHECKGLERROR
+               }
+       }
+       else
+       {
+               glBindTexture(GL_TEXTURE_2D, (texture[0] = 0));
+CHECKGLERROR
+               glDisable(GL_TEXTURE_2D);
+CHECKGLERROR
+               glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+CHECKGLERROR
+
+               glTexCoordPointer(2, GL_FLOAT, sizeof(buf_texcoord_t), buf_texcoord[0]);
+CHECKGLERROR
+               glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+CHECKGLERROR
+       }
+
+       // lock as early as possible
+       GL_LockArray(0, currentvertex);
+CHECKGLERROR
+
+       for (k = 0;k < currentmesh;)
+       {
+               mesh = &buf_mesh[k];
+
+               if (backendunits > 1)
+               {
+//                     int topunit = 0;
+                       for (i = 0;i < backendunits;i++)
+                       {
+                               if (texture[i] != mesh->textures[i])
+                               {
+                                       if (unit != i)
+                                       {
+                                               glActiveTextureARB(GL_TEXTURE0_ARB + (unit = i));
+CHECKGLERROR
+                                       }
+                                       if (texture[i] == 0)
+                                       {
+                                               glEnable(GL_TEXTURE_2D);
+CHECKGLERROR
+                                               // have to disable texcoord array on disabled texture
+                                               // units due to NVIDIA driver bug with
+                                               // compiled_vertex_array
+                                               if (clientunit != i)
+                                               {
+                                                       glClientActiveTextureARB(GL_TEXTURE0_ARB + (clientunit = i));
+CHECKGLERROR
+                                               }
+                                               glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+CHECKGLERROR
+                                       }
+                                       glBindTexture(GL_TEXTURE_2D, (texture[i] = mesh->textures[i]));
+CHECKGLERROR
+                                       if (texture[i] == 0)
+                                       {
+                                               glDisable(GL_TEXTURE_2D);
+CHECKGLERROR
+                                               // have to disable texcoord array on disabled texture
+                                               // units due to NVIDIA driver bug with
+                                               // compiled_vertex_array
+                                               if (clientunit != i)
+                                               {
+                                                       glClientActiveTextureARB(GL_TEXTURE0_ARB + (clientunit = i));
+CHECKGLERROR
+                                               }
+                                               glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+CHECKGLERROR
+                                       }
+                               }
+                               if (texturergbscale[i] != mesh->texturergbscale[i])
+                               {
+                                       if (unit != i)
+                                       {
+                                               glActiveTextureARB(GL_TEXTURE0_ARB + (unit = i));
+CHECKGLERROR
+                                       }
+                                       glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, (texturergbscale[i] = mesh->texturergbscale[i]));
+CHECKGLERROR
+                               }
+//                             if (texture[i])
+//                                     topunit = i;
+                       }
+//                     if (unit != topunit)
+//                     {
+//                             glActiveTextureARB(GL_TEXTURE0_ARB + (unit = topunit));
+//CHECKGLERROR
+//                     }
+               }
+               else
+               {
+                       if (texture[0] != mesh->textures[0])
+                       {
+                               if (texture[0] == 0)
+                               {
+                                       glEnable(GL_TEXTURE_2D);
+CHECKGLERROR
+                                       glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+CHECKGLERROR
+                               }
+                               glBindTexture(GL_TEXTURE_2D, (texture[0] = mesh->textures[0]));
+CHECKGLERROR
+                               if (texture[0] == 0)
+                               {
+                                       glDisable(GL_TEXTURE_2D);
+CHECKGLERROR
+                                       glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+CHECKGLERROR
+                               }
+                       }
+               }
+               if (blendfunc1 != mesh->blendfunc1 || blendfunc2 != mesh->blendfunc2)
+               {
+                       blendfunc1 = mesh->blendfunc1;
+                       blendfunc2 = mesh->blendfunc2;
+                       glBlendFunc(blendfunc1, blendfunc2);
+CHECKGLERROR
+                       if (blendfunc2 == GL_ZERO)
+                       {
+                               if (blendfunc1 == GL_ONE)
+                               {
+                                       if (blend)
+                                       {
+                                               blend = 0;
+                                               glDisable(GL_BLEND);
+CHECKGLERROR
+                                       }
+                               }
+                               else
+                               {
+                                       if (!blend)
+                                       {
+                                               blend = 1;
+                                               glEnable(GL_BLEND);
+CHECKGLERROR
+                                       }
+                               }
+                       }
+                       else
+                       {
+                               if (!blend)
+                               {
+                                       blend = 1;
+                                       glEnable(GL_BLEND);
+CHECKGLERROR
+                               }
+                       }
+               }
+               if (depthmask != mesh->depthmask)
+               {
+                       depthmask = mesh->depthmask;
+                       glDepthMask(depthmask);
+CHECKGLERROR
+               }
+
+               firsttriangle = mesh->firsttriangle;
+               triangles = mesh->triangles;
+               mesh = &buf_mesh[++k];
+
+               if (meshmerge)
+               {
+                       #if MAX_TEXTUREUNITS != 4
+                       #error update this code
+                       #endif
+                       while (k < currentmesh
+                               && mesh->blendfunc1 == blendfunc1
+                               && mesh->blendfunc2 == blendfunc2
+                               && mesh->depthmask == depthmask
+                               && mesh->textures[0] == texture[0]
+                               && mesh->textures[1] == texture[1]
+                               && mesh->textures[2] == texture[2]
+                               && mesh->textures[3] == texture[3]
+                               && mesh->texturergbscale[0] == texturergbscale[0]
+                               && mesh->texturergbscale[1] == texturergbscale[1]
+                               && mesh->texturergbscale[2] == texturergbscale[2]
+                               && mesh->texturergbscale[3] == texturergbscale[3])
+                       {
+                               triangles += mesh->triangles;
+                               mesh = &buf_mesh[++k];
+                       }
+               }
+
+               glDrawElements(GL_TRIANGLES, triangles * 3, GL_UNSIGNED_INT, (unsigned int *)&buf_tri[firsttriangle]);
+CHECKGLERROR
+       }
+
+       currentmesh = 0;
+       currenttriangle = 0;
+       currentvertex = 0;
+
+       GL_UnlockArray();
+CHECKGLERROR
+
+       if (backendunits > 1)
+       {
+               for (i = backendunits - 1;i >= 0;i--)
+               {
+                       glActiveTextureARB(GL_TEXTURE0_ARB + (unit = i));
+CHECKGLERROR
+                       glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+CHECKGLERROR
+                       if (gl_combine.integer)
+                       {
+                               glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1.0f);
+CHECKGLERROR
+                       }
+                       if (i > 0)
+                       {
+                               glDisable(GL_TEXTURE_2D);
+CHECKGLERROR
+                       }
+                       else
+                       {
+                               glEnable(GL_TEXTURE_2D);
+CHECKGLERROR
+                       }
+                       glBindTexture(GL_TEXTURE_2D, 0);
+CHECKGLERROR
+
+                       glClientActiveTextureARB(GL_TEXTURE0_ARB + (clientunit = i));
+CHECKGLERROR
+                       glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+CHECKGLERROR
+               }
+       }
+       else
+       {
+               glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+CHECKGLERROR
+               glEnable(GL_TEXTURE_2D);
+CHECKGLERROR
+               glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+CHECKGLERROR
+       }
+       glDisableClientState(GL_COLOR_ARRAY);
+CHECKGLERROR
+       glDisableClientState(GL_VERTEX_ARRAY);
+CHECKGLERROR
+
+       glDisable(GL_BLEND);
+CHECKGLERROR
+       glDepthMask(1);
+CHECKGLERROR
+       glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+CHECKGLERROR
+}
+
+void R_Mesh_AddTransparent(void)
+{
+       int i, j, k;
+       float viewdistcompare, centerscaler, dist1, dist2, dist3, center, maxdist;
+       buf_vertex_t *vert1, *vert2, *vert3;
+       buf_transtri_t *tri;
+       buf_mesh_t *mesh;
+
+       // process and add transparent mesh triangles
+       if (!currenttranstriangle)
+               return;
+
+       // map farclip to 0-4095 list range
+       centerscaler = (TRANSDEPTHRES / r_farclip) * (1.0f / 3.0f);
+       viewdistcompare = viewdist + 4.0f;
+
+       memset(buf_transtri_list, 0, TRANSDEPTHRES * sizeof(buf_transtri_t *));
+
+       // process in reverse because transtri_list adding code is in reverse as well
+       k = 0;
+       for (j = currenttranstriangle - 1;j >= 0;j--)
+       {
+               tri = &buf_transtri[j];
+
+               vert1 = &buf_transvertex[tri->index[0]];
+               vert2 = &buf_transvertex[tri->index[1]];
+               vert3 = &buf_transvertex[tri->index[2]];
+
+               dist1 = DotProduct(vert1->v, vpn);
+               dist2 = DotProduct(vert2->v, vpn);
+               dist3 = DotProduct(vert3->v, vpn);
+
+               maxdist = max(dist1, max(dist2, dist3));
+               if (maxdist < viewdistcompare)
+                       continue;
+
+               center = (dist1 + dist2 + dist3) * centerscaler - viewdist;
+#if SLOWMATH
+               i = (int) center;
+               i = bound(0, i, (TRANSDEPTHRES - 1));
+#else
+               if (center < 0.0f)
+                       center = 0.0f;
+               center += 8388608.0f;
+               i = *((long *)&center) & 0x7FFFFF;
+               i = min(i, (TRANSDEPTHRES - 1));
+#endif
+               tri->next = buf_transtri_list[i];
+               buf_transtri_list[i] = tri;
+               k++;
+       }
+
+       if (currentmesh + k > max_meshs || currenttriangle + k > max_batch || currentvertex + currenttransvertex > max_verts)
+               R_Mesh_Render();
+
+       // note: can't batch these because they can be rendered in any order
+       // there can never be more transparent triangles than fit in main buffers
+       memcpy(&buf_vertex[currentvertex], &buf_transvertex[0], currenttransvertex * sizeof(buf_vertex_t));
+       if (floatcolors)
+               memcpy(&buf_fcolor[currentvertex], &buf_transfcolor[0], currenttransvertex * sizeof(buf_fcolor_t));
+       else
+               memcpy(&buf_fcolor[currentvertex], &buf_transbcolor[0], currenttransvertex * sizeof(buf_bcolor_t));
+       for (i = 0;i < backendunits;i++)
+               memcpy(&buf_texcoord[i][currentvertex], &buf_transtexcoord[i][0], currenttransvertex * sizeof(buf_texcoord_t));
+
+       for (j = TRANSDEPTHRES - 1;j >= 0;j--)
+       {
+               if ((tri = buf_transtri_list[j]))
+               {
+                       while(tri)
+                       {
+                               mesh = &buf_mesh[currentmesh++];
+                               *mesh = *tri->mesh; // copy mesh properties
+                               buf_tri[currenttriangle].index[0] = tri->index[0] + currentvertex;
+                               buf_tri[currenttriangle].index[1] = tri->index[1] + currentvertex;
+                               buf_tri[currenttriangle].index[2] = tri->index[2] + currentvertex;
+                               mesh->firsttriangle = currenttriangle++;
+                               mesh->triangles = 1;
+                               tri = tri->next;
+                       }
+               }
+       }
+       currentvertex += currenttransvertex;
+       currenttransmesh = 0;
+       currenttranstriangle = 0;
+       currenttransvertex = 0;
+}
+
+void R_Mesh_Draw(const rmeshinfo_t *m)
+{
+       static int i, j, *index, overbright;
+       static float c, *in, scaler, cr, cg, cb, ca;
+       static buf_mesh_t *mesh;
+       static buf_vertex_t *vert;
+       static buf_fcolor_t *fcolor;
+       static buf_bcolor_t *bcolor;
+       static buf_texcoord_t *texcoord[MAX_TEXTUREUNITS];
+       static buf_transtri_t *tri;
+       static byte br, bg, bb, ba;
+
+       if (m->index == NULL
+        || !m->numtriangles
+        || m->vertex == NULL
+        || !m->numverts)
+               return;
+
+       if (!backendactive)
+               Sys_Error("R_DrawMesh: called when backend is not active\n");
+
+       if (m->transparent)
+       {
+               if (currenttransmesh >= max_meshs || (currenttranstriangle + m->numtriangles) > max_meshs || (currenttransvertex + m->numverts) > max_verts)
+               {
+                       if (!transranout)
+                       {
+                               Con_Printf("R_DrawMesh: ran out of room for transparent meshs\n");
+                               transranout = true;
+                       }
+                       return;
+               }
+
+               vert = &buf_transvertex[currenttransvertex];
+               fcolor = &buf_transfcolor[currenttransvertex];
+               bcolor = &buf_transbcolor[currenttransvertex];
+               for (i = 0;i < backendunits;i++)
+                       texcoord[i] = &buf_transtexcoord[i][currenttransvertex];
+       }
+       else
+       {
+               if (m->numtriangles > max_meshs || m->numverts > max_verts)
+               {
+                       Con_Printf("R_DrawMesh: mesh too big for buffers\n");
+                       return;
+               }
+
+               if (currentmesh >= max_meshs || (currenttriangle + m->numtriangles) > max_batch || (currentvertex + m->numverts) > max_verts)
+                       R_Mesh_Render();
+
+               vert = &buf_vertex[currentvertex];
+               fcolor = &buf_fcolor[currentvertex];
+               bcolor = &buf_bcolor[currentvertex];
+               for (i = 0;i < backendunits;i++)
+                       texcoord[i] = &buf_texcoord[i][currentvertex];
+       }
+
+       // vertex array code is shared for transparent and opaque meshs
+
+       for (i = 0, in = m->vertex;i < m->numverts;i++, (int)in += m->vertexstep)
+       {
+               vert[i].v[0] = in[0];
+               vert[i].v[1] = in[1];
+               vert[i].v[2] = in[2];
+               // push out farclip based on vertices encountered
+               c = DotProduct(vert[i].v, vpn);
+               if (meshfarclip < c)
+                       meshfarclip = c;
+       }
+
+       scaler = 1;
+       if (m->blendfunc2 == GL_SRC_COLOR)
+       {
+               if (m->blendfunc1 == GL_DST_COLOR) // 2x modulate with framebuffer
+                       scaler *= 0.5f;
+       }
+       else
+       {
+               if (m->tex[0])
+               {
+                       overbright = gl_combine.integer;
+                       if (overbright)
+                               scaler *= 0.25f;
+               }
+               if (lighthalf)
+                       scaler *= 0.5f;
+       }
+
+       if (floatcolors)
+       {
+               if (m->color)
+               {
+                       for (i = 0, in = m->color;i < m->numverts;i++, (int)in += m->colorstep)
+                       {
+                               fcolor[i].c[0] = in[0] * scaler;
+                               fcolor[i].c[1] = in[1] * scaler;
+                               fcolor[i].c[2] = in[2] * scaler;
+                               fcolor[i].c[3] = in[3];
+                       }
+               }
+               else
+               {
+                       cr = m->cr * scaler;
+                       cg = m->cg * scaler;
+                       cb = m->cb * scaler;
+                       ca = m->ca;
+                       for (i = 0;i < m->numverts;i++)
+                       {
+                               fcolor[i].c[0] = cr;
+                               fcolor[i].c[1] = cg;
+                               fcolor[i].c[2] = cb;
+                               fcolor[i].c[3] = ca;
+                       }
+               }
+       }
+       else
+       {
+               if (m->color)
+               {
+                       for (i = 0, in = m->color;i < m->numverts;i++, (int)in += m->colorstep)
+                       {
+                               // shift float to have 8bit fraction at base of number,
+                               // then read as integer and kill float bits...
+                               c = in[0] * scaler + 32768.0f;j = (*((long *)&c) & 0x7FFFFF);if (j > 255) j = 255;bcolor[i].c[0] = (byte) j;
+                               c = in[1] * scaler + 32768.0f;j = (*((long *)&c) & 0x7FFFFF);if (j > 255) j = 255;bcolor[i].c[1] = (byte) j;
+                               c = in[2] * scaler + 32768.0f;j = (*((long *)&c) & 0x7FFFFF);if (j > 255) j = 255;bcolor[i].c[2] = (byte) j;
+                               c = in[3]          + 32768.0f;j = (*((long *)&c) & 0x7FFFFF);if (j > 255) j = 255;bcolor[i].c[3] = (byte) j;
+                       }
+               }
+               else
+               {
+                       c = in[0] * scaler + 32768.0f;j = (*((long *)&c) & 0x7FFFFF);if (j > 255) j = 255;br = (byte) j;
+                       c = in[1] * scaler + 32768.0f;j = (*((long *)&c) & 0x7FFFFF);if (j > 255) j = 255;bg = (byte) j;
+                       c = in[2] * scaler + 32768.0f;j = (*((long *)&c) & 0x7FFFFF);if (j > 255) j = 255;bb = (byte) j;
+                       c = in[3]          + 32768.0f;j = (*((long *)&c) & 0x7FFFFF);if (j > 255) j = 255;ba = (byte) j;
+                       for (i = 0;i < m->numverts;i++)
+                       {
+                               bcolor[i].c[0] = br;
+                               bcolor[i].c[1] = bg;
+                               bcolor[i].c[2] = bb;
+                               bcolor[i].c[3] = ba;
+                       }
+               }
+       }
+
+       for (j = 0;j < MAX_TEXTUREUNITS && m->tex[j];j++)
+       {
+               if (j >= backendunits)
+                       Sys_Error("R_DrawMesh: texture %i supplied when there are only %i texture units\n", j + 1, backendunits);
+               for (i = 0, in = m->texcoords[j];i < m->numverts;i++, (int)in += m->texcoordstep[j])
+               {
+                       texcoord[j][i].t[0] = in[0];
+                       texcoord[j][i].t[1] = in[1];
+               }
+       }
+       for (;j < backendunits;j++)
+       {
+               for (i = 0;i < m->numverts;i++)
+               {
+                       texcoord[j][i].t[0] = 0;
+                       texcoord[j][i].t[1] = 0;
+               }
+       }
+
+       if (m->transparent)
+       {
+               // transmesh is only for storage of tranparent meshs until they
+               // are inserted into the main mesh array
+               mesh = &buf_transmesh[currenttransmesh++];
+               mesh->blendfunc1 = m->blendfunc1;
+               mesh->blendfunc2 = m->blendfunc2;
+               mesh->depthmask = false;
+               j = -1;
+               for (i = 0;i < backendunits;i++)
+               {
+                       if ((mesh->textures[i] = m->tex[i]))
+                               j = i;
+                       mesh->texturergbscale[i] = m->texrgbscale[i];
+                       if (mesh->texturergbscale[i] != 1 && mesh->texturergbscale[i] != 2 && mesh->texturergbscale[i] != 4)
+                               mesh->texturergbscale[i] = 1;
+               }
+               if (overbright && j >= 0)
+                       mesh->texturergbscale[j] = 4;
+
+               // transparent meshs are broken up into individual triangles which can
+               // be sorted by depth
+               index = m->index;
+               for (i = 0;i < m->numtriangles;i++)
+               {
+                       tri = &buf_transtri[currenttranstriangle++];
+                       tri->mesh = mesh;
+                       tri->index[0] = *index++ + currenttransvertex;
+                       tri->index[1] = *index++ + currenttransvertex;
+                       tri->index[2] = *index++ + currenttransvertex;
+               }
+               currenttransvertex += m->numverts;
+       }
+       else
+       {
+               mesh = &buf_mesh[currentmesh++];
+               mesh->blendfunc1 = m->blendfunc1;
+               mesh->blendfunc2 = m->blendfunc2;
+               mesh->depthmask = (m->blendfunc2 == GL_ZERO || m->depthwrite);
+               mesh->firsttriangle = currenttriangle;
+               mesh->triangles = m->numtriangles;
+               j = -1;
+               for (i = 0;i < backendunits;i++)
+               {
+                       if ((mesh->textures[i] = m->tex[i]))
+                               j = i;
+                       mesh->texturergbscale[i] = m->texrgbscale[i];
+                       if (mesh->texturergbscale[i] != 1 && mesh->texturergbscale[i] != 2 && mesh->texturergbscale[i] != 4)
+                               mesh->texturergbscale[i] = 1;
+               }
+               if (overbright && j >= 0)
+                       mesh->texturergbscale[j] = 4;
+
+               // opaque meshs are rendered directly
+               index = (int *)&buf_tri[currenttriangle];
+               for (i = 0;i < m->numtriangles * 3;i++)
+                       index[i] = m->index[i] + currentvertex;
+               currenttriangle += m->numtriangles;
+               currentvertex += m->numverts;
+       }
+
+       c_meshtris += m->numtriangles;
+}
+
+void R_Mesh_DrawPolygon(rmeshinfo_t *m, int numverts)
+{
+       m->index = polyindexarray;
+       m->numverts = numverts;
+       m->numtriangles = numverts - 2;
+       if (m->numtriangles < 1)
+       {
+               Con_Printf("R_Mesh_DrawPolygon: invalid vertex count\n");
+               return;
+       }
+       if (m->numtriangles >= 256)
+       {
+               Con_Printf("R_Mesh_DrawPolygon: only up to 256 triangles (258 verts) supported\n");
+               return;
+       }
+       R_Mesh_Draw(m);
+}
diff --git a/gl_backend.h b/gl_backend.h
new file mode 100644 (file)
index 0000000..c9f98d4
--- /dev/null
@@ -0,0 +1,41 @@
+
+#define MAX_TEXTUREUNITS 4
+
+extern int c_meshtris;
+
+typedef struct
+{
+       int transparent;
+       int depthwrite; // force depth writing enabled even if polygon is not opaque
+       int blendfunc1;
+       int blendfunc2;
+       int numtriangles;
+       int *index;
+       int numverts;
+       float *vertex;
+       int vertexstep;
+       float *color;
+       int colorstep;
+       // if color is NULL, these are used for all vertices
+       float cr, cg, cb, ca;
+       int tex[MAX_TEXTUREUNITS];
+       float *texcoords[MAX_TEXTUREUNITS];
+       int texcoordstep[MAX_TEXTUREUNITS];
+       float texrgbscale[MAX_TEXTUREUNITS]; // used only if COMBINE is present
+}
+rmeshinfo_t;
+
+// adds console variables and registers the render module (only call from GL_Init)
+void gl_backend_init(void);
+// sets up mesh renderer for the frame
+void R_Mesh_Clear(void);
+// renders queued meshs
+void R_Mesh_Render(void);
+// queues a mesh to be rendered (invokes Render if queue is full)
+void R_Mesh_Draw(const rmeshinfo_t *m);
+// renders the queued transparent meshs
+void R_Mesh_AddTransparent(void);
+// ease-of-use frontend to R_Mesh_Draw, set up meshinfo, except for index and numtriangles and numverts, then call this
+void R_Mesh_DrawPolygon(rmeshinfo_t *m, int numverts);
+// ease-of-use frontend to R_Mesh_Draw for particles, no speed gain
+void R_Mesh_DrawParticle(vec3_t org, vec3_t right, vec3_t up, vec_t scale, int texnum, float cr, float cg, float cb, float ca, float s1, float t1, float s2, float t2, float fs1, float ft1, float fs2, float ft2);
\ No newline at end of file
index bf3de8f98252d974c1098baaca33aa57e3aa9236..d9eebeb44ca70bc0f7bed524152ff8be6eb0380c 100644 (file)
--- a/gl_draw.c
+++ b/gl_draw.c
@@ -8,7 +8,7 @@ of the License, or (at your option) any later version.
 
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 See the GNU General Public License for more details.
 
@@ -18,18 +18,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 */
 
-// draw.c -- this is the only file outside the refresh that touches the
-// vid buffer
-
 #include "quakedef.h"
 
 //#define GL_COLOR_INDEX8_EXT     0x80E5
 
 cvar_t         scr_conalpha = {CVAR_SAVE, "scr_conalpha", "1"};
 
-byte           *draw_chars;                            // 8*8 graphic characters
-qpic_t         *draw_disc;
-
 rtexture_t     *char_texture;
 
 typedef struct
@@ -45,45 +39,38 @@ rtexture_t  *conbacktex;
 typedef struct cachepic_s
 {
        char            name[MAX_QPATH];
+       // FIXME: qpic is evil
        qpic_t          pic;
        byte            padding[32];    // for appended glpic
-} cachepic_t;
+}
+cachepic_t;
 
-#define        MAX_CACHED_PICS         128
+#define        MAX_CACHED_PICS         256
 cachepic_t     menu_cachepics[MAX_CACHED_PICS];
 int                    menu_numcachepics;
 
 byte           menuplyr_pixels[4096];
 
-int            pic_texels;
-int            pic_count;
-
-qpic_t *Draw_PicFromWad (char *name)
-{
-       qpic_t  *p;
-       glpic_t *gl;
-
-       p = W_GetLumpName (name);
-       gl = (glpic_t *)p->data;
-
-       gl->tex = R_LoadTexture (name, p->width, p->height, p->data, TEXF_ALPHA | TEXF_PRECACHE);
-       return p;
-}
+int                    pic_texels;
+int                    pic_count;
 
+rtexturepool_t *drawtexturepool;
 
 /*
 ================
 Draw_CachePic
 ================
 */
+// FIXME: qpic is evil
 qpic_t *Draw_CachePic (char *path)
 {
        cachepic_t      *pic;
        int                     i;
        qpic_t          *dat;
        glpic_t         *gl;
+       rtexture_t      *tex;
 
-       for (pic=menu_cachepics, i=0 ; i<menu_numcachepics ; pic++, i++)
+       for (pic = menu_cachepics, i = 0;i < menu_numcachepics;pic++, i++)
                if (!strcmp (path, pic->name))
                        return &pic->pic;
 
@@ -92,31 +79,43 @@ qpic_t      *Draw_CachePic (char *path)
        menu_numcachepics++;
        strcpy (pic->name, path);
 
-//
-// load the pic from disk
-//
-       dat = (qpic_t *)COM_LoadMallocFile (path, false);
-       if (!dat)
-               Sys_Error ("Draw_CachePic: failed to load %s", path);
-       SwapPic (dat);
-
+       // FIXME: move this to menu code
        // HACK HACK HACK --- we need to keep the bytes for
        // the translatable player picture just for the menu
        // configuration dialog
        if (!strcmp (path, "gfx/menuplyr.lmp"))
-               memcpy (menuplyr_pixels, dat->data, dat->width*dat->height);
-
-       pic->pic.width = dat->width;
-       pic->pic.height = dat->height;
-
-       gl = (glpic_t *)pic->pic.data;
-       gl->tex = loadtextureimage(path, 0, 0, false, false, true);
-       if (!gl->tex)
-               gl->tex = R_LoadTexture (path, dat->width, dat->height, dat->data, TEXF_ALPHA | TEXF_PRECACHE);
+       {
+               dat = (qpic_t *)COM_LoadFile (path, false);
+               if (!dat)
+                       Sys_Error("unable to load gfx/menuplyr.lmp");
+               SwapPic (dat);
 
-       qfree(dat);
+               memcpy (menuplyr_pixels, dat->data, dat->width*dat->height);
+       }
 
-       return &pic->pic;
+       // load the pic from disk
+       if ((tex = loadtextureimage(drawtexturepool, path, 0, 0, false, false, true)))
+       {
+               // load the pic from an image file
+               pic->pic.width = image_width;
+               pic->pic.height = image_height;
+               gl = (glpic_t *)pic->pic.data;
+               gl->tex = tex;
+               return &pic->pic;
+       }
+       else
+       {
+               qpic_t *p;
+               // load the pic from gfx.wad
+               p = W_GetLumpName (path);
+               if (!p)
+                       Sys_Error ("Draw_CachePic: failed to load %s", path);
+               pic->pic.width = p->width;
+               pic->pic.height = p->height;
+               gl = (glpic_t *)pic->pic.data;
+               gl->tex = R_LoadTexture (drawtexturepool, path, p->width, p->height, p->data, TEXTYPE_QPALETTE, TEXF_ALPHA | TEXF_PRECACHE);
+               return &pic->pic;
+       }
 }
 
 /*
@@ -124,51 +123,58 @@ qpic_t    *Draw_CachePic (char *path)
 Draw_Init
 ===============
 */
-void gl_draw_start(void)
+static void gl_draw_start(void)
 {
-       int             i;
+       int i;
+       byte *draw_chars;
+
+       menu_numcachepics = 0;
 
-       char_texture = loadtextureimage ("conchars", 0, 0, false, false, true);
+       drawtexturepool = R_AllocTexturePool();
+       char_texture = loadtextureimage (drawtexturepool, "conchars", 0, 0, false, false, true);
        if (!char_texture)
        {
                draw_chars = W_GetLumpName ("conchars");
-               for (i=0 ; i<128*128 ; i++)
+               // convert font to proper transparent color
+               for (i = 0;i < 128 * 128;i++)
                        if (draw_chars[i] == 0)
-                               draw_chars[i] = 255;    // proper transparent color
+                               draw_chars[i] = 255;
 
-               // now turn them into textures
-               char_texture = R_LoadTexture ("charset", 128, 128, draw_chars, TEXF_ALPHA | TEXF_PRECACHE);
+               // now turn into texture
+               char_texture = R_LoadTexture (drawtexturepool, "charset", 128, 128, draw_chars, TEXTYPE_QPALETTE, TEXF_ALPHA | TEXF_PRECACHE);
        }
 
-       conbacktex = loadtextureimage("gfx/conback", 0, 0, false, false, true);
-
-       // get the other pics we need
-       draw_disc = Draw_PicFromWad ("disc");
+       conbacktex = loadtextureimage(drawtexturepool, "gfx/conback", 0, 0, false, false, true);
 }
 
-void gl_draw_shutdown(void)
+static void gl_draw_shutdown(void)
 {
+       R_FreeTexturePool(&drawtexturepool);
+
+       menu_numcachepics = 0;
 }
 
-void gl_draw_newmap(void)
+void SHOWLMP_clear(void);
+static void gl_draw_newmap(void)
 {
+       SHOWLMP_clear();
 }
 
 extern char engineversion[40];
 int engineversionx, engineversiony;
 
-extern void R_Textures_Init();
 void GL_Draw_Init (void)
 {
        int i;
        Cvar_RegisterVariable (&scr_conalpha);
 
        for (i = 0;i < 40 && engineversion[i];i++)
-               engineversion[i] += 0x80; // shift to orange
+               engineversion[i] |= 0x80; // shift to orange
        engineversionx = vid.conwidth - strlen(engineversion) * 8 - 8;
        engineversiony = vid.conheight - 8;
 
-       R_Textures_Init();
+       menu_numcachepics = 0;
+
        R_RegisterModule("GL_Draw", gl_draw_start, gl_draw_shutdown, gl_draw_newmap);
 }
 
@@ -201,25 +207,31 @@ void Draw_Character (int x, int y, int num)
        fcol = col*0.0625;
        size = 0.0625;
 
-       if (!r_render.value)
+       if (!r_render.integer)
                return;
        glBindTexture(GL_TEXTURE_2D, R_GetTexture(char_texture));
+       CHECKGLERROR
        // LordHavoc: NEAREST mode on text if not scaling up
        if (vid.realwidth <= (int) vid.conwidth)
        {
                glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+               CHECKGLERROR
                glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+               CHECKGLERROR
        }
        else
        {
                glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+               CHECKGLERROR
                glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+               CHECKGLERROR
        }
 
        if (lighthalf)
                glColor3f(0.5f,0.5f,0.5f);
        else
                glColor3f(1.0f,1.0f,1.0f);
+       CHECKGLERROR
        glBegin (GL_QUADS);
        glTexCoord2f (fcol, frow);
        glVertex2f (x, y);
@@ -230,6 +242,7 @@ void Draw_Character (int x, int y, int num)
        glTexCoord2f (fcol, frow + size);
        glVertex2f (x, y+8);
        glEnd ();
+       CHECKGLERROR
 
        // LordHavoc: revert to LINEAR mode
 //     if (vid.realwidth <= (int) vid.conwidth)
@@ -249,7 +262,7 @@ void Draw_String (int x, int y, char *str, int maxlen)
 {
        int num;
        float frow, fcol;
-       if (!r_render.value)
+       if (!r_render.integer)
                return;
        if (y <= -8 || y >= (int) vid.conheight || x >= (int) vid.conwidth || *str == 0) // completely offscreen or no text to print
                return;
@@ -263,18 +276,23 @@ void Draw_String (int x, int y, char *str, int maxlen)
        if (vid.realwidth <= (int) vid.conwidth)
        {
                glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+               CHECKGLERROR
                glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+               CHECKGLERROR
        }
        else
        {
                glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+               CHECKGLERROR
                glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+               CHECKGLERROR
        }
 
        if (lighthalf)
                glColor3f(0.5f,0.5f,0.5f);
        else
                glColor3f(1.0f,1.0f,1.0f);
+       CHECKGLERROR
        glBegin (GL_QUADS);
        while (maxlen-- && x < (int) vid.conwidth) // stop rendering when out of characters or room
        {
@@ -290,6 +308,7 @@ void Draw_String (int x, int y, char *str, int maxlen)
                x += 8;
        }
        glEnd ();
+       CHECKGLERROR
 
        // LordHavoc: revert to LINEAR mode
 //     if (vid.realwidth < (int) vid.conwidth)
@@ -301,28 +320,33 @@ void Draw_String (int x, int y, char *str, int maxlen)
 
 void Draw_AdditiveString (int x, int y, char *str, int maxlen)
 {
-       if (!r_render.value)
+       if (!r_render.integer)
                return;
        glBlendFunc(GL_SRC_ALPHA, GL_ONE);
+       CHECKGLERROR
        Draw_String(x, y, str, maxlen);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+       CHECKGLERROR
 }
 
 void Draw_GenericPic (rtexture_t *tex, float red, float green, float blue, float alpha, int x, int y, int width, int height)
 {
-       if (!r_render.value)
+       if (!r_render.integer)
                return;
        if (lighthalf)
                glColor4f(red * 0.5f, green * 0.5f, blue * 0.5f, alpha);
        else
                glColor4f(red, green, blue, alpha);
+       CHECKGLERROR
        glBindTexture(GL_TEXTURE_2D, R_GetTexture(tex));
+       CHECKGLERROR
        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 ();
+       CHECKGLERROR
 }
 
 /*
@@ -354,8 +378,10 @@ void Draw_AdditivePic (int x, int y, qpic_t *pic)
        if (pic)
        {
                glBlendFunc(GL_SRC_ALPHA, GL_ONE);
+               CHECKGLERROR
                Draw_GenericPic(((glpic_t *)pic->data)->tex, 1,1,1,1, x,y,pic->width, pic->height);
                glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+               CHECKGLERROR
        }
 }
 
@@ -378,14 +404,14 @@ void Draw_PicTranslate (int x, int y, qpic_t *pic, byte *translation)
 
        c = pic->width * pic->height;
        src = menuplyr_pixels;
-       dest = trans = qmalloc(c);
+       dest = trans = Mem_Alloc(tempmempool, c);
        for (i = 0;i < c;i++)
                *dest++ = translation[*src++];
 
-       rt = R_LoadTexture ("translatedplayerpic", pic->width, pic->height, trans, TEXF_ALPHA | TEXF_PRECACHE);
-       qfree(trans);
+       rt = R_LoadTexture (drawtexturepool, "translatedplayerpic", pic->width, pic->height, trans, TEXTYPE_QPALETTE, TEXF_ALPHA | TEXF_PRECACHE);
+       Mem_Free(trans);
 
-       if (!r_render.value)
+       if (!r_render.integer)
                return;
        Draw_GenericPic (rt, 1,1,1,1, x, y, pic->width, pic->height);
 }
@@ -413,9 +439,10 @@ Fills a box of pixels with a single color
 */
 void Draw_Fill (int x, int y, int w, int h, int c)
 {
-       if (!r_render.value)
+       if (!r_render.integer)
                return;
        glDisable (GL_TEXTURE_2D);
+       CHECKGLERROR
        if (lighthalf)
        {
                byte *tempcolor = (byte *)&d_8to24table[c];
@@ -423,6 +450,7 @@ void Draw_Fill (int x, int y, int w, int h, int c)
        }
        else
                glColor4ubv ((byte *)&d_8to24table[c]);
+       CHECKGLERROR
 
        glBegin (GL_QUADS);
 
@@ -432,8 +460,11 @@ void Draw_Fill (int x, int y, int w, int h, int c)
        glVertex2f (x, y+h);
 
        glEnd ();
+       CHECKGLERROR
        glColor3f(1,1,1);
+       CHECKGLERROR
        glEnable (GL_TEXTURE_2D);
+       CHECKGLERROR
 }
 //=============================================================================
 
@@ -448,28 +479,40 @@ Setup as if the screen was 320*200
 */
 void GL_Set2D (void)
 {
-       if (!r_render.value)
+       if (!r_render.integer)
                return;
        glViewport (vid.realx, vid.realy, vid.realwidth, vid.realheight);
+       CHECKGLERROR
 
        glMatrixMode(GL_PROJECTION);
+       CHECKGLERROR
     glLoadIdentity ();
+       CHECKGLERROR
        glOrtho  (0, vid.conwidth, vid.conheight, 0, -99999, 99999);
+       CHECKGLERROR
 
        glMatrixMode(GL_MODELVIEW);
+       CHECKGLERROR
     glLoadIdentity ();
+       CHECKGLERROR
 
        glDisable (GL_DEPTH_TEST);
+       CHECKGLERROR
        glDisable (GL_CULL_FACE);
+       CHECKGLERROR
        glEnable (GL_BLEND);
-       glDisable (GL_ALPHA_TEST);
+       CHECKGLERROR
        glEnable(GL_TEXTURE_2D);
+       CHECKGLERROR
 
        // LordHavoc: added this
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+       CHECKGLERROR
        glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+       CHECKGLERROR
 
        glColor3f(1,1,1);
+       CHECKGLERROR
 }
 
 // LordHavoc: SHOWLMP stuff
index 1a18c9512d3be1f57b9bb5994517a782149ba1fe..8684a8f025330e1618eb752f0062ca976108be7b 100644 (file)
@@ -1,7 +1,7 @@
 
 #include "quakedef.h"
 
-cvar_t gl_transform = {0, "gl_transform", "1"};
+//cvar_t gl_transform = {0, "gl_transform", "1"};
 cvar_t gl_lockarrays = {0, "gl_lockarrays", "1"};
 
 typedef struct
@@ -12,17 +12,19 @@ typedef struct
 // LordHavoc: vertex array
 float *aliasvert;
 float *aliasvertnorm;
-byte *aliasvertcolor;
-byte *aliasvertcolor2;
+float *aliasvertcolor;
+float *aliasvertcolor2;
 zymbonematrix *zymbonepose;
 int *aliasvertusage;
 
+rmeshinfo_t aliasmeshinfo;
+
 rtexture_t *chrometexture;
 
 int arraylocked = false;
 void GL_LockArray(int first, int count)
 {
-       if (gl_supportslockarrays && gl_lockarrays.value)
+       if (gl_supportslockarrays && gl_lockarrays.integer)
        {
                qglLockArraysEXT(first, count);
                arraylocked = true;
@@ -38,6 +40,7 @@ void GL_UnlockArray(void)
        }
 }
 
+/*
 void GL_SetupModelTransform (vec3_t origin, vec3_t angles, vec_t scale)
 {
     glTranslatef (origin[0], origin[1], origin[2]);
@@ -51,6 +54,9 @@ void GL_SetupModelTransform (vec3_t origin, vec3_t angles, vec_t scale)
        if (angles[2])
            glRotatef (angles[2],  1, 0, 0);
 }
+*/
+
+rtexturepool_t *chrometexturepool;
 
 // currently unused reflection effect texture
 void makechrometexture(void)
@@ -68,29 +74,29 @@ void makechrometexture(void)
                data[i][3] = 255;
        }
 
-       chrometexture = R_LoadTexture ("chrometexture", 64, 64, &data[0][0], TEXF_MIPMAP | TEXF_RGBA | TEXF_PRECACHE);
+       chrometexture = R_LoadTexture (chrometexturepool, "chrometexture", 64, 64, &data[0][0], TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_PRECACHE);
 }
 
+mempool_t *gl_models_mempool;
+
 void gl_models_start(void)
 {
        // allocate vertex processing arrays
-       aliasvert = qmalloc(sizeof(float[MD2MAX_VERTS][3]));
-       aliasvertnorm = qmalloc(sizeof(float[MD2MAX_VERTS][3]));
-       aliasvertcolor = qmalloc(sizeof(byte[MD2MAX_VERTS][4]));
-       aliasvertcolor2 = qmalloc(sizeof(byte[MD2MAX_VERTS][4])); // used temporarily for tinted coloring
-       zymbonepose = qmalloc(sizeof(zymbonematrix[256]));
-       aliasvertusage = qmalloc(sizeof(int[MD2MAX_VERTS]));
+       gl_models_mempool = Mem_AllocPool("GL_Models");
+       aliasvert = Mem_Alloc(gl_models_mempool, sizeof(float[MD2MAX_VERTS][3]));
+       aliasvertnorm = Mem_Alloc(gl_models_mempool, sizeof(float[MD2MAX_VERTS][3]));
+       aliasvertcolor = Mem_Alloc(gl_models_mempool, sizeof(float[MD2MAX_VERTS][4]));
+       aliasvertcolor2 = Mem_Alloc(gl_models_mempool, sizeof(float[MD2MAX_VERTS][4])); // used temporarily for tinted coloring
+       zymbonepose = Mem_Alloc(gl_models_mempool, sizeof(zymbonematrix[256]));
+       aliasvertusage = Mem_Alloc(gl_models_mempool, sizeof(int[MD2MAX_VERTS]));
+       chrometexturepool = R_AllocTexturePool();
        makechrometexture();
 }
 
 void gl_models_shutdown(void)
 {
-       qfree(aliasvert);
-       qfree(aliasvertnorm);
-       qfree(aliasvertcolor);
-       qfree(aliasvertcolor2);
-       qfree(zymbonepose);
-       qfree(aliasvertusage);
+       R_FreeTexturePool(&chrometexturepool);
+       Mem_FreePool(&gl_models_mempool);
 }
 
 void gl_models_newmap(void)
@@ -99,7 +105,7 @@ void gl_models_newmap(void)
 
 void GL_Models_Init(void)
 {
-       Cvar_RegisterVariable(&gl_transform);
+//     Cvar_RegisterVariable(&gl_transform);
        Cvar_RegisterVariable(&gl_lockarrays);
 
        R_RegisterModule("GL_Models", gl_models_start, gl_models_shutdown, gl_models_newmap);
@@ -107,34 +113,27 @@ void GL_Models_Init(void)
 
 void R_AliasTransformVerts(int vertcount)
 {
-       int i;
-       vec3_t point, matrix_x, matrix_y, matrix_z;
+       vec3_t point;
        float *av, *avn;
        av = aliasvert;
        avn = aliasvertnorm;
-       matrix_x[0] = softwaretransform_x[0] * softwaretransform_scale;
-       matrix_x[1] = softwaretransform_y[0] * softwaretransform_scale;
-       matrix_x[2] = softwaretransform_z[0] * softwaretransform_scale;
-       matrix_y[0] = softwaretransform_x[1] * softwaretransform_scale;
-       matrix_y[1] = softwaretransform_y[1] * softwaretransform_scale;
-       matrix_y[2] = softwaretransform_z[1] * softwaretransform_scale;
-       matrix_z[0] = softwaretransform_x[2] * softwaretransform_scale;
-       matrix_z[1] = softwaretransform_y[2] * softwaretransform_scale;
-       matrix_z[2] = softwaretransform_z[2] * softwaretransform_scale;
-       for (i = 0;i < vertcount;i++)
+       while (vertcount >= 4)
+       {
+               VectorCopy(av, point);softwaretransform(point, av);av += 3;
+               VectorCopy(av, point);softwaretransform(point, av);av += 3;
+               VectorCopy(av, point);softwaretransform(point, av);av += 3;
+               VectorCopy(av, point);softwaretransform(point, av);av += 3;
+               VectorCopy(avn, point);softwaretransformdirection(point, avn);avn += 3;
+               VectorCopy(avn, point);softwaretransformdirection(point, avn);avn += 3;
+               VectorCopy(avn, point);softwaretransformdirection(point, avn);avn += 3;
+               VectorCopy(avn, point);softwaretransformdirection(point, avn);avn += 3;
+               vertcount -= 4;
+       }
+       while(vertcount > 0)
        {
-               // rotate, scale, and translate the vertex locations
-               VectorCopy(av, point);
-               av[0] = DotProduct(point, matrix_x) + softwaretransform_offset[0];
-               av[1] = DotProduct(point, matrix_y) + softwaretransform_offset[1];
-               av[2] = DotProduct(point, matrix_z) + softwaretransform_offset[2];
-               // rotate the normals
-               VectorCopy(avn, point);
-               avn[0] = point[0] * softwaretransform_x[0] + point[1] * softwaretransform_y[0] + point[2] * softwaretransform_z[0];
-               avn[1] = point[0] * softwaretransform_x[1] + point[1] * softwaretransform_y[1] + point[2] * softwaretransform_z[1];
-               avn[2] = point[0] * softwaretransform_x[2] + point[1] * softwaretransform_y[2] + point[2] * softwaretransform_z[2];
-               av += 3;
-               avn += 3;
+               VectorCopy(av, point);softwaretransform(point, av);av += 3;
+               VectorCopy(avn, point);softwaretransformdirection(point, avn);avn += 3;
+               vertcount--;
        }
 }
 
@@ -266,254 +265,229 @@ void R_AliasLerpVerts(int vertcount,
        }
 }
 
-void GL_DrawModelMesh(rtexture_t *skin, byte *colors, maliashdr_t *m)
+void GL_DrawModelMesh(rtexture_t *skin, float *colors, float cred, float cgreen, float cblue)
 {
-       if (!r_render.value)
-               return;
-       glBindTexture(GL_TEXTURE_2D, R_GetTexture(skin));
-       if (!colors)
+       aliasmeshinfo.tex[0] = R_GetTexture(skin);
+       aliasmeshinfo.color = colors;
+       if (colors == NULL)
        {
-               if (lighthalf)
-                       glColor3f(0.5f, 0.5f, 0.5f);
-               else
-                       glColor3f(1.0f, 1.0f, 1.0f);
-       }
-       if (colors)
-       {
-               glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(byte[4]), colors);
-               glEnableClientState(GL_COLOR_ARRAY);
+               aliasmeshinfo.cr = cred;
+               aliasmeshinfo.cg = cgreen;
+               aliasmeshinfo.cb = cblue;
+               aliasmeshinfo.ca = currentrenderentity->alpha;
        }
 
-       glDrawElements(GL_TRIANGLES, m->numtris * 3, GL_UNSIGNED_SHORT, (void *)((int) m + m->tridata));
+       R_Mesh_Draw(&aliasmeshinfo);
 
-       if (colors)
-               glDisableClientState(GL_COLOR_ARRAY);
        // leave it in a state for additional passes
-       glDepthMask(0);
-       glEnable(GL_BLEND);
-       glBlendFunc(GL_SRC_ALPHA, GL_ONE); // additive
+       aliasmeshinfo.blendfunc1 = GL_SRC_ALPHA;
+       aliasmeshinfo.blendfunc2 = GL_ONE;
 }
 
-void R_TintModel(byte *in, byte *out, int verts, byte *color)
+void R_TintModel(float *in, float *out, int verts, float r, float g, float b)
 {
        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];
+               out[0] = in[0] * r;
+               out[1] = in[1] * g;
+               out[2] = in[2] * b;
+               out[3] = in[3];
                in += 4;
                out += 4;
        }
 }
 
-/*
-=================
-R_DrawAliasFrame
-
-=================
-*/
-void R_DrawAliasFrame (void)
+void R_SetupMDLMD2Frames(skinframe_t **skinframe)
 {
-       maliashdr_t *m = Mod_Extradata(currentrenderentity->model);
-//     int *skinanimrange = (int *) (currentrenderentity->model->skinanimrange + (int) modelheader) + skin * 2;
-//     int *skinanim = (int *) (currentrenderentity->model->skinanim + (int) modelheader);
-       int *skinanimrange = currentrenderentity->model->skinanimrange;
-       int skin;
-       rtexture_t **skinanim = currentrenderentity->model->skinanim;
-       rtexture_t **skinset;
-
-       skinanimrange += currentrenderentity->skinnum * 2;
-       skin = skinanimrange[0];
-       if (skinanimrange[1] > 1) // animated
-               skin += (int) (cl.time * 10) % skinanimrange[1];
-       skinset = skinanim + skin * 5;
-
-       if (gl_transform.value)
-       {
-               if (r_render.value)
-               {
-                       glPushMatrix();
-                       GL_SetupModelTransform(currentrenderentity->origin, currentrenderentity->angles, currentrenderentity->scale);
-               }
-       }
-       // always needed, for model lighting
+       md2frame_t *frame1, *frame2, *frame3, *frame4;
+       trivertx_t *frame1verts, *frame2verts, *frame3verts, *frame4verts;
+       model_t *model;
+       model = currentrenderentity->model;
+
+       if (model->skinscenes[currentrenderentity->skinnum].framecount > 1)
+               *skinframe = &model->skinframes[model->skinscenes[currentrenderentity->skinnum].firstframe + (int) (cl.time * 10) % model->skinscenes[currentrenderentity->skinnum].framecount];
+       else
+               *skinframe = &model->skinframes[model->skinscenes[currentrenderentity->skinnum].firstframe];
+
        softwaretransformforentity(currentrenderentity);
 
-       R_AliasLerpVerts(m->numverts,
-               currentrenderentity->frameblend[0].lerp, ((trivertx_t *)((int) m + m->posedata)) + currentrenderentity->frameblend[0].frame * m->numverts, m->scale, m->scale_origin,
-               currentrenderentity->frameblend[1].lerp, ((trivertx_t *)((int) m + m->posedata)) + currentrenderentity->frameblend[1].frame * m->numverts, m->scale, m->scale_origin,
-               currentrenderentity->frameblend[2].lerp, ((trivertx_t *)((int) m + m->posedata)) + currentrenderentity->frameblend[2].frame * m->numverts, m->scale, m->scale_origin,
-               currentrenderentity->frameblend[3].lerp, ((trivertx_t *)((int) m + m->posedata)) + currentrenderentity->frameblend[3].frame * m->numverts, m->scale, m->scale_origin);
+       frame1 = &model->mdlmd2data_frames[currentrenderentity->frameblend[0].frame];
+       frame2 = &model->mdlmd2data_frames[currentrenderentity->frameblend[1].frame];
+       frame3 = &model->mdlmd2data_frames[currentrenderentity->frameblend[2].frame];
+       frame4 = &model->mdlmd2data_frames[currentrenderentity->frameblend[3].frame];
+       frame1verts = &model->mdlmd2data_pose[currentrenderentity->frameblend[0].frame * model->numverts];
+       frame2verts = &model->mdlmd2data_pose[currentrenderentity->frameblend[1].frame * model->numverts];
+       frame3verts = &model->mdlmd2data_pose[currentrenderentity->frameblend[2].frame * model->numverts];
+       frame4verts = &model->mdlmd2data_pose[currentrenderentity->frameblend[3].frame * model->numverts];
+       /*
+       if (currentrenderentity->frameblend[0].lerp)
+               Con_Printf("frame1: %i/%i %s scale %f %f %f translate %f %f %f\n", currentrenderentity->frameblend[0].frame, model->numframes, frame1->name, frame1->scale[0], frame1->scale[1], frame1->scale[2], frame1->translate[0], frame1->translate[1], frame1->translate[2]);
+       if (currentrenderentity->frameblend[1].lerp)
+               Con_Printf("frame2: %i/%i %s scale %f %f %f translate %f %f %f\n", currentrenderentity->frameblend[0].frame, model->numframes, frame2->name, frame2->scale[0], frame2->scale[1], frame2->scale[2], frame2->translate[0], frame2->translate[1], frame2->translate[2]);
+       if (currentrenderentity->frameblend[2].lerp)
+               Con_Printf("frame3: %i/%i %s scale %f %f %f translate %f %f %f\n", currentrenderentity->frameblend[0].frame, model->numframes, frame3->name, frame3->scale[0], frame3->scale[1], frame3->scale[2], frame3->translate[0], frame3->translate[1], frame3->translate[2]);
+       if (currentrenderentity->frameblend[3].lerp)
+               Con_Printf("frame4: %i/%i %s scale %f %f %f translate %f %f %f\n", currentrenderentity->frameblend[0].frame, model->numframes, frame4->name, frame4->scale[0], frame4->scale[1], frame4->scale[2], frame4->translate[0], frame4->translate[1], frame4->translate[2]);
+       */
+       R_AliasLerpVerts(model->numverts,
+               currentrenderentity->frameblend[0].lerp, frame1verts, frame1->scale, frame1->translate,
+               currentrenderentity->frameblend[1].lerp, frame2verts, frame2->scale, frame2->translate,
+               currentrenderentity->frameblend[2].lerp, frame3verts, frame3->scale, frame3->translate,
+               currentrenderentity->frameblend[3].lerp, frame4verts, frame4->scale, frame4->translate);
+       R_AliasTransformVerts(model->numverts);
+
+       R_LightModel(model->numverts);
+}
+
+void R_DrawQ1AliasModel (void)
+{
+       float fog;
+       vec3_t diff;
+       model_t *model;
+       skinframe_t *skinframe;
+
+       model = currentrenderentity->model;
 
-       if (!gl_transform.value)
-               R_AliasTransformVerts(m->numverts);
+       R_SetupMDLMD2Frames(&skinframe);
 
-       // prep the vertex array as early as possible
-       if (r_render.value)
+       memset(&aliasmeshinfo, 0, sizeof(aliasmeshinfo));
+
+       aliasmeshinfo.vertex = aliasvert;
+       aliasmeshinfo.vertexstep = sizeof(float[3]);
+       aliasmeshinfo.numverts = model->numverts;
+       aliasmeshinfo.numtriangles = model->numtris;
+       aliasmeshinfo.index = model->mdldata_indices;
+       aliasmeshinfo.colorstep = sizeof(float[4]);
+       aliasmeshinfo.texcoords[0] = model->mdldata_texcoords;
+       aliasmeshinfo.texcoordstep[0] = sizeof(float[2]);
+
+       fog = 0;
+       if (fogenabled)
        {
-               glVertexPointer(3, GL_FLOAT, sizeof(float[3]), aliasvert);
-               glEnableClientState(GL_VERTEX_ARRAY);
-               glTexCoordPointer(2, GL_FLOAT, sizeof(float[2]), (void *)((int) m->texdata + (int) m));
-               glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-               GL_LockArray(0, m->numverts);
+               VectorSubtract(currentrenderentity->origin, r_origin, diff);
+               fog = exp(fogdensity/DotProduct(diff,diff));
+               if (fog > 1)
+                       fog = 1;
+               if (fog < 0.01f)
+                       fog = 0;
+               // fog method: darken, additive fog
+               // 1. render model as normal, scaled by inverse of fog alpha (darkens it)
+               // 2. render fog as additive
        }
 
-       R_LightModel(m->numverts);
-
-       if (!r_render.value)
-               return;
-       glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-//     glShadeModel(GL_SMOOTH);
        if (currentrenderentity->effects & EF_ADDITIVE)
        {
-               glBlendFunc(GL_SRC_ALPHA, GL_ONE); // additive rendering
-               glEnable(GL_BLEND);
-               glDepthMask(0);
+               aliasmeshinfo.transparent = true;
+               aliasmeshinfo.blendfunc1 = GL_SRC_ALPHA;
+               aliasmeshinfo.blendfunc2 = GL_ONE;
        }
-       else if (currentrenderentity->alpha != 1.0 || (currentrenderentity->model->flags2 & MODF_TRANSPARENT))
+       else if (currentrenderentity->alpha != 1.0 || skinframe->fog != NULL)
        {
-               glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-               glEnable(GL_BLEND);
-               glDepthMask(0);
+               aliasmeshinfo.transparent = true;
+               aliasmeshinfo.blendfunc1 = GL_SRC_ALPHA;
+               aliasmeshinfo.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
        }
        else
        {
-               glDisable(GL_BLEND);
-               glDepthMask(1);
+               aliasmeshinfo.transparent = false;
+               aliasmeshinfo.blendfunc1 = GL_ONE;
+               aliasmeshinfo.blendfunc2 = GL_ZERO;
        }
 
-       if (skinset[0] || skinset[1] || skinset[2] || skinset[3] || skinset[4])
+       // darken source
+       if (fog)
+               R_TintModel(aliasvertcolor, aliasvertcolor, model->numverts, 1 - fog, 1 - fog, 1 - fog);
+
+       if (skinframe->base || skinframe->pants || skinframe->shirt || skinframe->glow || skinframe->merged)
        {
-               if (currentrenderentity->colormap >= 0 && (skinset[0] || skinset[1] || skinset[2]))
+               if (currentrenderentity->colormap >= 0 && (skinframe->base || skinframe->pants || skinframe->shirt))
                {
                        int c;
-                       if (skinset[0])
-                               GL_DrawModelMesh(skinset[0], aliasvertcolor, m);
-                       if (skinset[1])
+                       byte *color;
+                       if (skinframe->base)
+                               GL_DrawModelMesh(skinframe->base, aliasvertcolor, 0, 0, 0);
+                       if (skinframe->pants)
                        {
                                c = (currentrenderentity->colormap & 0xF) << 4;c += (c >= 128 && c < 224) ? 4 : 12; // 128-224 are backwards ranges
-                               R_TintModel(aliasvertcolor, aliasvertcolor2, m->numverts, (byte *) (&d_8to24table[c]));
-                               GL_DrawModelMesh(skinset[1], aliasvertcolor2, m);
+                               color = (byte *) (&d_8to24table[c]);
+                               if (c >= 224) // fullbright ranges
+                                       GL_DrawModelMesh(skinframe->pants, NULL, color[0] * (1.0f / 255.0f), color[1] * (1.0f / 255.0f), color[2] * (1.0f / 255.0f));
+                               else
+                               {
+                                       R_TintModel(aliasvertcolor, aliasvertcolor2, model->numverts, color[0] * (1.0f / 255.0f), color[1] * (1.0f / 255.0f), color[2] * (1.0f / 255.0f));
+                                       GL_DrawModelMesh(skinframe->pants, aliasvertcolor2, 0, 0, 0);
+                               }
                        }
-                       if (skinset[2])
+                       if (skinframe->shirt)
                        {
                                c = currentrenderentity->colormap & 0xF0      ;c += (c >= 128 && c < 224) ? 4 : 12; // 128-224 are backwards ranges
-                               R_TintModel(aliasvertcolor, aliasvertcolor2, m->numverts, (byte *) (&d_8to24table[c]));
-                               GL_DrawModelMesh(skinset[2], aliasvertcolor2, m);
+                               color = (byte *) (&d_8to24table[c]);
+                               if (c >= 224) // fullbright ranges
+                                       GL_DrawModelMesh(skinframe->shirt, NULL, color[0] * (1.0f / 255.0f), color[1] * (1.0f / 255.0f), color[2] * (1.0f / 255.0f));
+                               else
+                               {
+                                       R_TintModel(aliasvertcolor, aliasvertcolor2, model->numverts, color[0] * (1.0f / 255.0f), color[1] * (1.0f / 255.0f), color[2] * (1.0f / 255.0f));
+                                       GL_DrawModelMesh(skinframe->shirt, aliasvertcolor2, 0, 0, 0);
+                               }
                        }
                }
                else
                {
-                       if (skinset[4])
-                               GL_DrawModelMesh(skinset[4], aliasvertcolor, m);
+                       if (skinframe->merged)
+                               GL_DrawModelMesh(skinframe->merged, aliasvertcolor, 0, 0, 0);
                        else
                        {
-                               if (skinset[0]) GL_DrawModelMesh(skinset[0], aliasvertcolor, m);
-                               if (skinset[1]) GL_DrawModelMesh(skinset[1], aliasvertcolor, m);
-                               if (skinset[2]) GL_DrawModelMesh(skinset[2], aliasvertcolor, m);
+                               if (skinframe->base) GL_DrawModelMesh(skinframe->base, aliasvertcolor, 0, 0, 0);
+                               if (skinframe->pants) GL_DrawModelMesh(skinframe->pants, aliasvertcolor, 0, 0, 0);
+                               if (skinframe->shirt) GL_DrawModelMesh(skinframe->shirt, aliasvertcolor, 0, 0, 0);
                        }
                }
-               if (skinset[3]) GL_DrawModelMesh(skinset[3], NULL, m);
+               if (skinframe->glow) GL_DrawModelMesh(skinframe->glow, NULL, 1 - fog, 1 - fog, 1 - fog);
        }
        else
-               GL_DrawModelMesh(0, NULL, m);
+               GL_DrawModelMesh(0, NULL, 1 - fog, 1 - fog, 1 - fog);
 
-       if (fogenabled)
+       if (fog)
        {
-               vec3_t diff;
-               glDisable (GL_TEXTURE_2D);
-               glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-               glEnable (GL_BLEND);
-               glDepthMask(0); // disable zbuffer updates
+               aliasmeshinfo.tex[0] = R_GetTexture(skinframe->fog);
+               aliasmeshinfo.blendfunc1 = GL_SRC_ALPHA;
+               aliasmeshinfo.blendfunc2 = GL_ONE;
+               aliasmeshinfo.color = NULL;
 
-               VectorSubtract(currentrenderentity->origin, r_origin, diff);
-               glColor4f(fogcolor[0], fogcolor[1], fogcolor[2], exp(fogdensity/DotProduct(diff,diff)));
+               aliasmeshinfo.cr = fogcolor[0];
+               aliasmeshinfo.cg = fogcolor[1];
+               aliasmeshinfo.cb = fogcolor[2];
+               aliasmeshinfo.ca = currentrenderentity->alpha * fog;
 
-               glDrawElements(GL_TRIANGLES, m->numtris * 3, GL_UNSIGNED_SHORT, (void *)((int) m + m->tridata));
-
-               glEnable (GL_TEXTURE_2D);
-               glColor3f (1,1,1);
+               R_Mesh_Draw(&aliasmeshinfo);
        }
-
-       GL_UnlockArray();
-       glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-       glDisableClientState(GL_VERTEX_ARRAY);
-
-       glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-       glEnable (GL_BLEND);
-       glDepthMask(1);
-
-       glPopMatrix();
 }
 
-/*
-=================
-R_DrawQ2AliasFrame
-
-=================
-*/
-void R_DrawQ2AliasFrame (void)
+void R_DrawQ2AliasModel (void)
 {
        int *order, count;
-       md2frame_t *frame1, *frame2, *frame3, *frame4;
        vec3_t diff;
-       md2mem_t *m = Mod_Extradata(currentrenderentity->model);
-//     int *skinanimrange = (int *) (currentrenderentity->model->skinanimrange + (int) modelheader) + skin * 2;
-//     int *skinanim = (int *) (currentrenderentity->model->skinanim + (int) modelheader);
-       int *skinanimrange = currentrenderentity->model->skinanimrange;
-       int skin;
-       rtexture_t **skinanim = currentrenderentity->model->skinanim;
-       rtexture_t **skinset;
-
-       skinanimrange += currentrenderentity->skinnum * 2;
-       skin = skinanimrange[0];
-       if (skinanimrange[1] > 1) // animated
-               skin += (int) (cl.time * 10) % skinanimrange[1];
-       skinset = skinanim + skin * 5;
-
-       if (r_render.value)
-               glBindTexture(GL_TEXTURE_2D, R_GetTexture(skinset[0]));
-
-       if (gl_transform.value)
-       {
-               if (r_render.value)
-               {
-                       glPushMatrix();
-                       GL_SetupModelTransform(currentrenderentity->origin, currentrenderentity->angles, currentrenderentity->scale);
-               }
-       }
-       // always needed, for model lighting
-       softwaretransformforentity(currentrenderentity);
+       skinframe_t *skinframe;
+       model_t *model;
 
-       frame1 = (void *)((int) m + m->ofs_frames + (m->framesize * currentrenderentity->frameblend[0].frame));
-       frame2 = (void *)((int) m + m->ofs_frames + (m->framesize * currentrenderentity->frameblend[1].frame));
-       frame3 = (void *)((int) m + m->ofs_frames + (m->framesize * currentrenderentity->frameblend[2].frame));
-       frame4 = (void *)((int) m + m->ofs_frames + (m->framesize * currentrenderentity->frameblend[3].frame));
-       R_AliasLerpVerts(m->num_xyz,
-               currentrenderentity->frameblend[0].lerp, frame1->verts, frame1->scale, frame1->translate,
-               currentrenderentity->frameblend[1].lerp, frame2->verts, frame2->scale, frame2->translate,
-               currentrenderentity->frameblend[2].lerp, frame3->verts, frame3->scale, frame3->translate,
-               currentrenderentity->frameblend[3].lerp, frame4->verts, frame4->scale, frame4->translate);
-       if (!gl_transform.value)
-               R_AliasTransformVerts(m->num_xyz);
-
-       R_LightModel(m->num_xyz);
-
-       if (!r_render.value)
+       model = currentrenderentity->model;
+
+       R_SetupMDLMD2Frames(&skinframe);
+
+       if (!r_render.integer)
                return;
 
+       // FIXME FIXME FIXME rewrite loader to convert to triangle mesh
+       glBindTexture(GL_TEXTURE_2D, R_GetTexture(skinframe->base));
+
        if (currentrenderentity->effects & EF_ADDITIVE)
        {
                glBlendFunc(GL_SRC_ALPHA, GL_ONE); // additive rendering
                glEnable(GL_BLEND);
                glDepthMask(0);
        }
-       else if (currentrenderentity->alpha != 1.0 || (currentrenderentity->model->flags2 & MODF_TRANSPARENT))
+       else if (currentrenderentity->alpha != 1.0 || R_TextureHasAlpha(skinframe->base))
        {
                glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
                glEnable(GL_BLEND);
@@ -529,11 +503,13 @@ void R_DrawQ2AliasFrame (void)
        // using vertex arrays only slightly, although it is enough to prevent duplicates
        // (saving half the transforms)
        glVertexPointer(3, GL_FLOAT, sizeof(float[3]), aliasvert);
-       glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(byte[4]), aliasvertcolor);
+       glColorPointer(4, GL_FLOAT, sizeof(float[4]), aliasvertcolor);
        glEnableClientState(GL_VERTEX_ARRAY);
        glEnableClientState(GL_COLOR_ARRAY);
 
-       order = (int *)((int)m + m->ofs_glcmds);
+       GL_LockArray(0, model->numverts);
+
+       order = model->md2data_glcmds;
        while(1)
        {
                if (!(count = *order++))
@@ -554,6 +530,8 @@ void R_DrawQ2AliasFrame (void)
                while (count--);
        }
 
+       GL_UnlockArray();
+
        glDisableClientState(GL_COLOR_ARRAY);
        glDisableClientState(GL_VERTEX_ARRAY);
 
@@ -565,7 +543,7 @@ void R_DrawQ2AliasFrame (void)
                glDepthMask(0); // disable zbuffer updates
 
                VectorSubtract(currentrenderentity->origin, r_origin, diff);
-               glColor4f(fogcolor[0], fogcolor[1], fogcolor[2], exp(fogdensity/DotProduct(diff,diff)));
+               glColor4f(fogcolor[0], fogcolor[1], fogcolor[2], currentrenderentity->alpha * exp(fogdensity/DotProduct(diff,diff)));
 
                // LordHavoc: big mess...
                // using vertex arrays only slightly, although it is enough to prevent duplicates
@@ -573,7 +551,9 @@ void R_DrawQ2AliasFrame (void)
                glVertexPointer(3, GL_FLOAT, sizeof(float[3]), aliasvert);
                glEnableClientState(GL_VERTEX_ARRAY);
 
-               order = (int *)((int)m + m->ofs_glcmds);
+               GL_LockArray(0, model->numverts);
+
+               order = model->md2data_glcmds;
                while(1)
                {
                        if (!(count = *order++))
@@ -593,6 +573,8 @@ void R_DrawQ2AliasFrame (void)
                        while (count--);
                }
 
+               GL_UnlockArray();
+
                glDisableClientState(GL_VERTEX_ARRAY);
 
                glEnable (GL_TEXTURE_2D);
@@ -602,9 +584,6 @@ void R_DrawQ2AliasFrame (void)
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        glEnable (GL_BLEND);
        glDepthMask(1);
-
-       if (gl_transform.value)
-               glPopMatrix();
 }
 
 void ZymoticLerpBones(int count, zymbonematrix *bonebase, frameblend_t *blend, zymbone_t *bone, float rootorigin[3], float rootangles[3], float rootscale)
@@ -824,7 +803,7 @@ void ZymoticCalcNormals(int vertcount, int shadercount, int *renderlist)
                        v2[1] = aliasvert[c+1] - aliasvert[b+1];
                        v2[2] = aliasvert[c+2] - aliasvert[b+2];
                        CrossProduct(v1, v2, normal);
-                       VectorNormalize(normal);
+                       VectorNormalizeFast(normal);
                        // add surface normal to vertices
                        aliasvertnorm[a+0] += normal[0];
                        aliasvertnorm[a+1] += normal[1];
@@ -858,137 +837,111 @@ void ZymoticCalcNormals(int vertcount, int shadercount, int *renderlist)
        }
 }
 
-void GL_DrawZymoticModelMesh(byte *colors, zymtype1header_t *m)
+void GL_DrawZymoticModelMesh(zymtype1header_t *m)
 {
-       int i, c, *renderlist;
+       int i, *renderlist;
        rtexture_t **texture;
-       if (!r_render.value)
-               return;
+
+       // FIXME: do better fog
        renderlist = (int *)(m->lump_render.start + (int) m);
        texture = (rtexture_t **)(m->lump_shaders.start + (int) m);
-       glVertexPointer(3, GL_FLOAT, sizeof(float[3]), aliasvert);
-       glEnableClientState(GL_VERTEX_ARRAY);
 
-       glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(byte[4]), colors);
-       glEnableClientState(GL_COLOR_ARRAY);
-
-       glTexCoordPointer(2, GL_FLOAT, sizeof(float[2]), (float *)(m->lump_texcoords.start + (int) m));
-       glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+       aliasmeshinfo.vertex = aliasvert;
+       aliasmeshinfo.vertexstep = sizeof(float[3]);
+       aliasmeshinfo.color = aliasvertcolor;
+       aliasmeshinfo.colorstep = sizeof(float[4]);
+       aliasmeshinfo.texcoords[0] = (float *)(m->lump_texcoords.start + (int) m);
+       aliasmeshinfo.texcoordstep[0] = sizeof(float[2]);
 
        for (i = 0;i < m->numshaders;i++)
        {
-               c = (*renderlist++) * 3;
-               glBindTexture(GL_TEXTURE_2D, R_GetTexture(*texture));
-               texture++;
-               glDrawElements(GL_TRIANGLES, c, GL_UNSIGNED_INT, renderlist);
-               renderlist += c;
+               aliasmeshinfo.tex[0] = R_GetTexture(*texture);
+               aliasmeshinfo.tex[1] = 0;
+               if (currentrenderentity->effects & EF_ADDITIVE)
+               {
+                       aliasmeshinfo.transparent = true;
+                       aliasmeshinfo.blendfunc1 = GL_SRC_ALPHA;
+                       aliasmeshinfo.blendfunc2 = GL_ONE;
+               }
+               else if (currentrenderentity->alpha != 1.0 || R_TextureHasAlpha(*texture))
+               {
+                       aliasmeshinfo.transparent = true;
+                       aliasmeshinfo.blendfunc1 = GL_SRC_ALPHA;
+                       aliasmeshinfo.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
+               }
+               else
+               {
+                       aliasmeshinfo.transparent = false;
+                       aliasmeshinfo.blendfunc1 = GL_ONE;
+                       aliasmeshinfo.blendfunc2 = GL_ZERO;
+               }
+               aliasmeshinfo.numtriangles = *renderlist++;
+               aliasmeshinfo.index = renderlist;
+               R_Mesh_Draw(&aliasmeshinfo);
+               renderlist += aliasmeshinfo.numtriangles * 3;
        }
-
-       glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-
-       glDisableClientState(GL_COLOR_ARRAY);
-
-       glDisableClientState(GL_VERTEX_ARRAY);
 }
 
 void GL_DrawZymoticModelMeshFog(vec3_t org, zymtype1header_t *m)
 {
+       int i, *renderlist;
        vec3_t diff;
-       int i, c, *renderlist;
-       if (!r_render.value)
-               return;
+
+       // FIXME: do better fog
        renderlist = (int *)(m->lump_render.start + (int) m);
-       glDisable(GL_TEXTURE_2D);
-       glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-       glEnable (GL_BLEND);
-       glDepthMask(0); // disable zbuffer updates
 
-       VectorSubtract(org, r_origin, diff);
-       glColor4f(fogcolor[0], fogcolor[1], fogcolor[2], exp(fogdensity/DotProduct(diff,diff)));
+       aliasmeshinfo.tex[0] = 0;
+       aliasmeshinfo.blendfunc1 = GL_SRC_ALPHA;
+       aliasmeshinfo.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
 
-       glVertexPointer(3, GL_FLOAT, sizeof(float[3]), aliasvert);
-       glEnableClientState(GL_VERTEX_ARRAY);
+       VectorSubtract(org, r_origin, diff);
+       aliasmeshinfo.cr = fogcolor[0];
+       aliasmeshinfo.cg = fogcolor[1];
+       aliasmeshinfo.cb = fogcolor[2];
+       aliasmeshinfo.ca = currentrenderentity->alpha * exp(fogdensity/DotProduct(diff,diff));
 
        for (i = 0;i < m->numshaders;i++)
        {
-               c = (*renderlist++) * 3;
-               glDrawElements(GL_TRIANGLES, c, GL_UNSIGNED_INT, renderlist);
-               renderlist += c;
+               aliasmeshinfo.numtriangles = *renderlist++;
+               aliasmeshinfo.index = renderlist;
+               R_Mesh_Draw(&aliasmeshinfo);
+               renderlist += aliasmeshinfo.numtriangles * 3;
        }
-
-       glDisableClientState(GL_VERTEX_ARRAY);
-
-       glEnable(GL_TEXTURE_2D);
-       glColor3f (1,1,1);
 }
 
-/*
-=================
-R_DrawZymoticFrame
-=================
-*/
-void R_DrawZymoticFrame (void)
+void R_DrawZymoticModel (void)
 {
-       zymtype1header_t *m = Mod_Extradata(currentrenderentity->model);
+       zymtype1header_t *m;
+
+       // FIXME: do better fog
+       m = currentrenderentity->model->zymdata_header;
        ZymoticLerpBones(m->numbones, (zymbonematrix *)(m->lump_poses.start + (int) m), currentrenderentity->frameblend, (zymbone_t *)(m->lump_bones.start + (int) m), currentrenderentity->origin, currentrenderentity->angles, currentrenderentity->scale);
        ZymoticTransformVerts(m->numverts, (int *)(m->lump_vertbonecounts.start + (int) m), (zymvertex_t *)(m->lump_verts.start + (int) m));
        ZymoticCalcNormals(m->numverts, m->numshaders, (int *)(m->lump_render.start + (int) m));
 
        R_LightModel(m->numverts);
 
-       if (!r_render.value)
-               return;
-       glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-//     glShadeModel(GL_SMOOTH);
-       if (currentrenderentity->effects & EF_ADDITIVE)
-       {
-               glBlendFunc(GL_SRC_ALPHA, GL_ONE); // additive rendering
-               glEnable(GL_BLEND);
-               glDepthMask(0);
-       }
-       else if (currentrenderentity->alpha != 1.0)
-       {
-               glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-               glEnable(GL_BLEND);
-               glDepthMask(0);
-       }
-       else
-       {
-               glDisable(GL_BLEND);
-               glDepthMask(1);
-       }
+       memset(&aliasmeshinfo, 0, sizeof(aliasmeshinfo));
+       aliasmeshinfo.numverts = m->numverts;
 
-       GL_DrawZymoticModelMesh(aliasvertcolor, m);
+       GL_DrawZymoticModelMesh(m);
 
        if (fogenabled)
                GL_DrawZymoticModelMeshFog(currentrenderentity->origin, m);
-
-       glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-       glEnable (GL_BLEND);
-       glDepthMask(1);
 }
 
-/*
-=================
-R_DrawAliasModel
-
-=================
-*/
 void R_DrawAliasModel (void)
 {
-       if (currentrenderentity->alpha < (1.0 / 64.0))
+       if (currentrenderentity->alpha < (1.0f / 64.0f))
                return; // basically completely transparent
 
        c_models++;
 
-       if (r_render.value)
-               glEnable (GL_TEXTURE_2D);
-
        c_alias_polys += currentrenderentity->model->numtris;
        if (currentrenderentity->model->aliastype == ALIASTYPE_ZYM)
-               R_DrawZymoticFrame ();
+               R_DrawZymoticModel ();
        else if (currentrenderentity->model->aliastype == ALIASTYPE_MD2)
-               R_DrawQ2AliasFrame ();
+               R_DrawQ2AliasModel ();
        else
-               R_DrawAliasFrame   ();
+               R_DrawQ1AliasModel   ();
 }
index f848defad3109e647fa9533251708d0c209c51ed..66b20cf8e73651cc6ebea4757f7d4f570e66e4b3 100644 (file)
@@ -23,7 +23,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 //static qboolean      r_cache_thrash;         // compatability
 
-vec3_t         modelorg;
 entity_render_t        *currentrenderentity;
 
 int                    r_framecount;           // used for dlight push checking
@@ -72,7 +71,6 @@ cvar_t        r_fullbrights = {CVAR_SAVE, "r_fullbrights", "1"};
 
 cvar_t gl_lightmode = {CVAR_SAVE, "gl_lightmode", "1"}; // LordHavoc: overbright lighting
 //cvar_t       r_dynamicbothsides = {CVAR_SAVE, "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 = {0, "r_farclip", "6144"}; // FIXME: make this go away (calculate based on farthest visible object/polygon)
 
 cvar_t gl_fogenable = {0, "gl_fogenable", "0"};
 cvar_t gl_fogdensity = {0, "gl_fogdensity", "0.25"};
@@ -81,11 +79,45 @@ cvar_t      gl_foggreen = {0, "gl_foggreen","0.3"};
 cvar_t gl_fogblue = {0, "gl_fogblue","0.3"};
 cvar_t gl_fogstart = {0, "gl_fogstart", "0"};
 cvar_t gl_fogend = {0, "gl_fogend","0"};
-cvar_t glfog = {0, "glfog", "0"};
 
 cvar_t r_ser = {CVAR_SAVE, "r_ser", "1"};
 cvar_t gl_viewmodeldepthhack = {0, "gl_viewmodeldepthhack", "1"};
 
+cvar_t r_multitexture = {0, "r_multitexture", "1"};
+
+/*
+====================
+R_TimeRefresh_f
+
+For program optimization
+====================
+*/
+qboolean intimerefresh = 0;
+static void R_TimeRefresh_f (void)
+{
+       int                     i;
+       float           start, stop, time;
+
+       intimerefresh = 1;
+       start = Sys_DoubleTime ();
+       glDrawBuffer (GL_FRONT);
+       for (i = 0;i < 128;i++)
+       {
+               r_refdef.viewangles[0] = 0;
+               r_refdef.viewangles[1] = i/128.0*360.0;
+               r_refdef.viewangles[2] = 0;
+               R_RenderView();
+       }
+       glDrawBuffer  (GL_BACK);
+
+       stop = Sys_DoubleTime ();
+       intimerefresh = 0;
+       time = stop-start;
+       Con_Printf ("%f seconds (%f fps)\n", time, 128/time);
+}
+
+extern cvar_t r_drawportals;
+
 int R_VisibleCullBox (vec3_t mins, vec3_t maxs)
 {
        int sides;
@@ -137,11 +169,11 @@ vec_t fogdensity;
 float fog_density, fog_red, fog_green, fog_blue;
 qboolean fogenabled;
 qboolean oldgl_fogenable;
-void FOG_framebegin(void)
+void R_SetupFog(void)
 {
        if (gamemode == GAME_NEHAHRA)
        {
-               if (gl_fogenable.value)
+               if (gl_fogenable.integer)
                {
                        oldgl_fogenable = true;
                        fog_density = gl_fogdensity.value;
@@ -160,63 +192,21 @@ void FOG_framebegin(void)
        }
        if (fog_density)
        {
-                       fogcolor[0] = fog_red   = bound(0.0f, fog_red  , 1.0f);
-                       fogcolor[1] = fog_green = bound(0.0f, fog_green, 1.0f);
-                       fogcolor[2] = fog_blue  = bound(0.0f, fog_blue , 1.0f);
-                       if (lighthalf)
-                       {
-                               fogcolor[0] *= 0.5f;
-                               fogcolor[1] *= 0.5f;
-                               fogcolor[2] *= 0.5f;
-                       }
+               fogcolor[0] = fog_red   = bound(0.0f, fog_red  , 1.0f);
+               fogcolor[1] = fog_green = bound(0.0f, fog_green, 1.0f);
+               fogcolor[2] = fog_blue  = bound(0.0f, fog_blue , 1.0f);
        }
-       if (glfog.value)
+       if (fog_density)
        {
-               if (!r_render.value)
-                       return;
-               if(fog_density)
-               {
-                       // LordHavoc: Borland C++ 5.0 was choking on this line...
-                       //GLfloat colors[4] = {(GLfloat) gl_fogred.value, (GLfloat) gl_foggreen.value, (GLfloat) gl_fogblue.value, (GLfloat) 1};
-                       GLfloat colors[4];
-                       colors[0] = fog_red;
-                       colors[1] = fog_green;
-                       colors[2] = fog_blue;
-                       colors[3] = 1;
-                       if (lighthalf)
-                       {
-                               colors[0] *= 0.5f;
-                               colors[1] *= 0.5f;
-                               colors[2] *= 0.5f;
-                       }
-
-                       glFogi (GL_FOG_MODE, GL_EXP2);
-                       glFogf (GL_FOG_DENSITY, (GLfloat) fog_density / 100);
-                       glFogfv (GL_FOG_COLOR, colors);
-                       glEnable (GL_FOG);
-               }
-               else
-                       glDisable(GL_FOG);
+               fogenabled = true;
+               fogdensity = -4000.0f / (fog_density * fog_density);
+               // fog color was already set
        }
        else
-       {
-               if (fog_density)
-               {
-                       fogenabled = true;
-                       fogdensity = -4000.0f / (fog_density * fog_density);
-                       // fog color was already set
-               }
-               else
-                       fogenabled = false;
-       }
-}
-
-void FOG_frameend(void)
-{
-       if (glfog.value)
-               glDisable(GL_FOG);
+               fogenabled = false;
 }
 
+// FIXME: move this to client?
 void FOG_clear(void)
 {
        if (gamemode == GAME_NEHAHRA)
@@ -230,9 +220,9 @@ void FOG_clear(void)
        fog_density = fog_red = fog_green = fog_blue = 0.0f;
 }
 
+// FIXME: move this to client?
 void FOG_registercvars(void)
 {
-       Cvar_RegisterVariable (&glfog);
        if (gamemode == GAME_NEHAHRA)
        {
                Cvar_RegisterVariable (&gl_fogenable);
@@ -255,11 +245,14 @@ void gl_main_shutdown(void)
 
 void gl_main_newmap(void)
 {
+       r_framecount = 1;
 }
 
 void GL_Main_Init(void)
 {
+// FIXME: move this to client?
        FOG_registercvars();
+       Cmd_AddCommand ("timerefresh", R_TimeRefresh_f);
        Cvar_RegisterVariable (&r_drawentities);
        Cvar_RegisterVariable (&r_drawviewmodel);
        Cvar_RegisterVariable (&r_speeds);
@@ -271,46 +264,67 @@ void GL_Main_Init(void)
        Cvar_RegisterVariable (&r_wateralpha);
        Cvar_RegisterVariable (&r_dynamic);
        Cvar_RegisterVariable (&r_waterripple);
-       Cvar_RegisterVariable (&r_farclip);
        Cvar_RegisterVariable (&r_fullbright);
        Cvar_RegisterVariable (&r_ser);
        Cvar_RegisterVariable (&gl_viewmodeldepthhack);
+       Cvar_RegisterVariable (&r_multitexture);
        if (gamemode == GAME_NEHAHRA)
                Cvar_SetValue("r_fullbrights", 0);
        R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap);
 }
 
+/*
+===============
+R_NewMap
+===============
+*/
+void CL_ParseEntityLump(char *entitystring);
+void R_NewMap (void)
+{
+       int             i;
+
+       for (i=0 ; i<256 ; i++)
+               d_lightstylevalue[i] = 264;             // normal light value
+
+       r_viewleaf = NULL;
+       if (cl.worldmodel->entities)
+               CL_ParseEntityLump(cl.worldmodel->entities);
+       R_Modules_NewMap();
+}
+
+extern void R_Textures_Init(void);
+extern void Mod_RenderInit(void);
 extern void GL_Draw_Init(void);
 extern void GL_Main_Init(void);
 extern void GL_Models_Init(void);
-extern void GL_Poly_Init(void);
+extern void R_Sky_Init(void);
 extern void GL_Surf_Init(void);
 extern void GL_Screen_Init(void);
-extern void GL_Misc_Init(void);
 extern void R_Crosshairs_Init(void);
 extern void R_Light_Init(void);
 extern void R_Particles_Init(void);
 extern void R_Explosion_Init(void);
-extern void CL_Effects_Init(void);
 extern void R_Clip_Init(void);
 extern void ui_init(void);
+extern void gl_backend_init(void);
 
 void Render_Init(void)
 {
        R_Modules_Shutdown();
+       R_Textures_Init();
+       Mod_RenderInit();
+       gl_backend_init();
        R_Clip_Init();
        GL_Draw_Init();
        GL_Main_Init();
        GL_Models_Init();
-       GL_Poly_Init();
+       R_Sky_Init();
        GL_Surf_Init();
        GL_Screen_Init();
-       GL_Misc_Init();
        R_Crosshairs_Init();
        R_Light_Init();
        R_Particles_Init();
        R_Explosion_Init();
-       CL_Effects_Init();
        R_Decals_Init();
        ui_init();
        R_Modules_Start();
@@ -336,9 +350,6 @@ void GL_Init (void)
 
 //     Con_Printf ("%s %s\n", gl_renderer, gl_version);
 
-//     VID_CheckMultitexture();
-//     VID_CheckCVA();
-//     VID_CheckCombine();
        VID_CheckExtensions();
 
        // LordHavoc: report supported extensions
@@ -346,8 +357,6 @@ void GL_Init (void)
 
        glCullFace(GL_FRONT);
        glEnable(GL_TEXTURE_2D);
-//     glDisable(GL_ALPHA_TEST);
-       glAlphaFunc(GL_GREATER, 0.5);
 
 //     glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
 }
@@ -360,17 +369,18 @@ void R_Entity_Callback(void *data, void *junk)
        ((entity_render_t *)data)->visframe = r_framecount;
 }
 
-static void R_AddModelEntities (void)
+static void R_MarkEntities (void)
 {
        int             i;
        vec3_t  v;
 
-       if (!r_drawentities.value)
+       if (!r_drawentities.integer)
                return;
 
        for (i = 0;i < cl_numvisedicts;i++)
        {
                currentrenderentity = &cl_visedicts[i]->render;
+               Mod_CheckLoaded(currentrenderentity->model);
 
                // move view-relative models to where they should be
                if (currentrenderentity->flags & RENDER_VIEWMODEL)
@@ -405,40 +415,45 @@ static void R_AddModelEntities (void)
                        continue;
 
                R_LerpAnimation(currentrenderentity);
-               if (r_ser.value)
+               if (r_ser.integer)
                        currentrenderentity->model->SERAddEntity();
                else
                        currentrenderentity->visframe = r_framecount;
        }
 }
 
-void R_DrawModels1 (void)
+// only used if skyrendermasked, and normally returns false
+int R_DrawBModelSky (void)
 {
-       int             i;
+       int             i, sky = false;
 
-       if (!r_drawentities.value)
-               return;
+       if (!r_drawentities.integer)
+               return false;
 
        for (i = 0;i < cl_numvisedicts;i++)
        {
                currentrenderentity = &cl_visedicts[i]->render;
-               if (currentrenderentity->visframe == r_framecount && currentrenderentity->model->DrawEarly)
-                       currentrenderentity->model->DrawEarly();
+               if (currentrenderentity->visframe == r_framecount && currentrenderentity->model->DrawSky)
+               {
+                       currentrenderentity->model->DrawSky();
+                       sky = true;
+               }
        }
+       return sky;
 }
 
-void R_DrawModels2 (void)
+void R_DrawModels (void)
 {
        int             i;
 
-       if (!r_drawentities.value)
+       if (!r_drawentities.integer)
                return;
 
        for (i = 0;i < cl_numvisedicts;i++)
        {
                currentrenderentity = &cl_visedicts[i]->render;
-               if (currentrenderentity->visframe == r_framecount && currentrenderentity->model->DrawLate)
-                       currentrenderentity->model->DrawLate();
+               if (currentrenderentity->visframe == r_framecount && currentrenderentity->model->Draw)
+                       currentrenderentity->model->Draw();
        }
 }
 
@@ -449,57 +464,50 @@ R_DrawViewModel
 */
 void R_DrawViewModel (void)
 {
-       if (!r_drawviewmodel.value || chase_active.value || envmap || !r_drawentities.value || cl.items & IT_INVISIBILITY || cl.stats[STAT_HEALTH] <= 0 || !cl.viewent.render.model)
+       // FIXME: move these checks to client
+       if (!r_drawviewmodel.integer || chase_active.integer || envmap || !r_drawentities.integer || cl.items & IT_INVISIBILITY || cl.stats[STAT_HEALTH] <= 0 || !cl.viewent.render.model)
                return;
 
        currentrenderentity = &cl.viewent.render;
+       Mod_CheckLoaded(currentrenderentity->model);
 
        R_LerpAnimation(currentrenderentity);
 
        // hack the depth range to prevent view model from poking into walls
-       if (gl_viewmodeldepthhack.value)
+       if (gl_viewmodeldepthhack.integer)
+       {
+               R_Mesh_Render();
                glDepthRange (gldepthmin, gldepthmin + 0.3*(gldepthmax-gldepthmin));
-       currentrenderentity->model->DrawLate();
-       if (gl_viewmodeldepthhack.value)
+       }
+       currentrenderentity->model->Draw();
+       if (gl_viewmodeldepthhack.integer)
+       {
+               R_Mesh_Render();
                glDepthRange (gldepthmin, gldepthmax);
+       }
 }
 
 static void R_SetFrustum (void)
 {
        int             i;
 
-       // LordHavoc: note to all quake engine coders, this code was making the
-       // view frustum taller than it should have been (it assumed the view is
-       // square; it is not square), so I disabled it
-       /*
-       if (r_refdef.fov_x == 90)
-       {
-               // front side is visible
-
-               VectorAdd (vpn, vright, frustum[0].normal);
-               VectorSubtract (vpn, vright, frustum[1].normal);
+       // LordHavoc: note to all quake engine coders, the special case for 90
+       // degrees assumed a square view (wrong), so I removed it, Quake2 has it
+       // disabled as well.
+       // rotate VPN right by FOV_X/2 degrees
+       RotatePointAroundVector( frustum[0].normal, vup, vpn, -(90-r_refdef.fov_x / 2 ) );
+       // rotate VPN left by FOV_X/2 degrees
+       RotatePointAroundVector( frustum[1].normal, vup, vpn, 90-r_refdef.fov_x / 2 );
+       // rotate VPN up by FOV_X/2 degrees
+       RotatePointAroundVector( frustum[2].normal, vright, vpn, 90-r_refdef.fov_y / 2 );
+       // rotate VPN down by FOV_X/2 degrees
+       RotatePointAroundVector( frustum[3].normal, vright, vpn, -( 90 - r_refdef.fov_y / 2 ) );
 
-               VectorAdd (vpn, vup, frustum[2].normal);
-               VectorSubtract (vpn, vup, frustum[3].normal);
-       }
-       else
-       {
-       */
-               // rotate VPN right by FOV_X/2 degrees
-               RotatePointAroundVector( frustum[0].normal, vup, vpn, -(90-r_refdef.fov_x / 2 ) );
-               // rotate VPN left by FOV_X/2 degrees
-               RotatePointAroundVector( frustum[1].normal, vup, vpn, 90-r_refdef.fov_x / 2 );
-               // rotate VPN up by FOV_X/2 degrees
-               RotatePointAroundVector( frustum[2].normal, vright, vpn, 90-r_refdef.fov_y / 2 );
-               // rotate VPN down by FOV_X/2 degrees
-               RotatePointAroundVector( frustum[3].normal, vright, vpn, -( 90 - r_refdef.fov_y / 2 ) );
-       //}
 
        for (i=0 ; i<4 ; i++)
        {
                frustum[i].type = PLANE_ANYZ;
                frustum[i].dist = DotProduct (r_origin, frustum[i].normal);
-//             frustum[i].signbits = SignbitsForPlane (&frustum[i]);
                PlaneClassify(&frustum[i]);
        }
 }
@@ -514,11 +522,13 @@ static void R_SetupFrame (void)
 // don't allow cheats in multiplayer
        if (cl.maxclients > 1)
        {
-               if (r_fullbright.value != 0)
+               if (r_fullbright.integer != 0)
                        Cvar_Set ("r_fullbright", "0");
                if (r_ambient.value != 0)
                        Cvar_Set ("r_ambient", "0");
        }
+       if (r_multitexture.integer && gl_textureunits < 2)
+               Cvar_SetValue("r_multitexture", 0);
 
        r_framecount++;
 
@@ -562,7 +572,7 @@ static void MYgluPerspective(GLdouble fovx, GLdouble fovy, GLdouble aspect, GLdo
        if (r_viewleaf->contents != CONTENTS_EMPTY && r_viewleaf->contents != CONTENTS_SOLID)
        {
                xmax *= (sin(cl.time * 4.7) * 0.03 + 0.97);
-               ymax *= (sin(cl.time * 3) * 0.03 + 0.97);
+               ymax *= (sin(cl.time * 3.0) * 0.03 + 0.97);
        }
 
        glFrustum(-xmax, xmax, -ymax, ymax, zNear, zFar );
@@ -576,9 +586,12 @@ R_SetupGL
 */
 static void R_SetupGL (void)
 {
-       if (!r_render.value)
+       if (!r_render.integer)
                return;
 
+       // update farclip based on previous frame
+       r_farclip = r_newfarclip;
+
        // set up viewpoint
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity ();
@@ -586,7 +599,7 @@ static void R_SetupGL (void)
        // y is weird beause OpenGL is bottom to top, we use top to bottom
        glViewport(r_refdef.x, vid.realheight - (r_refdef.y + r_refdef.height), r_refdef.width, r_refdef.height);
 //     yfov = 2*atan((float)r_refdef.height/r_refdef.width)*180/M_PI;
-       MYgluPerspective (r_refdef.fov_x, r_refdef.fov_y, r_refdef.width/r_refdef.height, 4, r_farclip.value);
+       MYgluPerspective (r_refdef.fov_x, r_refdef.fov_y, r_refdef.width/r_refdef.height, 4, r_farclip);
 
        glCullFace(GL_FRONT);
 
@@ -605,17 +618,14 @@ static void R_SetupGL (void)
        //
        // set drawing parms
        //
-//     if (gl_cull.value)
+//     if (gl_cull.integer)
                glEnable(GL_CULL_FACE);
 //     else
 //             glDisable(GL_CULL_FACE);
 
        glEnable(GL_BLEND); // was Disable
-       glDisable(GL_ALPHA_TEST);
-       glAlphaFunc(GL_GREATER, 0.5);
        glEnable(GL_DEPTH_TEST);
        glDepthMask(1);
-       glShadeModel(GL_SMOOTH);
 }
 
 /*
@@ -625,7 +635,7 @@ R_Clear
 */
 static void R_Clear (void)
 {
-       if (!r_render.value)
+       if (!r_render.integer)
                return;
 //     glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // LordHavoc: moved to SCR_UpdateScreen
        gldepthmin = 0;
@@ -637,7 +647,7 @@ static void R_Clear (void)
 
 static void GL_BlendView(void)
 {
-       if (!r_render.value)
+       if (!r_render.integer)
                return;
 
        if (v_blend[3] < 0.01f)
@@ -645,7 +655,7 @@ static void GL_BlendView(void)
 
        glMatrixMode(GL_PROJECTION);
     glLoadIdentity ();
-       glOrtho  (0, 256, 256, 0, -99999, 99999);
+       glOrtho  (0, 1, 1, 0, -99999, 99999);
        glMatrixMode(GL_MODELVIEW);
     glLoadIdentity ();
        glDisable (GL_DEPTH_TEST);
@@ -658,9 +668,9 @@ static void GL_BlendView(void)
                glColor4f (v_blend[0] * 0.5f, v_blend[1] * 0.5f, v_blend[2] * 0.5f, v_blend[3]);
        else
                glColor4fv (v_blend);
-       glVertex2f (-5000, -5000);
-       glVertex2f (10000, -5000);
-       glVertex2f (-5000, 10000);
+       glVertex2f (-5, -5);
+       glVertex2f (10, -5);
+       glVertex2f (-5, 10);
        glEnd ();
 
        glEnable (GL_CULL_FACE);
@@ -676,9 +686,6 @@ R_RenderView
 r_refdef must be set before the first call
 ================
 */
-extern void UploadLightmaps(void);
-extern void R_DrawSurfaces(void);
-extern void R_DrawPortals(void);
 char r_speeds2_string[1024];
 int speedstringcount;
 
@@ -687,14 +694,14 @@ void timestring(int t, char *desc)
        char tempbuf[256];
        int length;
        if (t < 1000000)
-               sprintf(tempbuf, " %6ius %s", t, desc);
+               sprintf(tempbuf, "%6ius %s", t, desc);
        else
-               sprintf(tempbuf, " %6ims %s", t / 1000, desc);
+               sprintf(tempbuf, "%6ims %s", t / 1000, desc);
        length = strlen(tempbuf);
 //     while (length < 20)
 //             tempbuf[length++] = ' ';
 //     tempbuf[length] = 0;
-       if (speedstringcount + length > 80)
+       if (speedstringcount + length > (vid.conwidth / 8))
        {
                strcat(r_speeds2_string, "\n");
                speedstringcount = 0;
@@ -713,7 +720,7 @@ void timestring(int t, char *desc)
 }
 
 #define TIMEREPORT(NAME) \
-       if (r_speeds2.value)\
+       if (r_speeds2.integer)\
        {\
                temptime = currtime;\
                currtime = Sys_DoubleTime();\
@@ -727,12 +734,12 @@ void R_RenderView (void)
        if (!cl.worldmodel)
                Host_Error ("R_RenderView: NULL worldmodel");
 
-       if (r_speeds2.value)
+       if (r_speeds2.integer)
        {
                speedstringcount = 0;
-               sprintf(r_speeds2_string, "org:'%c%6.2f %c%6.2f %c%6.2f' ang:'%c%3.0f %c%3.0f %c%3.0f' dir:'%c%2.3f %c%2.3f %c%2.3f'\n%6i walls %6i dlitwalls %7i modeltris %7i transpoly\nBSP: %6i faces %6i nodes %6i leafs\n%4i models %4i bmodels %4i sprites %5i particles %3i dlights\n",
+               sprintf(r_speeds2_string, "org:'%c%6.2f %c%6.2f %c%6.2f' ang:'%c%3.0f %c%3.0f %c%3.0f' dir:'%c%2.3f %c%2.3f %c%2.3f'\n%6i walls %6i dlitwalls %7i modeltris %7i meshtris\nBSP: %6i faces %6i nodes %6i leafs\n%4i models %4i bmodels %4i sprites %5i particles %3i dlights\n",
                        r_origin[0] < 0 ? '-' : ' ', fabs(r_origin[0]), r_origin[1] < 0 ? '-' : ' ', fabs(r_origin[1]), r_origin[2] < 0 ? '-' : ' ', fabs(r_origin[2]), r_refdef.viewangles[0] < 0 ? '-' : ' ', fabs(r_refdef.viewangles[0]), r_refdef.viewangles[1] < 0 ? '-' : ' ', fabs(r_refdef.viewangles[1]), r_refdef.viewangles[2] < 0 ? '-' : ' ', fabs(r_refdef.viewangles[2]), vpn[0] < 0 ? '-' : ' ', fabs(vpn[0]), vpn[1] < 0 ? '-' : ' ', fabs(vpn[1]), vpn[2] < 0 ? '-' : ' ', fabs(vpn[2]),
-                       c_brush_polys, c_light_polys, c_alias_polys, currenttranspoly,
+                       c_brush_polys, c_light_polys, c_alias_polys, c_meshtris,
                        c_faces, c_nodes, c_leafs,
                        c_models, c_bmodels, c_sprites, c_particles, c_dlights);
 
@@ -741,86 +748,89 @@ void R_RenderView (void)
        else
                starttime = currtime = 0;
 
-       R_MoveParticles ();
-       TIMEREPORT("mparticles")
+       // FIXME: move to client
        R_MoveExplosions();
        TIMEREPORT("mexplosion")
 
-       FOG_framebegin();
-
        R_Clear();
        TIMEREPORT("clear     ")
 
        // render normal view
 
-       R_SetupFrame ();
-       R_SetFrustum ();
-       R_SetupGL ();
-       R_Clip_StartFrame();
-
-       skypolyclear();
-       wallpolyclear();
-       transpolyclear();
+       R_SetupFrame();
+       R_SetFrustum();
+       R_SetupGL();
+       R_SetupFog();
+       R_SkyStartFrame();
+       R_Mesh_Clear();
+       if (r_ser.integer)
+               R_Clip_StartFrame();
+       R_BuildLightList();
 
        TIMEREPORT("setup     ")
 
-       R_DrawWorld ();
-       TIMEREPORT("addworld  ")
+       R_DrawWorld();
+       TIMEREPORT("worldnode ")
 
-       R_AddModelEntities();
-       TIMEREPORT("addmodels ")
+       R_MarkEntities();
+       TIMEREPORT("markentity")
 
-       R_Clip_EndFrame();
-       TIMEREPORT("scanedge  ")
+       if (r_ser.integer)
+       {
+               R_Clip_EndFrame();
+       TIMEREPORT("hiddensurf")
+       }
 
-       // now mark the lit surfaces
-       R_PushDlights ();
+       R_MarkWorldLights();
        TIMEREPORT("marklights")
 
-       R_DrawModels1 ();
-
-       // yes this does add the world after the brush models when using the SER
-       R_DrawSurfaces ();
-       R_DrawPortals ();
-       TIMEREPORT("surfaces  ");
-
-       UploadLightmaps();
-       TIMEREPORT("uploadlmap")
-
-       skypolyrender();
-       TIMEREPORT("skypoly   ")
+       if (skyrendermasked && R_DrawBModelSky())
+       {
+       TIMEREPORT("bmodelsky ")
+       }
 
-       wallpolyrender1();
-       TIMEREPORT("wallpoly1 ")
+       R_SetupForWorldRendering();
+       R_PrepareSurfaces();
+       TIMEREPORT("surfprep  ")
 
-       GL_DrawDecals();
-       TIMEREPORT("ddecal    ")
+       R_DrawSurfacesAll();
+       TIMEREPORT("surf      ")
 
-       wallpolyrender2();
-       TIMEREPORT("wallpoly2 ")
+       if (r_drawportals.integer)
+       {
+               R_DrawPortals();
+       TIMEREPORT("portals   ")
+       }
 
        // don't let sound skip if going slow
-       if (!intimerefresh && !r_speeds2.value)
+       if (!intimerefresh && !r_speeds2.integer)
                S_ExtraUpdate ();
 
-       R_DrawViewModel ();
-       R_DrawModels();
+       R_DrawViewModel();
+       R_DrawModels();
        TIMEREPORT("models    ")
 
-       R_DrawParticles ();
-       TIMEREPORT("dparticles")
+       R_DrawDecals();
+       TIMEREPORT("decals    ")
+
+       R_DrawParticles();
+       TIMEREPORT("particles ")
 
        R_DrawExplosions();
-       TIMEREPORT("dexplosion")
+       TIMEREPORT("explosions")
 
-       transpolyrender();
-       TIMEREPORT("transpoly ")
+       // draw transparent meshs
+       R_Mesh_AddTransparent();
+       TIMEREPORT("transmesh ")
 
-       FOG_frameend();
+       // render any queued meshs
+       R_Mesh_Render();
+       TIMEREPORT("finishmesh")
 
        GL_BlendView();
        TIMEREPORT("blend     ")
 
-       if (r_speeds2.value)
-               timestring((int) ((Sys_DoubleTime() - starttime) * 1000000.0), "total    ");
+       if (r_speeds2.integer)
+               timestring((int) ((Sys_DoubleTime() - starttime) * 1000000.0),
+                  "total     ");
 }
diff --git a/gl_rmisc.c b/gl_rmisc.c
deleted file mode 100644 (file)
index 5cf5612..0000000
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
-Copyright (C) 1996-1997 Id Software, Inc.
-
-This program is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License
-as published by the Free Software Foundation; either version 2
-of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
-See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-
-*/
-// r_misc.c
-
-#include "quakedef.h"
-
-
-/*
-===============
-R_Envmap_f
-
-Grab six views for environment mapping tests
-===============
-*/
-float CalcFov (float fov_x, float width, float height);
-struct
-{
-       float angles[3];
-       char *name;
-}
-envmapinfo[6] =
-{
-       {{  0,   0, 0}, "ft"},
-       {{  0,  90, 0}, "rt"},
-       {{  0, 180, 0}, "bk"},
-       {{  0, 270, 0}, "lf"},
-       {{-90,  90, 0}, "up"},
-       {{ 90,  90, 0}, "dn"}
-};
-void R_Envmap_f (void)
-{
-       int             i, size;
-       char    filename[256];
-       char    basename[256];
-       byte    *buffer, gamma[256];
-
-       if (Cmd_Argc() != 3)
-       {
-               Con_Printf ("envmap <basename> <size>: save out 6 cubic environment map images, usable with loadsky, note that size must one of 128, 256, 512, or 1024 and can't be bigger than your current resolution\n");
-               return;
-       }
-
-       if (!r_render.value)
-               return;
-
-       strcpy(basename, Cmd_Argv(1));
-       size = atoi(Cmd_Argv(2));
-       if (size != 128 && size != 256 && size != 512 && size != 1024)
-       {
-               Con_Printf("envmap: size must be one of 128, 256, 512, or 1024\n");
-               return;
-       }
-       if (size > vid.realwidth || size > vid.realheight)
-       {
-               Con_Printf("envmap: your resolution is not big enough to render that size\n");
-               return;
-       }
-
-       buffer = malloc(size*size*3);
-       if (buffer == NULL)
-       {
-               Con_Printf("envmap: unable to allocate memory for image\n");
-               return;
-       }
-
-       BuildGammaTable8((lighthalf && hardwaregammasupported) ? 2.0f : 1.0f, 1, 1, 0, gamma);
-
-//     glDrawBuffer  (GL_FRONT);
-//     glReadBuffer  (GL_FRONT);
-       glDrawBuffer  (GL_BACK);
-       glReadBuffer  (GL_BACK);
-       envmap = true;
-
-       r_refdef.x = 0;
-       r_refdef.y = 0;
-       r_refdef.width = size;
-       r_refdef.height = size;
-
-       r_refdef.fov_x = 90;
-       r_refdef.fov_y = 90;
-
-       for (i = 0;i < 6;i++)
-       {
-               VectorCopy(envmapinfo[i].angles, r_refdef.viewangles);
-               glClearColor(0,0,0,0);
-               glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // LordHavoc: clear the screen (around the view as well)
-               R_RenderView ();
-               glReadPixels (0, 0, size, size, GL_RGB, GL_UNSIGNED_BYTE, buffer);
-               sprintf(filename, "env/%s%s.tga", basename, envmapinfo[i].name);
-               Image_GammaRemapRGB(buffer, buffer, size * size, gamma, gamma, gamma);
-               Image_WriteTGARGB_preflipped(filename, size, size, buffer);
-       }
-
-       envmap = false;
-       glDrawBuffer  (GL_BACK);
-       glReadBuffer  (GL_BACK);
-
-       free(buffer);
-
-       // cause refdef to be fixed
-//     vid.recalc_refdef = 1;
-}
-
-static void gl_misc_start(void)
-{
-}
-
-static void gl_misc_shutdown(void)
-{
-}
-
-static void gl_misc_newmap(void)
-{
-}
-
-/*
-===============
-R_Init
-===============
-*/
-static void R_TimeRefresh_f (void);
-void GL_Misc_Init (void)
-{
-       Cmd_AddCommand ("envmap", R_Envmap_f);
-       Cmd_AddCommand ("timerefresh", R_TimeRefresh_f);
-
-       R_RegisterModule("GL_Misc", gl_misc_start, gl_misc_shutdown, gl_misc_newmap);
-}
-
-extern void GL_BuildLightmaps (void);
-
-/*
-===============
-R_NewMap
-===============
-*/
-void R_NewMap (void)
-{
-       int             i;
-
-       for (i=0 ; i<256 ; i++)
-               d_lightstylevalue[i] = 264;             // normal light value
-
-       r_viewleaf = NULL;
-       R_Modules_NewMap();
-
-       GL_BuildLightmaps ();
-
-       SHOWLMP_clear();
-}
-
-
-/*
-====================
-R_TimeRefresh_f
-
-For program optimization
-====================
-*/
-qboolean intimerefresh = 0;
-static void R_TimeRefresh_f (void)
-{
-       int                     i;
-       float           start, stop, time;
-
-       intimerefresh = 1;
-       start = Sys_DoubleTime ();
-       glDrawBuffer (GL_FRONT);
-       for (i = 0;i < 128;i++)
-       {
-               r_refdef.viewangles[0] = 0;
-               r_refdef.viewangles[1] = i/128.0*360.0;
-               r_refdef.viewangles[2] = 0;
-               R_RenderView();
-       }
-       glDrawBuffer  (GL_BACK);
-
-       stop = Sys_DoubleTime ();
-       intimerefresh = 0;
-       time = stop-start;
-       Con_Printf ("%f seconds (%f fps)\n", time, 128/time);
-}
-
-
index 0b9f07f2b1bbac66711a141160ab96adb1b43e22..336cde393d1cec3ab6f6ad8be8a279d3b8c17d9c 100644 (file)
@@ -21,64 +21,34 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 #include "quakedef.h"
 
-int            lightmap_textures;
+#define MAX_LIGHTMAP_SIZE 256
 
-#define        BLOCK_WIDTH             256
-#define        BLOCK_HEIGHT    256
-// LordHavoc: increased lightmap limit from 64 to 1024
-#define        MAX_LIGHTMAPS   1024
-#define LIGHTMAPSIZE   (BLOCK_WIDTH*BLOCK_HEIGHT*4)
+static signed int blocklights[MAX_LIGHTMAP_SIZE*MAX_LIGHTMAP_SIZE*3]; // LordHavoc: *3 for colored lighting
 
-int                    active_lightmaps;
+static byte templight[MAX_LIGHTMAP_SIZE*MAX_LIGHTMAP_SIZE*4];
 
-short allocated[MAX_LIGHTMAPS][BLOCK_WIDTH];
-
-byte *lightmaps[MAX_LIGHTMAPS];
-short lightmapupdate[MAX_LIGHTMAPS][2];
-
-signed int blocklights[BLOCK_WIDTH*BLOCK_HEIGHT*3]; // LordHavoc: *3 for colored lighting
-
-byte templight[BLOCK_WIDTH*BLOCK_HEIGHT*4];
-
-int lightmapalign, lightmapalignmask; // LordHavoc: align texsubimage updates on 4 byte boundaries
-cvar_t gl_lightmapalign = {0, "gl_lightmapalign", "4"}; // align texsubimage updates on 4 byte boundaries
-cvar_t gl_lightmaprgba = {0, "gl_lightmaprgba", "1"};
-cvar_t gl_nosubimagefragments = {0, "gl_nosubimagefragments", "0"};
-cvar_t gl_nosubimage = {0, "gl_nosubimage", "0"};
 cvar_t r_ambient = {0, "r_ambient", "0"};
-cvar_t gl_vertex = {0, "gl_vertex", "0"};
+cvar_t r_vertexsurfaces = {0, "r_vertexsurfaces", "0"};
 cvar_t r_dlightmap = {CVAR_SAVE, "r_dlightmap", "1"};
 cvar_t r_drawportals = {0, "r_drawportals", "0"};
 cvar_t r_testvis = {0, "r_testvis", "0"};
 
-qboolean lightmaprgba, nosubimagefragments, nosubimage;
-int lightmapbytes;
-
-int wateralpha;
-
-void gl_surf_start(void)
+static void gl_surf_start(void)
 {
 }
 
-void gl_surf_shutdown(void)
+static void gl_surf_shutdown(void)
 {
 }
 
-void gl_surf_newmap(void)
+static void gl_surf_newmap(void)
 {
 }
 
 void GL_Surf_Init(void)
 {
-       int i;
-       for (i = 0;i < MAX_LIGHTMAPS;i++)
-               lightmaps[i] = NULL;
-       Cvar_RegisterVariable(&gl_lightmapalign);
-       Cvar_RegisterVariable(&gl_lightmaprgba);
-       Cvar_RegisterVariable(&gl_nosubimagefragments);
-       Cvar_RegisterVariable(&gl_nosubimage);
        Cvar_RegisterVariable(&r_ambient);
-       Cvar_RegisterVariable(&gl_vertex);
+       Cvar_RegisterVariable(&r_vertexsurfaces);
        Cvar_RegisterVariable(&r_dlightmap);
        Cvar_RegisterVariable(&r_drawportals);
        Cvar_RegisterVariable(&r_testvis);
@@ -86,14 +56,11 @@ void GL_Surf_Init(void)
        R_RegisterModule("GL_Surf", gl_surf_start, gl_surf_shutdown, gl_surf_newmap);
 }
 
-int dlightdivtable[32768];
+static int dlightdivtable[32768];
 
-/*
-       R_AddDynamicLights
-*/
-int R_AddDynamicLights (msurface_t *surf)
+static int R_AddDynamicLights (msurface_t *surf)
 {
-       int         sdtable[18], lnum, td, maxdist, maxdist2, maxdist3, i, s, t, smax, tmax, red, green, blue, lit, dist2, impacts, impactt;
+       int         sdtable[18], lnum, td, maxdist, maxdist2, maxdist3, i, s, t, smax, tmax, smax3, red, green, blue, lit, dist2, impacts, impactt, subtract;
        unsigned int *bl;
        float       dist;
        vec3_t      impact, local;
@@ -117,28 +84,31 @@ int R_AddDynamicLights (msurface_t *surf)
        smax = (surf->extents[0] >> 4) + 1;
        tmax = (surf->extents[1] >> 4) + 1;
 
-       for (lnum = 0; lnum < MAX_DLIGHTS; lnum++)
+       for (lnum = 0; lnum < r_numdlights; lnum++)
        {
                if (!(surf->dlightbits[lnum >> 5] & (1 << (lnum & 31))))
                        continue;                                       // not lit by this light
 
-               VectorSubtract (cl_dlights[lnum].origin, currentrenderentity->origin, local);
+               softwareuntransform(r_dlight[lnum].origin, local);
+//             VectorSubtract (r_dlight[lnum].origin, currentrenderentity->origin, local);
                dist = DotProduct (local, surf->plane->normal) - surf->plane->dist;
 
                // for comparisons to minimum acceptable light
-               maxdist = (int) ((cl_dlights[lnum].radius * cl_dlights[lnum].radius));
+               maxdist = (int) r_dlight[lnum].cullradius2;
 
+               // already clamped, skip this
                // clamp radius to avoid exceeding 32768 entry division table
-               if (maxdist > 4194304)
-                       maxdist = 4194304;
+               //if (maxdist > 4194304)
+               //      maxdist = 4194304;
 
                dist2 = dist * dist;
+               dist2 += LIGHTOFFSET;
                if (dist2 >= maxdist)
                        continue;
 
-               impact[0] = cl_dlights[lnum].origin[0] - surf->plane->normal[0] * dist;
-               impact[1] = cl_dlights[lnum].origin[1] - surf->plane->normal[1] * dist;
-               impact[2] = cl_dlights[lnum].origin[2] - surf->plane->normal[2] * dist;
+               impact[0] = local[0] - surf->plane->normal[0] * dist;
+               impact[1] = local[1] - surf->plane->normal[1] * dist;
+               impact[2] = local[2] - surf->plane->normal[2] * dist;
 
                impacts = DotProduct (impact, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3] - surf->texturemins[0];
                impactt = DotProduct (impact, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3] - surf->texturemins[1];
@@ -151,78 +121,49 @@ int R_AddDynamicLights (msurface_t *surf)
 
                // reduce calculations
                for (s = 0, i = impacts; s < smax; s++, i -= 16)
-                       sdtable[s] = i * i + dist2 + LIGHTOFFSET;
+                       sdtable[s] = i * i + dist2;
 
-               maxdist3 = maxdist - (int) (dist * dist);
+               maxdist3 = maxdist - dist2;
 
-               // convert to 8.8 blocklights format and scale up by radius
-               red = cl_dlights[lnum].color[0] * maxdist;
-               green = cl_dlights[lnum].color[1] * maxdist;
-               blue = cl_dlights[lnum].color[2] * maxdist;
+               // convert to 8.8 blocklights format
+               red = r_dlight[lnum].light[0];
+               green = r_dlight[lnum].light[1];
+               blue = r_dlight[lnum].light[2];
+               subtract = (int) (r_dlight[lnum].lightsubtract * 4194304.0f);
                bl = blocklights;
+               smax3 = smax * 3;
 
                i = impactt;
-               for (t = 0; t < tmax; t++, i -= 16)
+               for (t = 0;t < tmax;t++, i -= 16)
                {
                        td = i * i;
                        // make sure some part of it is visible on this line
                        if (td < maxdist3)
                        {
                                maxdist2 = maxdist - td;
-                               for (s = 0; s < smax; s++)
+                               for (s = 0;s < smax;s++)
                                {
                                        if (sdtable[s] < maxdist2)
                                        {
-                                               k = dlightdivtable[(sdtable[s] + td) >> 7];
-                                               bl[0] += (red   * k) >> 9;
-                                               bl[1] += (green * k) >> 9;
-                                               bl[2] += (blue  * k) >> 9;
-                                               lit = true;
+                                               k = dlightdivtable[(sdtable[s] + td) >> 7] - subtract;
+                                               if (k > 0)
+                                               {
+                                                       bl[0] += (red   * k) >> 8;
+                                                       bl[1] += (green * k) >> 8;
+                                                       bl[2] += (blue  * k) >> 8;
+                                                       lit = true;
+                                               }
                                        }
                                        bl += 3;
                                }
                        }
                        else // skip line
-                               bl += smax * 3;
+                               bl += smax3;
                }
        }
        return lit;
 }
 
-
-void R_ConvertLightmap (int *in, byte *out, int width, int height, int stride)
-{
-       int i, j, shift;
-       stride -= (width*lightmapbytes);
-       // deal with lightmap brightness scale
-       shift = 7 + lightscalebit;
-       if (lightmaprgba)
-       {
-               for (i = 0;i < height;i++, out += stride)
-               {
-                       for (j = 0;j < width;j++, in += 3, out += 4)
-                       {
-                               out[0] = min(in[0] >> shift, 255);
-                               out[1] = min(in[1] >> shift, 255);
-                               out[2] = min(in[2] >> shift, 255);
-                               out[3] = 255;
-                       }
-               }
-       }
-       else
-       {
-               for (i = 0;i < height;i++, out += stride)
-               {
-                       for (j = 0;j < width;j++, in += 3, out += 3)
-                       {
-                               out[0] = min(in[0] >> shift, 255);
-                               out[1] = min(in[1] >> shift, 255);
-                               out[2] = min(in[2] >> shift, 255);
-                       }
-               }
-       }
-}
-
 /*
 ===============
 R_BuildLightMap
@@ -230,14 +171,10 @@ R_BuildLightMap
 Combine and scale multiple lightmaps into the 8.8 format in blocklights
 ===============
 */
-void R_BuildLightMap (msurface_t *surf, byte *dest, int stride, int dlightchanged)
+static void R_BuildLightMap (msurface_t *surf, int dlightchanged)
 {
-       int             smax, tmax;
-       int             i, j, size, size3;
-       byte    *lightmap;
-       int             scale;
-       int             maps;
-       int             *bl;
+       int             smax, tmax, i, j, size, size3, shift, scale, maps, *bl, stride, l;
+       byte    *lightmap, *out;
 
        // update cached lighting info
        surf->cached_dlight = 0;
@@ -278,9 +215,10 @@ void R_BuildLightMap (msurface_t *surf, byte *dest, int stride, int dlightchange
                else
                        memset(&blocklights[0], 0, size*3*sizeof(int));
 
-               if (r_dlightmap.value && surf->dlightframe == r_framecount)
+               if (surf->dlightframe == r_framecount && r_dlightmap.integer)
                {
-                       if ((surf->cached_dlight = R_AddDynamicLights(surf)))
+                       surf->cached_dlight = R_AddDynamicLights(surf);
+                       if (surf->cached_dlight)
                                c_light_polys++;
                        else if (dlightchanged)
                                return; // don't upload if only updating dlights and none mattered
@@ -293,45 +231,40 @@ void R_BuildLightMap (msurface_t *surf, byte *dest, int stride, int dlightchange
                                        *bl++ += *lightmap++ * scale;
        }
 
-       R_ConvertLightmap(blocklights, dest, smax, tmax, stride);
-}
-
-void R_UpdateLightmap(msurface_t *s, int lnum, int dlightschanged)
-{
-       int smax, tmax;
-       // upload the new lightmap texture fragment
-       if(r_upload.value)
-               glBindTexture(GL_TEXTURE_2D, lightmap_textures + lnum);
-       if (nosubimage || nosubimagefragments)
+       bl = blocklights;
+       out = templight;
+       // deal with lightmap brightness scale
+       shift = 7 + lightscalebit;
+       if (currentrenderentity->model->lightmaprgba)
        {
-               if (lightmapupdate[lnum][0] > s->light_t)
-                       lightmapupdate[lnum][0] = s->light_t;
-               if (lightmapupdate[lnum][1] < (s->light_t + ((s->extents[1]>>4)+1)))
-                       lightmapupdate[lnum][1] = (s->light_t + ((s->extents[1]>>4)+1));
-               if (lightmaprgba)
-                       R_BuildLightMap (s, lightmaps[s->lightmaptexturenum] + (s->light_t * BLOCK_WIDTH + s->light_s) * 4, BLOCK_WIDTH * 4, false);
-               else
-                       R_BuildLightMap (s, lightmaps[s->lightmaptexturenum] + (s->light_t * BLOCK_WIDTH + s->light_s) * 3, BLOCK_WIDTH * 3, false);
+               stride = (surf->lightmaptexturestride - smax) * 4;
+               for (i = 0;i < tmax;i++, out += stride)
+               {
+                       for (j = 0;j < smax;j++)
+                       {
+                               l = *bl++ >> shift;*out++ = min(l, 255);
+                               l = *bl++ >> shift;*out++ = min(l, 255);
+                               l = *bl++ >> shift;*out++ = min(l, 255);
+                               *out++ = 255;
+                       }
+               }
        }
        else
        {
-               smax = ((s->extents[0]>>4)+lightmapalign) & lightmapalignmask;
-               tmax = (s->extents[1]>>4)+1;
-               if (lightmaprgba)
+               stride = (surf->lightmaptexturestride - smax) * 3;
+               for (i = 0;i < tmax;i++, out += stride)
                {
-                       R_BuildLightMap (s, templight, smax * 4, false);
-                       if(r_upload.value)
-                               glTexSubImage2D(GL_TEXTURE_2D, 0, s->light_s, s->light_t, smax, tmax, GL_RGBA, GL_UNSIGNED_BYTE, templight);
-               }
-               else
-               {
-                       R_BuildLightMap (s, templight, smax * 3, false);
-                       if(r_upload.value)
-                               glTexSubImage2D(GL_TEXTURE_2D, 0, s->light_s, s->light_t, smax, tmax, GL_RGB , GL_UNSIGNED_BYTE, templight);
+                       for (j = 0;j < smax;j++)
+                       {
+                               l = *bl++ >> shift;*out++ = min(l, 255);
+                               l = *bl++ >> shift;*out++ = min(l, 255);
+                               l = *bl++ >> shift;*out++ = min(l, 255);
+                       }
                }
        }
-}
 
+       R_UpdateTexture(surf->lightmaptexture, templight);
+}
 
 /*
 ===============
@@ -340,7 +273,9 @@ R_TextureAnimation
 Returns the proper texture for a given time and base texture
 ===============
 */
-texture_t *R_TextureAnimation (texture_t *base)
+/*
+// note: this was manually inlined in R_PrepareSurfaces
+static texture_t *R_TextureAnimation (texture_t *base)
 {
        if (currentrenderentity->frame && base->alternate_anims != NULL)
                base = base->alternate_anims;
@@ -350,6 +285,7 @@ texture_t *R_TextureAnimation (texture_t *base)
 
        return base->anim_frames[(int)(cl.time * 5.0f) % base->anim_total];
 }
+*/
 
 
 /*
@@ -361,747 +297,1069 @@ texture_t *R_TextureAnimation (texture_t *base)
 */
 
 
-float  turbsin[256] =
+static float turbsin[256] =
 {
        #include "gl_warp_sin.h"
 };
 #define TURBSCALE (256.0 / (2 * M_PI))
 
-
-void UploadLightmaps(void)
+#define MAX_SURFVERTS 1024
+typedef struct
 {
-       int i;
-       if (nosubimage || nosubimagefragments)
-       {
-               for (i = 0;i < MAX_LIGHTMAPS;i++)
-               {
-                       if (lightmapupdate[i][0] < lightmapupdate[i][1])
-                       {
-                               if(r_upload.value)
-                               {
-                                       glBindTexture(GL_TEXTURE_2D, lightmap_textures + i);
-                                       if (nosubimage)
-                                       {
-                                               if (lightmaprgba)
-                                                       glTexImage2D(GL_TEXTURE_2D, 0, 3, BLOCK_WIDTH, BLOCK_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, lightmaps[i]);
-                                               else
-                                                       glTexImage2D(GL_TEXTURE_2D, 0, 3, BLOCK_WIDTH, BLOCK_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, lightmaps[i]);
-                                       }
-                                       else
-                                       {
-                                               if (lightmaprgba)
-                                                       glTexSubImage2D(GL_TEXTURE_2D, 0, 0, lightmapupdate[i][0], BLOCK_WIDTH, lightmapupdate[i][1] - lightmapupdate[i][0], GL_RGBA, GL_UNSIGNED_BYTE, lightmaps[i] + (BLOCK_WIDTH * 4 * lightmapupdate[i][0]));
-                                               else
-                                                       glTexSubImage2D(GL_TEXTURE_2D, 0, 0, lightmapupdate[i][0], BLOCK_WIDTH, lightmapupdate[i][1] - lightmapupdate[i][0], GL_RGB, GL_UNSIGNED_BYTE, lightmaps[i] + (BLOCK_WIDTH * 3 * lightmapupdate[i][0]));
-                                       }
-                               }
-                       }
-                       lightmapupdate[i][0] = BLOCK_HEIGHT;
-                       lightmapupdate[i][1] = 0;
-               }
-       }
+       float v[4];
+       float st[2];
+       float uv[2];
+       float c[4];
 }
+surfvert_t;
+static surfvert_t svert[MAX_SURFVERTS]; // used by the following functions
 
-float  wvert[1024*6]; // used by the following functions
-
-void RSurf_DrawSky(msurface_t *s, int transform)
+static int RSurfShader_Sky(int stage, msurface_t *s)
 {
-       glpoly_t *p;
-       int i;
-       float *v;
+       int                             i;
+       float                   number, length, dir[3], speedscale;
+       surfvertex_t    *v;
+       surfvert_t              *sv;
+       rmeshinfo_t             m;
 
        // LordHavoc: HalfLife maps have freaky skypolys...
-       if (hlbsp)
-               return;
+       if (currentrenderentity->model->ishlbsp)
+               return true;
 
-       for (p=s->polys ; p ; p=p->next)
+       if (stage == 0)
        {
-               if (currentskypoly < MAX_SKYPOLYS && currentskyvert + p->numverts <= MAX_SKYVERTS)
+               if (skyrendermasked)
                {
-                       skypoly[currentskypoly].firstvert = currentskyvert;
-                       skypoly[currentskypoly++].verts = p->numverts;
-                       if (transform)
+                       if (skyrendernow)
                        {
-                               for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
-                               {
-                                       softwaretransform(v, skyvert[currentskyvert].v);
-                                       currentskyvert++;
-                               }
+                               skyrendernow = false;
+                               R_Sky();
                        }
-                       else
+                       // draw depth-only polys
+                       memset(&m, 0, sizeof(m));
+                       m.transparent = false;
+                       m.blendfunc1 = GL_ZERO;
+                       m.blendfunc2 = GL_ONE;
+                       m.depthwrite = true;
+                       m.numtriangles = s->mesh.numtriangles;
+                       m.numverts = s->mesh.numverts;
+                       m.index = s->mesh.index;
+                       //m.cr = 0;
+                       //m.cg = 0;
+                       //m.cb = 0;
+                       //m.ca = 0;
+                       if (softwaretransform_complexity)
                        {
-                               for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
-                               {
-                                       VectorCopy(v, skyvert[currentskyvert].v);
-                                       currentskyvert++;
-                               }
+                               m.vertex = &svert[0].v[0];
+                               m.vertexstep = sizeof(surfvert_t);
+                               for (i = 0, sv = svert, v = s->mesh.vertex;i < m.numverts;i++, sv++, v++)
+                                       softwaretransform(v->v, sv->v);
                        }
-               }
-       }
-}
-
-int RSurf_Light(int *dlightbits, glpoly_t *polys)
-{
-       float           cr, cg, cb, radius, radius2, f, *v, *wv;
-       int                     i, a, b, lit = false;
-       unsigned int c, d;
-       dlight_t        *light;
-       vec_t           *lightorigin;
-       glpoly_t        *p;
-       for (a = 0;a < 8;a++)
-       {
-               if ((c = dlightbits[a]))
-               {
-                       for (b = 0, d = 1;c;b++, d <<= 1)
+                       else
                        {
-                               if (c & d)
-                               {
-                                       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;
-                                       radius2 = radius * 256.0f;
-                                       wv = wvert;
-                                       for (p = polys;p;p = p->next)
-                                       {
-                                               for (i = 0, v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
-                                               {
-                                                       f = VectorDistance2(wv, lightorigin);
-                                                       if (f < radius)
-                                                       {
-                                                               f = radius2 / (f + LIGHTOFFSET);
-                                                               wv[3] += cr * f;
-                                                               wv[4] += cg * f;
-                                                               wv[5] += cb * f;
-                                                               lit = true;
-                                                       }
-                                                       wv += 6;
-                                               }
-                                       }
-                               }
+                               m.vertex = &s->mesh.vertex[0].v[0];
+                               m.vertexstep = sizeof(surfvertex_t);
                        }
+                       R_Mesh_Draw(&m);
                }
-       }
-       return lit;
-}
-
-void RSurf_DrawWater(msurface_t *s, texture_t *t, int transform, int alpha)
-{
-       int             i;
-       float   os = turbsin[(int)(cl.time * TURBSCALE) & 255], ot = turbsin[(int)(cl.time * TURBSCALE + 96.0) & 255];
-       glpoly_t *p;
-       float   *v;
-       // FIXME: make fog texture if water texture is transparent?
-
-       if (s->dlightframe != r_framecount)
-       {
-               vec3_t temp;
-               // LordHavoc: fast path for no vertex lighting cases
-               if (transform)
+               else if (skyrenderglquake)
                {
-                       if (r_waterripple.value)
-                       {
-                               for (p=s->polys ; p ; p=p->next)
-                               {
-                                       transpolybegin(R_GetTexture(t->texture), R_GetTexture(t->glowtexture), 0, TPOLYTYPE_ALPHA);
-                                       for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
-                                       {
-                                               softwaretransform(v, temp);
-                                               transpolyvert(temp[0], temp[1], temp[2] + r_waterripple.value * turbsin[(int)((temp[0]*(1.0f/32.0f)+cl.time) * TURBSCALE) & 255] * turbsin[(int)((temp[1]*(1.0f/32.0f)+cl.time) * TURBSCALE) & 255] * (1.0f / 64.0f), (v[3] + os) * (1.0f/64.0f), (v[4] + ot) * (1.0f/64.0f), 128, 128, 128, alpha);
-                                       }
-                                       transpolyend();
-                               }
-                       }
+                       memset(&m, 0, sizeof(m));
+                       m.transparent = false;
+                       m.blendfunc1 = GL_ONE;
+                       m.blendfunc2 = GL_ZERO;
+                       m.numtriangles = s->mesh.numtriangles;
+                       m.numverts = s->mesh.numverts;
+                       m.index = s->mesh.index;
+                       m.vertex = &svert[0].v[0];
+                       m.vertexstep = sizeof(surfvert_t);
+                       m.cr = 1;
+                       m.cg = 1;
+                       m.cb = 1;
+                       m.ca = 1;
+                       if (r_mergesky.integer)
+                               m.tex[0] = R_GetTexture(mergeskytexture);
                        else
+                               m.tex[0] = R_GetTexture(solidskytexture);
+                       m.texcoords[0] = &svert[0].st[0];
+                       m.texcoordstep[0] = sizeof(surfvert_t);
+                       speedscale = cl.time * (8.0/128.0);
+                       speedscale -= (int)speedscale;
+                       for (i = 0, sv = svert, v = s->mesh.vertex;i < m.numverts;i++, sv++, v++)
                        {
-                               for (p=s->polys ; p ; p=p->next)
-                               {
-                                       transpolybegin(R_GetTexture(t->texture), R_GetTexture(t->glowtexture), 0, TPOLYTYPE_ALPHA);
-                                       for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
-                                       {
-                                               softwaretransform(v, temp);
-                                               transpolyvert(temp[0], temp[1], temp[2], (v[3] + os) * (1.0f/64.0f), (v[4] + ot) * (1.0f/64.0f), 128, 128, 128, alpha);
-                                       }
-                                       transpolyend();
-                               }
+                               softwaretransform(v->v, sv->v);
+                               VectorSubtract (sv->v, r_origin, dir);
+                               // flatten the sphere
+                               dir[2] *= 3;
+
+                               number = DotProduct(dir, dir);
+                               #if SLOWMATH
+                               length = 3.0f / sqrt(number);
+                               #else
+                               *((long *)&length) = 0x5f3759df - ((* (long *) &number) >> 1);
+                               length = 3.0f * (length * (1.5f - (number * 0.5f * length * length)));
+                               #endif
+
+                               sv->st[0] = speedscale + dir[0] * length;
+                               sv->st[1] = speedscale + dir[1] * length;
                        }
+                       R_Mesh_Draw(&m);
                }
                else
                {
-                       if (r_waterripple.value)
+                       // flat color
+                       memset(&m, 0, sizeof(m));
+                       m.transparent = false;
+                       m.blendfunc1 = GL_ONE;
+                       m.blendfunc2 = GL_ZERO;
+                       m.numtriangles = s->mesh.numtriangles;
+                       m.numverts = s->mesh.numverts;
+                       m.index = s->mesh.index;
+                       m.cr = fogcolor[0];
+                       m.cg = fogcolor[1];
+                       m.cb = fogcolor[2];
+                       m.ca = 1;
+                       if (softwaretransform_complexity)
                        {
-                               for (p=s->polys ; p ; p=p->next)
-                               {
-                                       transpolybegin(R_GetTexture(t->texture), R_GetTexture(t->glowtexture), 0, TPOLYTYPE_ALPHA);
-                                       for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
-                                               transpolyvert(v[0], v[1], v[2] + r_waterripple.value * turbsin[(int)((v[0]*(1.0f/32.0f)+cl.time) * TURBSCALE) & 255] * turbsin[(int)((v[1]*(1.0f/32.0f)+cl.time) * TURBSCALE) & 255] * (1.0f / 64.0f), (v[3] + os) * (1.0f/64.0f), (v[4] + ot) * (1.0f/64.0f), 128, 128, 128, alpha);
-                                       transpolyend();
-                               }
+                               m.vertex = &svert[0].v[0];
+                               m.vertexstep = sizeof(surfvert_t);
+                               for (i = 0, sv = svert, v = s->mesh.vertex;i < m.numverts;i++, sv++, v++)
+                                       softwaretransform(v->v, sv->v);
                        }
                        else
                        {
-                               for (p=s->polys ; p ; p=p->next)
-                               {
-                                       transpolybegin(R_GetTexture(t->texture), R_GetTexture(t->glowtexture), 0, TPOLYTYPE_ALPHA);
-                                       for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
-                                               transpolyvert(v[0], v[1], v[2], (v[3] + os) * (1.0f/64.0f), (v[4] + ot) * (1.0f/64.0f), 128, 128, 128, alpha);
-                                       transpolyend();
-                               }
+                               m.vertex = &s->mesh.vertex[0].v[0];
+                               m.vertexstep = sizeof(surfvertex_t);
                        }
+                       R_Mesh_Draw(&m);
                }
+               return false;
        }
-       else
+       else if (stage == 1)
        {
-               float *wv;
-               wv = wvert;
-               for (p = s->polys;p;p = p->next)
+               if (skyrenderglquake && !r_mergesky.integer)
                {
-                       for (i = 0, v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
+                       memset(&m, 0, sizeof(m));
+                       m.transparent = false;
+                       m.blendfunc1 = GL_SRC_ALPHA;
+                       m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
+                       m.numtriangles = s->mesh.numtriangles;
+                       m.numverts = s->mesh.numverts;
+                       m.index = s->mesh.index;
+                       m.vertex = &svert[0].v[0];
+                       m.vertexstep = sizeof(surfvert_t);
+                       m.cr = 1;
+                       m.cg = 1;
+                       m.cb = 1;
+                       m.ca = 1;
+                       m.tex[0] = R_GetTexture(alphaskytexture);
+                       m.texcoords[0] = &svert[0].st[0];
+                       m.texcoordstep[0] = sizeof(surfvert_t);
+                       speedscale = cl.time * (16.0/128.0);
+                       speedscale -= (int)speedscale;
+                       for (i = 0, sv = svert, v = s->mesh.vertex;i < m.numverts;i++, sv++, v++)
                        {
-                               if (transform)
-                                       softwaretransform(v, wv);
-                               else
-                                       VectorCopy(v, wv);
-                               if (r_waterripple.value)
-                                       wv[2] += r_waterripple.value * turbsin[(int)((wv[0]*(1.0f/32.0f)+cl.time) * TURBSCALE) & 255] * turbsin[(int)((wv[1]*(1.0f/32.0f)+cl.time) * TURBSCALE) & 255] * (1.0f / 64.0f);
-                               wv[3] = wv[4] = wv[5] = 128.0f;
-                               wv += 6;
+                               softwaretransform(v->v, sv->v);
+                               VectorSubtract (sv->v, r_origin, dir);
+                               // flatten the sphere
+                               dir[2] *= 3;
+
+                               number = DotProduct(dir, dir);
+                               #if SLOWMATH
+                               length = 3.0f / sqrt(number);
+                               #else
+                               *((long *)&length) = 0x5f3759df - ((* (long *) &number) >> 1);
+                               length = 3.0f * (length * (1.5f - (number * 0.5f * length * length)));
+                               #endif
+
+                               sv->st[0] = speedscale + dir[0] * length;
+                               sv->st[1] = speedscale + dir[1] * length;
                        }
+                       R_Mesh_Draw(&m);
+                       return false;
                }
-               if (s->dlightframe == r_framecount)
-                       RSurf_Light(s->dlightbits, s->polys);
-               wv = wvert;
-               for (p=s->polys ; p ; p=p->next)
-               {
-                       transpolybegin(R_GetTexture(t->texture), R_GetTexture(t->glowtexture), 0, 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] + os) * (1.0f/64.0f), (v[4] + ot) * (1.0f/64.0f), wv[3], wv[4], wv[5], alpha);
-                       transpolyend();
-               }
+               return true;
        }
+       else
+               return true;
 }
 
-void RSurf_DrawWall(msurface_t *s, texture_t *t, int transform)
+static int RSurf_Light(int *dlightbits, int numverts)
 {
-       int             i, lit = false, polys = 0, verts = 0;
-       float   *v;
-       glpoly_t *p;
-       wallpoly_t *wp;
-       wallvert_t *out;
-       wallvertcolor_t *outcolor;
-       // check for lightmap modification
-       if (s->cached_dlight
-        || r_ambient.value != s->cached_ambient
-        || lightscalebit != s->cached_lightscalebit
-        || (r_dynamic.value
-        && (d_lightstylevalue[s->styles[0]] != s->cached_light[0]
-        ||  d_lightstylevalue[s->styles[1]] != s->cached_light[1]
-        ||  d_lightstylevalue[s->styles[2]] != s->cached_light[2]
-        ||  d_lightstylevalue[s->styles[3]] != s->cached_light[3])))
-               R_UpdateLightmap(s, s->lightmaptexturenum, false); // base lighting changed
-       else if (r_dynamic.value && r_dlightmap.value && s->dlightframe == r_framecount)
-               R_UpdateLightmap(s, s->lightmaptexturenum, true); // only dlights
-
-       if (s->dlightframe != r_framecount || r_dlightmap.value)
+       float           f;
+       int                     i, l, lit = false;
+       rdlight_t       *rd;
+       vec3_t          lightorigin;
+       surfvert_t      *sv;
+       for (l = 0;l < r_numdlights;l++)
        {
-               // LordHavoc: fast path version for no vertex lighting cases
-               out = &wallvert[currentwallvert];
-               for (p = s->polys;p;p = p->next)
+               if (dlightbits[l >> 5] & (1 << (l & 31)))
                {
-                       if ((currentwallpoly >= MAX_WALLPOLYS) || (currentwallvert+p->numverts > MAX_WALLVERTS))
-                               return;
-                       wp = &wallpoly[currentwallpoly++];
-                       wp->texnum = (unsigned short) R_GetTexture(t->texture);
-                       wp->lighttexnum = (unsigned short) (lightmap_textures + s->lightmaptexturenum);
-                       wp->glowtexnum = (unsigned short) R_GetTexture(t->glowtexture);
-                       wp->firstvert = currentwallvert;
-                       wp->numverts = p->numverts;
-                       wp->lit = false;
-                       wp++;
-                       currentwallvert += p->numverts;
-                       v = p->verts[0];
-                       if (transform)
-                       {
-                               for (i = 0;i < p->numverts;i++, v += VERTEXSIZE, out++)
-                               {
-                                       softwaretransform(v, out->vert);
-                                       out->vert[3] = v[3];
-                                       out->vert[4] = v[4];
-                                       out->vert[5] = v[5];
-                                       out->vert[6] = v[6];
-                               }
-                       }
-                       else
+                       rd = &r_dlight[l];
+                       // FIXME: support softwareuntransform here and make bmodels use hardware transform?
+                       VectorCopy(rd->origin, lightorigin);
+                       for (i = 0, sv = svert;i < numverts;i++, sv++)
                        {
-                               /*
-                               for (i = 0;i < p->numverts;i++, v += VERTEXSIZE, out++)
+                               f = VectorDistance2(sv->v, lightorigin) + LIGHTOFFSET;
+                               if (f < rd->cullradius2)
                                {
-                                       VectorCopy(v, out->vert);
-                                       out->vert[3] = v[3];
-                                       out->vert[4] = v[4];
-                                       out->vert[5] = v[5];
-                                       out->vert[6] = v[6];
+                                       f = (1.0f / f) - rd->lightsubtract;
+                                       sv->c[0] += rd->light[0] * f;
+                                       sv->c[1] += rd->light[1] * f;
+                                       sv->c[2] += rd->light[2] * f;
+                                       lit = true;
                                }
-                               */
-                               memcpy(out, v, sizeof(vec_t) * VERTEXSIZE * p->numverts);
-                               out += p->numverts;
                        }
                }
        }
+       return lit;
+}
+
+static void RSurfShader_Water_Pass_Base(msurface_t *s)
+{
+       int                             i;
+       float                   diff[3], alpha, ifog;
+       surfvertex_t    *v;
+       surfvert_t              *sv;
+       rmeshinfo_t             m;
+       alpha = s->flags & SURF_DRAWNOALPHA ? 1 : r_wateralpha.value;
+
+       memset(&m, 0, sizeof(m));
+       if (alpha != 1 || s->currenttexture->fogtexture != NULL)
+       {
+               m.transparent = true;
+               m.blendfunc1 = GL_SRC_ALPHA;
+               m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
+       }
        else
        {
-               float *wv;
-               wv = wvert;
-               for (p = s->polys;p;p = p->next)
+               m.transparent = false;
+               m.blendfunc1 = GL_SRC_ALPHA;
+               m.blendfunc2 = GL_ZERO;
+       }
+       m.numtriangles = s->mesh.numtriangles;
+       m.numverts = s->mesh.numverts;
+       m.index = s->mesh.index;
+       m.vertex = &svert[0].v[0];
+       m.vertexstep = sizeof(surfvert_t);
+       m.color = &svert[0].c[0];
+       m.colorstep = sizeof(surfvert_t);
+       m.tex[0] = R_GetTexture(s->currenttexture->texture);
+       m.texcoords[0] = &svert[0].st[0];
+       m.texcoordstep[0] = sizeof(surfvert_t);
+       for (i = 0, sv = svert, v = s->mesh.vertex;i < m.numverts;i++, sv++, v++)
+       {
+               softwaretransform(v->v, sv->v);
+               if (r_waterripple.value)
+                       sv->v[2] += r_waterripple.value * (1.0f / 64.0f) * turbsin[(int)((v->v[0]*(1.0f/32.0f)+cl.time) * TURBSCALE) & 255] * turbsin[(int)((v->v[1]*(1.0f/32.0f)+cl.time) * TURBSCALE) & 255];
+               if (s->flags & SURF_DRAWFULLBRIGHT)
                {
-                       for (i = 0, v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
-                       {
-                               if (transform)
-                                       softwaretransform(v, wv);
-                               else
-                                       VectorCopy(v, wv);
-                               wv[3] = wv[4] = wv[5] = 0.0f;
-                               wv += 6;
-                       }
-                       verts += p->numverts;
-                       polys++;
+                       sv->c[0] = 1;
+                       sv->c[1] = 1;
+                       sv->c[2] = 1;
+                       sv->c[3] = alpha;
                }
-               if ((currentwallpoly + polys > MAX_WALLPOLYS) || (currentwallvert+verts > MAX_WALLVERTS))
-                       return;
-               if ((!r_dlightmap.value) && s->dlightframe == r_framecount)
-                       lit = RSurf_Light(s->dlightbits, s->polys);
-               wv = wvert;
-               wp = &wallpoly[currentwallpoly];
-               out = &wallvert[currentwallvert];
-               outcolor = &wallvertcolor[currentwallvert];
-               currentwallpoly += polys;
-               for (p = s->polys;p;p = p->next)
+               else
                {
-                       v = p->verts[0];
-                       wp->texnum = (unsigned short) R_GetTexture(t->texture);
-                       wp->lighttexnum = (unsigned short) (lightmap_textures + s->lightmaptexturenum);
-                       wp->glowtexnum = (unsigned short) R_GetTexture(t->glowtexture);
-                       wp->firstvert = currentwallvert;
-                       wp->numverts = p->numverts;
-                       wp->lit = lit;
-                       wp++;
-                       currentwallvert += p->numverts;
-                       for (i = 0;i < p->numverts;i++, v += VERTEXSIZE, wv += 6, out++, outcolor++)
-                       {
-                               if (lit)
-                               {
-                                       if (lighthalf)
-                                       {
-                                               outcolor->r = (byte) (bound(0, (int) wv[3] >> 1, 255));
-                                               outcolor->g = (byte) (bound(0, (int) wv[4] >> 1, 255));
-                                               outcolor->b = (byte) (bound(0, (int) wv[5] >> 1, 255));
-                                               outcolor->a = 255;
-                                       }
-                                       else
-                                       {
-                                               outcolor->r = (byte) (bound(0, (int) wv[3], 255));
-                                               outcolor->g = (byte) (bound(0, (int) wv[4], 255));
-                                               outcolor->b = (byte) (bound(0, (int) wv[5], 255));
-                                               outcolor->a = 255;
-                                       }
-                               }
-                               out->vert[0] = wv[0];
-                               out->vert[1] = wv[1];
-                               out->vert[2] = wv[2];
-                               out->vert[3] = v[3];
-                               out->vert[4] = v[4];
-                               out->vert[5] = v[5];
-                               out->vert[6] = v[6];
-                       }
+                       sv->c[0] = 0.5f;
+                       sv->c[1] = 0.5f;
+                       sv->c[2] = 0.5f;
+                       sv->c[3] = alpha;
+               }
+               sv->st[0] = (v->st[0] + turbsin[(int)((v->st[1]*0.125f+cl.time) * TURBSCALE) & 255]) * (1.0f / 64.0f);
+               sv->st[1] = (v->st[1] + turbsin[(int)((v->st[0]*0.125f+cl.time) * TURBSCALE) & 255]) * (1.0f / 64.0f);
+       }
+       if (s->dlightframe == r_framecount && !(s->flags & SURF_DRAWFULLBRIGHT))
+               RSurf_Light(s->dlightbits, m.numverts);
+       if (fogenabled)
+       {
+               for (i = 0, sv = svert;i < m.numverts;i++, sv++)
+               {
+                       VectorSubtract(sv->v, r_origin, diff);
+                       ifog = 1 - exp(fogdensity/DotProduct(diff, diff));
+                       sv->c[0] *= ifog;
+                       sv->c[1] *= ifog;
+                       sv->c[2] *= ifog;
                }
        }
+       R_Mesh_Draw(&m);
 }
 
-// LordHavoc: transparent brush models
-void RSurf_DrawWallVertex(msurface_t *s, texture_t *t, int transform, int isbmodel)
+static void RSurfShader_Water_Pass_Glow(msurface_t *s)
 {
-       int i, alpha, size3;
-       float *v, *wv, scale;
-       glpoly_t *p;
-       byte *lm;
-       alpha = (int) (currentrenderentity->alpha * 255.0f);
-       size3 = ((s->extents[0]>>4)+1)*((s->extents[1]>>4)+1)*3; // *3 for colored lighting
-       wv = wvert;
-       for (p = s->polys;p;p = p->next)
+       int                             i;
+       float                   diff[3], alpha, ifog;
+       surfvertex_t    *v;
+       surfvert_t              *sv;
+       rmeshinfo_t             m;
+       alpha = s->flags & SURF_DRAWNOALPHA ? 1 : r_wateralpha.value;
+
+       memset(&m, 0, sizeof(m));
+       m.transparent = alpha != 1 || s->currenttexture->fogtexture != NULL;
+       m.blendfunc1 = GL_SRC_ALPHA;
+       m.blendfunc2 = GL_ONE;
+       m.numtriangles = s->mesh.numtriangles;
+       m.numverts = s->mesh.numverts;
+       m.index = s->mesh.index;
+       m.vertex = &svert[0].v[0];
+       m.vertexstep = sizeof(surfvert_t);
+       m.cr = 1;
+       m.cg = 1;
+       m.cb = 1;
+       m.ca = alpha;
+       m.tex[0] = R_GetTexture(s->currenttexture->glowtexture);
+       m.texcoords[0] = &svert[0].st[0];
+       m.texcoordstep[0] = sizeof(surfvert_t);
+       if (fogenabled)
        {
-               for (i = 0, v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
+               m.color = &svert[0].c[0];
+               m.colorstep = sizeof(surfvert_t);
+               for (i = 0, sv = svert, v = s->mesh.vertex;i < m.numverts;i++, sv++, v++)
                {
-                       if (transform)
-                               softwaretransform(v, wv);
-                       else
-                               VectorCopy(v, wv);
-                       wv[3] = wv[4] = wv[5] = r_ambient.value * 2.0f;
-                       if (s->styles[0] != 255)
-                       {
-                               lm = (byte *)((long) s->samples + (int) v[7]);
-                               scale = d_lightstylevalue[s->styles[0]] * (1.0f / 128.0f);wv[3] += lm[size3*0+0] * scale;wv[4] += lm[size3*0+1] * scale;wv[5] += lm[size3*0+2] * scale;
-                               if (s->styles[1] != 255)
-                               {
-                                       scale = d_lightstylevalue[s->styles[1]] * (1.0f / 128.0f);wv[3] += lm[size3*1+0] * scale;wv[4] += lm[size3*1+1] * scale;wv[5] += lm[size3*1+2] * scale;
-                                       if (s->styles[2] != 255)
-                                       {
-                                               scale = d_lightstylevalue[s->styles[2]] * (1.0f / 128.0f);wv[3] += lm[size3*2+0] * scale;wv[4] += lm[size3*2+1] * scale;wv[5] += lm[size3*2+2] * scale;
-                                               if (s->styles[3] != 255)
-                                               {
-                                                       scale = d_lightstylevalue[s->styles[3]] * (1.0f / 128.0f);wv[3] += lm[size3*3+0] * scale;wv[4] += lm[size3*3+1] * scale;wv[5] += lm[size3*3+2] * scale;
-                                               }
-                                       }
-                               }
-                       }
-                       wv += 6;
+                       softwaretransform(v->v, sv->v);
+                       if (r_waterripple.value)
+                               sv->v[2] += r_waterripple.value * (1.0f / 64.0f) * turbsin[(int)((v->v[0]*(1.0f/32.0f)+cl.time) * TURBSCALE) & 255] * turbsin[(int)((v->v[1]*(1.0f/32.0f)+cl.time) * TURBSCALE) & 255];
+                       sv->st[0] = (v->st[0] + turbsin[(int)((v->st[1]*0.125f+cl.time) * TURBSCALE) & 255]) * (1.0f / 64.0f);
+                       sv->st[1] = (v->st[1] + turbsin[(int)((v->st[0]*0.125f+cl.time) * TURBSCALE) & 255]) * (1.0f / 64.0f);
+                       VectorSubtract(sv->v, r_origin, diff);
+                       ifog = 1 - exp(fogdensity/DotProduct(diff, diff));
+                       sv->c[0] = m.cr * ifog;
+                       sv->c[1] = m.cg * ifog;
+                       sv->c[2] = m.cb * ifog;
+                       sv->c[3] = m.ca;
                }
        }
-       if (s->dlightframe == r_framecount)
-               RSurf_Light(s->dlightbits, s->polys);
-       wv = wvert;
-       if (alpha != 255 || currentrenderentity->colormod[0] != 1 || currentrenderentity->colormod[1] != 1 || currentrenderentity->colormod[2] != 1)
+       else
        {
-               for (p = s->polys;p;p = p->next)
+               for (i = 0, sv = svert, v = s->mesh.vertex;i < m.numverts;i++, sv++, v++)
                {
-                       v = p->verts[0];
-                       transpolybegin(R_GetTexture(t->texture), R_GetTexture(t->glowtexture), 0, currentrenderentity->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] * currentrenderentity->colormod[0], wv[4] * currentrenderentity->colormod[1], wv[5] * currentrenderentity->colormod[2], alpha);
-                       transpolyend();
+                       softwaretransform(v->v, sv->v);
+                       if (r_waterripple.value)
+                               sv->v[2] += r_waterripple.value * (1.0f / 64.0f) * turbsin[(int)((v->v[0]*(1.0f/32.0f)+cl.time) * TURBSCALE) & 255] * turbsin[(int)((v->v[1]*(1.0f/32.0f)+cl.time) * TURBSCALE) & 255];
+                       sv->st[0] = (v->st[0] + turbsin[(int)((v->st[1]*0.125f+cl.time) * TURBSCALE) & 255]) * (1.0f / 64.0f);
+                       sv->st[1] = (v->st[1] + turbsin[(int)((v->st[0]*0.125f+cl.time) * TURBSCALE) & 255]) * (1.0f / 64.0f);
                }
        }
-       else
+       R_Mesh_Draw(&m);
+}
+
+static void RSurfShader_Water_Pass_Fog(msurface_t *s)
+{
+       int                             i;
+       float                   alpha;
+       surfvertex_t    *v;
+       surfvert_t              *sv;
+       rmeshinfo_t             m;
+       vec3_t                  diff;
+       alpha = s->flags & SURF_DRAWNOALPHA ? 1 : r_wateralpha.value;
+
+       memset(&m, 0, sizeof(m));
+       m.transparent = alpha != 1 || s->currenttexture->fogtexture != NULL;
+       m.blendfunc1 = GL_SRC_ALPHA;
+       m.blendfunc2 = GL_ONE;
+       m.numtriangles = s->mesh.numtriangles;
+       m.numverts = s->mesh.numverts;
+       m.index = s->mesh.index;
+       m.vertex = &svert[0].v[0];
+       m.vertexstep = sizeof(surfvert_t);
+       m.color = &svert[0].c[0];
+       m.colorstep = sizeof(surfvert_t);
+       m.tex[0] = R_GetTexture(s->currenttexture->fogtexture);
+       m.texcoords[0] = &svert[0].st[0];
+       m.texcoordstep[0] = sizeof(surfvert_t);
+
+       for (i = 0, sv = svert, v = s->mesh.vertex;i < m.numverts;i++, sv++, v++)
        {
-               for (p = s->polys;p;p = p->next)
+               softwaretransform(v->v, sv->v);
+               if (r_waterripple.value)
+                       sv->v[2] += r_waterripple.value * (1.0f / 64.0f) * turbsin[(int)((v->v[0]*(1.0f/32.0f)+cl.time) * TURBSCALE) & 255] * turbsin[(int)((v->v[1]*(1.0f/32.0f)+cl.time) * TURBSCALE) & 255];
+               if (m.tex[0])
                {
-                       v = p->verts[0];
-                       transpolybegin(R_GetTexture(t->texture), R_GetTexture(t->glowtexture), 0, currentrenderentity->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();
+                       sv->st[0] = (v->st[0] + turbsin[(int)((v->st[1]*0.125f+cl.time) * TURBSCALE) & 255]) * (1.0f / 64.0f);
+                       sv->st[1] = (v->st[1] + turbsin[(int)((v->st[0]*0.125f+cl.time) * TURBSCALE) & 255]) * (1.0f / 64.0f);
                }
+               VectorSubtract(sv->v, r_origin, diff);
+               sv->c[0] = fogcolor[0];
+               sv->c[1] = fogcolor[1];
+               sv->c[2] = fogcolor[2];
+               sv->c[3] = alpha * exp(fogdensity/DotProduct(diff, diff));
        }
+       R_Mesh_Draw(&m);
 }
 
-void R_NoVisMarkLights (vec3_t lightorigin, dlight_t *light, int bit, int bitindex, model_t *model);
-
-float bmverts[256*3];
-
-int vertexworld;
-
-// LordHavoc: disabled clipping on bmodels because they tend to intersect things sometimes
-/*
-void RBrushModelSurf_DoVisible(msurface_t *surf)
+static int RSurfShader_Water(int stage, msurface_t *s)
 {
-//     float *v, *bmv, *endbmv;
-//     glpoly_t *p;
-//     for (p = surf->polys;p;p = p->next)
-//     {
-//             for (v = p->verts[0], bmv = bmpoints, endbmv = bmv + p->numverts * 3;bmv < endbmv;v += VERTEXSIZE, bmv += 3)
-//                     softwaretransform(v, bmv);
-//             if (R_Clip_Polygon(bmpoints, p->numverts, sizeof(float) * 3, surf->flags & SURF_CLIPSOLID))
-                       surf->visframe = r_framecount;
-//     }
+       switch(stage)
+       {
+       case 0:
+               RSurfShader_Water_Pass_Base(s);
+               return false;
+       case 1:
+               if (s->currenttexture->glowtexture)
+                       RSurfShader_Water_Pass_Glow(s);
+               return false;
+       case 2:
+               if (fogenabled)
+               {
+                       RSurfShader_Water_Pass_Fog(s);
+                       return false;
+               }
+               else
+                       return true;
+       default:
+               return true;
+       }
 }
-*/
 
-/*
-void RBrushModelSurf_Callback(void *data, void *data2)
+static void RSurfShader_Wall_Pass_BaseMTex(msurface_t *s)
 {
-       msurface_t *surf = data;
-       texture_t *t;
-
-       currentrenderentity = data2;
-*/
-       /*
-       // FIXME: implement better dupe prevention in AddPolygon callback code
-       if (ent->render.model->firstmodelsurface != 0)
+       int                             i;
+       float                   diff[3], ifog;
+       surfvertex_t    *v;
+       surfvert_t              *sv;
+       rmeshinfo_t             m;
+
+       memset(&m, 0, sizeof(m));
+       if (currentrenderentity->effects & EF_ADDITIVE)
        {
-               // it's not an instanced model, so we already rely on there being only one of it (usually a valid assumption, but QC can break this)
-               if (surf->visframe == r_framecount)
-                       return;
+               m.transparent = true;
+               m.blendfunc1 = GL_SRC_ALPHA;
+               m.blendfunc2 = GL_ONE;
        }
-       */
-/*
-       surf->visframe = r_framecount;
-
-       c_faces++;
-
-       softwaretransformforbrushentity (currentrenderentity);
-
-       if (surf->flags & (SURF_DRAWSKY | SURF_DRAWTURB))
+       else if (currentrenderentity != &cl_entities[0].render && (s->currenttexture->fogtexture != NULL || currentrenderentity->alpha != 1))
        {
-               // sky and liquid don't need sorting (skypoly/transpoly)
-               if (surf->flags & SURF_DRAWSKY)
-                       RSurf_DrawSky(surf, true);
+               m.transparent = true;
+               m.blendfunc1 = GL_SRC_ALPHA;
+               m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
+       }
+       else
+       {
+               m.transparent = false;
+               m.blendfunc1 = GL_ONE;
+               m.blendfunc2 = GL_ZERO;
+       }
+       m.numtriangles = s->mesh.numtriangles;
+       m.numverts = s->mesh.numverts;
+       m.index = s->mesh.index;
+       m.cr = 1;
+       if (lighthalf)
+               m.cr *= 2;
+       if (gl_combine.integer)
+               m.cr *= 4;
+       m.cg = m.cr;
+       m.cb = m.cr;
+       m.ca = 1;
+       m.tex[0] = R_GetTexture(s->currenttexture->texture);
+       m.tex[1] = R_GetTexture(s->lightmaptexture);
+       m.texcoords[0] = &s->mesh.vertex->st[0];
+       m.texcoords[1] = &s->mesh.vertex->uv[0];
+       m.texcoordstep[0] = sizeof(surfvertex_t);
+       m.texcoordstep[1] = sizeof(surfvertex_t);
+       if (fogenabled)
+       {
+               m.color = &svert[0].c[0];
+               m.colorstep = sizeof(surfvert_t);
+               if (softwaretransform_complexity)
+               {
+                       m.vertex = &svert[0].v[0];
+                       m.vertexstep = sizeof(surfvert_t);
+                       for (i = 0, sv = svert, v = s->mesh.vertex;i < m.numverts;i++, sv++, v++)
+                       {
+                               softwaretransform(v->v, sv->v);
+                               VectorSubtract(sv->v, r_origin, diff);
+                               ifog = 1 - exp(fogdensity/DotProduct(diff, diff));
+                               sv->c[0] = m.cr * ifog;
+                               sv->c[1] = m.cg * ifog;
+                               sv->c[2] = m.cb * ifog;
+                               sv->c[3] = m.ca;
+                       }
+               }
                else
-                       RSurf_DrawWater(surf, R_TextureAnimation(surf->texinfo->texture), true, surf->flags & SURF_DRAWNOALPHA ? 255 : wateralpha);
+               {
+                       m.vertex = &s->mesh.vertex->v[0];
+                       m.vertexstep = sizeof(surfvertex_t);
+                       for (i = 0, sv = svert, v = s->mesh.vertex;i < m.numverts;i++, sv++, v++)
+                       {
+                               VectorSubtract(v->v, r_origin, diff);
+                               ifog = 1 - exp(fogdensity/DotProduct(diff, diff));
+                               sv->c[0] = m.cr * ifog;
+                               sv->c[1] = m.cg * ifog;
+                               sv->c[2] = m.cb * ifog;
+                               sv->c[3] = m.ca;
+                       }
+               }
        }
        else
        {
-               t = R_TextureAnimation(surf->texinfo->texture);
-               if (t->transparent || vertexworld || ent->render.alpha != 1 || ent->render.model->firstmodelsurface == 0 || (ent->render.effects & EF_FULLBRIGHT) || ent->render.colormod[0] != 1 || ent->render.colormod[2] != 1 || ent->render.colormod[2] != 1)
-                       RSurf_DrawWallVertex(surf, t, true, true);
+               if (softwaretransform_complexity)
+               {
+                       m.vertex = &svert[0].v[0];
+                       m.vertexstep = sizeof(surfvert_t);
+                       for (i = 0, sv = svert, v = s->mesh.vertex;i < m.numverts;i++, sv++, v++)
+                               softwaretransform(v->v, sv->v);
+               }
                else
-                       RSurf_DrawWall(surf, t, true);
+               {
+                       m.vertex = &s->mesh.vertex->v[0];
+                       m.vertexstep = sizeof(surfvertex_t);
+               }
        }
+       R_Mesh_Draw(&m);
 }
-*/
 
-/*
-=================
-R_DrawBrushModel
-=================
-*/
-void R_DrawBrushModel (void)
+static void RSurfShader_Wall_Pass_BaseTexture(msurface_t *s)
 {
-       int                     i/*, j*/, vertexlit, rotated, transform;
-       msurface_t      *s;
-       model_t         *model;
-       vec3_t          org, temp, forward, right, up;
-//     glpoly_t        *p;
-       texture_t       *t;
-
-       model = currentrenderentity->model;
-
-       c_bmodels++;
-
-       VectorSubtract (r_origin, currentrenderentity->origin, modelorg);
-       rotated = false;
-       transform = false;
-       if (currentrenderentity->angles[0] || currentrenderentity->angles[1] || currentrenderentity->angles[2])
+       int                             i;
+       surfvertex_t    *v;
+       surfvert_t              *sv;
+       rmeshinfo_t             m;
+
+       memset(&m, 0, sizeof(m));
+       m.transparent = false;
+       m.blendfunc1 = GL_ONE;
+       m.blendfunc2 = GL_ZERO;
+       m.numtriangles = s->mesh.numtriangles;
+       m.numverts = s->mesh.numverts;
+       m.index = s->mesh.index;
+       if (lighthalf)
        {
-               transform = true;
-               rotated = true;
-               VectorCopy (modelorg, temp);
-               AngleVectors (currentrenderentity->angles, forward, right, up);
-               modelorg[0] = DotProduct (temp, forward);
-               modelorg[1] = -DotProduct (temp, right);
-               modelorg[2] = DotProduct (temp, up);
+               m.cr = 2;
+               m.cg = 2;
+               m.cb = 2;
        }
-       else if (currentrenderentity->origin[0] || currentrenderentity->origin[1] || currentrenderentity->origin[2] || currentrenderentity->scale)
-               transform = true;
-
-       if (transform)
-               softwaretransformforbrushentity (currentrenderentity);
-
-       for (i = 0, s = &model->surfaces[model->firstmodelsurface];i < model->nummodelsurfaces;i++, s++)
+       else
        {
-               s->visframe = -1;
-               if (((s->flags & SURF_PLANEBACK) == 0) == (PlaneDiff(modelorg, s->plane) >= 0))
-                       s->visframe = r_framecount;
+               m.cr = 1;
+               m.cg = 1;
+               m.cb = 1;
        }
-
-// calculate dynamic lighting for bmodel if it's not an instanced model
-       for (i = 0;i < MAX_DLIGHTS;i++)
+       m.ca = 1;
+       m.tex[0] = R_GetTexture(s->currenttexture->texture);
+       m.texcoords[0] = &s->mesh.vertex->st[0];
+       m.texcoordstep[0] = sizeof(surfvertex_t);
+       if (softwaretransform_complexity)
        {
-               if (!cl_dlights[i].radius)
-                       continue;
-
-               if (rotated)
-               {
-                       VectorSubtract(cl_dlights[i].origin, currentrenderentity->origin, temp);
-                       org[0] = DotProduct (temp, forward);
-                       org[1] = -DotProduct (temp, right);
-                       org[2] = DotProduct (temp, up);
-               }
-               else
-                       VectorSubtract(cl_dlights[i].origin, currentrenderentity->origin, org);
-               R_NoVisMarkLights (org, &cl_dlights[i], 1<<(i&31), i >> 5, model);
+               m.vertex = &svert[0].v[0];
+               m.vertexstep = sizeof(surfvert_t);
+               for (i = 0, sv = svert, v = s->mesh.vertex;i < m.numverts;i++, sv++, v++)
+                       softwaretransform(v->v, sv->v);
+       }
+       else
+       {
+               m.vertex = &s->mesh.vertex->v[0];
+               m.vertexstep = sizeof(surfvertex_t);
        }
-       vertexlit = vertexworld || currentrenderentity->alpha != 1 || model->firstmodelsurface == 0 || (currentrenderentity->effects & EF_FULLBRIGHT) || currentrenderentity->colormod[0] != 1 || currentrenderentity->colormod[2] != 1 || currentrenderentity->colormod[2] != 1;
+       R_Mesh_Draw(&m);
+}
 
-       // draw texture
-       for (i = 0, s = &model->surfaces[model->firstmodelsurface];i < model->nummodelsurfaces;i++, s++)
+static void RSurfShader_Wall_Pass_BaseLightmap(msurface_t *s)
+{
+       int                             i;
+       float                   diff[3], ifog;
+       surfvertex_t    *v;
+       surfvert_t              *sv;
+       rmeshinfo_t             m;
+
+       memset(&m, 0, sizeof(m));
+       m.transparent = false;
+       m.blendfunc1 = GL_ZERO;
+       m.blendfunc2 = GL_SRC_COLOR;
+       m.numtriangles = s->mesh.numtriangles;
+       m.numverts = s->mesh.numverts;
+       m.index = s->mesh.index;
+       m.cr = 1;
+       if (lighthalf)
+               m.cr *= 2.0f;
+       m.cg = m.cr;
+       m.cb = m.cr;
+       m.ca = 1;
+       m.tex[0] = R_GetTexture(s->lightmaptexture);
+       m.texcoords[0] = &s->mesh.vertex->uv[0];
+       m.texcoordstep[0] = sizeof(surfvertex_t);
+       if (fogenabled)
        {
-               if (s->visframe == r_framecount)
+               m.color = &svert[0].c[0];
+               m.colorstep = sizeof(surfvert_t);
+               if (softwaretransform_complexity)
                {
-//                     R_DrawSurf(s, true, vertexlit || s->texinfo->texture->transparent);
-                       /*
-                       if (r_ser.value)
+                       m.vertex = &svert[0].v[0];
+                       m.vertexstep = sizeof(surfvert_t);
+                       for (i = 0, sv = svert, v = s->mesh.vertex;i < m.numverts;i++, sv++, v++)
                        {
-                               for (p = s->polys;p;p = p->next)
-                               {
-                                       for (j = 0;j < p->numverts;j++)
-                                               softwaretransform(&p->verts[j][0], bmverts + j * 3);
-                                       R_Clip_AddPolygon(bmverts, p->numverts, 3 * sizeof(float), (s->flags & SURF_CLIPSOLID) != 0 && currentrenderentity->alpha == 1, RBrushModelSurf_Callback, s, e, NULL);
-                               }
+                               softwaretransform(v->v, sv->v);
+                               VectorSubtract(sv->v, r_origin, diff);
+                               ifog = 1 - exp(fogdensity/DotProduct(diff, diff));
+                               sv->c[0] = m.cr * ifog;
+                               sv->c[1] = m.cg * ifog;
+                               sv->c[2] = m.cb * ifog;
+                               sv->c[3] = m.ca;
                        }
-                       else
+               }
+               else
+               {
+                       m.vertex = &s->mesh.vertex->v[0];
+                       m.vertexstep = sizeof(surfvertex_t);
+                       for (i = 0, sv = svert, v = s->mesh.vertex;i < m.numverts;i++, sv++, v++)
                        {
-                       */
-                               c_faces++;
-                               t = R_TextureAnimation(s->texinfo->texture);
-                               if (s->flags & (SURF_DRAWSKY | SURF_DRAWTURB))
-                               {
-                                       // sky and liquid don't need sorting (skypoly/transpoly)
-                                       if (s->flags & SURF_DRAWSKY)
-                                               RSurf_DrawSky(s, transform);
-                                       else
-                                               RSurf_DrawWater(s, t, transform, s->flags & SURF_DRAWNOALPHA ? 255 : wateralpha);
-                               }
-                               else
-                               {
-                                       if (t->transparent || vertexlit)
-                                               RSurf_DrawWallVertex(s, t, transform, true);
-                                       else
-                                               RSurf_DrawWall(s, t, transform);
-                               }
-                       //}
+                               VectorSubtract(v->v, r_origin, diff);
+                               ifog = 1 - exp(fogdensity/DotProduct(diff, diff));
+                               sv->c[0] = m.cr * ifog;
+                               sv->c[1] = m.cg * ifog;
+                               sv->c[2] = m.cb * ifog;
+                               sv->c[3] = m.ca;
+                       }
+               }
+       }
+       else
+       {
+               if (softwaretransform_complexity)
+               {
+                       m.vertex = &svert[0].v[0];
+                       m.vertexstep = sizeof(surfvert_t);
+                       for (i = 0, sv = svert, v = s->mesh.vertex;i < m.numverts;i++, sv++, v++)
+                               softwaretransform(v->v, sv->v);
+               }
+               else
+               {
+                       m.vertex = &s->mesh.vertex->v[0];
+                       m.vertexstep = sizeof(surfvertex_t);
                }
        }
-       UploadLightmaps();
+       R_Mesh_Draw(&m);
 }
 
-/*
-=============================================================
+static void RSurfShader_Wall_Pass_BaseVertex(msurface_t *s)
+{
+       int                             i, size3;
+       float                   c[3], base[3], scale, diff[3], ifog;
+       surfvertex_t    *v;
+       surfvert_t              *sv;
+       rmeshinfo_t             m;
+       byte                    *lm;
 
-       WORLD MODEL
+       size3 = ((s->extents[0]>>4)+1)*((s->extents[1]>>4)+1)*3;
 
-=============================================================
-*/
+       base[0] = base[1] = base[2] = r_ambient.value * (1.0f / 128.0f);
 
-/*
-static byte *worldvis;
-
-void R_MarkLeaves (void)
-{
-       static float noviscache;
-       if (r_oldviewleaf == r_viewleaf && noviscache == r_novis.value)
-               return;
-
-       r_oldviewleaf = r_viewleaf;
-       noviscache = r_novis.value;
-
-       worldvis = Mod_LeafPVS (r_viewleaf, cl.worldmodel);
+       memset(&m, 0, sizeof(m));
+       if (currentrenderentity->effects & EF_ADDITIVE)
+       {
+               m.transparent = true;
+               m.blendfunc1 = GL_SRC_ALPHA;
+               m.blendfunc2 = GL_ONE;
+       }
+       else if (currentrenderentity != &cl_entities[0].render && (s->currenttexture->fogtexture != NULL || currentrenderentity->alpha != 1))
+       {
+               m.transparent = true;
+               m.blendfunc1 = GL_SRC_ALPHA;
+               m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
+       }
+       else
+       {
+               m.transparent = false;
+               m.blendfunc1 = GL_ONE;
+               m.blendfunc2 = GL_ZERO;
+       }
+       m.numtriangles = s->mesh.numtriangles;
+       m.numverts = s->mesh.numverts;
+       m.index = s->mesh.index;
+       m.vertex = &svert[0].v[0];
+       m.vertexstep = sizeof(surfvert_t);
+       m.color = &svert[0].c[0];
+       m.colorstep = sizeof(surfvert_t);
+       m.tex[0] = R_GetTexture(s->currenttexture->texture);
+       m.texcoords[0] = &s->mesh.vertex->st[0];
+       m.texcoordstep[0] = sizeof(surfvertex_t);
+       for (i = 0, sv = svert, v = s->mesh.vertex;i < m.numverts;i++, sv++, v++)
+       {
+               softwaretransform(v->v, sv->v);
+               VectorCopy(base, c);
+               if (s->styles[0] != 255)
+               {
+                       lm = s->samples + v->lightmapoffset;
+                       scale = d_lightstylevalue[s->styles[0]] * (1.0f / 32768.0f);
+                       VectorMA(c, scale, lm, c);
+                       if (s->styles[1] != 255)
+                       {
+                               lm += size3;
+                               scale = d_lightstylevalue[s->styles[1]] * (1.0f / 32768.0f);
+                               VectorMA(c, scale, lm, c);
+                               if (s->styles[2] != 255)
+                               {
+                                       lm += size3;
+                                       scale = d_lightstylevalue[s->styles[2]] * (1.0f / 32768.0f);
+                                       VectorMA(c, scale, lm, c);
+                                       if (s->styles[3] != 255)
+                                       {
+                                               lm += size3;
+                                               scale = d_lightstylevalue[s->styles[3]] * (1.0f / 32768.0f);
+                                               VectorMA(c, scale, lm, c);
+                                       }
+                               }
+                       }
+               }
+               sv->c[0] = c[0];
+               sv->c[1] = c[1];
+               sv->c[2] = c[2];
+               sv->c[3] = currentrenderentity->alpha;
+       }
+       if (s->dlightframe == r_framecount)
+               RSurf_Light(s->dlightbits, m.numverts);
+       if (fogenabled)
+       {
+               for (i = 0, sv = svert, v = s->mesh.vertex;i < m.numverts;i++, sv++, v++)
+               {
+                       VectorSubtract(sv->v, r_origin, diff);
+                       ifog = 1 - exp(fogdensity/DotProduct(diff, diff));
+                       sv->c[0] *= ifog;
+                       sv->c[1] *= ifog;
+                       sv->c[2] *= ifog;
+               }
+       }
+       R_Mesh_Draw(&m);
 }
-*/
 
-void RSurf_Callback(void *data, void *junk)
+static void RSurfShader_Wall_Pass_Light(msurface_t *s)
 {
-       ((msurface_t *)data)->visframe = r_framecount;
+       int                             i;
+       float                   diff[3], ifog;
+       surfvertex_t    *v;
+       surfvert_t              *sv;
+       rmeshinfo_t             m;
+
+       memset(&m, 0, sizeof(m));
+       if (currentrenderentity->effects & EF_ADDITIVE)
+               m.transparent = true;
+       else if (currentrenderentity != &cl_entities[0].render && (s->currenttexture->fogtexture != NULL || currentrenderentity->alpha != 1))
+               m.transparent = true;
+       else
+               m.transparent = false;
+       m.blendfunc1 = GL_SRC_ALPHA;
+       m.blendfunc2 = GL_ONE;
+       m.numtriangles = s->mesh.numtriangles;
+       m.numverts = s->mesh.numverts;
+       m.index = s->mesh.index;
+       m.vertex = &svert[0].v[0];
+       m.vertexstep = sizeof(surfvert_t);
+       m.color = &svert[0].c[0];
+       m.colorstep = sizeof(surfvert_t);
+       m.tex[0] = R_GetTexture(s->currenttexture->texture);
+       m.texcoords[0] = &s->mesh.vertex->st[0];
+       m.texcoordstep[0] = sizeof(surfvertex_t);
+       for (i = 0, sv = svert, v = s->mesh.vertex;i < m.numverts;i++, sv++, v++)
+       {
+               softwaretransform(v->v, sv->v);
+               sv->c[0] = 0;
+               sv->c[1] = 0;
+               sv->c[2] = 0;
+               sv->c[3] = currentrenderentity->alpha;
+       }
+       if (RSurf_Light(s->dlightbits, m.numverts))
+       {
+               if (fogenabled)
+               {
+                       for (i = 0, sv = svert;i < m.numverts;i++, sv++)
+                       {
+                               VectorSubtract(sv->v, r_origin, diff);
+                               ifog = 1 - exp(fogdensity/DotProduct(diff, diff));
+                               sv->c[0] *= ifog;
+                               sv->c[1] *= ifog;
+                               sv->c[2] *= ifog;
+                       }
+               }
+               R_Mesh_Draw(&m);
+       }
 }
 
-/*
-void RSurf_Callback(void *data, void *junk)
+static void RSurfShader_Wall_Pass_Glow(msurface_t *s)
 {
-       msurface_t *surf = data;
-       texture_t *t;
-
-//     if (surf->visframe == r_framecount)
-//             return;
-
-       surf->visframe = r_framecount;
-
-       c_faces++;
-
-       if (surf->flags & (SURF_DRAWSKY | SURF_DRAWTURB))
+       int                             i;
+       float                   diff[3], ifog;
+       surfvertex_t    *v;
+       surfvert_t              *sv;
+       rmeshinfo_t             m;
+
+       memset(&m, 0, sizeof(m));
+       if (currentrenderentity->effects & EF_ADDITIVE)
+               m.transparent = true;
+       else if (currentrenderentity != &cl_entities[0].render && (s->currenttexture->fogtexture != NULL || currentrenderentity->alpha != 1))
+               m.transparent = true;
+       else
+               m.transparent = false;
+       m.blendfunc1 = GL_SRC_ALPHA;
+       m.blendfunc2 = GL_ONE;
+       m.numtriangles = s->mesh.numtriangles;
+       m.numverts = s->mesh.numverts;
+       m.index = s->mesh.index;
+       m.cr = 1;
+       m.cg = 1;
+       m.cb = 1;
+       m.ca = currentrenderentity->alpha;
+       m.tex[0] = R_GetTexture(s->currenttexture->glowtexture);
+       m.texcoords[0] = &s->mesh.vertex->st[0];
+       m.texcoordstep[0] = sizeof(surfvertex_t);
+       if (fogenabled)
        {
-               // sky and liquid don't need sorting (skypoly/transpoly)
-               if (surf->flags & SURF_DRAWSKY)
-                       RSurf_DrawSky(surf, false);
+               m.color = &svert[0].c[0];
+               m.colorstep = sizeof(surfvert_t);
+               if (softwaretransform_complexity)
+               {
+                       m.vertex = &svert[0].v[0];
+                       m.vertexstep = sizeof(surfvert_t);
+                       for (i = 0, sv = svert, v = s->mesh.vertex;i < m.numverts;i++, sv++, v++)
+                       {
+                               softwaretransform(v->v, sv->v);
+                               VectorSubtract(sv->v, r_origin, diff);
+                               ifog = 1 - exp(fogdensity/DotProduct(diff, diff));
+                               sv->c[0] = m.cr * ifog;
+                               sv->c[1] = m.cg * ifog;
+                               sv->c[2] = m.cb * ifog;
+                               sv->c[3] = m.ca;
+                       }
+               }
                else
-                       RSurf_DrawWater(surf, R_TextureAnimation(surf->texinfo->texture), false, surf->flags & SURF_DRAWNOALPHA ? 255 : wateralpha);
+               {
+                       m.vertex = &s->mesh.vertex->v[0];
+                       m.vertexstep = sizeof(surfvertex_t);
+                       for (i = 0, sv = svert, v = s->mesh.vertex;i < m.numverts;i++, sv++, v++)
+                       {
+                               VectorSubtract(v->v, r_origin, diff);
+                               ifog = 1 - exp(fogdensity/DotProduct(diff, diff));
+                               sv->c[0] = m.cr * ifog;
+                               sv->c[1] = m.cg * ifog;
+                               sv->c[2] = m.cb * ifog;
+                               sv->c[3] = m.ca;
+                       }
+               }
        }
        else
        {
-               t = R_TextureAnimation(surf->texinfo->texture);
-               if (vertexworld)
-                       RSurf_DrawWallVertex(surf, t, false, false);
+               if (softwaretransform_complexity)
+               {
+                       m.vertex = &svert[0].v[0];
+                       m.vertexstep = sizeof(surfvert_t);
+                       for (i = 0, sv = svert, v = s->mesh.vertex;i < m.numverts;i++, sv++, v++)
+                               softwaretransform(v->v, sv->v);
+               }
                else
-                       RSurf_DrawWall(surf, t, false);
+               {
+                       m.vertex = &s->mesh.vertex->v[0];
+                       m.vertexstep = sizeof(surfvertex_t);
+               }
        }
+       R_Mesh_Draw(&m);
 }
-*/
 
-/*
-mleaf_t *r_oldviewleaf;
-int r_markvisframecount = 0;
-
-void R_MarkLeaves (void)
+static void RSurfShader_Wall_Pass_Fog(msurface_t *s)
 {
-       static float noviscache;
-       int i, l, k, c;
-       mleaf_t *leaf;
-       msurface_t *surf, **mark, **endmark;
-       model_t *model = cl.worldmodel;
-//     mportal_t *portal;
-       glpoly_t *p;
-       byte    *in;
-       int             row;
-
-       // ignore testvis if the map just changed
-       if (r_testvis.value && model->nodes->markvisframe == r_markvisframecount)
-               return;
-
-       if (r_oldviewleaf == r_viewleaf && noviscache == r_novis.value)
-               return;
-
-       r_oldviewleaf = r_viewleaf;
-       noviscache = r_novis.value;
-
-       if ((in = r_viewleaf->compressed_vis))
+       int                             i;
+       surfvertex_t    *v;
+       surfvert_t              *sv;
+       rmeshinfo_t             m;
+       vec3_t                  diff;
+
+       memset(&m, 0, sizeof(m));
+       if (currentrenderentity->effects & EF_ADDITIVE)
+               m.transparent = true;
+       else if (currentrenderentity != &cl_entities[0].render && (s->currenttexture->fogtexture != NULL || currentrenderentity->alpha != 1))
+               m.transparent = true;
+       else
+               m.transparent = false;
+       m.blendfunc1 = GL_SRC_ALPHA;
+       m.blendfunc2 = GL_ONE;
+       m.numtriangles = s->mesh.numtriangles;
+       m.numverts = s->mesh.numverts;
+       m.index = s->mesh.index;
+       m.color = &svert[0].c[0];
+       m.colorstep = sizeof(surfvert_t);
+       m.tex[0] = R_GetTexture(s->currenttexture->fogtexture);
+       m.texcoords[0] = &s->mesh.vertex->st[0];
+       m.texcoordstep[0] = sizeof(surfvertex_t);
+       if (softwaretransform_complexity)
        {
-               row = (model->numleafs+7)>>3;
-
-               if (!r_testvis.value)
-                       r_markvisframecount++;
+               m.vertex = &svert[0].v[0];
+               m.vertexstep = sizeof(surfvert_t);
+               for (i = 0, sv = svert, v = s->mesh.vertex;i < m.numverts;i++, sv++, v++)
+               {
+                       softwaretransform(v->v, sv->v);
+                       VectorSubtract(sv->v, r_origin, diff);
+                       sv->c[0] = fogcolor[0];
+                       sv->c[1] = fogcolor[1];
+                       sv->c[2] = fogcolor[2];
+                       sv->c[3] = currentrenderentity->alpha * exp(fogdensity/DotProduct(diff,diff));
+               }
+       }
+       else
+       {
+               m.vertex = &s->mesh.vertex->v[0];
+               m.vertexstep = sizeof(surfvertex_t);
+               for (i = 0, sv = svert, v = s->mesh.vertex;i < m.numverts;i++, sv++, v++)
+               {
+                       VectorSubtract(v->v, r_origin, diff);
+                       sv->c[0] = fogcolor[0];
+                       sv->c[1] = fogcolor[1];
+                       sv->c[2] = fogcolor[2];
+                       sv->c[3] = currentrenderentity->alpha * exp(fogdensity/DotProduct(diff,diff));
+               }
+       }
+       R_Mesh_Draw(&m);
+}
 
-               // LordHavoc: mark the root node as visible, it will terminate all other ascensions
-               model->nodes->markvisframe = r_markvisframecount;
+static int RSurfShader_Wall_Vertex(int stage, msurface_t *s)
+{
+       switch(stage)
+       {
+       case 0:
+               RSurfShader_Wall_Pass_BaseVertex(s);
+               return false;
+       case 1:
+               if (s->currenttexture->glowtexture)
+                       RSurfShader_Wall_Pass_Glow(s);
+               return false;
+       default:
+               return true;
+       }
+}
 
-               k = 0;
-               while (k < row)
+static int RSurfShader_Wall_Lightmap(int stage, msurface_t *s)
+{
+       if (r_vertexsurfaces.integer)
+       {
+               switch(stage)
+               {
+               case 0:
+                       RSurfShader_Wall_Pass_BaseVertex(s);
+                       return false;
+               case 1:
+                       if (s->currenttexture->glowtexture)
+                               RSurfShader_Wall_Pass_Glow(s);
+                       return false;
+               default:
+                       return true;
+               }
+       }
+       else if (r_multitexture.integer)
+       {
+               if (r_dlightmap.integer)
                {
-                       c = *in++;
-                       if (c)
+                       switch(stage)
                        {
-                               l = model->numleafs - (k << 3);
-                               if (l > 8)
-                                       l = 8;
-                               for (i=0 ; i<l ; i++)
-                               {
-                                       if (c & (1<<i))
-                                       {
-                                               leaf = &model->leafs[(k << 3)+i+1];
-                                               node = (mnode_t *)leaf;
-                                               do
-                                               {
-                                                       node->markvisframe = r_markvisframecount;
-                                                       node = node->parent;
-                                               }
-                                               while (node->markvisframecount != r_markvisframecount);
-                                       }
-                               }
-                               k++;
+                       case 0:
+                               RSurfShader_Wall_Pass_BaseMTex(s);
+                               return false;
+                       case 1:
+                               if (s->currenttexture->glowtexture)
+                                       RSurfShader_Wall_Pass_Glow(s);
+                               return false;
+                       default:
+                               return true;
+                       }
+               }
+               else
+               {
+                       switch(stage)
+                       {
+                       case 0:
+                               RSurfShader_Wall_Pass_BaseMTex(s);
+                               return false;
+                       case 1:
+                               if (s->dlightframe == r_framecount)
+                                       RSurfShader_Wall_Pass_Light(s);
+                               return false;
+                       case 2:
+                               if (s->currenttexture->glowtexture)
+                                       RSurfShader_Wall_Pass_Glow(s);
+                               return false;
+                       default:
+                               return true;
                        }
-                       else
-                               k += *in++;
+               }
+       }
+       else if (currentrenderentity != &cl_entities[0].render && (s->currenttexture->fogtexture != NULL || currentrenderentity->alpha != 1 || currentrenderentity->effects & EF_ADDITIVE))
+       {
+               switch(stage)
+               {
+               case 0:
+                       RSurfShader_Wall_Pass_BaseVertex(s);
+                       return false;
+               case 1:
+                       if (s->currenttexture->glowtexture)
+                               RSurfShader_Wall_Pass_Glow(s);
+                       return false;
+               default:
+                       return true;
                }
        }
        else
        {
-               // LordHavoc: no vis data, mark everything as visible
-               model->nodes->markvisframe = r_markvisframecount;
-
-               for (i = 1;i < model->numleafs;i++)
+               if (r_dlightmap.integer)
                {
-                       node = (mnode_t *)&model->leafs[i];
-                       do
+                       switch(stage)
                        {
-                               node->markvisframe = r_markvisframecount;
-                               node = node->parent;
+                       case 0:
+                               RSurfShader_Wall_Pass_BaseTexture(s);
+                               return false;
+                       case 1:
+                               RSurfShader_Wall_Pass_BaseLightmap(s);
+                               return false;
+                       case 2:
+                               if (s->currenttexture->glowtexture)
+                                       RSurfShader_Wall_Pass_Glow(s);
+                               return false;
+                       default:
+                               return true;
                        }
-                       while (node->markvisframecount != r_markvisframecount);
                }
+               else
+               {
+                       switch(stage)
+                       {
+                       case 0:
+                               RSurfShader_Wall_Pass_BaseTexture(s);
+                               return false;
+                       case 1:
+                               RSurfShader_Wall_Pass_BaseLightmap(s);
+                               return false;
+                       case 2:
+                               if (s->dlightframe == r_framecount)
+                                       RSurfShader_Wall_Pass_Light(s);
+                               return false;
+                       case 3:
+                               if (s->currenttexture->glowtexture)
+                                       RSurfShader_Wall_Pass_Glow(s);
+                               return false;
+                       default:
+                               return true;
+                       }
+               }
+       }
+}
+
+static int RSurfShader_Wall_Fog(int stage, msurface_t *s)
+{
+       if (stage == 0 && fogenabled)
+       {
+               RSurfShader_Wall_Pass_Fog(s);
+               return false;
        }
+       else
+               return true;
 }
+
+/*
+=============================================================
+
+       WORLD MODEL
+
+=============================================================
 */
 
-void R_SolidWorldNode (void)
+static void RSurf_Callback(void *data, void *junk)
+{
+       ((msurface_t *)data)->visframe = r_framecount;
+}
+
+static void R_SolidWorldNode (void)
 {
        if (r_viewleaf->contents != CONTENTS_SOLID)
        {
@@ -1109,7 +1367,6 @@ void R_SolidWorldNode (void)
                mportal_t *p, *pstack[8192];
                msurface_t *surf, **mark, **endmark;
                mleaf_t *leaf;
-               glpoly_t *poly;
                tinyplane_t plane;
                // LordHavoc: portal-passage worldnode; follows portals leading
                // outward from viewleaf, if a portal leads offscreen it is not
@@ -1128,7 +1385,7 @@ void R_SolidWorldNode (void)
                {
                        mark = leaf->firstmarksurface;
                        endmark = mark + leaf->nummarksurfaces;
-                       if (r_ser.value)
+                       if (r_ser.integer)
                        {
                                do
                                {
@@ -1143,15 +1400,13 @@ void R_SolidWorldNode (void)
                                                {
                                                        VectorNegate(surf->plane->normal, plane.normal);
                                                        plane.dist = -surf->plane->dist;
-                                                       for (poly = surf->polys;poly;poly = poly->next)
-                                                               R_Clip_AddPolygon((float *)poly->verts, poly->numverts, VERTEXSIZE * sizeof(float), (surf->flags & SURF_CLIPSOLID) != 0, RSurf_Callback, surf, NULL, &plane);
+                                                       R_Clip_AddPolygon((float *)surf->poly_verts, surf->poly_numverts, sizeof(float[3]), (surf->flags & SURF_CLIPSOLID) != 0, RSurf_Callback, surf, NULL, &plane);
                                                }
                                        }
                                        else
                                        {
                                                if (!(surf->flags & SURF_PLANEBACK))
-                                                       for (poly = surf->polys;poly;poly = poly->next)
-                                                               R_Clip_AddPolygon((float *)poly->verts, poly->numverts, VERTEXSIZE * sizeof(float), (surf->flags & SURF_CLIPSOLID) != 0, RSurf_Callback, surf, NULL, (tinyplane_t *)surf->plane);
+                                                       R_Clip_AddPolygon((float *)surf->poly_verts, surf->poly_numverts, sizeof(float[3]), (surf->flags & SURF_CLIPSOLID) != 0, RSurf_Callback, surf, NULL, (tinyplane_t *)surf->plane);
                                        }
                                }
                                while (mark < endmark);
@@ -1194,6 +1449,7 @@ void R_SolidWorldNode (void)
                                        {
                                                if (R_NotCulledBox(leaf->mins, leaf->maxs))
                                                {
+                                                       p->visframe = r_framecount;
                                                        pstack[portalstack++] = p;
                                                        goto loc0;
 
@@ -1212,7 +1468,6 @@ void R_SolidWorldNode (void)
        {
                mnode_t *nodestack[8192], *node = cl.worldmodel->nodes;
                int nodestackpos = 0;
-               glpoly_t *poly;
                // LordHavoc: recursive descending worldnode; if portals are not
                // available, this is a good last resort, can cull large amounts of
                // geometry, but is more time consuming than portal-passage and renders
@@ -1223,7 +1478,7 @@ loc2:
                {
                        if (node->numsurfaces)
                        {
-                               if (r_ser.value)
+                               if (r_ser.integer)
                                {
                                        msurface_t *surf = cl.worldmodel->surfaces + node->firstsurface, *surfend = surf + node->numsurfaces;
                                        tinyplane_t plane;
@@ -1235,8 +1490,7 @@ loc2:
                                                        {
                                                                VectorNegate(surf->plane->normal, plane.normal);
                                                                plane.dist = -surf->plane->dist;
-                                                               for (poly = surf->polys;poly;poly = poly->next)
-                                                                       R_Clip_AddPolygon((float *)poly->verts, poly->numverts, VERTEXSIZE * sizeof(float), surf->flags & SURF_CLIPSOLID, RSurf_Callback, surf, NULL, &plane);
+                                                               R_Clip_AddPolygon((float *)surf->poly_verts, surf->poly_numverts, sizeof(float[3]), surf->flags & SURF_CLIPSOLID, RSurf_Callback, surf, NULL, &plane);
                                                        }
                                                }
                                        }
@@ -1245,8 +1499,7 @@ loc2:
                                                for (;surf < surfend;surf++)
                                                {
                                                        if (!(surf->flags & SURF_PLANEBACK))
-                                                               for (poly = surf->polys;poly;poly = poly->next)
-                                                                       R_Clip_AddPolygon((float *)poly->verts, poly->numverts, VERTEXSIZE * sizeof(float), surf->flags & SURF_CLIPSOLID, RSurf_Callback, surf, NULL, (tinyplane_t *)surf->plane);
+                                                               R_Clip_AddPolygon((float *)surf->poly_verts, surf->poly_numverts, sizeof(float[3]), surf->flags & SURF_CLIPSOLID, RSurf_Callback, surf, NULL, (tinyplane_t *)surf->plane);
                                                }
                                        }
                                }
@@ -1311,195 +1564,15 @@ loc2:
        }
 }
 
-/*
-void RSurf_Callback(void *data, void *junk)
-{
-       ((msurface_t *)data)->visframe = r_framecount;
-}
-
-int R_FrustumTestPolygon(float *points, int numpoints, int stride);
-
-void RSurf_DoVisible(msurface_t *surf)
-{
-       glpoly_t *p;
-       for (p = surf->polys;p;p = p->next)
-               if (R_FrustumTestPolygon((float *) p->verts, p->numverts, VERTEXSIZE * sizeof(float)) >= 3)
-//             R_Clip_Polygon((float *) p->verts, p->numverts, VERTEXSIZE * sizeof(float), true, RSurf_Callback, surf, 1);
-//             if (R_Clip_Polygon((float *) p->verts, p->numverts, VERTEXSIZE * sizeof(float), surf->flags & SURF_CLIPSOLID))
-                       surf->visframe = r_framecount;
-}
-*/
-
-//mleaf_t *llistbuffer[32768], *l, **llist;
-
-/*
-void RSurfLeaf_Callback(void *data)
-{
-       int portalstackpos = 0;
-       mleaf_t *leaf;
-       mportal_t *p, *portalstack[32768];
-       msurface_t *surf, **mark, **endmark;
-       do
-       {
-
-               leaf = data;
-               if (leaf->visframe == r_framecount)
-                       return;
-               leaf->visframe = r_framecount;
-
-               c_leafs++;
-
-               if (leaf->nummarksurfaces)
-               {
-                       mark = leaf->firstmarksurface;
-                       endmark = mark + leaf->nummarksurfaces;
-                       do
-                       {
-                               surf = *mark++;
-                               // make sure surfaces are only processed once
-                               if (surf->worldnodeframe == r_framecount)
-                                       continue;
-                               surf->worldnodeframe = r_framecount;
-                               if (PlaneDist(modelorg, surf->plane) < surf->plane->dist)
-                               {
-                                       if (surf->flags & SURF_PLANEBACK)
-                                               RSurf_DoVisible(surf);
-                               }
-                               else
-                               {
-                                       if (!(surf->flags & SURF_PLANEBACK))
-                                               RSurf_DoVisible(surf);
-                               }
-                       }
-                       while (mark < endmark);
-               }
-
-               // follow portals into other leafs
-               for (p = leaf->portals;p;p = p->next)
-               {
-                       if (p->past->visframe != r_framecount && DotProduct(r_origin, p->plane.normal) < p->plane.dist)
-                       {
-       //                      R_Clip_Portal((float *) p->points, p->numpoints, sizeof(float) * 3, RSurfLeaf_Callback, p->past, 1);
-                               if (R_Clip_Portal((float *) p->points, p->numpoints, sizeof(float) * 3))
-                                       portalstack[portalstackpos++] = p;
-                       }
-               }
-       }
-       while(portalstackpos);
-       RSurfLeaf_Callback(p->past);
-       // upon returning, R_ProcessSpans will notice that the spans have changed and restart the line, this is ok because we're not adding any polygons that aren't already behind the portal
-}
-*/
-
-/*
-// experimental and inferior to the other in recursion depth allowances
-void R_PortalWorldNode (void)
-{
-//     int i, j;
-       mportal_t *p;
-       msurface_t *surf, **mark, **endmark;
-       mleaf_t *leaf, *llistbuffer[32768], **l, **llist;
-
-       leaf = r_viewleaf;
-       leaf->visframe = r_framecount;
-       l = llist = &llistbuffer[0];
-       *llist++ = r_viewleaf;
-       while (l < llist)
-       {
-               leaf = *l++;
-
-               c_leafs++;
-
-               if (leaf->nummarksurfaces)
-               {
-                       mark = leaf->firstmarksurface;
-                       endmark = mark + leaf->nummarksurfaces;
-                       do
-                       {
-                               surf = *mark++;
-                               // make sure surfaces are only processed once
-                               if (surf->worldnodeframe == r_framecount)
-                                       continue;
-                               surf->worldnodeframe = r_framecount;
-                               if (PlaneDist(modelorg, surf->plane) < surf->plane->dist)
-                               {
-                                       if (surf->flags & SURF_PLANEBACK)
-                                               RSurf_DoVisible(surf);
-                               }
-                               else
-                               {
-                                       if (!(surf->flags & SURF_PLANEBACK))
-                                               RSurf_DoVisible(surf);
-                               }
-                       }
-                       while (mark < endmark);
-               }
-
-               // follow portals into other leafs
-               for (p = leaf->portals;p;p = p->next)
-               {
-                       if (p->past->visframe != r_framecount)
-                       {
-                               if (R_Clip_Portal((float *) p->points, p->numpoints, sizeof(float) * 3))
-                               {
-                                       p->past->visframe = r_framecount;
-                                       *llist++ = p->past;
-                               }
-                       }
-               }
-
-//             for (p = leaf->portals;p;p = p->next)
-//             {
-//                     leaf = p->past;
-//                     if (leaf->worldnodeframe != r_framecount)
-//                     {
-//                             leaf->worldnodeframe = r_framecount;
-//                             i = (leaf - cl.worldmodel->leafs) - 1;
-//                             if ((worldvis[i>>3] & (1<<(i&7))) && R_NotCulledBox(leaf->mins, leaf->maxs))
-//                                     *llist++ = leaf;
-//                     }
-//             }
-       }
-
-//     i = 0;
-//     j = 0;
-//     p = r_viewleaf->portals;
-//     for (;p;p = p->next)
-//     {
-//             j++;
-//             if (p->past->worldnodeframe != r_framecount)
-//                     i++;
-//     }
-//     if (i)
-//             Con_Printf("%i portals of viewleaf (%i portals) were not checked\n", i, j);
-}
-*/
-
+static int r_portalframecount = 0;
 
-int r_portalframecount = 0;
-
-/*
-void R_Portal_Callback(void *data, void *data2)
-{
-       mleaf_t *leaf = data;
-       if (!r_testvis.value)
-               ((mportal_t *)data2)->visframe = r_portalframecount;
-       if (leaf->visframe != r_framecount)
-       {
-               c_leafs++;
-               leaf->visframe = r_framecount;
-       }
-}
-*/
-
-void R_PVSWorldNode()
+static void R_PVSWorldNode()
 {
        int portalstack, i;
        mportal_t *p, *pstack[8192];
        msurface_t *surf, **mark, **endmark;
        mleaf_t *leaf;
        tinyplane_t plane;
-       glpoly_t *poly;
        byte *worldvis;
 
        worldvis = Mod_LeafPVS (r_viewleaf, cl.worldmodel);
@@ -1516,7 +1589,7 @@ loc0:
        {
                mark = leaf->firstmarksurface;
                endmark = mark + leaf->nummarksurfaces;
-               if (r_ser.value)
+               if (r_ser.integer)
                {
                        do
                        {
@@ -1525,21 +1598,19 @@ loc0:
                                if (surf->worldnodeframe == r_framecount)
                                        continue;
                                surf->worldnodeframe = r_framecount;
-                               if (PlaneDist(modelorg, surf->plane) < surf->plane->dist)
+                               if (PlaneDist(r_origin, surf->plane) < surf->plane->dist)
                                {
                                        if (surf->flags & SURF_PLANEBACK)
                                        {
                                                VectorNegate(surf->plane->normal, plane.normal);
                                                plane.dist = -surf->plane->dist;
-                                               for (poly = surf->polys;poly;poly = poly->next)
-                                                       R_Clip_AddPolygon((float *)poly->verts, poly->numverts, VERTEXSIZE * sizeof(float), (surf->flags & SURF_CLIPSOLID) != 0, RSurf_Callback, surf, NULL, &plane);
+                                               R_Clip_AddPolygon((float *)surf->poly_verts, surf->poly_numverts, sizeof(float[3]), (surf->flags & SURF_CLIPSOLID) != 0, RSurf_Callback, surf, NULL, &plane);
                                        }
                                }
                                else
                                {
                                        if (!(surf->flags & SURF_PLANEBACK))
-                                               for (poly = surf->polys;poly;poly = poly->next)
-                                                       R_Clip_AddPolygon((float *)poly->verts, poly->numverts, VERTEXSIZE * sizeof(float), (surf->flags & SURF_CLIPSOLID) != 0, RSurf_Callback, surf, NULL, (tinyplane_t *)surf->plane);
+                                               R_Clip_AddPolygon((float *)surf->poly_verts, surf->poly_numverts, sizeof(float[3]), (surf->flags & SURF_CLIPSOLID) != 0, RSurf_Callback, surf, NULL, (tinyplane_t *)surf->plane);
                                }
                        }
                        while (mark < endmark);
@@ -1553,7 +1624,7 @@ loc0:
                                if (surf->worldnodeframe == r_framecount)
                                        continue;
                                surf->worldnodeframe = r_framecount;
-                               if (PlaneDist(modelorg, surf->plane) < surf->plane->dist)
+                               if (PlaneDist(r_origin, surf->plane) < surf->plane->dist)
                                {
                                        if (surf->flags & SURF_PLANEBACK)
                                                surf->visframe = r_framecount;
@@ -1569,8 +1640,7 @@ loc0:
        }
 
        // follow portals into other leafs
-       p = leaf->portals;
-       for (;p;p = p->next)
+       for (p = leaf->portals;p;p = p->next)
        {
                if (DotProduct(r_origin, p->plane.normal) < p->plane.dist)
                {
@@ -1601,61 +1671,92 @@ loc1:
                goto loc1;
 }
 
-entity_t clworldent;
+Cshader_t Cshader_wall_vertex = {{NULL, RSurfShader_Wall_Vertex, RSurfShader_Wall_Fog}, NULL};
+Cshader_t Cshader_wall_lightmap = {{NULL, RSurfShader_Wall_Lightmap, RSurfShader_Wall_Fog}, NULL};
+Cshader_t Cshader_water = {{NULL, RSurfShader_Water, NULL}, NULL};
+Cshader_t Cshader_sky = {{RSurfShader_Sky, NULL, NULL}, NULL};
 
-void R_DrawSurfaces (void)
+int Cshader_count = 4;
+Cshader_t *Cshaders[4] =
 {
-       msurface_t      *surf, *endsurf;
-       texture_t       *t, *currentt;
-       int vertex = gl_vertex.value;
+       &Cshader_wall_vertex,
+       &Cshader_wall_lightmap,
+       &Cshader_water,
+       &Cshader_sky
+};
 
-       currentrenderentity = &clworldent.render;
-       softwaretransformidentity();
-       surf = &cl.worldmodel->surfaces[cl.worldmodel->firstmodelsurface];
-       endsurf = surf + cl.worldmodel->nummodelsurfaces;
-       t = currentt = NULL;
-       for (;surf < endsurf;surf++)
+void R_PrepareSurfaces(void)
+{
+       int i;
+       texture_t *t;
+       model_t *model;
+       msurface_t *surf;
+
+       for (i = 0;i < Cshader_count;i++)
+               Cshaders[i]->chain = NULL;
+
+       model = currentrenderentity->model;
+
+       for (i = 0;i < model->nummodelsurfaces;i++)
        {
+               surf = model->modelsortedsurfaces[i];
                if (surf->visframe == r_framecount)
                {
-                       c_faces++;
-                       if (surf->flags & (SURF_DRAWSKY | SURF_DRAWTURB))
+                       if (surf->insertframe != r_framecount)
                        {
-                               if (surf->flags & SURF_DRAWSKY)
-                                       RSurf_DrawSky(surf, false);
-                               else
-                               {
-                                       if (currentt != surf->texinfo->texture)
-                                       {
-                                               currentt = surf->texinfo->texture;
-                                               t = R_TextureAnimation(surf->texinfo->texture);
-                                       }
-                                       RSurf_DrawWater(surf, t, false, surf->flags & SURF_DRAWNOALPHA ? 255 : wateralpha);
-                               }
-                       }
-                       else
-                       {
-                               if (currentt != surf->texinfo->texture)
-                               {
-                                       currentt = surf->texinfo->texture;
-                                       t = R_TextureAnimation(surf->texinfo->texture);
-                               }
-                               if (vertex)
-                                       RSurf_DrawWallVertex(surf, t, false, false);
-                               else
-                                       RSurf_DrawWall(surf, t, false);
+                               surf->insertframe = r_framecount;
+                               c_faces++;
+                               // manually inlined R_TextureAnimation
+                               //t = R_TextureAnimation(surf->texinfo->texture);
+                               t = surf->texinfo->texture;
+                               if (t->alternate_anims != NULL && currentrenderentity->frame)
+                                       t = t->alternate_anims;
+                               if (t->anim_total >= 2)
+                                       t = t->anim_frames[(int)(cl.time * 5.0f) % t->anim_total];
+                               surf->currenttexture = t;
                        }
+
+                       surf->chain = surf->shader->chain;
+                       surf->shader->chain = surf;
                }
        }
 }
 
+void R_DrawSurfaces (int type)
+{
+       int                     i, stage;
+       msurface_t      *surf;
+       Cshader_t       *shader;
+
+       for (i = 0;i < Cshader_count;i++)
+       {
+               shader = Cshaders[i];
+               if (shader->chain && shader->shaderfunc[type])
+                       for (stage = 0;stage < 1000;stage++)
+                               for (surf = shader->chain;surf;surf = surf->chain)
+                                       if (shader->shaderfunc[type](stage, surf))
+                                               goto done;
+done:;
+       }
+}
+
+void R_DrawSurfacesAll (void)
+{
+       R_DrawSurfaces(SHADERSTAGE_SKY);
+       R_DrawSurfaces(SHADERSTAGE_NORMAL);
+       R_DrawSurfaces(SHADERSTAGE_FOG);
+}
+
+static float portalpointbuffer[256][3];
+
 void R_DrawPortals(void)
 {
-       int drawportals, i, r, g, b;
+       int drawportals, i;
 //     mleaf_t *leaf, *endleaf;
        mportal_t *portal, *endportal;
        mvertex_t *point/*, *endpoint*/;
-       drawportals = (int)r_drawportals.value;
+       rmeshinfo_t m;
+       drawportals = r_drawportals.integer;
        if (drawportals < 1)
                return;
        /*
@@ -1683,398 +1784,165 @@ void R_DrawPortals(void)
                }
        }
        */
-       portal = cl.worldmodel->portals;
-       endportal = portal + cl.worldmodel->numportals;
-       for (;portal < endportal;portal++)
+       memset(&m, 0, sizeof(m));
+       m.transparent = true;
+       m.blendfunc1 = GL_SRC_ALPHA;
+       m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
+       m.vertex = &portalpointbuffer[0][0];
+       m.vertexstep = sizeof(float[3]);
+       m.ca = 0.125;
+       for (portal = cl.worldmodel->portals, endportal = portal + cl.worldmodel->numportals;portal < endportal;portal++)
        {
                if (portal->visframe == r_portalframecount)
                {
-                       i = portal - cl.worldmodel->portals;
-                       r = (i & 0x0007) << 5;
-                       g = (i & 0x0038) << 2;
-                       b = (i & 0x01C0) >> 1;
-                       transpolybegin(0, 0, 0, TPOLYTYPE_ALPHA);
-                       point = portal->points;
-                       if (PlaneDiff(r_origin, (&portal->plane)) > 0)
-                       {
-                               for (i = portal->numpoints - 1;i >= 0;i--)
-                                       transpolyvertub(point[i].position[0], point[i].position[1], point[i].position[2], 0, 0, r, g, b, 32);
-                       }
-                       else
+                       if (portal->numpoints <= 256)
                        {
-                               for (i = 0;i < portal->numpoints;i++)
-                                       transpolyvertub(point[i].position[0], point[i].position[1], point[i].position[2], 0, 0, r, g, b, 32);
+                               i = portal - cl.worldmodel->portals;
+                               m.cr = ((i & 0x0007) >> 0) * (1.0f / 7.0f);
+                               m.cg = ((i & 0x0038) >> 3) * (1.0f / 7.0f);
+                               m.cb = ((i & 0x01C0) >> 6) * (1.0f / 7.0f);
+                               point = portal->points;
+                               if (PlaneDiff(r_origin, (&portal->plane)) > 0)
+                               {
+                                       for (i = portal->numpoints - 1;i >= 0;i--)
+                                               VectorCopy(point[i].position, portalpointbuffer[i]);
+                               }
+                               else
+                               {
+                                       for (i = 0;i < portal->numpoints;i++)
+                                               VectorCopy(point[i].position, portalpointbuffer[i]);
+                               }
+                               R_Mesh_DrawPolygon(&m, portal->numpoints);
                        }
-                       transpolyend();
                }
        }
 }
 
-void R_SetupWorldEnt(void)
-{
-       memset (&clworldent, 0, sizeof(clworldent));
-       clworldent.render.model = cl.worldmodel;
-       clworldent.render.colormod[0] = clworldent.render.colormod[1] = clworldent.render.colormod[2] = 1;
-       clworldent.render.alpha = 1;
-       clworldent.render.scale = 1;
-
-       VectorCopy (r_origin, modelorg);
-
-       currentrenderentity = &clworldent.render;
-}
-
-/*
-=============
-R_DrawWorld
-=============
-*/
-void R_DrawWorld (void)
+void R_SetupForBModelRendering(void)
 {
-       wateralpha = bound(0, r_wateralpha.value*255.0f, 255);
-       vertexworld = gl_vertex.value;
-
-       R_SetupWorldEnt();
-
-       softwaretransformidentity(); // LordHavoc: clear transform
-
-       if (r_viewleaf->contents == CONTENTS_SOLID || r_novis.value || r_viewleaf->compressed_vis == NULL)
-               R_SolidWorldNode ();
-       else
-               R_PVSWorldNode ();
-}
-
-/*
-=============================================================================
+       int                     i;
+       msurface_t      *s;
+       model_t         *model;
+       vec3_t          modelorg;
 
-  LIGHTMAP ALLOCATION
+       // because bmodels can be reused, we have to decide which things to render
+       // from scratch every time
 
-=============================================================================
-*/
+       model = currentrenderentity->model;
 
-// returns a texture number and the position inside it
-int AllocBlock (int w, int h, short *x, short *y)
-{
-       int             i, j;
-       int             best, best2;
-       int             texnum;
+       softwaretransformforentity (currentrenderentity);
+       softwareuntransform(r_origin, modelorg);
 
-       for (texnum = 0;texnum < MAX_LIGHTMAPS;texnum++)
+       for (i = 0;i < model->nummodelsurfaces;i++)
        {
-               best = BLOCK_HEIGHT;
-
-               for (i = 0;i < BLOCK_WIDTH - w;i += lightmapalign) // LordHavoc: align updates on 4 byte boundaries
-               {
-                       best2 = 0;
-
-                       for (j=0 ; j<w ; j++)
-                       {
-                               if (allocated[texnum][i+j] >= best)
-                                       break;
-                               if (allocated[texnum][i+j] > best2)
-                                       best2 = allocated[texnum][i+j];
-                       }
-                       if (j == w)
-                       {       // this is a valid spot
-                               *x = i;
-                               *y = best = best2;
-                       }
-               }
-
-               if (best + h > BLOCK_HEIGHT)
-                       continue;
-
-               if (nosubimagefragments || nosubimage)
-               {
-                       if (!lightmaps[texnum])
-                       {
-                               lightmaps[texnum] = qmalloc(BLOCK_WIDTH*BLOCK_HEIGHT*4);
-                               memset(lightmaps[texnum], 0, BLOCK_WIDTH*BLOCK_HEIGHT*4);
-                       }
-               }
-               // LordHavoc: clear texture to blank image, fragments are uploaded using subimage
-               else if (!allocated[texnum][0])
-               {
-                       memset(templight, 0, sizeof(templight));
-                       if(r_upload.value)
-                       {
-                               glBindTexture(GL_TEXTURE_2D, lightmap_textures + texnum);
-                               glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-                               glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-                               if (lightmaprgba)
-                                       glTexImage2D (GL_TEXTURE_2D, 0, 3, BLOCK_WIDTH, BLOCK_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, templight);
-                               else
-                                       glTexImage2D (GL_TEXTURE_2D, 0, 3, BLOCK_WIDTH, BLOCK_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, templight);
-                       }
-               }
-
-               for (i = 0;i < w;i++)
-                       allocated[texnum][*x + i] = best + h;
-
-               return texnum;
+               s = model->modelsortedsurfaces[i];
+               if (((s->flags & SURF_PLANEBACK) == 0) == (PlaneDiff(modelorg, s->plane) >= 0))
+                       s->visframe = r_framecount;
+               else
+                       s->visframe = -1;
+               s->worldnodeframe = -1;
+               s->lightframe = -1;
+               s->dlightframe = -1;
+               s->insertframe = -1;
        }
-
-       Host_Error ("AllocBlock: full, unable to find room for %i by %i lightmap", w, h);
-       return 0;
 }
 
+void R_SetupForWorldRendering(void)
+{
+       // there is only one instance of the world, but it can be rendered in
+       // multiple stages
 
-//int  nColinElim;
+       currentrenderentity = &cl_entities[0].render;
+       softwaretransformidentity();
+}
 
-/*
-================
-BuildSurfaceDisplayList
-================
-*/
-void BuildSurfaceDisplayList (model_t *model, mvertex_t *vertices, msurface_t *fa)
+static void R_SurfMarkLights (void)
 {
-       int                     i, j, lindex, lnumverts;
-       medge_t         *pedges;
-       float           *vec;
-       float           s, t;
-       glpoly_t        *poly;
-
-// reconstruct the polygon
-       pedges = model->edges;
-       lnumverts = fa->numedges;
-
-       //
-       // draw texture
-       //
-       poly = Hunk_AllocName (sizeof(glpolysizeof_t) + lnumverts * sizeof(float[VERTEXSIZE]), "surfaces");
-       poly->next = fa->polys;
-       fa->polys = poly;
-//     poly->flags = fa->flags;
-       poly->numverts = lnumverts;
-
-       for (i=0 ; i<lnumverts ; i++)
-       {
-               lindex = model->surfedges[fa->firstedge + i];
+       int                     i;
+       msurface_t      *s;
 
-               if (lindex > 0)
-                       vec = vertices[pedges[lindex].v[0]].position;
-               else
-                       vec = vertices[pedges[-lindex].v[1]].position;
-
-               s = DotProduct (vec, fa->texinfo->vecs[0]) + fa->texinfo->vecs[0][3];
-               t = DotProduct (vec, fa->texinfo->vecs[1]) + fa->texinfo->vecs[1][3];
-
-               VectorCopy (vec, poly->verts[i]);
-               poly->verts[i][3] = s / fa->texinfo->texture->width;
-               poly->verts[i][4] = t / fa->texinfo->texture->height;
-
-               //
-               // lightmap texture coordinates
-               //
-               s -= fa->texturemins[0];
-               t -= fa->texturemins[1];
-               s += 8;
-               t += 8;
-               // LordHavoc: calc lightmap data offset
-               j = (bound(0l, (int)t>>4, fa->extents[1]>>4) * ((fa->extents[0]>>4)+1) + bound(0l, (int)s>>4, fa->extents[0]>>4)) * 3;
-               poly->verts[i][7] = j;
-               s += fa->light_s*16;
-               s /= BLOCK_WIDTH*16; //fa->texinfo->texture->width;
-
-               t += fa->light_t*16;
-               t /= BLOCK_HEIGHT*16; //fa->texinfo->texture->height;
-
-               poly->verts[i][5] = s;
-               poly->verts[i][6] = t;
-       }
+       if (r_dynamic.integer)
+               R_MarkLights();
 
-       //
-       // remove co-linear points - Ed
-       //
-       /*
-       if (!gl_keeptjunctions.value)
+       if (!r_vertexsurfaces.integer)
        {
-               for (i = 0 ; i < lnumverts ; ++i)
+               for (i = 0;i < currentrenderentity->model->nummodelsurfaces;i++)
                {
-                       vec3_t v1, v2;
-                       float *prev, *this, *next;
-
-                       prev = poly->verts[(i + lnumverts - 1) % lnumverts];
-                       this = poly->verts[i];
-                       next = poly->verts[(i + 1) % lnumverts];
-
-                       VectorSubtract( this, prev, v1 );
-                       VectorNormalize( v1 );
-                       VectorSubtract( next, prev, v2 );
-                       VectorNormalize( v2 );
-
-                       // skip co-linear points
-                       #define COLINEAR_EPSILON 0.001
-                       if ((fabs( v1[0] - v2[0] ) <= COLINEAR_EPSILON) &&
-                               (fabs( v1[1] - v2[1] ) <= COLINEAR_EPSILON) &&
-                               (fabs( v1[2] - v2[2] ) <= COLINEAR_EPSILON))
+                       s = currentrenderentity->model->modelsortedsurfaces[i];
+                       if (s->visframe == r_framecount && s->lightmaptexture != NULL)
                        {
-                               int j;
-                               for (j = i + 1; j < lnumverts; ++j)
+                               if (s->cached_dlight
+                                || s->cached_ambient != r_ambient.value
+                                || s->cached_lightscalebit != lightscalebit)
+                                       R_BuildLightMap(s, false); // base lighting changed
+                               else if (r_dynamic.integer)
                                {
-                                       int k;
-                                       for (k = 0; k < VERTEXSIZE; ++k)
-                                               poly->verts[j - 1][k] = poly->verts[j][k];
+                                       if  (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]))))))))
+                                       //if (s->cached_light[0] != d_lightstylevalue[s->styles[0]]
+                                       // || s->cached_light[1] != d_lightstylevalue[s->styles[1]]
+                                       // || s->cached_light[2] != d_lightstylevalue[s->styles[2]]
+                                       // || s->cached_light[3] != d_lightstylevalue[s->styles[3]])
+                                               R_BuildLightMap(s, false); // base lighting changed
+                                       else if (s->dlightframe == r_framecount && r_dlightmap.integer)
+                                               R_BuildLightMap(s, true); // only dlights
                                }
-                               --lnumverts;
-                               ++nColinElim;
-                               // retry next vertex next time, which is now current vertex
-                               --i;
                        }
                }
-               poly->numverts = lnumverts;
        }
-       */
+}
+
+void R_MarkWorldLights(void)
+{
+       R_SetupForWorldRendering();
+       R_SurfMarkLights();
 }
 
 /*
-========================
-GL_CreateSurfaceLightmap
-========================
+=============
+R_DrawWorld
+=============
 */
-void GL_CreateSurfaceLightmap (msurface_t *surf)
+void R_DrawWorld (void)
 {
-       int             smax, tmax;
+       R_SetupForWorldRendering();
 
-       if (surf->flags & (SURF_DRAWSKY|SURF_DRAWTURB))
-               return;
-
-       smax = (surf->extents[0]>>4)+1;
-       tmax = (surf->extents[1]>>4)+1;
-
-       surf->lightmaptexturenum = AllocBlock (smax, tmax, &surf->light_s, &surf->light_t);
-       if (nosubimage || nosubimagefragments)
-               return;
-       glBindTexture(GL_TEXTURE_2D, lightmap_textures + surf->lightmaptexturenum);
-       smax = ((surf->extents[0]>>4)+lightmapalign) & lightmapalignmask;
-       if (lightmaprgba)
-       {
-               R_BuildLightMap (surf, templight, smax * 4, false);
-               if(r_upload.value)
-                       glTexSubImage2D(GL_TEXTURE_2D, 0, surf->light_s, surf->light_t, smax, tmax, GL_RGBA, GL_UNSIGNED_BYTE, templight);
-       }
+       if (r_viewleaf->contents == CONTENTS_SOLID || r_novis.integer || r_viewleaf->compressed_vis == NULL)
+               R_SolidWorldNode ();
        else
-       {
-               R_BuildLightMap (surf, templight, smax * 3, false);
-               if(r_upload.value)
-                       glTexSubImage2D(GL_TEXTURE_2D, 0, surf->light_s, surf->light_t, smax, tmax, GL_RGB , GL_UNSIGNED_BYTE, templight);
-       }
+               R_PVSWorldNode ();
 }
 
-
 /*
-==================
-GL_BuildLightmaps
-
-Builds the lightmap texture
-with all the surfaces from all brush models
-==================
+=================
+R_DrawBrushModel
+=================
 */
-void GL_BuildLightmaps (void)
+void R_DrawBrushModelSky (void)
 {
-       int             i, j;
-       model_t *m;
-
-       memset (allocated, 0, sizeof(allocated));
-
-       r_framecount = 1;               // no dlightcache
-
-       if (gl_nosubimagefragments.value)
-               nosubimagefragments = 1;
-       else
-               nosubimagefragments = 0;
+       R_SetupForBModelRendering();
 
-       if (gl_nosubimage.value)
-               nosubimage = 1;
-       else
-               nosubimage = 0;
+       R_PrepareSurfaces();
+       R_DrawSurfaces(SHADERSTAGE_SKY);
+}
 
-       if (gl_lightmaprgba.value)
-       {
-               lightmaprgba = true;
-               lightmapbytes = 4;
-       }
-       else
-       {
-               lightmaprgba = false;
-               lightmapbytes = 3;
-       }
+void R_DrawBrushModelNormal (void)
+{
+       c_bmodels++;
 
-       // LordHavoc: TexSubImage2D needs data aligned on 4 byte boundaries unless
-       // I specify glPixelStorei(GL_UNPACK_ALIGNMENT, 1), I suspect 4 byte may be
-       // faster anyway, so I implemented an adjustable lightmap alignment...
-
-       // validate the lightmap alignment
-       i = 1;
-       while (i < 16 && i < gl_lightmapalign.value)
-               i <<= 1;
-       Cvar_SetValue("gl_lightmapalign", i);
-
-       // find the lowest pixel count which satisfies the byte alignment
-       lightmapalign = 1;
-       j = lightmaprgba ? 4 : 3; // bytes per pixel
-       while ((lightmapalign * j) & (i - 1))
-               lightmapalign <<= 1;
-       lightmapalignmask = ~(lightmapalign - 1);
-
-       // alignment is irrelevant if using fallback modes
-       if (nosubimagefragments || nosubimage)
-       {
-               lightmapalign = 1;
-               lightmapalignmask = ~0;
-       }
+       // have to flush queue because of possible lightmap reuse
+       R_Mesh_Render();
 
-       if (!lightmap_textures)
-               lightmap_textures = R_GetTextureSlots(MAX_LIGHTMAPS);
+       R_SetupForBModelRendering();
 
-       // need a world entity for lightmap code
-       R_SetupWorldEnt();
+       R_SurfMarkLights();
 
-       for (j=1 ; j<MAX_MODELS ; j++)
-       {
-               m = cl.model_precache[j];
-               if (!m)
-                       break;
-               if (m->name[0] == '*')
-                       continue;
-               for (i=0 ; i<m->numsurfaces ; i++)
-               {
-                       if ( m->surfaces[i].flags & SURF_DRAWTURB )
-                               continue;
-                       if ( m->surfaces[i].flags & SURF_DRAWSKY )
-                               continue;
-                       GL_CreateSurfaceLightmap (m->surfaces + i);
-                       BuildSurfaceDisplayList (m, m->vertexes, m->surfaces + i);
-               }
-       }
+       R_PrepareSurfaces();
 
-       if (nosubimage || nosubimagefragments)
-       {
-               // LordHavoc: switch to second TMU as an upload hint for voodoo2
-               // (don't know if it really pays attention or not, but original
-               // glquake did this...)
-               if(r_upload.value)
-                       if (gl_mtexable)
-                               qglActiveTexture(GL_TEXTURE1_ARB);
-               for (i = 0;i < MAX_LIGHTMAPS;i++)
-               {
-                       if (!allocated[i][0])
-                               break;
-                       lightmapupdate[i][0] = BLOCK_HEIGHT;
-                       lightmapupdate[i][1] = 0;
-                       if(r_upload.value)
-                       {
-                               glBindTexture(GL_TEXTURE_2D, lightmap_textures + i);
-                               glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-                               glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-                               if (lightmaprgba)
-                                       glTexImage2D(GL_TEXTURE_2D, 0, 3, BLOCK_WIDTH, BLOCK_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, lightmaps[i]);
-                               else
-                                       glTexImage2D(GL_TEXTURE_2D, 0, 3, BLOCK_WIDTH, BLOCK_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, lightmaps[i]);
-                       }
-               }
-               if(r_upload.value)
-                       if (gl_mtexable)
-                               qglActiveTexture(GL_TEXTURE0_ARB);
-       }
+       if (!skyrendermasked)
+               R_DrawSurfaces(SHADERSTAGE_SKY);
+       R_DrawSurfaces(SHADERSTAGE_NORMAL);
+       R_DrawSurfaces(SHADERSTAGE_FOG);
 }
-
index 0cfd6ac1d5aceca24d0659f4cb8f949e3f137fd5..54ebddbe9eb3bbcbf8267dc46560f60a346be886 100644 (file)
@@ -55,7 +55,7 @@ SlowPrint ()
 Screen_Update ();
 Con_Printf ();
 
-net 
+net
 turn off messages option
 
 the refresh is always rendered, unless the console is full screen
@@ -86,13 +86,10 @@ cvar_t      showfps = {CVAR_SAVE, "showfps", "0"};
 cvar_t r_render = {0, "r_render", "1"};
 cvar_t r_brightness = {CVAR_SAVE, "r_brightness", "1"}; // LordHavoc: a method of operating system independent color correction
 cvar_t r_contrast = {CVAR_SAVE, "r_contrast", "1"}; // LordHavoc: a method of operating system independent color correction
+cvar_t gl_dither = {CVAR_SAVE, "gl_dither", "1"}; // whether or not to use dithering
 
 qboolean       scr_initialized;                // ready to draw
 
-qpic_t         *scr_ram;
-qpic_t         *scr_net;
-qpic_t         *scr_turtle;
-
 int                    clearconsole;
 int                    clearnotify;
 
@@ -332,9 +329,6 @@ void SCR_SizeDown_f (void)
 
 void gl_screen_start(void)
 {
-       scr_ram = Draw_PicFromWad ("ram");
-       scr_net = Draw_PicFromWad ("net");
-       scr_turtle = Draw_PicFromWad ("turtle");
 }
 
 void gl_screen_shutdown(void)
@@ -350,9 +344,9 @@ void gl_screen_newmap(void)
 SCR_Init
 ==================
 */
+static void R_Envmap_f (void);
 void GL_Screen_Init (void)
 {
-
        Cvar_RegisterVariable (&scr_fov);
        Cvar_RegisterVariable (&scr_viewsize);
        Cvar_RegisterVariable (&scr_conspeed);
@@ -365,14 +359,16 @@ void GL_Screen_Init (void)
        Cvar_RegisterVariable (&r_render);
        Cvar_RegisterVariable (&r_brightness);
        Cvar_RegisterVariable (&r_contrast);
+       Cvar_RegisterVariable (&gl_dither);
 #ifdef NORENDER
-       r_render.value = 0;
+       Cvar_SetValue("r_render", 0);
 #endif
 
 //
 // register our commands
 //
        Cmd_AddCommand ("screenshot",SCR_ScreenShot_f);
+       Cmd_AddCommand ("envmap", R_Envmap_f);
        Cmd_AddCommand ("sizeup",SCR_SizeUp_f);
        Cmd_AddCommand ("sizedown",SCR_SizeDown_f);
 
@@ -390,9 +386,9 @@ SCR_DrawRam
 */
 void SCR_DrawRam (void)
 {
-//     if (!scr_showram.value)
+//     if (!scr_showram.integer)
 //             return;
-//     Draw_Pic (32, 0, scr_ram);
+//     Draw_Pic (32, 0, Draw_CachePic("ram"));
 }
 
 /*
@@ -403,11 +399,11 @@ SCR_DrawTurtle
 void SCR_DrawTurtle (void)
 {
        static int      count;
-       
-       if (!scr_showturtle.value)
+
+       if (!scr_showturtle.integer)
                return;
 
-       if (cl.frametime < 0.1)
+       if (host_frametime < 0.1)
        {
                count = 0;
                return;
@@ -417,7 +413,7 @@ void SCR_DrawTurtle (void)
        if (count < 3)
                return;
 
-       Draw_Pic (0, 0, scr_turtle);
+       Draw_Pic (0, 0, Draw_CachePic("turtle"));
 }
 
 /*
@@ -432,7 +428,7 @@ void SCR_DrawNet (void)
        if (cls.demoplayback)
                return;
 
-       Draw_Pic (64, 0, scr_net);
+       Draw_Pic (64, 0, Draw_CachePic("net"));
 }
 
 /*
@@ -444,7 +440,7 @@ void SCR_DrawPause (void)
 {
        qpic_t  *pic;
 
-       if (!scr_showpause.value)               // turn off for screenshots
+       if (!scr_showpause.integer)             // turn off for screenshots
                return;
 
        if (!cl.paused)
@@ -543,7 +539,7 @@ void SCR_DrawConsole (void)
 ============================================================================== 
 
                                                SCREEN SHOTS 
+
 ============================================================================== 
 */ 
 
@@ -579,8 +575,9 @@ void SCR_ScreenShot_f (void)
                return;
        }
 
-       buffer = qmalloc(vid.realwidth*vid.realheight*3);
+       buffer = Mem_Alloc(tempmempool, vid.realwidth*vid.realheight*3);
        glReadPixels (vid.realx, vid.realy, vid.realwidth, vid.realheight, GL_RGB, GL_UNSIGNED_BYTE, buffer);
+       CHECKGLERROR
 
        // apply hardware gamma to the image
        BuildGammaTable8((lighthalf && hardwaregammasupported) ? 2.0f : 1.0f, 1, 1, 0, gamma);
@@ -588,10 +585,105 @@ void SCR_ScreenShot_f (void)
 
        Image_WriteTGARGB_preflipped(filename, vid.realwidth, vid.realheight, buffer);
 
-       qfree(buffer);
+       Mem_Free(buffer);
        Con_Printf ("Wrote %s\n", filename);
 }
 
+/*
+===============
+R_Envmap_f
+
+Grab six views for environment mapping tests
+===============
+*/
+float CalcFov (float fov_x, float width, float height);
+struct
+{
+       float angles[3];
+       char *name;
+}
+envmapinfo[6] =
+{
+       {{  0,   0, 0}, "ft"},
+       {{  0,  90, 0}, "rt"},
+       {{  0, 180, 0}, "bk"},
+       {{  0, 270, 0}, "lf"},
+       {{-90,  90, 0}, "up"},
+       {{ 90,  90, 0}, "dn"}
+};
+static void R_Envmap_f (void)
+{
+       int             i, size;
+       char    filename[256];
+       char    basename[256];
+       byte    *buffer, gamma[256];
+
+       if (Cmd_Argc() != 3)
+       {
+               Con_Printf ("envmap <basename> <size>: save out 6 cubic environment map images, usable with loadsky, note that size must one of 128, 256, 512, or 1024 and can't be bigger than your current resolution\n");
+               return;
+       }
+
+       if (!r_render.integer)
+               return;
+
+       strcpy(basename, Cmd_Argv(1));
+       size = atoi(Cmd_Argv(2));
+       if (size != 128 && size != 256 && size != 512 && size != 1024)
+       {
+               Con_Printf("envmap: size must be one of 128, 256, 512, or 1024\n");
+               return;
+       }
+       if (size > vid.realwidth || size > vid.realheight)
+       {
+               Con_Printf("envmap: your resolution is not big enough to render that size\n");
+               return;
+       }
+
+       buffer = Mem_Alloc(tempmempool, size*size*3);
+       if (buffer == NULL)
+       {
+               Con_Printf("envmap: unable to allocate memory for image\n");
+               return;
+       }
+
+       BuildGammaTable8((lighthalf && hardwaregammasupported) ? 2.0f : 1.0f, 1, 1, 0, gamma);
+
+//     glDrawBuffer  (GL_FRONT);
+//     glReadBuffer  (GL_FRONT);
+       glDrawBuffer  (GL_BACK);
+       glReadBuffer  (GL_BACK);
+       envmap = true;
+
+       r_refdef.x = 0;
+       r_refdef.y = 0;
+       r_refdef.width = size;
+       r_refdef.height = size;
+
+       r_refdef.fov_x = 90;
+       r_refdef.fov_y = 90;
+
+       for (i = 0;i < 6;i++)
+       {
+               VectorCopy(envmapinfo[i].angles, r_refdef.viewangles);
+               glClearColor(0,0,0,0);
+               glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // LordHavoc: clear the screen (around the view as well)
+               R_RenderView ();
+               glReadPixels (0, 0, size, size, GL_RGB, GL_UNSIGNED_BYTE, buffer);
+               sprintf(filename, "env/%s%s.tga", basename, envmapinfo[i].name);
+               Image_GammaRemapRGB(buffer, buffer, size * size, gamma, gamma, gamma);
+               Image_WriteTGARGB_preflipped(filename, size, size, buffer);
+       }
+
+       envmap = false;
+       glDrawBuffer  (GL_BACK);
+       glReadBuffer  (GL_BACK);
+
+       Mem_Free(buffer);
+
+       // cause refdef to be fixed
+//     vid.recalc_refdef = 1;
+}
 
 //=============================================================================
 
@@ -699,11 +791,13 @@ void GL_BrightenScreen(void)
        if (!(lighthalf && !hardwaregammasupported) && r_brightness.value < 1.01f && r_contrast.value > 0.99f)
                return;
 
-       if (!r_render.value)
+       if (!r_render.integer)
                return;
 
        glDisable(GL_TEXTURE_2D);
+       CHECKGLERROR
        glEnable(GL_BLEND);
+       CHECKGLERROR
        f = r_brightness.value;
        // only apply lighthalf using software color correction if hardware is not available (speed reasons)
        if (lighthalf && !hardwaregammasupported)
@@ -711,6 +805,7 @@ void GL_BrightenScreen(void)
        if (f >= 1.01f)
        {
                glBlendFunc (GL_DST_COLOR, GL_ONE);
+               CHECKGLERROR
                glBegin (GL_TRIANGLES);
                while (f >= 1.01f)
                {
@@ -724,26 +819,35 @@ void GL_BrightenScreen(void)
                        f *= 0.5;
                }
                glEnd ();
+               CHECKGLERROR
        }
        if (r_contrast.value <= 0.99f)
        {
                glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+               CHECKGLERROR
                if (lighthalf && hardwaregammasupported)
                        glColor4f (0.5, 0.5, 0.5, 1 - r_contrast.value);
                else
                        glColor4f (1, 1, 1, 1 - r_contrast.value);
+               CHECKGLERROR
                glBegin (GL_TRIANGLES);
                glVertex2f (-5000, -5000);
                glVertex2f (10000, -5000);
                glVertex2f (-5000, 10000);
                glEnd ();
+               CHECKGLERROR
        }
        glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+       CHECKGLERROR
 
        glEnable (GL_CULL_FACE);
+       CHECKGLERROR
        glEnable (GL_DEPTH_TEST);
+       CHECKGLERROR
        glDisable(GL_BLEND);
+       CHECKGLERROR
        glEnable(GL_TEXTURE_2D);
+       CHECKGLERROR
 }
 
 /*
@@ -762,7 +866,7 @@ void SCR_UpdateScreen (void)
 {
        double  time1 = 0, time2;
 
-       if (r_speeds.value)
+       if (r_speeds.integer)
                time1 = Sys_DoubleTime ();
 
        VID_UpdateGamma(false);
@@ -786,16 +890,16 @@ void SCR_UpdateScreen (void)
 
        GL_BeginRendering (&vid.realx, &vid.realy, &vid.realwidth, &vid.realheight);
 
-       if (gl_combine.value && !gl_combine_extension)
-               Cvar_SetValue("gl_combine", false);
+       if (gl_combine.integer && !gl_combine_extension)
+               Cvar_SetValue("gl_combine", 0);
 
-       lighthalf = gl_lightmode.value;
+       lighthalf = gl_lightmode.integer;
 
        lightscalebit = 0;
        if (lighthalf)
                lightscalebit += 1;
 
-       if (gl_combine.value)
+       if (gl_combine.integer && r_multitexture.integer)
                lightscalebit += 2;
 
        lightscale = 1.0f / (float) (1 << lightscalebit);
@@ -818,12 +922,20 @@ void SCR_UpdateScreen (void)
 //     if (vid.recalc_refdef)
                SCR_CalcRefdef();
 
-       if (r_render.value)
+       if (r_render.integer)
        {
                glClearColor(0,0,0,0);
+               CHECKGLERROR
                glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // LordHavoc: clear the screen (around the view as well)
+               CHECKGLERROR
        }
 
+       if (gl_dither.integer)
+               glEnable(GL_DITHER);
+       else
+               glDisable(GL_DITHER);
+       CHECKGLERROR
+
 //
 // do 3D refresh drawing, and then update the screen
 //
@@ -843,8 +955,8 @@ void SCR_UpdateScreen (void)
        Sbar_Draw();
        SHOWLMP_drawall();
 
-       if (crosshair.value)
-               DrawCrosshair(crosshair.value - 1);
+       if (crosshair.integer)
+               DrawCrosshair(crosshair.integer - 1);
 
        if (cl.intermission == 1)
                Sbar_IntermissionOverlay();
@@ -859,20 +971,40 @@ void SCR_UpdateScreen (void)
 //     if (scr_drawloading)
 //             SCR_DrawLoading();
 
-       if (showfps.value)
+       if (showfps.integer)
        {
-               static double currtime;
-               double newtime;
+               static double currtime, frametimes[32];
+               double newtime, total;
                char temp[32];
-               int calc;
+               int calc, count, i;
+               static int framecycle = 0;
                newtime = Sys_DoubleTime();
-               calc = (int) ((1.0 / (newtime - currtime)) + 0.5);
+               frametimes[framecycle] = newtime - currtime;
+               framecycle++;
+               framecycle &= 31;
+               total = 0;
+               count = 0;
+               for (i = 0;i < 32;i++)
+               {
+                       if (frametimes[i])
+                       {
+                               total += frametimes[i];
+                               count++;
+                               // limit how far back we look
+                               if (total >= 0.25)
+                                       break;
+                       }
+               }
+               if (showfps.integer == 1)
+                       calc = (int) ((count / total) + 0.5);
+               else // showfps 2, rapid update
+                       calc = (int) ((1.0 / (newtime - currtime)) + 0.5);
                sprintf(temp, "%4i fps", calc);
                currtime = newtime;
                Draw_String(vid.conwidth - (8*8), vid.conheight - sb_lines - 8, temp, 9999);
        }
 
-       if (r_speeds2.value && r_speeds2_string[0])
+       if (r_speeds2.integer && r_speeds2_string[0])
        {
                int i, j, lines, y;
                lines = 1;
@@ -902,10 +1034,10 @@ void SCR_UpdateScreen (void)
 
        GL_Finish();
 
-       if (r_speeds.value)
+       if (r_speeds.integer)
        {
                time2 = Sys_DoubleTime ();
-               Con_Printf ("%3i ms  %4i wpoly %4i epoly %4i transpoly %4i lightpoly %4i BSPnodes %4i BSPleafs %4i BSPfaces %4i models %4i bmodels %4i sprites %4i particles %3i dlights\n", (int)((time2-time1)*1000), c_brush_polys, c_alias_polys, currenttranspoly, c_light_polys, c_nodes, c_leafs, c_faces, c_models, c_bmodels, c_sprites, c_particles, c_dlights);
+               Con_Printf ("%3i ms  %4i wpoly %4i epoly %6i meshtris %4i lightpoly %4i BSPnodes %4i BSPleafs %4i BSPfaces %4i models %4i bmodels %4i sprites %4i particles %3i dlights\n", (int)((time2-time1)*1000), c_brush_polys, c_alias_polys, c_meshtris, c_light_polys, c_nodes, c_leafs, c_faces, c_models, c_bmodels, c_sprites, c_particles, c_dlights);
        }
        GL_EndRendering ();
 }
@@ -913,8 +1045,9 @@ void SCR_UpdateScreen (void)
 // for profiling, this is separated
 void GL_Finish(void)
 {
-       if (!r_render.value)
+       if (!r_render.integer)
                return;
        glFinish ();
+       CHECKGLERROR
 }
 
index eea2586d8d605bfeffe7b360612064a7dfb47a0c..00ad39b3da8331960247ffa53dff9befbee75446 100644 (file)
 #include "quakedef.h"
 
-cvar_t         r_max_size = {0, "r_max_size", "2048"};
-cvar_t         r_picmip = {0, "r_picmip", "0"};
-cvar_t         r_lerpimages = {CVAR_SAVE, "r_lerpimages", "1"};
-cvar_t         r_upload = {0, "r_upload", "1"};
-cvar_t         r_precachetextures = {CVAR_SAVE, "r_precachetextures", "1"};
+cvar_t r_max_size = {0, "r_max_size", "2048"};
+cvar_t r_picmip = {0, "r_picmip", "0"};
+cvar_t r_lerpimages = {CVAR_SAVE, "r_lerpimages", "1"};
+cvar_t r_precachetextures = {CVAR_SAVE, "r_precachetextures", "1"};
 
 int            gl_filter_min = GL_LINEAR_MIPMAP_LINEAR; //NEAREST;
-int            gl_filter_max = GL_LINEAR;
+int            gl_filter_mag = GL_LINEAR;
 
 
-int            texels;
+static mempool_t *texturemempool;
 
-// 65536x65536
-#define MAXMIPS 16
+// note: this must not conflict with TEXF_ flags in r_textures.h
+// cleared when a texture is uploaded
+#define GLTEXF_UPLOAD 0x00010000
+// texture generated by code, also causes permanent GLTEXF_UPLOAD effect
+#define GLTEXF_PROCEDURAL 0x00020000
+// bitmask for mismatch checking
+#define GLTEXF_IMPORTANTBITS (GLTEXF_PROCEDURAL)
+// set when image is uploaded and freed
+#define GLTEXF_DESTROYED 0x00040000
 
-#define GLTEXF_LERPED 1
-#define GLTEXF_UPLOADED 2
+// size of images which hold fragment textures, ignores picmip and max_size
+#define BLOCK_SIZE 256
+
+// really this number only governs gltexnuminuse
+#define MAX_GLTEXTURES 65536
+
+// since there is only one set of GL texture numbers, we have to track them
+// globally, everything else is per texture pool
+static byte *gltexnuminuse;
 
 typedef struct
 {
-       char    identifier[64];
-       int             texnum; // GL texture slot number
-       int             texeldatasize; // computed memory usage of this texture (including mipmaps, expansion to 32bit, etc)
-       byte    *inputtexels; // copy of the original texture supplied to the upload function, for re-uploading or deferred uploads (non-precached)
-       int             inputtexeldatasize; // size of the original texture
-       unsigned short width, height;
-// LordHavoc: CRC to identify cache mismatchs
-       unsigned short crc;
-       int flags; // the requested flags when the texture was supplied to the upload function
-       int internalflags; // internal notes (lerped, etc)
-} gltexture_t;
+       int textype;
+       int inputbytesperpixel;
+       int internalbytesperpixel;
+       int glformat;
+       int glinternalformat;
+       int align;
+}
+textypeinfo_t;
+
+static textypeinfo_t textype_qpalette       = {TEXTYPE_QPALETTE, 1, 4, GL_RGBA, 3, 1};
+static textypeinfo_t textype_rgb            = {TEXTYPE_RGB     , 3, 3, GL_RGB , 3, 3};
+static textypeinfo_t textype_rgba           = {TEXTYPE_RGBA    , 4, 4, GL_RGBA, 3, 1};
+static textypeinfo_t textype_qpalette_alpha = {TEXTYPE_QPALETTE, 1, 4, GL_RGBA, 4, 1};
+static textypeinfo_t textype_rgba_alpha     = {TEXTYPE_RGBA    , 4, 4, GL_RGBA, 4, 1};
+
+// a tiling texture (most common type)
+#define GLIMAGETYPE_TILE 0
+// a fragments texture (contains one or more fragment textures)
+#define GLIMAGETYPE_FRAGMENTS 1
+
+// a gltextureimage can have one (or more if fragments) gltextures inside
+typedef struct gltextureimage_s
+{
+       struct gltextureimage_s *imagechain;
+       int texturecount;
+       int type; // one of the GLIMAGETYPE_ values
+       int texnum; // GL texture slot number
+       int width, height;
+       int bytesperpixel; // bytes per pixel
+       int glformat; // GL_RGB or GL_RGBA
+       int glinternalformat; // 3 or 4
+       int flags;
+       short *blockallocation; // fragment allocation
+}
+gltextureimage_t;
+
+typedef struct gltexture_s
+{
+       // pointer to texturepool (check this to see if the texture is allocated)
+       struct gltexturepool_s *pool;
+       // pointer to next texture in texturepool chain
+       struct gltexture_s *chain;
+       // pointer into gltextureimage array
+       gltextureimage_t *image;
+       // name of the texture (this might be removed someday), no duplicates
+       char *identifier;
+       // location in the image, and size
+       int x, y, width, height;
+       // copy of the original texture supplied to the upload function, for re-uploading or deferred uploads (non-precached)
+       byte *inputtexels;
+       // to identify cache mismatchs (this might be removed someday)
+       int crc;
+       // flags supplied to the LoadTexture/ProceduralTexture functions
+       // (might be altered to remove TEXF_ALPHA), and GLTEXF_ private flags
+       int flags;
+       // procedural texture generation function, called once per frame if the texture is used
+       int (*generate)(byte *buffer, int width, int height, void *parameterdata, int parameterdatasize);
+       // data provided to generate, persistent from call to call
+       byte *proceduraldata;
+       // size of data
+       int proceduraldatasize;
+       // used only to avoid updating the texture more than once per frame
+       int proceduralframecount;
+       // pointer to one of the textype_ structs
+       textypeinfo_t *textype;
+}
+gltexture_t;
+
+#define TEXTUREPOOL_SENTINEL 0xC0DEDBAD
+
+typedef struct gltexturepool_s
+{
+       int sentinel;
+       struct gltextureimage_s *imagechain;
+       struct gltexture_s *gltchain;
+       struct gltexturepool_s *next;
+}
+gltexturepool_t;
+
+static gltexturepool_t *gltexturepoolchain = NULL;
+
+static byte *resamplerow1 = NULL, *resamplerow2 = NULL;
+static int resamplerowsize = 0;
+static byte *resizebuffer = NULL, *colorconvertbuffer;
+static int resizebuffersize = 0;
+static byte *texturebuffer;
+static int texturebuffersize = 0;
+
+static int realmaxsize = 0;
+
+static textypeinfo_t *R_GetTexTypeInfo(int textype, int flags)
+{
+       if (flags & TEXF_ALPHA)
+       {
+               switch(textype)
+               {
+               case TEXTYPE_QPALETTE:
+                       return &textype_qpalette_alpha;
+               case TEXTYPE_RGB:
+                       Host_Error("R_GetTexTypeInfo: RGB format has no alpha, TEXF_ALPHA not allowed\n");
+                       return NULL;
+               case TEXTYPE_RGBA:
+                       return &textype_rgba_alpha;
+               default:
+                       Host_Error("R_GetTexTypeInfo: unknown texture format\n");
+                       return NULL;
+               }
+       }
+       else
+       {
+               switch(textype)
+               {
+               case TEXTYPE_QPALETTE:
+                       return &textype_qpalette;
+               case TEXTYPE_RGB:
+                       return &textype_rgb;
+               case TEXTYPE_RGBA:
+                       return &textype_rgba;
+               default:
+                       Host_Error("R_GetTexTypeInfo: unknown texture format\n");
+                       return NULL;
+               }
+       }
+}
+
+static void R_UploadTexture(gltexture_t *t);
 
-#define        MAX_GLTEXTURES  4096
-gltexture_t    *gltextures;
-unsigned int numgltextures = 0, gl_texture_number = 1;
+static void R_PrecacheTexture(gltexture_t *glt)
+{
+       int precache;
+       precache = false;
+       if (glt->flags & TEXF_ALWAYSPRECACHE)
+               precache = true;
+       else if (r_precachetextures.integer >= 2)
+               precache = true;
+       else if (r_precachetextures.integer >= 1)
+               if (glt->flags & TEXF_PRECACHE)
+                       precache = true;
 
-void GL_UploadTexture(gltexture_t *t);
+       if (precache)
+               R_UploadTexture(glt);
+}
 
 int R_GetTexture(rtexture_t *rt)
 {
@@ -44,22 +182,123 @@ int R_GetTexture(rtexture_t *rt)
        if (!rt)
                return 0;
        glt = (gltexture_t *)rt;
-       if (!(glt->internalflags & GLTEXF_UPLOADED))
+       if (glt->flags & (GLTEXF_UPLOAD | GLTEXF_PROCEDURAL))
+       {
+               if (glt->flags & GLTEXF_PROCEDURAL)
+               {
+                       if (glt->proceduralframecount != r_framecount)
+                       {
+                               glt->proceduralframecount = r_framecount;
+                               R_UploadTexture(glt);
+                       }
+               }
+               else
+                       R_UploadTexture(glt);
+       }
+       return glt->image->texnum;
+}
+
+static void R_FreeTexture(gltexture_t *glt)
+{
+       gltexture_t **gltpointer;
+       gltextureimage_t *image, **gltimagepointer;
+       GLuint texnum;
+
+       for (gltpointer = &glt->pool->gltchain;*gltpointer && *gltpointer != glt;gltpointer = &(*gltpointer)->chain);
+       if (*gltpointer == glt)
+               *gltpointer = glt->chain;
+       else
+               Host_Error("R_FreeTexture: texture not linked in pool\n");
+
+       // note: if freeing a fragment texture, this will not make the claimed
+       // space available for new textures unless all other fragments in the
+       // image are also freed
+       image = glt->image;
+       image->texturecount--;
+       if (image->texturecount < 1)
        {
-               GL_UploadTexture(glt);
-               if (!(glt->internalflags & GLTEXF_UPLOADED))
-                       Host_Error("R_GetTexture: unable to upload texture\n");
+               for (gltimagepointer = &glt->pool->imagechain;*gltimagepointer && *gltimagepointer != image;gltimagepointer = &(*gltimagepointer)->imagechain);
+               if (*gltimagepointer == image)
+                       *gltimagepointer = image->imagechain;
+               else
+                       Host_Error("R_FreeTexture: image not linked in pool\n");
+               if (image->texnum)
+               {
+                       texnum = image->texnum;
+                       gltexnuminuse[image->texnum] = 0;
+                       glDeleteTextures(1, &texnum);
+               }
+               if (image->blockallocation)
+                       Mem_Free(image->blockallocation);
+               Mem_Free(image);
        }
-       return glt->texnum;
+
+       if (glt->identifier)
+               Mem_Free(glt->identifier);
+       if (glt->inputtexels)
+               Mem_Free(glt->inputtexels);
+       if (glt->proceduraldata)
+               Mem_Free(glt->proceduraldata);
+       Mem_Free(glt);
+}
+
+static gltexture_t *R_FindTexture (gltexturepool_t *pool, char *identifier)
+{
+       gltexture_t     *glt;
+
+       if (!identifier)
+               return NULL;
+
+       for (glt = pool->gltchain;glt;glt = glt->chain)
+               if (glt->identifier && !strcmp (identifier, glt->identifier))
+                       return glt;
+
+       return NULL;
+}
+
+rtexturepool_t *R_AllocTexturePool(void)
+{
+       gltexturepool_t *pool;
+       pool = Mem_Alloc(texturemempool, sizeof(gltexturepool_t));
+       if (pool == NULL)
+               return NULL;
+       //memset(pool, 0, sizeof(gltexturepool_t));
+       pool->next = gltexturepoolchain;
+       gltexturepoolchain = pool;
+       pool->sentinel = TEXTUREPOOL_SENTINEL;
+       return (rtexturepool_t *)pool;
+}
+
+void R_FreeTexturePool(rtexturepool_t **rtexturepool)
+{
+       gltexturepool_t *pool, **poolpointer;
+       if (rtexturepool == NULL)
+               return;
+       if (*rtexturepool == NULL)
+               return;
+       pool = (gltexturepool_t *)(*rtexturepool);
+       *rtexturepool = NULL;
+       if (pool->sentinel != TEXTUREPOOL_SENTINEL)
+               Host_Error("R_FreeTexturePool: pool already freed\n");
+       for (poolpointer = &gltexturepoolchain;*poolpointer && *poolpointer != pool;poolpointer = &(*poolpointer)->next);
+       if (*poolpointer == pool)
+               *poolpointer = pool->next;
+       else
+               Host_Error("R_FreeTexturePool: pool not linked\n");
+       while (pool->gltchain)
+               R_FreeTexture(pool->gltchain);
+       Mem_Free(pool);
 }
 
+
 typedef struct
 {
        char *name;
-       int     minimize, maximize;
-} glmode_t;
+       int minification, magnification;
+}
+glmode_t;
 
-glmode_t modes[] =
+static glmode_t modes[] =
 {
        {"GL_NEAREST", GL_NEAREST, GL_NEAREST},
        {"GL_LINEAR", GL_LINEAR, GL_LINEAR},
@@ -69,181 +308,263 @@ glmode_t modes[] =
        {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR}
 };
 
-/*
-===============
-Draw_TextureMode_f
-===============
-*/
-void Draw_TextureMode_f (void)
+static void GL_TextureMode_f (void)
 {
-       int             i;
-       gltexture_t     *glt;
+       int i;
+       gltextureimage_t *image;
+       gltexturepool_t *pool;
 
        if (Cmd_Argc() == 1)
        {
-               for (i=0 ; i< 6 ; i++)
-                       if (gl_filter_min == modes[i].minimize)
+               for (i = 0;i < 6;i++)
+               {
+                       if (gl_filter_min == modes[i].minification)
                        {
                                Con_Printf ("%s\n", modes[i].name);
                                return;
                        }
+               }
                Con_Printf ("current filter is unknown???\n");
                return;
        }
 
-       for (i=0 ; i< 6 ; i++)
-       {
+       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;
+       gl_filter_min = modes[i].minification;
+       gl_filter_mag = modes[i].magnification;
 
-       if (!r_upload.value)
-               return;
        // change all the existing mipmap texture objects
-       for (i=0, glt=gltextures ; i<numgltextures ; i++, glt++)
+       // FIXME: force renderer(/client/something?) restart instead?
+       for (pool = gltexturepoolchain;pool;pool = pool->next)
        {
-               if (glt->flags & TEXF_MIPMAP)
+               for (image = pool->imagechain;image;image = image->imagechain)
                {
-                       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);
+                       // only update already uploaded images
+                       if (!(image->flags & GLTEXF_UPLOAD))
+                       {
+                               glBindTexture(GL_TEXTURE_2D, image->texnum);
+                               if (image->flags & TEXF_MIPMAP)
+                                       glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
+                               else
+                                       glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_mag);
+                               glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_mag);
+                       }
                }
        }
 }
 
-void GL_TextureStats_Print(char *name, int total, int total2, int loaded, int crc, int mip, int alpha, int total2valid)
+static int R_CalcTexelDataSize (gltexture_t *glt)
 {
-       if (!name[0])
-               name = "<unnamed>";
-       Con_Printf("%5iK %c%5iK%c %04X %s %s %s %s\n", total, total2valid ? ' ' : '(', total2, total2valid ? ' ' : ')', crc, loaded ? "loaded" : "      ", mip ? "mip" : "   ", alpha ? "alpha" : "     ", name);
+       int width2, height2, size;
+       if (glt->flags & TEXF_FRAGMENT)
+               size = glt->width * glt->height;
+       else
+       {
+               if (r_max_size.integer > realmaxsize)
+                       Cvar_SetValue("r_max_size", realmaxsize);
+               // calculate final size
+               width2 = 1;while (width2 < glt->width) width2 <<= 1;
+               height2 = 1;while (height2 < glt->height) height2 <<= 1;
+               width2 >>= (int) r_picmip.integer;
+               height2 >>= (int) r_picmip.integer;
+               while (width2 > (int) r_max_size.integer) width2 >>= 1;
+               while (height2 > (int) r_max_size.integer) height2 >>= 1;
+               if (width2 < 1) width2 = 1;
+               if (height2 < 1) height2 = 1;
+
+               size = 0;
+               if (glt->flags & TEXF_MIPMAP)
+               {
+                       while (width2 > 1 || height2 > 1)
+                       {
+                               size += width2 * height2;
+                               if (width2 > 1)
+                                       width2 >>= 1;
+                               if (height2 > 1)
+                                       height2 >>= 1;
+                       }
+                       size++; // count the last 1x1 mipmap
+               }
+               else
+                       size = width2*height2;
+       }
+       size *= glt->textype->internalbytesperpixel;
+
+       return size;
 }
 
-void GL_TextureStats_PrintTotal(void)
+void R_TextureStats_PrintTotal(void)
 {
-       int i, t = 0, p = 0, loaded = 0, loadedt = 0, loadedp = 0;
+       int glsize, inputsize, total = 0, totalt = 0, totalp = 0, loaded = 0, loadedt = 0, loadedp = 0;
        gltexture_t *glt;
-       for (i = 0, glt = gltextures;i < numgltextures;i++, glt++)
+       gltexturepool_t *pool;
+       for (pool = gltexturepoolchain;pool;pool = pool->next)
        {
-               t += glt->texeldatasize;
-               p += glt->inputtexeldatasize;
-               if (glt->internalflags & GLTEXF_UPLOADED)
+               for (glt = pool->gltchain;glt;glt = glt->chain)
                {
-                       loaded++;
-                       loadedt += glt->texeldatasize;
-                       loadedp += glt->inputtexeldatasize;
+                       glsize = R_CalcTexelDataSize(glt);
+                       inputsize = glt->width * glt->height * glt->textype->inputbytesperpixel;
+
+                       total++;
+                       totalt += glsize;
+                       totalp += inputsize;
+                       if (!(glt->flags & GLTEXF_UPLOAD))
+                       {
+                               loaded++;
+                               loadedt += glsize;
+                               loadedp += inputsize;
+                       }
                }
        }
-       Con_Printf("total: %i (%.3fMB, %.3fMB original), uploaded %i (%.3fMB, %.3fMB original), upload on demand %i (%.3fMB, %.3fMB original)\n", numgltextures, t / 1048576.0, p / 1048576.0, loaded, loadedt / 1048576.0, loadedp / 1048576.0, numgltextures - loaded, (t - loadedt) / 1048576.0, (p - loadedp) / 1048576.0);
+       Con_Printf("total: %i (%.3fMB, %.3fMB original), uploaded %i (%.3fMB, %.3fMB original), upload on demand %i (%.3fMB, %.3fMB original)\n", total, totalt / 1048576.0, totalp / 1048576.0, loaded, loadedt / 1048576.0, loadedp / 1048576.0, total - loaded, (totalt - loadedt) / 1048576.0, (totalp - loadedp) / 1048576.0);
 }
 
-void GL_TextureStats_f(void)
+static void R_TextureStats_f(void)
 {
-       int i;
+       int loaded;
        gltexture_t *glt;
-       Con_Printf("kbytes original crc  loaded mip alpha name\n");
-       for (i = 0, glt = gltextures;i < numgltextures;i++, glt++)
-               GL_TextureStats_Print(glt->identifier, (glt->texeldatasize + 1023) / 1024, (glt->inputtexeldatasize + 1023) / 1024, glt->internalflags & GLTEXF_UPLOADED, glt->crc, glt->flags & TEXF_MIPMAP, glt->flags & TEXF_ALPHA, glt->inputtexels != NULL);
-       GL_TextureStats_PrintTotal();
+       gltexturepool_t *pool;
+       Con_Printf("glsize input crc  loaded mip alpha name\n");
+       for (pool = gltexturepoolchain;pool;pool = pool->next)
+       {
+               for (glt = pool->gltchain;glt;glt = glt->chain)
+               {
+                       loaded = !(glt->flags & GLTEXF_UPLOAD);
+                       if (glt->flags & GLTEXF_PROCEDURAL)
+                               Con_Printf("%c%4i%c %4i  PROC %s %s %s %s\n"  , loaded ? '[' : ' ', (R_CalcTexelDataSize(glt) + 1023) / 1024, loaded ? ']' : ' ',                               (glt->width * glt->height * glt->textype->inputbytesperpixel + 1023) / 1024,                                         loaded ? "loaded" : "      ", (glt->flags & TEXF_MIPMAP) ? "mip" : "   ", (glt->flags & TEXF_ALPHA) ? "alpha" : "     ", glt->identifier ? glt->identifier : "<unnamed>");
+                       else
+                               Con_Printf("%c%4i%c%c%4i%c %04X %s %s %s %s\n", loaded ? '[' : ' ', (R_CalcTexelDataSize(glt) + 1023) / 1024, loaded ? ']' : ' ', glt->inputtexels ? '[' : ' ', (glt->width * glt->height * glt->textype->inputbytesperpixel + 1023) / 1024, glt->inputtexels ? ']' : ' ', glt->crc, loaded ? "loaded" : "      ", (glt->flags & TEXF_MIPMAP) ? "mip" : "   ", (glt->flags & TEXF_ALPHA) ? "alpha" : "     ", glt->identifier ? glt->identifier : "<unnamed>");
+               }
+               Con_Printf("pool %10p\n", pool);
+       }
+       R_TextureStats_PrintTotal();
 }
 
 char engineversion[40];
 
-//void GL_UploadTexture (gltexture_t *glt);
-void r_textures_start(void)
+static void r_textures_start(void)
 {
-//     int i;
-//     gltexture_t *glt;
-//     for (i=0, glt=gltextures ; i<numgltextures ; i++, glt++)
-//             GL_UploadTexture(glt);
+       // deal with size limits of various drivers (3dfx in particular)
+       glGetIntegerv(GL_MAX_TEXTURE_SIZE, &realmaxsize);
+       CHECKGLERROR
+
+       texturemempool = Mem_AllocPool("Textures");
+       gltexnuminuse = Mem_Alloc(texturemempool, MAX_GLTEXTURES);
+       //memset(gltexnuminuse, 0, MAX_GLTEXTURES);
 }
 
-void r_textures_shutdown(void)
+static void r_textures_shutdown(void)
 {
+       rtexturepool_t *temp;
+       while(gltexturepoolchain)
+       {
+               temp = (rtexturepool_t *) gltexturepoolchain;
+               R_FreeTexturePool(&temp);
+       }
+
+       /*
+       if (resizebuffer) Mem_Free(resizebuffer);resizebuffer = NULL;
+       if (colorconvertbuffer) Mem_Free(colorconvertbuffer);colorconvertbuffer = NULL;
+       if (resamplerow1) Mem_Free(resamplerow1);resamplerow1 = NULL;
+       if (resamplerow2) Mem_Free(resamplerow2);resamplerow2 = NULL;
+       if (texturebuffer) Mem_Free(texturebuffer);texturebuffer = NULL;
+       if (gltexnuminuse) Mem_Free(gltexnuminuse);gltexnuminuse = NULL;
+       */
+       resizebuffersize = 0;
+       resamplerowsize = 0;
+       texturebuffersize = 0;
+       resizebuffer = NULL;
+       colorconvertbuffer = NULL;
+       resamplerow1 = NULL;
+       resamplerow2 = NULL;
+       texturebuffer = NULL;
+       gltexnuminuse = NULL;
+       Mem_FreePool(&texturemempool);
 }
 
-void r_textures_newmap(void)
+static void r_textures_newmap(void)
 {
 }
 
 void R_Textures_Init (void)
 {
-       Cmd_AddCommand("r_texturestats", GL_TextureStats_f);
+       Cmd_AddCommand ("gl_texturemode", &GL_TextureMode_f);
+       Cmd_AddCommand("r_texturestats", R_TextureStats_f);
        Cvar_RegisterVariable (&r_max_size);
        Cvar_RegisterVariable (&r_picmip);
        Cvar_RegisterVariable (&r_lerpimages);
-       Cvar_RegisterVariable (&r_upload);
        Cvar_RegisterVariable (&r_precachetextures);
-#ifdef NORENDER
-       r_upload.value = 0;
-#endif
-
-       // 3dfx can only handle 256 wide textures
-       if (!Q_strncasecmp ((char *)gl_renderer, "3dfx",4) || strstr((char *)gl_renderer, "Glide"))
-               Cvar_Set ("r_max_size", "256");
-
-       gltextures = qmalloc(sizeof(gltexture_t) * MAX_GLTEXTURES);
-       memset(gltextures, 0, sizeof(gltexture_t) * MAX_GLTEXTURES);
-       Cmd_AddCommand ("gl_texturemode", &Draw_TextureMode_f);
+       gltexnuminuse = NULL;
 
        R_RegisterModule("R_Textures", r_textures_start, r_textures_shutdown, r_textures_newmap);
 }
 
-/*
-================
-R_FindTexture
-================
-*/
-int R_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;
-}
-
-void R_ResampleTextureLerpLine (byte *in, byte *out, int inwidth, int outwidth)
+static void R_ResampleTextureLerpLine (byte *in, byte *out, int inwidth, int outwidth, int bytesperpixel)
 {
-       int             j, xi, oldx = 0, f, fstep, endx;
+       int             j, xi, oldx = 0, f, fstep, endx, lerp;
        fstep = (int) (inwidth*65536.0f/outwidth);
        endx = (inwidth-1);
-       for (j = 0,f = 0;j < outwidth;j++, f += fstep)
+       if (bytesperpixel == 4)
        {
-               xi = (int) f >> 16;
-               if (xi != oldx)
-               {
-                       in += (xi - oldx) * 4;
-                       oldx = xi;
-               }
-               if (xi < endx)
+               for (j = 0,f = 0;j < outwidth;j++, f += fstep)
                {
-                       int lerp = f & 0xFFFF;
-                       *out++ = (byte) ((((in[4] - in[0]) * lerp) >> 16) + in[0]);
-                       *out++ = (byte) ((((in[5] - in[1]) * lerp) >> 16) + in[1]);
-                       *out++ = (byte) ((((in[6] - in[2]) * lerp) >> 16) + in[2]);
-                       *out++ = (byte) ((((in[7] - in[3]) * lerp) >> 16) + in[3]);
+                       xi = f >> 16;
+                       if (xi != oldx)
+                       {
+                               in += (xi - oldx) * 4;
+                               oldx = xi;
+                       }
+                       if (xi < endx)
+                       {
+                               lerp = f & 0xFFFF;
+                               *out++ = (byte) ((((in[4] - in[0]) * lerp) >> 16) + in[0]);
+                               *out++ = (byte) ((((in[5] - in[1]) * lerp) >> 16) + in[1]);
+                               *out++ = (byte) ((((in[6] - in[2]) * lerp) >> 16) + in[2]);
+                               *out++ = (byte) ((((in[7] - in[3]) * lerp) >> 16) + in[3]);
+                       }
+                       else // last pixel of the line has no pixel to lerp to
+                       {
+                               *out++ = in[0];
+                               *out++ = in[1];
+                               *out++ = in[2];
+                               *out++ = in[3];
+                       }
                }
-               else // last pixel of the line has no pixel to lerp to
+       }
+       else if (bytesperpixel == 3)
+       {
+               for (j = 0,f = 0;j < outwidth;j++, f += fstep)
                {
-                       *out++ = in[0];
-                       *out++ = in[1];
-                       *out++ = in[2];
-                       *out++ = in[3];
+                       xi = f >> 16;
+                       if (xi != oldx)
+                       {
+                               in += (xi - oldx) * 3;
+                               oldx = xi;
+                       }
+                       if (xi < endx)
+                       {
+                               lerp = f & 0xFFFF;
+                               *out++ = (byte) ((((in[3] - in[0]) * lerp) >> 16) + in[0]);
+                               *out++ = (byte) ((((in[4] - in[1]) * lerp) >> 16) + in[1]);
+                               *out++ = (byte) ((((in[5] - in[2]) * lerp) >> 16) + in[2]);
+                       }
+                       else // last pixel of the line has no pixel to lerp to
+                       {
+                               *out++ = in[0];
+                               *out++ = in[1];
+                               *out++ = in[2];
+                       }
                }
        }
+       else
+               Sys_Error("R_ResampleTextureLerpLine: unsupported bytesperpixel %i\n", bytesperpixel);
 }
 
 /*
@@ -251,486 +572,959 @@ void R_ResampleTextureLerpLine (byte *in, byte *out, int inwidth, int outwidth)
 R_ResampleTexture
 ================
 */
-void R_ResampleTexture (void *indata, int inwidth, int inheight, void *outdata,  int outwidth, int outheight)
+static void R_ResampleTexture (void *indata, int inwidth, int inheight, void *outdata,  int outwidth, int outheight, int bytesperpixel)
 {
-       if (r_lerpimages.value)
+       if (resamplerowsize < outwidth*4)
        {
-               int             i, j, yi, oldy, f, fstep, endy = (inheight-1);
-               byte    *inrow, *out, *row1, *row2;
-               out = outdata;
-               fstep = (int) (inheight*65536.0f/outheight);
-
-               row1 = qmalloc(outwidth*4);
-               row2 = qmalloc(outwidth*4);
-               inrow = indata;
-               oldy = 0;
-               R_ResampleTextureLerpLine (inrow, row1, inwidth, outwidth);
-               R_ResampleTextureLerpLine (inrow + inwidth*4, row2, inwidth, outwidth);
-               for (i = 0, f = 0;i < outheight;i++,f += fstep)
+               if (resamplerow1)
+                       Mem_Free(resamplerow1);
+               if (resamplerow2)
+                       Mem_Free(resamplerow2);
+               resamplerowsize = outwidth*4;
+               resamplerow1 = Mem_Alloc(texturemempool, resamplerowsize);
+               resamplerow2 = Mem_Alloc(texturemempool, resamplerowsize);
+       }
+#define row1 resamplerow1
+#define row2 resamplerow2
+       if (bytesperpixel == 4)
+       {
+               if (r_lerpimages.integer)
                {
-                       yi = f >> 16;
-                       if (yi < endy)
+                       int             i, j, yi, oldy, f, fstep, lerp, endy = (inheight-1), inwidth4 = inwidth*4, outwidth4 = outwidth*4;
+                       byte    *inrow, *out;
+                       out = outdata;
+                       fstep = (int) (inheight*65536.0f/outheight);
+
+                       inrow = indata;
+                       oldy = 0;
+                       R_ResampleTextureLerpLine (inrow, row1, inwidth, outwidth, bytesperpixel);
+                       R_ResampleTextureLerpLine (inrow + inwidth4, row2, inwidth, outwidth, bytesperpixel);
+                       for (i = 0, f = 0;i < outheight;i++,f += fstep)
                        {
-                               int lerp = f & 0xFFFF;
-                               if (yi != oldy)
+                               yi = f >> 16;
+                               if (yi < endy)
+                               {
+                                       lerp = f & 0xFFFF;
+                                       if (yi != oldy)
+                                       {
+                                               inrow = (byte *)indata + inwidth4*yi;
+                                               if (yi == oldy+1)
+                                                       memcpy(row1, row2, outwidth4);
+                                               else
+                                                       R_ResampleTextureLerpLine (inrow, row1, inwidth, outwidth, bytesperpixel);
+                                               R_ResampleTextureLerpLine (inrow + inwidth4, row2, inwidth, outwidth, bytesperpixel);
+                                               oldy = yi;
+                                       }
+                                       j = outwidth - 4;
+                                       while(j >= 0)
+                                       {
+#define LERPBYTE(i) out[i] = (byte) ((((row2[i] - row1[i]) * lerp) >> 16) + row1[i])
+                                               LERPBYTE( 0);
+                                               LERPBYTE( 1);
+                                               LERPBYTE( 2);
+                                               LERPBYTE( 3);
+                                               LERPBYTE( 4);
+                                               LERPBYTE( 5);
+                                               LERPBYTE( 6);
+                                               LERPBYTE( 7);
+                                               LERPBYTE( 8);
+                                               LERPBYTE( 9);
+                                               LERPBYTE(10);
+                                               LERPBYTE(11);
+                                               LERPBYTE(12);
+                                               LERPBYTE(13);
+                                               LERPBYTE(14);
+                                               LERPBYTE(15);
+                                               out += 16;
+                                               row1 += 16;
+                                               row2 += 16;
+                                               j -= 4;
+                                       }
+                                       if (j & 2)
+                                       {
+                                               LERPBYTE( 0);
+                                               LERPBYTE( 1);
+                                               LERPBYTE( 2);
+                                               LERPBYTE( 3);
+                                               LERPBYTE( 4);
+                                               LERPBYTE( 5);
+                                               LERPBYTE( 6);
+                                               LERPBYTE( 7);
+                                               out += 8;
+                                               row1 += 8;
+                                               row2 += 8;
+                                       }
+                                       if (j & 1)
+                                       {
+                                               LERPBYTE( 0);
+                                               LERPBYTE( 1);
+                                               LERPBYTE( 2);
+                                               LERPBYTE( 3);
+                                               out += 4;
+                                               row1 += 4;
+                                               row2 += 4;
+                                       }
+                                       row1 -= outwidth4;
+                                       row2 -= outwidth4;
+                               }
+                               else
                                {
-                                       inrow = (byte *)indata + inwidth*4*yi;
-                                       if (yi == oldy+1)
-                                               memcpy(row1, row2, outwidth*4);
-                                       else
-                                               R_ResampleTextureLerpLine (inrow, row1, inwidth, outwidth);
-                                       R_ResampleTextureLerpLine (inrow + inwidth*4, row2, inwidth, outwidth);
-                                       oldy = yi;
+                                       if (yi != oldy)
+                                       {
+                                               inrow = (byte *)indata + inwidth4*yi;
+                                               if (yi == oldy+1)
+                                                       memcpy(row1, row2, outwidth4);
+                                               else
+                                                       R_ResampleTextureLerpLine (inrow, row1, inwidth, outwidth, bytesperpixel);
+                                               oldy = yi;
+                                       }
+                                       memcpy(out, row1, outwidth4);
                                }
+                       }
+               }
+               else
+               {
+                       int i, j;
+                       unsigned frac, fracstep;
+                       // relies on int being 4 bytes
+                       int *inrow, *out;
+                       out = outdata;
+
+                       fracstep = inwidth*0x10000/outwidth;
+                       for (i = 0;i < outheight;i++)
+                       {
+                               inrow = (int *)indata + inwidth*(i*inheight/outheight);
+                               frac = fracstep >> 1;
                                j = outwidth - 4;
-                               while(j >= 0)
+                               while (j >= 0)
                                {
-                                       out[ 0] = (byte) ((((row2[ 0] - row1[ 0]) * lerp) >> 16) + row1[ 0]);
-                                       out[ 1] = (byte) ((((row2[ 1] - row1[ 1]) * lerp) >> 16) + row1[ 1]);
-                                       out[ 2] = (byte) ((((row2[ 2] - row1[ 2]) * lerp) >> 16) + row1[ 2]);
-                                       out[ 3] = (byte) ((((row2[ 3] - row1[ 3]) * lerp) >> 16) + row1[ 3]);
-                                       out[ 4] = (byte) ((((row2[ 4] - row1[ 4]) * lerp) >> 16) + row1[ 4]);
-                                       out[ 5] = (byte) ((((row2[ 5] - row1[ 5]) * lerp) >> 16) + row1[ 5]);
-                                       out[ 6] = (byte) ((((row2[ 6] - row1[ 6]) * lerp) >> 16) + row1[ 6]);
-                                       out[ 7] = (byte) ((((row2[ 7] - row1[ 7]) * lerp) >> 16) + row1[ 7]);
-                                       out[ 8] = (byte) ((((row2[ 8] - row1[ 8]) * lerp) >> 16) + row1[ 8]);
-                                       out[ 9] = (byte) ((((row2[ 9] - row1[ 9]) * lerp) >> 16) + row1[ 9]);
-                                       out[10] = (byte) ((((row2[10] - row1[10]) * lerp) >> 16) + row1[10]);
-                                       out[11] = (byte) ((((row2[11] - row1[11]) * lerp) >> 16) + row1[11]);
-                                       out[12] = (byte) ((((row2[12] - row1[12]) * lerp) >> 16) + row1[12]);
-                                       out[13] = (byte) ((((row2[13] - row1[13]) * lerp) >> 16) + row1[13]);
-                                       out[14] = (byte) ((((row2[14] - row1[14]) * lerp) >> 16) + row1[14]);
-                                       out[15] = (byte) ((((row2[15] - row1[15]) * lerp) >> 16) + row1[15]);
-                                       out += 16;
-                                       row1 += 16;
-                                       row2 += 16;
+                                       out[0] = inrow[frac >> 16];frac += fracstep;
+                                       out[1] = inrow[frac >> 16];frac += fracstep;
+                                       out[2] = inrow[frac >> 16];frac += fracstep;
+                                       out[3] = inrow[frac >> 16];frac += fracstep;
+                                       out += 4;
                                        j -= 4;
                                }
                                if (j & 2)
                                {
-                                       out[ 0] = (byte) ((((row2[ 0] - row1[ 0]) * lerp) >> 16) + row1[ 0]);
-                                       out[ 1] = (byte) ((((row2[ 1] - row1[ 1]) * lerp) >> 16) + row1[ 1]);
-                                       out[ 2] = (byte) ((((row2[ 2] - row1[ 2]) * lerp) >> 16) + row1[ 2]);
-                                       out[ 3] = (byte) ((((row2[ 3] - row1[ 3]) * lerp) >> 16) + row1[ 3]);
-                                       out[ 4] = (byte) ((((row2[ 4] - row1[ 4]) * lerp) >> 16) + row1[ 4]);
-                                       out[ 5] = (byte) ((((row2[ 5] - row1[ 5]) * lerp) >> 16) + row1[ 5]);
-                                       out[ 6] = (byte) ((((row2[ 6] - row1[ 6]) * lerp) >> 16) + row1[ 6]);
-                                       out[ 7] = (byte) ((((row2[ 7] - row1[ 7]) * lerp) >> 16) + row1[ 7]);
-                                       out += 8;
-                                       row1 += 8;
-                                       row2 += 8;
+                                       out[0] = inrow[frac >> 16];frac += fracstep;
+                                       out[1] = inrow[frac >> 16];frac += fracstep;
+                                       out += 2;
                                }
                                if (j & 1)
                                {
-                                       out[ 0] = (byte) ((((row2[ 0] - row1[ 0]) * lerp) >> 16) + row1[ 0]);
-                                       out[ 1] = (byte) ((((row2[ 1] - row1[ 1]) * lerp) >> 16) + row1[ 1]);
-                                       out[ 2] = (byte) ((((row2[ 2] - row1[ 2]) * lerp) >> 16) + row1[ 2]);
-                                       out[ 3] = (byte) ((((row2[ 3] - row1[ 3]) * lerp) >> 16) + row1[ 3]);
-                                       out += 4;
-                                       row1 += 4;
-                                       row2 += 4;
-                               }
-                               row1 -= outwidth*4;
-                               row2 -= outwidth*4;
-                       }
-                       else
-                       {
-                               if (yi != oldy)
-                               {
-                                       inrow = (byte *)indata + inwidth*4*yi;
-                                       if (yi == oldy+1)
-                                               memcpy(row1, row2, outwidth*4);
-                                       else
-                                               R_ResampleTextureLerpLine (inrow, row1, inwidth, outwidth);
-                                       oldy = yi;
+                                       out[0] = inrow[frac >> 16];frac += fracstep;
+                                       out += 1;
                                }
-                               memcpy(out, row1, outwidth * 4);
                        }
                }
-               qfree(row1);
-               qfree(row2);
        }
-       else
+       else if (bytesperpixel == 3)
        {
-               int i, j;
-               unsigned frac, fracstep;
-               // relies on int being 4 bytes
-               int *inrow, *out;
-               out = outdata;
-
-               fracstep = inwidth*0x10000/outwidth;
-               for (i = 0;i < outheight;i++)
+               if (r_lerpimages.integer)
                {
-                       inrow = (int *)indata + inwidth*(i*inheight/outheight);
-                       frac = fracstep >> 1;
-                       j = outwidth - 4;
-                       while (j >= 0)
-                       {
-                               out[0] = inrow[frac >> 16];frac += fracstep;
-                               out[1] = inrow[frac >> 16];frac += fracstep;
-                               out[2] = inrow[frac >> 16];frac += fracstep;
-                               out[3] = inrow[frac >> 16];frac += fracstep;
-                               out += 4;
-                               j -= 4;
-                       }
-                       if (j & 2)
+                       int             i, j, yi, oldy, f, fstep, lerp, endy = (inheight-1), inwidth3 = inwidth * 3, outwidth3 = outwidth * 3;
+                       byte    *inrow, *out;
+                       out = outdata;
+                       fstep = (int) (inheight*65536.0f/outheight);
+
+                       inrow = indata;
+                       oldy = 0;
+                       R_ResampleTextureLerpLine (inrow, row1, inwidth, outwidth, bytesperpixel);
+                       R_ResampleTextureLerpLine (inrow + inwidth3, row2, inwidth, outwidth, bytesperpixel);
+                       for (i = 0, f = 0;i < outheight;i++,f += fstep)
                        {
-                               out[0] = inrow[frac >> 16];frac += fracstep;
-                               out[1] = inrow[frac >> 16];frac += fracstep;
-                               out += 2;
+                               yi = f >> 16;
+                               if (yi < endy)
+                               {
+                                       lerp = f & 0xFFFF;
+                                       if (yi != oldy)
+                                       {
+                                               inrow = (byte *)indata + inwidth3*yi;
+                                               if (yi == oldy+1)
+                                                       memcpy(row1, row2, outwidth3);
+                                               else
+                                                       R_ResampleTextureLerpLine (inrow, row1, inwidth, outwidth, bytesperpixel);
+                                               R_ResampleTextureLerpLine (inrow + inwidth3, row2, inwidth, outwidth, bytesperpixel);
+                                               oldy = yi;
+                                       }
+                                       j = outwidth - 4;
+                                       while(j >= 0)
+                                       {
+#define LERPBYTE(i) out[i] = (byte) ((((row2[i] - row1[i]) * lerp) >> 16) + row1[i])
+                                               LERPBYTE( 0);
+                                               LERPBYTE( 1);
+                                               LERPBYTE( 2);
+                                               LERPBYTE( 3);
+                                               LERPBYTE( 4);
+                                               LERPBYTE( 5);
+                                               LERPBYTE( 6);
+                                               LERPBYTE( 7);
+                                               LERPBYTE( 8);
+                                               LERPBYTE( 9);
+                                               LERPBYTE(10);
+                                               LERPBYTE(11);
+                                               out += 12;
+                                               row1 += 12;
+                                               row2 += 12;
+                                               j -= 4;
+                                       }
+                                       if (j & 2)
+                                       {
+                                               LERPBYTE( 0);
+                                               LERPBYTE( 1);
+                                               LERPBYTE( 2);
+                                               LERPBYTE( 3);
+                                               LERPBYTE( 4);
+                                               LERPBYTE( 5);
+                                               out += 6;
+                                               row1 += 6;
+                                               row2 += 6;
+                                       }
+                                       if (j & 1)
+                                       {
+                                               LERPBYTE( 0);
+                                               LERPBYTE( 1);
+                                               LERPBYTE( 2);
+                                               out += 3;
+                                               row1 += 3;
+                                               row2 += 3;
+                                       }
+                                       row1 -= outwidth3;
+                                       row2 -= outwidth3;
+                               }
+                               else
+                               {
+                                       if (yi != oldy)
+                                       {
+                                               inrow = (byte *)indata + inwidth3*yi;
+                                               if (yi == oldy+1)
+                                                       memcpy(row1, row2, outwidth3);
+                                               else
+                                                       R_ResampleTextureLerpLine (inrow, row1, inwidth, outwidth, bytesperpixel);
+                                               oldy = yi;
+                                       }
+                                       memcpy(out, row1, outwidth3);
+                               }
                        }
-                       if (j & 1)
+               }
+               else
+               {
+                       int i, j, f, inwidth3 = inwidth * 3;
+                       unsigned frac, fracstep;
+                       byte *inrow, *out;
+                       out = outdata;
+
+                       fracstep = inwidth*0x10000/outwidth;
+                       for (i = 0;i < outheight;i++)
                        {
-                               out[0] = inrow[frac >> 16];frac += fracstep;
-                               out += 1;
+                               inrow = indata + inwidth3*(i*inheight/outheight);
+                               frac = fracstep >> 1;
+                               j = outwidth - 4;
+                               while (j >= 0)
+                               {
+                                       f = (frac >> 16)*3;*out++ = inrow[f+0];*out++ = inrow[f+1];*out++ = inrow[f+2];frac += fracstep;
+                                       f = (frac >> 16)*3;*out++ = inrow[f+0];*out++ = inrow[f+1];*out++ = inrow[f+2];frac += fracstep;
+                                       f = (frac >> 16)*3;*out++ = inrow[f+0];*out++ = inrow[f+1];*out++ = inrow[f+2];frac += fracstep;
+                                       f = (frac >> 16)*3;*out++ = inrow[f+0];*out++ = inrow[f+1];*out++ = inrow[f+2];frac += fracstep;
+                                       j -= 4;
+                               }
+                               if (j & 2)
+                               {
+                                       f = (frac >> 16)*3;*out++ = inrow[f+0];*out++ = inrow[f+1];*out++ = inrow[f+2];frac += fracstep;
+                                       f = (frac >> 16)*3;*out++ = inrow[f+0];*out++ = inrow[f+1];*out++ = inrow[f+2];frac += fracstep;
+                                       out += 2;
+                               }
+                               if (j & 1)
+                               {
+                                       f = (frac >> 16)*3;*out++ = inrow[f+0];*out++ = inrow[f+1];*out++ = inrow[f+2];frac += fracstep;
+                                       out += 1;
+                               }
                        }
                }
        }
+       else
+               Sys_Error("R_ResampleTexture: unsupported bytesperpixel %i\n", bytesperpixel);
+#undef row1
+#undef row2
 }
 
 // in can be the same as out
-void GL_MipReduce(byte *in, byte *out, int width, int height, int destwidth, int destheight)
+static void R_MipReduce(byte *in, byte *out, int *width, int *height, int destwidth, int destheight, int bytesperpixel)
 {
-       int x, y, width2, height2, nextrow;
-       if (width > destwidth)
+       int x, y, nextrow;
+       nextrow = *width * bytesperpixel;
+       if (*width > destwidth)
        {
-               if (height > destheight)
+               *width >>= 1;
+               if (*height > destheight)
                {
                        // reduce both
-                       width2 = width >> 1;
-                       height2 = height >> 1;
-                       nextrow = width << 2;
-                       for (y = 0;y < height2;y++)
+                       *height >>= 1;
+                       if (bytesperpixel == 4)
                        {
-                               for (x = 0;x < width2;x++)
+                               for (y = 0;y < *height;y++)
                                {
-                                       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;
+                                       for (x = 0;x < *width;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
                                }
-                               in += nextrow; // skip a line
                        }
+                       else if (bytesperpixel == 3)
+                       {
+                               for (y = 0;y < *height;y++)
+                               {
+                                       for (x = 0;x < *width;x++)
+                                       {
+                                               out[0] = (byte) ((in[0] + in[3] + in[nextrow  ] + in[nextrow+3]) >> 2);
+                                               out[1] = (byte) ((in[1] + in[4] + in[nextrow+1] + in[nextrow+4]) >> 2);
+                                               out[2] = (byte) ((in[2] + in[5] + in[nextrow+2] + in[nextrow+5]) >> 2);
+                                               out += 3;
+                                               in += 6;
+                                       }
+                                       in += nextrow; // skip a line
+                               }
+                       }
+                       else
+                               Sys_Error("R_MipReduce: unsupported bytesperpixel %i\n", bytesperpixel);
                }
                else
                {
                        // reduce width
-                       width2 = width >> 1;
-                       for (y = 0;y < height;y++)
+                       if (bytesperpixel == 4)
                        {
-                               for (x = 0;x < width2;x++)
+                               for (y = 0;y < *height;y++)
                                {
-                                       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;
+                                       for (x = 0;x < *width;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 (bytesperpixel == 3)
+                       {
+                               for (y = 0;y < *height;y++)
+                               {
+                                       for (x = 0;x < *width;x++)
+                                       {
+                                               out[0] = (byte) ((in[0] + in[3]) >> 1);
+                                               out[1] = (byte) ((in[1] + in[4]) >> 1);
+                                               out[2] = (byte) ((in[2] + in[5]) >> 1);
+                                               out += 3;
+                                               in += 6;
+                                       }
                                }
                        }
+                       else
+                               Sys_Error("R_MipReduce: unsupported bytesperpixel %i\n", bytesperpixel);
                }
        }
        else
        {
-               if (height > destheight)
+               if (*height > destheight)
                {
                        // reduce height
-                       height2 = height >> 1;
-                       nextrow = width << 2;
-                       for (y = 0;y < height2;y++)
+                       *height >>= 1;
+                       if (bytesperpixel == 4)
                        {
-                               for (x = 0;x < width;x++)
+                               for (y = 0;y < *height;y++)
                                {
-                                       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;
+                                       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 if (bytesperpixel == 3)
+                       {
+                               for (y = 0;y < *height;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;
+                                               in += 3;
+                                       }
+                                       in += nextrow; // skip a line
                                }
-                               in += nextrow; // skip a line
                        }
+                       else
+                               Sys_Error("R_MipReduce: unsupported bytesperpixel %i\n", bytesperpixel);
                }
                else
-                       Sys_Error("GL_MipReduce: desired size already achieved\n");
+                       Sys_Error("R_MipReduce: desired size already achieved\n");
        }
 }
 
-void GL_Upload32(int glslot, byte *data, int width, int height, int flags)
+static void R_Upload(gltexture_t *glt, byte *data)
 {
-       int mip, width2, height2, width3, height3, internalformat;
-       byte *gammadata, *buffer;
+       int mip, width, height, internalformat;
+       byte *prevbuffer;
+       prevbuffer = data;
 
-       if (!r_upload.value)
-               return;
+       glBindTexture(GL_TEXTURE_2D, glt->image->texnum);
+       CHECKGLERROR
 
-       // 3 and 4 are converted by the driver to it's preferred format for the current display mode
-       internalformat = 3;
-       if (flags & TEXF_ALPHA)
-               internalformat = 4;
+       glt->flags &= ~GLTEXF_UPLOAD;
+
+       if (glt->flags & TEXF_FRAGMENT)
+       {
+               if (resizebuffersize < glt->image->width * glt->image->height * glt->image->bytesperpixel)
+               {
+                       resizebuffersize = glt->image->width * glt->image->height * glt->image->bytesperpixel;
+                       if (resizebuffer)
+                               Mem_Free(resizebuffer);
+                       if (colorconvertbuffer)
+                               Mem_Free(colorconvertbuffer);
+                       resizebuffer = Mem_Alloc(texturemempool, resizebuffersize);
+                       colorconvertbuffer = Mem_Alloc(texturemempool, resizebuffersize);
+                       if (!resizebuffer || !colorconvertbuffer)
+                               Host_Error("R_Upload: out of memory\n");
+               }
+
+               if (glt->image->flags & GLTEXF_UPLOAD)
+               {
+                       glt->image->flags &= ~GLTEXF_UPLOAD;
+                       memset(resizebuffer, 255, glt->image->width * glt->image->height * glt->image->bytesperpixel);
+                       glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_mag);
+                       CHECKGLERROR
+                       glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_mag);
+                       CHECKGLERROR
+                       glTexImage2D (GL_TEXTURE_2D, 0, glt->image->glinternalformat, glt->image->width, glt->image->height, 0, glt->image->glformat, GL_UNSIGNED_BYTE, resizebuffer);
+                       CHECKGLERROR
+               }
 
-       // 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) r_picmip.value;
-       height3 = height2 >> (int) r_picmip.value;
-       while (width3 > (int) r_max_size.value) width3 >>= 1;
-       while (height3 > (int) r_max_size.value) height3 >>= 1;
-       if (width3 < 1) width3 = 1;
-       if (height3 < 1) height3 = 1;
+               if (prevbuffer == NULL)
+               {
+                       memset(resizebuffer, 255, glt->width * glt->height * glt->image->bytesperpixel);
+                       prevbuffer = resizebuffer;
+               }
+               else if (glt->textype->textype == TEXTYPE_QPALETTE)
+               {
+                       // promote paletted to RGBA, so we only have to worry about RGB and
+                       // RGBA in the rest of this code
+                       Image_Copy8bitRGBA(prevbuffer, colorconvertbuffer, glt->width * glt->height, d_8to24table);
+                       prevbuffer = colorconvertbuffer;
+               }
 
-       gammadata = qmalloc(width*height*4);
-       buffer = qmalloc(width2*height2*4);
-       if (!gammadata || !buffer)
-               Host_Error("GL_Upload32: out of memory\n");
+               glTexSubImage2D(GL_TEXTURE_2D, 0, glt->x, glt->y, glt->width, glt->height, glt->image->glformat, GL_UNSIGNED_BYTE, prevbuffer);
+               CHECKGLERROR
+               return;
+       }
 
-       Image_CopyRGBAGamma(data, gammadata, width*height);
+       glt->image->flags &= ~GLTEXF_UPLOAD;
 
-       R_ResampleTexture(gammadata, width, height, buffer, width2, height2);
+       // these are rounded up versions of the size to do better resampling
+       width = 1;while(width < glt->width) width *= 2;
+       height = 1;while(height < glt->height) height *= 2;
 
-       qfree(gammadata);
+       if (resizebuffersize < width * height * glt->image->bytesperpixel)
+       {
+               resizebuffersize = width * height * glt->image->bytesperpixel;
+               if (resizebuffer)
+                       Mem_Free(resizebuffer);
+               if (colorconvertbuffer)
+                       Mem_Free(colorconvertbuffer);
+               resizebuffer = Mem_Alloc(texturemempool, resizebuffersize);
+               colorconvertbuffer = Mem_Alloc(texturemempool, resizebuffersize);
+               if (!resizebuffer || !colorconvertbuffer)
+                       Host_Error("R_Upload: out of memory\n");
+       }
 
-       while (width2 > width3 || height2 > height3)
+       if (prevbuffer == NULL)
+       {
+               width = glt->image->width;
+               height = glt->image->height;
+               memset(resizebuffer, 255, width * height * glt->image->bytesperpixel);
+               prevbuffer = resizebuffer;
+       }
+       else
        {
-               GL_MipReduce(buffer, buffer, width2, height2, width3, height3);
+               if (glt->textype->textype == TEXTYPE_QPALETTE)
+               {
+                       // promote paletted to RGBA, so we only have to worry about RGB and
+                       // RGBA in the rest of this code
+                       Image_Copy8bitRGBA(prevbuffer, colorconvertbuffer, glt->width * glt->height, d_8to24table);
+                       prevbuffer = colorconvertbuffer;
+               }
+
+               if (glt->width != width || glt->height != height)
+               {
+                       R_ResampleTexture(prevbuffer, glt->width, glt->height, resizebuffer, width, height, glt->image->bytesperpixel);
+                       prevbuffer = resizebuffer;
+               }
 
-               if (width2 > width3)
-                       width2 >>= 1;
-               if (height2 > height3)
-                       height2 >>= 1;
+               // apply picmip/max_size limitations
+               while (width > glt->image->width || height > glt->image->height)
+               {
+                       R_MipReduce(prevbuffer, resizebuffer, &width, &height, glt->image->width, glt->image->height, glt->image->bytesperpixel);
+                       prevbuffer = resizebuffer;
+               }
        }
 
-       glBindTexture(GL_TEXTURE_2D, glslot);
+       // 3 and 4 are converted by the driver to it's preferred format for the current display mode
+       internalformat = 3;
+       if (glt->flags & TEXF_ALPHA)
+               internalformat = 4;
+
        mip = 0;
-       glTexImage2D(GL_TEXTURE_2D, mip++, internalformat, width2, height2, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
-       if (flags & TEXF_MIPMAP)
+       glTexImage2D(GL_TEXTURE_2D, mip++, internalformat, width, height, 0, glt->image->glformat, GL_UNSIGNED_BYTE, prevbuffer);
+       CHECKGLERROR
+       if (glt->flags & TEXF_MIPMAP)
        {
-               while (width2 > 1 || height2 > 1)
+               while (width > 1 || height > 1)
                {
-                       GL_MipReduce(buffer, buffer, width2, height2, 1, 1);
-
-                       if (width2 > 1)
-                               width2 >>= 1;
-                       if (height2 > 1)
-                               height2 >>= 1;
+                       R_MipReduce(prevbuffer, resizebuffer, &width, &height, 1, 1, glt->image->bytesperpixel);
+                       prevbuffer = resizebuffer;
 
-                       glTexImage2D(GL_TEXTURE_2D, mip++, internalformat, width2, height2, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
+                       glTexImage2D(GL_TEXTURE_2D, mip++, internalformat, width, height, 0, glt->image->glformat, GL_UNSIGNED_BYTE, prevbuffer);
+                       CHECKGLERROR
                }
 
                glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
-               glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
+               CHECKGLERROR
+               glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_mag);
+               CHECKGLERROR
        }
        else
        {
-               glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_max);
-               glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
+               glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_mag);
+               CHECKGLERROR
+               glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_mag);
+               CHECKGLERROR
        }
-       glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-
-       qfree(buffer);
 }
 
-void GL_Upload8 (int glslot, byte *data, int width, int height, int flags)
+static void R_FindImageForTexture(gltexture_t *glt)
 {
-       byte *data32;
-       data32 = qmalloc(width*height*4);
-       Image_Copy8bitRGBA(data, data32, width*height, d_8to24table);
-       GL_Upload32(glslot, data32, width, height, flags);
-       qfree(data32);
+       int i, j, best, best2, x, y, w, h;
+       textypeinfo_t *texinfo;
+       gltexturepool_t *pool;
+       gltextureimage_t *image, **imagechainpointer;
+       texinfo = glt->textype;
+       pool = glt->pool;
+
+       x = 0;
+       y = 0;
+       w = glt->width;
+       h = glt->height;
+       if (glt->flags & TEXF_FRAGMENT)
+       {
+               for (imagechainpointer = &pool->imagechain;*imagechainpointer;imagechainpointer = &(*imagechainpointer)->imagechain)
+               {
+                       image = *imagechainpointer;
+                       if (image->type != GLIMAGETYPE_FRAGMENTS)
+                               continue;
+                       if (image->glformat != texinfo->glformat || image->glinternalformat != texinfo->glinternalformat)
+                               continue;
+
+                       // got a fragments texture, find a place in it if we can
+                       best = BLOCK_SIZE;
+                       for (best = BLOCK_SIZE, i = 0;i < BLOCK_SIZE - w;i += texinfo->align)
+                       {
+                               for (best2 = 0, j = 0;j < w;j++)
+                               {
+                                       if (image->blockallocation[i+j] >= best)
+                                               break;
+                                       if (best2 < image->blockallocation[i+j])
+                                               best2 = image->blockallocation[i+j];
+                               }
+                               if (j == w)
+                               {
+                                       // this is a valid spot
+                                       x = i;
+                                       y = best = best2;
+                               }
+                       }
+
+                       if (best + h > BLOCK_SIZE)
+                               continue;
+
+                       for (i = 0;i < w;i++)
+                               image->blockallocation[x + i] = best + h;
+
+                       glt->x = x;
+                       glt->y = y;
+                       glt->image = image;
+                       image->texturecount++;
+                       return;
+               }
+
+               image = Mem_Alloc(texturemempool, sizeof(gltextureimage_t));
+               if (image == NULL)
+                       Sys_Error("R_FindImageForTexture: ran out of memory\n");
+               //memset(image, 0, sizeof(*image));
+               image->type = GLIMAGETYPE_FRAGMENTS;
+               image->width = BLOCK_SIZE;
+               image->height = BLOCK_SIZE;
+               image->blockallocation = Mem_Alloc(texturemempool, BLOCK_SIZE * sizeof(short));
+               memset(image->blockallocation, 0, BLOCK_SIZE * sizeof(short));
+
+               x = 0;
+               y = 0;
+               for (i = 0;i < w;i++)
+                       image->blockallocation[x + i] = y + h;
+       }
+       else
+       {
+               for (imagechainpointer = &pool->imagechain;*imagechainpointer;imagechainpointer = &(*imagechainpointer)->imagechain);
+
+               image = Mem_Alloc(texturemempool, sizeof(gltextureimage_t));
+               if (image == NULL)
+                       Sys_Error("R_FindImageForTexture: ran out of memory\n");
+               //memset(image, 0, sizeof(*image));
+               image->type = GLIMAGETYPE_TILE;
+               image->blockallocation = NULL;
+
+               // calculate final size
+               if (r_max_size.integer > realmaxsize)
+                       Cvar_SetValue("r_max_size", realmaxsize);
+               image->width = 1;while (image->width < glt->width) image->width <<= 1;
+               image->height = 1;while (image->height < glt->height) image->height <<= 1;
+               image->width >>= r_picmip.integer;while (image->width > r_max_size.integer) image->width >>= 1;
+               image->height >>= r_picmip.integer;while (image->height > r_max_size.integer) image->height >>= 1;
+               if (image->width < 1) image->width = 1;
+               if (image->height < 1) image->height = 1;
+       }
+       image->glinternalformat = texinfo->glinternalformat;
+       image->glformat = texinfo->glformat;
+       image->flags = (glt->flags & (TEXF_MIPMAP | TEXF_ALPHA)) | GLTEXF_UPLOAD;
+       image->bytesperpixel = texinfo->internalbytesperpixel;
+       for (i = 1;i < MAX_GLTEXTURES;i++)
+               if (!gltexnuminuse[i])
+                       break;
+       if (i < MAX_GLTEXTURES)
+               gltexnuminuse[image->texnum = i] = true;
+       else
+               Sys_Error("R_FindImageForTexture: ran out of GL textures\n");
+       *imagechainpointer = image;
+       image->texturecount++;
+
+       glt->x = x;
+       glt->y = y;
+       glt->image = image;
 }
 
-void GL_UploadTexture (gltexture_t *glt)
+// note: R_FindImageForTexture must be called before this
+static void R_UploadTexture (gltexture_t *glt)
 {
-       if (glt->inputtexels == NULL)
+       if (!(glt->flags & (GLTEXF_UPLOAD | GLTEXF_PROCEDURAL)))
                return;
-       if (glt->flags & TEXF_RGBA)
-               GL_Upload32(glt->texnum, glt->inputtexels, glt->width, glt->height, glt->flags);
-       else // 8bit
-               GL_Upload8(glt->texnum, glt->inputtexels, glt->width, glt->height, glt->flags);
-       glt->internalflags |= GLTEXF_UPLOADED;
-       qfree(glt->inputtexels);
-       glt->inputtexels = NULL;
-}
 
-int R_CalcTexelDataSize (int width, int height, int mipmapped)
-{
-       int width2, height2, size;
-       width2 = 1;while (width2 < width) width2 <<= 1;
-       height2 = 1;while (height2 < height) height2 <<= 1;
-       // calculate final size (mipmapped downward to this)
-       width2 >>= (int) r_picmip.value;
-       height2 >>= (int) r_picmip.value;
-       while (width2 > (int) r_max_size.value) width2 >>= 1;
-       while (height2 > (int) r_max_size.value) height2 >>= 1;
-       if (width2 < 1) width2 = 1;
-       if (height2 < 1) height2 = 1;
+       if (glt->flags & GLTEXF_PROCEDURAL)
+       {
+               if (glt->generate)
+               {
+                       if (texturebuffersize < glt->width * glt->height * glt->textype->inputbytesperpixel)
+                       {
+                               if (texturebuffer)
+                                       Mem_Free(texturebuffer);
+                               texturebuffersize = glt->width * glt->height * glt->textype->inputbytesperpixel;
+                               texturebuffer = Mem_Alloc(texturemempool, texturebuffersize);
+                       }
 
-       size = 0;
-       if (mipmapped)
+                       glt->generate(texturebuffer, glt->width, glt->height, (void *)glt->proceduraldata, glt->proceduraldatasize);
+               }
+       }
+       else
        {
-               while (width2 > 1 || height2 > 1)
+               R_Upload(glt, glt->inputtexels);
+               if (glt->inputtexels)
                {
-                       size += width2 * height2;
-                       if (width2 > 1)
-                               width2 >>= 1;
-                       if (height2 > 1)
-                               height2 >>= 1;
+                       Mem_Free(glt->inputtexels);
+                       glt->inputtexels = NULL;
+                       glt->flags |= GLTEXF_DESTROYED;
                }
-               size++; // count the last 1x1 mipmap
+               else if (glt->flags & GLTEXF_DESTROYED)
+                       Con_Printf("R_UploadTexture: Texture %s already uploaded and destroyed.  Can not upload original image again.  Uploaded blank texture.\n", glt->identifier);
+       }
+}
+
+static gltexture_t *R_SetupTexture(gltexturepool_t *pool, char *identifier, int crc, int width, int height, int flags, textypeinfo_t *texinfo, byte *data, int (*generate)(byte *buffer, int width, int height, void *proceduraldata, int proceduraldatasize), void *proceduraldata, int proceduraldatasize)
+{
+       gltexture_t *glt;
+       glt = Mem_Alloc(texturemempool, sizeof(gltexture_t));
+       //memset(glt, 0, sizeof(gltexture_t));
+       if (identifier)
+       {
+               glt->identifier = Mem_Alloc(texturemempool, strlen(identifier)+1);
+               strcpy (glt->identifier, identifier);
        }
        else
-               size = width2*height2;
+               glt->identifier = NULL;
+       glt->pool = pool;
+       glt->chain = pool->gltchain;
+       pool->gltchain = glt;
+       glt->crc = crc;
+       glt->width = width;
+       glt->height = height;
+       glt->flags = flags;
+       glt->textype = texinfo;
 
-       size *= 4; // RGBA
+       if (data)
+       {
+               glt->inputtexels = Mem_Alloc(texturemempool, glt->width * glt->height * texinfo->inputbytesperpixel);
+               if (glt->inputtexels == NULL)
+                       Sys_Error("R_SetupTexture: out of memory\n");
+               memcpy(glt->inputtexels, data, glt->width * glt->height * texinfo->inputbytesperpixel);
+       }
+       else
+               glt->inputtexels = NULL;
 
-       return size;
+       glt->generate = generate;
+       glt->proceduraldatasize = proceduraldatasize;
+       if (proceduraldatasize)
+       {
+               glt->proceduraldata = Mem_Alloc(texturemempool, proceduraldatasize);
+               if (glt->proceduraldata == NULL)
+                       Sys_Error("R_SetupTexture: out of memory\n");
+       }
+       else
+               glt->proceduraldata = NULL;
+
+       R_FindImageForTexture(glt);
+       R_PrecacheTexture(glt);
+
+       return glt;
 }
 
 /*
 ================
-GL_LoadTexture
+R_LoadTexture
 ================
 */
-rtexture_t *R_LoadTexture (char *identifier, int width, int height, byte *data, int flags)
+rtexture_t *R_LoadTexture (rtexturepool_t *rtexturepool, char *identifier, int width, int height, byte *data, int textype, int flags)
 {
-       int                             i, bytesperpixel, internalflags, precache;
-       gltexture_t             *glt;
-       unsigned short  crc;
+       int i;
+       gltexture_t *glt;
+       gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
+       textypeinfo_t *texinfo;
+       unsigned short crc;
 
        if (cls.state == ca_dedicated)
                return NULL;
 
-       if (!identifier[0])
-               Host_Error("R_LoadTexture: no identifier\n");
-       if (data == NULL)
-               Host_Error("R_LoadTexture: \"%s\" has no data\n", identifier);
+       texinfo = R_GetTexTypeInfo(textype, flags);
+
+       // data can be NULL
+//     if (data == NULL)
+//             Host_Error("R_LoadTexture: \"%s\" has no data\n", identifier);
+
+       if (flags & TEXF_FRAGMENT)
+       {
+               if (width > BLOCK_SIZE || height > BLOCK_SIZE)
+                       Host_Error("R_LoadTexture: fragment too big, must be no more than %dx%d\n", BLOCK_SIZE, BLOCK_SIZE);
+               if ((width * texinfo->internalbytesperpixel) & 3)
+                       Host_Error("R_LoadTexture: incompatible width for fragment");
+       }
 
        // clear the alpha flag if the texture has no transparent pixels
-       if (flags & TEXF_ALPHA)
+       switch(textype)
        {
-               int alpha = false;
-               if (flags & TEXF_RGBA)
+       case TEXTYPE_QPALETTE:
+               if (flags & TEXF_ALPHA)
                {
+                       flags &= ~TEXF_ALPHA;
                        for (i = 0;i < width * height;i++)
                        {
-                               if (data[i * 4 + 3] < 255)
+                               if (data[i] == 255)
                                {
-                                       alpha = true;
+                                       flags |= TEXF_ALPHA;
                                        break;
                                }
                        }
                }
-               else
+               break;
+       case TEXTYPE_RGB:
+               if (flags & TEXF_ALPHA)
+                       Host_Error("R_LoadTexture: RGB has no alpha, don't specify TEXF_ALPHA\n");
+               break;
+       case TEXTYPE_RGBA:
+               if (flags & TEXF_ALPHA)
                {
+                       flags &= ~TEXF_ALPHA;
                        for (i = 0;i < width * height;i++)
                        {
-                               if (data[i] == 255)
+                               if (data[i * 4 + 3] < 255)
                                {
-                                       alpha = true;
+                                       flags |= TEXF_ALPHA;
                                        break;
                                }
                        }
                }
-               if (!alpha)
-                       flags &= ~TEXF_ALPHA;
+               break;
+       default:
+               Host_Error("R_LoadTexture: unknown texture type\n");
        }
 
-       if (flags & TEXF_RGBA)
-               bytesperpixel = 4;
+       // LordHavoc: do a CRC to confirm the data really is the same as previous occurances.
+       if (data == NULL)
+               crc = 0;
        else
-               bytesperpixel = 1;
-
-       internalflags = 0;
-       if (r_lerpimages.value != 0)
-               internalflags |= GLTEXF_LERPED;
+               crc = CRC_Block(data, width*height*texinfo->inputbytesperpixel);
 
-       // 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
-       for (i=0, glt=gltextures ; i<numgltextures ; i++, glt++)
+       if (identifier && (glt = R_FindTexture(pool, identifier)))
        {
-               if (!strcmp (identifier, glt->identifier))
-               {
-                       // LordHavoc: everyone hates cache mismatchs, so I fixed it
-                       if (crc != glt->crc || width != glt->width || height != glt->height || flags != glt->flags)
-                       {
-                               Con_DPrintf("GL_LoadTexture: cache mismatch, replacing old texture\n");
-                               goto GL_LoadTexture_setup; // drop out with glt pointing to the texture to replace
-                       }
-                       if (internalflags != glt->internalflags)
-                               goto GL_LoadTexture_setup; // drop out with glt pointing to the texture to replace
-                       return (rtexture_t *)glt;
-               }
+               if (crc == glt->crc && width == glt->width && height == glt->height && texinfo == glt->textype && ((flags ^ glt->flags) & TEXF_IMPORTANTBITS) == 0 && ((flags ^ glt->flags) & GLTEXF_IMPORTANTBITS) == 0)
+                       return (rtexture_t *)glt; // exact match, use existing
+               Con_Printf("R_LoadTexture: cache mismatch on %s, replacing old texture\n", identifier);
+               R_FreeTexture(glt);
        }
 
-/*
-       if (freeglt)
-       {
-               glt = freeglt;
-               strcpy (glt->identifier, identifier);
-       }
-       else
-       {
-*/
-               // 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++];
-               glt->texnum = gl_texture_number++;
-               strcpy (glt->identifier, identifier);
-//     }
+       return (rtexture_t *)R_SetupTexture(pool, identifier, crc, width, height, flags | GLTEXF_UPLOAD, texinfo, data, NULL, NULL, 0);
+}
 
-// 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->flags = flags;
-       glt->internalflags = internalflags;
+rtexture_t *R_ProceduralTexture (rtexturepool_t *rtexturepool, char *identifier, int width, int height, int textype, int flags, int (*generate)(byte *buffer, int width, int height, void *proceduraldata, int proceduraldatasize), void *proceduraldata, int proceduraldatasize)
+{
+       gltexture_t             *glt;
+       gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
+       textypeinfo_t   *texinfo;
 
-       if (glt->inputtexels)
-               qfree(glt->inputtexels);
-       glt->inputtexeldatasize = width*height*bytesperpixel;
-       glt->inputtexels = qmalloc(glt->inputtexeldatasize);
+       if (cls.state == ca_dedicated)
+               return NULL;
 
-       memcpy(glt->inputtexels, data, glt->inputtexeldatasize);
+       texinfo = R_GetTexTypeInfo(textype, flags);
 
-       glt->texeldatasize = R_CalcTexelDataSize(width, height, flags & TEXF_MIPMAP);
+       // no function is supported, for odd uses
+//     if (generate == NULL)
+//             Host_Error("R_ProceduralTexture: \"%s\" has no generate function\n", identifier);
+       if (flags & TEXF_FRAGMENT)
+       {
+               if (width > BLOCK_SIZE || height > BLOCK_SIZE)
+                       Host_Error("R_ProceduralTexture: fragment too big, must be no more than %dx%d\n", BLOCK_SIZE, BLOCK_SIZE);
+               if ((width * texinfo->internalbytesperpixel) & 3)
+                       Host_Error("R_ProceduralTexture: incompatible width for fragment");
+       }
 
-       precache = false;
-       if (flags & TEXF_ALWAYSPRECACHE)
-               precache = true;
-       else if (r_precachetextures.value >= 1)
+       // see if the texture is already present
+       if (identifier && (glt = R_FindTexture(pool, identifier)))
        {
-               if (flags & TEXF_PRECACHE)
-                       precache = true;
-               if (r_precachetextures.value >= 2)
-                       precache = true;
+               if (width == glt->width && height == glt->height && texinfo == glt->textype && ((flags ^ glt->flags) & TEXF_IMPORTANTBITS) == 0 && ((flags ^ glt->flags) & GLTEXF_IMPORTANTBITS) == 0)
+                       return (rtexture_t *)glt; // exact match, use existing
+               Con_DPrintf("R_LoadTexture: cache mismatch, replacing old texture\n");
+               R_FreeTexture(glt);
        }
 
-       if (precache)
-               GL_UploadTexture(glt);
+       return (rtexture_t *)R_SetupTexture(pool, identifier, 0, width, height, flags | GLTEXF_PROCEDURAL | GLTEXF_UPLOAD, texinfo, NULL, generate, proceduraldata, proceduraldatasize);
+}
+
+int R_TextureHasAlpha(rtexture_t *rt)
+{
+       gltexture_t *glt;
+       if (!rt)
+               return false;
+       glt = (gltexture_t *)rt;
+       return (glt->flags & TEXF_ALPHA) != 0;
+}
 
-       return (rtexture_t *)glt;
+int R_TextureWidth(rtexture_t *rt)
+{
+       if (!rt)
+               return false;
+       return ((gltexture_t *)rt)->width;
 }
 
-// only used for lightmaps
-int R_GetTextureSlots(int count)
+int R_TextureHeight(rtexture_t *rt)
 {
-       int i;
-       i = gl_texture_number;
-       gl_texture_number += count;
-       return i;
+       if (!rt)
+               return false;
+       return ((gltexture_t *)rt)->height;
 }
 
-int R_TextureHasAlpha(rtexture_t *rt)
+void R_GetFragmentLocation(rtexture_t *rt, int *x, int *y, float *fx1, float *fy1, float *fx2, float *fy2)
 {
        gltexture_t *glt;
+       float iwidth, iheight;
        if (!rt)
-               return false;
+               Host_Error("R_GetFragmentLocation: no texture supplied\n");
        glt = (gltexture_t *)rt;
-       return (glt->flags & TEXF_ALPHA) != 0;
+       if (glt->flags & TEXF_FRAGMENT)
+       {
+               if (x)
+                       *x = glt->x;
+               if (y)
+                       *y = glt->y;
+               if (fx1 || fy1 || fx2 || fy2)
+               {
+                       iwidth = 1.0f / glt->image->width;
+                       iheight = 1.0f / glt->image->height;
+                       if (fx1)
+                               *fx1 = glt->x * iwidth;
+                       if (fy1)
+                               *fy1 = glt->y * iheight;
+                       if (fx2)
+                               *fx2 = (glt->x + glt->width) * iwidth;
+                       if (fy2)
+                               *fy2 = (glt->y + glt->height) * iheight;
+               }
+       }
+       else
+       {
+               if (x)
+                       *x = 0;
+               if (y)
+                       *y = 0;
+               if (fx1 || fy1 || fx2 || fy2)
+               {
+                       if (fx1)
+                               *fx1 = 0;
+                       if (fy1)
+                               *fy1 = 0;
+                       if (fx2)
+                               *fx2 = 1;
+                       if (fy2)
+                               *fy2 = 1;
+               }
+       }
+}
+
+int R_CompatibleFragmentWidth(int width, int textype, int flags)
+{
+       textypeinfo_t *texinfo = R_GetTexTypeInfo(textype, flags);
+       while ((width * texinfo->internalbytesperpixel) & 3)
+               width++;
+       return width;
 }
+
+void R_UpdateTexture(rtexture_t *rt, byte *data)
+{
+       gltexture_t *glt;
+       if (rt == NULL)
+               Host_Error("R_UpdateTexture: no texture supplied\n");
+       if (data == NULL)
+               Host_Error("R_UpdateTexture: no data supplied\n");
+       glt = (gltexture_t *)rt;
+       if (!(glt->flags & GLTEXF_PROCEDURAL))
+       {
+               if (glt->inputtexels == NULL)
+               {
+                       glt->inputtexels = Mem_Alloc(texturemempool, glt->width * glt->height * glt->textype->inputbytesperpixel);
+                       if (glt->inputtexels == NULL)
+                               Host_Error("R_UpdateTexture: ran out of memory\n");
+               }
+               memcpy(glt->inputtexels, data, glt->width * glt->height * glt->textype->inputbytesperpixel);
+       }
+       R_Upload(glt, data);
+}
+
index be414912de626a7add5b4ea89ca4e0b8d3287d74..40b440635e576e5ec99d4770c43d72d615ca77fd 100644 (file)
--- a/glquake.h
+++ b/glquake.h
@@ -45,15 +45,6 @@ extern void GL_EndRendering (void);
 
 extern float   gldepthmin, gldepthmax;
 
-typedef struct
-{
-       float   x, y, z;
-       float   s, t;
-       float   r, g, b;
-} glvert_t;
-
-extern glvert_t glv;
-
 //====================================================
 
 extern const char *gl_vendor;
@@ -71,14 +62,14 @@ extern      const char *gl_extensions;
 #endif
 
 // GL_ARB_multitexture
-extern int gl_mtexable;
+extern int gl_textureunits;
 extern void (GLAPIENTRY *qglMultiTexCoord2f) (GLenum, GLfloat, GLfloat);
 extern void (GLAPIENTRY *qglActiveTexture) (GLenum);
 extern void (GLAPIENTRY *qglClientActiveTexture) (GLenum);
 #ifndef GL_ACTIVE_TEXTURE_ARB
 #define GL_ACTIVE_TEXTURE_ARB                  0x84E0
 #define GL_CLIENT_ACTIVE_TEXTURE_ARB   0x84E1
-#define GL_MAX_TEXTURES_UNITS_ARB              0x84E2
+#define GL_MAX_TEXTURE_UNITS_ARB               0x84E2
 #define GL_TEXTURE0_ARB                                        0x84C0
 #define GL_TEXTURE1_ARB                                        0x84C1
 #define GL_TEXTURE2_ARB                                        0x84C2
@@ -154,3 +145,13 @@ extern cvar_t gl_combine;
 //#endif
 
 #endif
+
+//#define DEBUGGL
+
+#ifdef DEBUGGL
+#define CHECKGLERROR if ((errornumber = glGetError())) GL_PrintError(errornumber, __FILE__, __LINE__);
+extern int errornumber;
+void GL_PrintError(int errornumber, char *filename, int linenumber);
+#else
+#define CHECKGLERROR
+#endif
diff --git a/hcompress.c b/hcompress.c
deleted file mode 100644 (file)
index 9e36868..0000000
+++ /dev/null
@@ -1,336 +0,0 @@
-
-// LordHavoc: my little compression library
-
-#if 0
-#include <stdlib.h>
-
-#ifndef byte
-typedef unsigned char byte;
-#endif
-
-#define HCOMPRESS_CORRUPT -1
-
-typedef struct
-{
-       int position;
-       int size;
-       byte *data;
-} hcblock;
-
-typedef struct
-{
-       int identifer;
-       int compressedsize;
-       int decompressedsize;
-       int compressedcrc;
-       int decompressedcrc;
-       byte data[0];
-} storagehcblock;
-
-int hc_readimmediate(hcblock *b)
-{
-       return b->data[b->position++];
-}
-
-int hc_readsize(hcblock *b)
-{
-       b->position += 2;
-       return b->data[b->position - 2];
-}
-
-int hc_readoffset(hcblock *b)
-{
-       b->position += 2;
-       return b->data[b->position - 2];
-}
-
-int hc_readbit(hcblock *b)
-{
-       return b->data[b->position++];
-}
-
-void hc_writeimmediate(hcblock *b, int num)
-{
-       b->data[b->size++] = num;
-}
-
-void hc_writesize(hcblock *b, int num)
-{
-       b->data[b->size] = num;
-       b->size += 2;
-}
-
-void hc_writeoffset(hcblock *b, int num)
-{
-       b->data[b->size] = num;
-       b->size += 2;
-}
-
-void hc_writebit(hcblock *b, int num)
-{
-       b->data[b->size++] = num;
-}
-
-int hcompress_decompress(void *inaddr, void *outaddr, int insize, int outsize)
-{
-       /*
-       byte *in, *out;
-       hcblock b;
-       b.position = 0;
-       b.size = 0;
-       b.
-       b = inaddr;
-       if (
-       int commandbits, commandbyte, count, temp;
-       in = inaddr;
-       out = outaddr;
-       while (outsize && insize)
-       {
-               hc_readbit(
-               if (!commandbits)
-               {
-                       if (!insize)
-                               return HCOMPRESS_CORRUPT;
-                       commandbyte = *in++;
-                       commandbits = 8;
-                       insize--;
-                       if (!insize)
-                               return HCOMPRESS_CORRUPT;
-               }
-               if (commandbyte)
-               {
-                       for (;commandbits && outsize;commandbits--,commandbyte >>= 1)
-                       {
-                               if (commandbyte & 1) // reference
-                               {
-                                       if (insize < 2)
-                                               return HCOMPRESS_CORRUPT;
-                                       size = (in[0] >> 4) + 3;
-                                       if (size > outsize)
-                                               return HCOMPRESS_CORRUPT;
-                                       insize -= 2;
-                                       outsize -= size;
-                                       tempout = out - ((((in[0] << 8) | in[1]) & 0xFFF) + 1);
-                                       if ((int) tempout < (int) outaddr)
-                                               return HCOMPRESS_CORRUPT;
-                                       while (size--)
-                                               *out++ = *tempout++;
-                               }
-                               else
-                               {
-                                       if (!insize || !outsize)
-                                               return HCOMPRESS_CORRUPT;
-                                       *out++ = *in++;
-                                       insize--;
-                                       outsize--;
-                               }
-                       }
-               }
-               else // copy 8 bytes straight
-               {
-                       if (insize < 8 || outsize < 8)
-                               return HCOMPRESS_CORRUPT;
-                       *out++ = *in++;
-                       *out++ = *in++;
-                       *out++ = *in++;
-                       *out++ = *in++;
-                       *out++ = *in++;
-                       *out++ = *in++;
-                       *out++ = *in++;
-                       *out++ = *in++;
-                       insize -= 8;
-                       outsize -= 8;
-               }
-       }
-       if (insize || outsize)
-               return HCOMPRESS_CORRUPT;
-       return ((int) out - (int) outaddr);
-       */
-       return HCOMPRESS_CORRUPT;
-}
-
-int hcompress_compress(void *indata, void *outdata, int size)
-{
-       byte *in, *out;
-       struct hctoken
-       {
-               unsigned short size; // if size == 0, offset holds the immediate value
-               unsigned short offset;
-       } *token;
-       int offsetcount[65536];
-       int sizecount[256];
-       int tokens = 0;
-       int position = 0;
-       int c, i, j, l, bestsize, bestposition, maxlen;
-       int *h;
-       byte *c1, *c2;
-       struct
-       {
-               int start; // start of the chain
-               int length; // length of the chain
-       } hashindex[256][256];
-       int *hashtable;
-       token = qmalloc(size*sizeof(struct hctoken));
-       hashtable = qmalloc(size*sizeof(int));
-       in = indata;
-       memset(&hashindex, 0, sizeof(hashindex));
-       // count the chain lengths
-       for (i = 0;i < size-1;i++)
-               hashindex[in[i]][in[i+1]].length++;
-       hashindex[in[i]][0].length++;
-       // assign starting positions for each chain
-       c = 0;
-       for (i = 0;i < 256;i++)
-       {
-               for (j = 0;j < 256;j++)
-               {
-                       hashindex[i][j].start = c;
-                       c += hashindex[i][j].length;
-               }
-       }
-       // enter the data into the chains
-       for (i = 0;i < size-1;i++)
-               hashtable[hashindex[in[i]][in[i+1]].start++] = i;
-       hashtable[hashindex[in[i]][0].start++] = i;
-       // adjust start positions back to what they should be
-       for (i = 0;i < 256;i++)
-               for (j = 0;j < 256;j++)
-                       hashindex[i][j].start -= hashindex[i][j].length;
-       // now the real work
-       out = outdata;
-       while (position < size)
-       {
-               c = *in++;
-               if (position + 1 == size) // this is the last byte
-               {
-                       h = &hashtable[hashindex[c][0].start];
-                       l = hashindex[c][0].length;
-               }
-               else
-               {
-                       h = &hashtable[hashindex[c][*in].start];
-                       l = hashindex[c][0].length;
-               }
-               if (l)
-               {
-                       if (*h < position - 65535) // too old, nudge up the chain to avoid finding this one again
-                       {
-                               if (position + 1 == size)
-                               {
-                                       hashindex[c][0].start++;
-                                       hashindex[c][0].length--;
-                               }
-                               else
-                               {
-                                       hashindex[c][*in].start++;
-                                       hashindex[c][*in].length--;
-                               }
-                               h++;
-                               l--;
-                       }
-                       if (l)
-                       {
-                               bestsize = 0;
-                               bestposition = 0;
-                               while (l--)
-                               {
-                                       c1 = &in[*h];
-                                       c2 = &in[position];
-                                       maxlen = size - position;
-                                       if (maxlen > 258)
-                                               maxlen = 258;
-                                       for (i = 0;i < maxlen;i++)
-                                               if (*c1++ != *c2++)
-                                                       break;
-                                       if (i > bestsize)
-                                       {
-                                               bestsize = i;
-                                               bestposition = *h;
-                                       }
-                                       h++;
-                               }
-                               if (bestsize >= 3)
-                               {
-                                       // write a reference
-                                       token[tokens].size = bestsize;
-                                       token[tokens++].offset = position - bestposition; // offset backward
-                                       sizecount[bestsize - 3]++;
-                                       offsetcount[position - bestposition]++;
-                               }
-                               else
-                               {
-                                       // write an immediate
-                                       token[tokens].size = 0;
-                                       token[tokens++].offset = c;
-                               }
-                       }
-                       else
-                       {
-                               // no remaining occurances, write an immediate
-                               token[tokens].size = 0;
-                               token[tokens++].offset = c;
-                       }
-               }
-               else
-               {
-                       // no remaining occurances, write an immediate
-                       token[tokens].size = 0;
-                       token[tokens++].offset = c;
-               }
-       }
-       return HCOMPRESS_CORRUPT;
-
-       /*
-       int i, index, insize = size, outsize = 0, commandbyte = 0, commandbits = 0;
-       struct hcompress_hashchain
-       {
-               short prev, next;
-               int key;
-       } hashchain[4096];
-       short hashindex[65536];
-       int hashvalue[4096];
-       struct
-       {
-               byte type;
-               unsigned short data;
-       } ref[8];
-       for (i = 0;i < 65536;i++)
-               hashindex[i] = -1;
-       for (i = 0;i < 4096;i++)
-       {
-               hashchain[i].next = -1;
-               hashchain[i].key = -1;
-       }
-       in = indata;
-       out = outdata;
-       while(insize)
-       {
-               if (insize >= 3) // enough data left to compress
-               {
-                       key = in[0] | (in[1] << 8);
-                       if (hashindex[
-                       for (
-                       index = ((int) in + 1) & 0xFFF;
-                       if (hash[index].key >= 0)
-                       {
-                               if (hashindex[hash[index].key] == index)
-                                       hashindex[hash[index].key] = -1;
-                               if (hash[index].prev >= 0)
-                                       hash[hash[index].prev].next = hash[index].next;
-                       }
-                       hash[index].key = key;
-                       hash[index].next = hashindex[key];
-                       hashindex[key] = index;
-               }
-               else
-               {
-                       while (insize--)
-                       {
-                               ref[commandbits].type = 0;
-                               ref[commandbits++].data = *in++;
-                       }
-               }
-       }
-       */
-}
-#endif
\ No newline at end of file
diff --git a/host.c b/host.c
index 38ef5231629c7fc1f18b3f9e1270e3747ed7b782..465c82d81aacb0e4707c789aa131260324c1a1d5 100644 (file)
--- a/host.c
+++ b/host.c
@@ -35,7 +35,8 @@ Memory is cleared / released when a server or client begins, not when they end.
 quakeparms_t host_parms;
 
 qboolean       host_initialized;               // true if into command execution
-qboolean       hostloopactive = 0;             // LordHavoc: used to turn Host_Error into Sys_Error if Host_Frame has not yet run
+qboolean       host_loopactive = false;        // LordHavoc: used to turn Host_Error into Sys_Error if starting up or shutting down
+qboolean       host_shuttingdown = false;      // LordHavoc: set when quit is executed
 
 double         host_frametime;
 double         host_realframetime;             // LordHavoc: the real frametime, before slowmo and clamping are applied (used for console scrolling)
@@ -45,8 +46,6 @@ int                   host_framecount;
 
 double         sv_frametime;
 
-int                    host_hunklevel;
-
 int                    minimum_memory;
 
 client_t       *host_client;                   // current client
@@ -124,8 +123,9 @@ void Host_Error (char *error, ...)
        va_list         argptr;
        static  qboolean inerror = false;
 
-       // LordHavoc: if host_frame loop has not been run yet, do a Sys_Error instead
-       if (!hostloopactive)
+       // LordHavoc: if first frame has not been shown, or currently shutting
+       // down, do Sys_Error instead
+       if (!host_loopactive || host_shuttingdown)
        {
                char string[4096];
                va_start (argptr,error);
@@ -165,6 +165,8 @@ void Host_Error (char *error, ...)
        longjmp (host_abortserver, 1);
 }
 
+static mempool_t *clients_mempool;
+
 /*
 ================
 Host_FindMaxClients
@@ -175,7 +177,7 @@ void        Host_FindMaxClients (void)
        int             i;
 
        svs.maxclients = 1;
-               
+
        i = COM_CheckParm ("-dedicated");
        if (i)
        {
@@ -208,7 +210,11 @@ void       Host_FindMaxClients (void)
        svs.maxclientslimit = svs.maxclients;
        if (svs.maxclientslimit < MAX_SCOREBOARD) // LordHavoc: upped listen mode limit from 4 to MAX_SCOREBOARD
                svs.maxclientslimit = MAX_SCOREBOARD;
-       svs.clients = Hunk_AllocName (svs.maxclientslimit*sizeof(client_t), "clients");
+       if (!clients_mempool)
+               clients_mempool = Mem_AllocPool("clients");
+       if (svs.clients)
+               Mem_Free(svs.clients);
+       svs.clients = Mem_Alloc(clients_mempool, svs.maxclientslimit*sizeof(client_t));
 
        if (svs.maxclients > 1)
                Cvar_SetValue ("deathmatch", 1.0);
@@ -225,7 +231,7 @@ Host_InitLocal
 void Host_InitLocal (void)
 {
        Host_InitCommands ();
-       
+
        Cvar_RegisterVariable (&host_framerate);
        Cvar_RegisterVariable (&host_speeds);
        Cvar_RegisterVariable (&slowmo);
@@ -498,8 +504,6 @@ void Host_ClearMemory (void)
 {
        Con_DPrintf ("Clearing memory\n");
        Mod_ClearAll ();
-       if (host_hunklevel)
-               Hunk_FreeToLowMark (host_hunklevel);
 
        cls.signon = 0;
        memset (&sv, 0, sizeof(sv));
@@ -640,7 +644,6 @@ void _Host_Frame (float time)
 
        if (setjmp (host_abortserver) )
                return;                 // something bad happened, or the server disconnected
-       hostloopactive = 1;
 
 // keep the random time dependent
        rand ();
@@ -698,12 +701,12 @@ void _Host_Frame (float time)
        ui_update();
 
 // update video
-       if (host_speeds.value)
+       if (host_speeds.integer)
                time1 = Sys_DoubleTime ();
 
        SCR_UpdateScreen ();
 
-       if (host_speeds.value)
+       if (host_speeds.integer)
                time2 = Sys_DoubleTime ();
 
 // update audio
@@ -717,7 +720,7 @@ void _Host_Frame (float time)
 
        CDAudio_Update();
 
-       if (host_speeds.value)
+       if (host_speeds.integer)
        {
                pass1 = (time1 - time3)*1000000;
                time3 = Sys_DoubleTime ();
@@ -728,6 +731,7 @@ void _Host_Frame (float time)
        }
 
        host_framecount++;
+       host_loopactive = true;
 }
 
 void Host_Frame (float time)
@@ -737,12 +741,12 @@ void Host_Frame (float time)
        static int              timecount;
        int             i, c, m;
 
-       if (!serverprofile.value)
+       if (!serverprofile.integer)
        {
                _Host_Frame (time);
                return;
        }
-       
+
        time1 = Sys_DoubleTime ();
        _Host_Frame (time);
        time2 = Sys_DoubleTime ();      
@@ -769,6 +773,7 @@ void Host_Frame (float time)
 //============================================================================
 
 void Render_Init(void);
+void QuakeIO_Init(void);
 
 /*
 ====================
@@ -777,48 +782,30 @@ Host_Init
 */
 void Host_Init (void)
 {
-       int i;
-
-       host_parms.memsize = DEFAULTMEM * 1024 * 1024;
-
-       i = COM_CheckParm("-mem");
-       if (i)
-               host_parms.memsize = (int) (atof(com_argv[i+1]) * 1024 * 1024);
-
-       i = COM_CheckParm("-winmem");
-       if (i)
-               host_parms.memsize = (int) (atof(com_argv[i+1]) * 1024 * 1024);
-
-       i = COM_CheckParm("-heapsize");
-       if (i)
-               host_parms.memsize = (int) (atof(com_argv[i+1]) * 1024);
-
-       host_parms.membase = qmalloc(host_parms.memsize);
-       if (!host_parms.membase)
-               Sys_Error("Not enough memory free, close some programs and try again, or free disk space\n");
-
        com_argc = host_parms.argc;
        com_argv = host_parms.argv;
 
-       Memory_Init (host_parms.membase, host_parms.memsize);
+       Memory_Init ();
+       Cmd_Init ();
+       Memory_Init_Commands();
+       R_Modules_Init();
        Cbuf_Init ();
-       Cmd_Init ();    
+       QuakeIO_Init ();
        V_Init ();
-       COM_Init (host_parms.basedir);
+       COM_Init ();
        Host_InitLocal ();
        W_LoadWadFile ("gfx.wad");
        Key_Init ();
-       Con_Init ();    
+       Con_Init ();
        Chase_Init ();
-       M_Init ();      
+       M_Init ();
        PR_Init ();
        Mod_Init ();
        NET_Init ();
        SV_Init ();
 
        Con_Printf ("Exe: "__TIME__" "__DATE__"\n");
-       Con_Printf ("%4.1f megabyte heap\n",host_parms.memsize/(1024*1024.0));
-       
+
        if (cls.state != ca_dedicated)
        {
                VID_InitCvars();
@@ -844,9 +831,6 @@ void Host_Init (void)
 
        Cbuf_InsertText ("exec quake.rc\n");
 
-       Hunk_AllocName (0, "-HOST_HUNKLEVEL-");
-       host_hunklevel = Hunk_LowMark ();
-
        host_initialized = true;
        
        Sys_Printf ("========Quake Initialized=========\n");    
index 780abeeb7ed0ab768040f57a97d1885bede96de4..f706171cb79866b858e061fb7a133751f2975835 100644 (file)
@@ -22,8 +22,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 int    current_skill;
 
-void Mod_Print (void);
-
 dfunction_t *ED_FindFunction (char *name);
 
 /*
@@ -35,6 +33,7 @@ Host_Quit_f
 // LordHavoc: didn't like it asking me if I wanted to quit
 //extern void M_Menu_Quit_f (void);
 
+extern qboolean host_shuttingdown;
 void Host_Quit_f (void)
 {
        /*
@@ -44,6 +43,7 @@ void Host_Quit_f (void)
                return;
        }
        */
+       host_shuttingdown = true;
        CL_Disconnect ();
        Host_ShutdownServer(false);
 
@@ -375,10 +375,7 @@ void Host_Connect_f (void)
        
        cls.demonum = -1;               // stop demo loop in case this fails
        if (cls.demoplayback)
-       {
-               CL_StopPlayback ();
                CL_Disconnect ();
-       }
        strcpy (name, Cmd_Argv(1));
        CL_EstablishConnection (name);
        Host_Reconnect_f ();
@@ -516,6 +513,8 @@ void Host_Savegame_f (void)
 }
 
 
+extern mempool_t *edictstring_mempool;
+
 /*
 ===============
 Host_Loadgame_f
@@ -533,7 +532,7 @@ void Host_Loadgame_f (void)
        edict_t *ent;
        int             entnum;
        int             version;
-       float                   spawn_parms[NUM_SPAWN_PARMS];
+       float   spawn_parms[NUM_SPAWN_PARMS];
 
        if (cmd_source != src_command)
                return;
@@ -602,7 +601,7 @@ void Host_Loadgame_f (void)
        for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
        {
                str = Qgetline (f);
-               sv.lightstyles[i] = Hunk_AllocName (strlen(str)+1, "lightstyles");
+               sv.lightstyles[i] = Mem_Alloc(edictstring_mempool, strlen(str)+1);
                strcpy (sv.lightstyles[i], str);
        }
 
@@ -676,17 +675,22 @@ Host_Name_f
 */
 void Host_Name_f (void)
 {
-       char    *newName;
+       char newName[64];
 
        if (Cmd_Argc () == 1)
        {
                Con_Printf ("\"name\" is \"%s\"\n", cl_name.string);
                return;
        }
+       //if (Cmd_Argc () == 2)
+       //      newName = Cmd_Argv(1);
+       //else
+       //      newName = Cmd_Args();
+       //newName[15] = 0;
        if (Cmd_Argc () == 2)
-               newName = Cmd_Argv(1);  
+               strncpy(newName, Cmd_Argv(1), 15);
        else
-               newName = Cmd_Args();
+               strncpy(newName, Cmd_Args(), 15);
        newName[15] = 0;
 
        if (cmd_source == src_command)
@@ -773,7 +777,7 @@ void Host_Say(qboolean teamonly)
        {
                if (!client || !client->active || !client->spawned)
                        continue;
-               if (teamplay.value && teamonly && client->edict->v.team != save->edict->v.team)
+               if (teamplay.integer && teamonly && client->edict->v.team != save->edict->v.team)
                        continue;
                host_client = client;
                SV_ClientPrintf("%s", text);
@@ -862,7 +866,7 @@ void Host_Color_f(void)
        
        if (Cmd_Argc() == 1)
        {
-               Con_Printf ("\"color\" is \"%i %i\"\n", ((int)cl_color.value) >> 4, ((int)cl_color.value) & 0x0f);
+               Con_Printf ("\"color\" is \"%i %i\"\n", cl_color.integer >> 4, cl_color.integer & 15);
                Con_Printf ("color <0-13> [0-13]\n");
                return;
        }
@@ -953,7 +957,7 @@ void Host_Pause_f (void)
                Cmd_ForwardToServer ();
                return;
        }
-       if (!pausable.value)
+       if (!pausable.integer)
                SV_ClientPrintf ("Pause not allowed.\n");
        else
        {
@@ -1439,7 +1443,7 @@ void Host_Viewmodel_f (void)
        if (!e)
                return;
 
-       m = Mod_ForName (Cmd_Argv(1), false);
+       m = Mod_ForName (Cmd_Argv(1), false, true, false);
        if (!m)
        {
                Con_Printf ("Can't load %s\n", Cmd_Argv(1));
@@ -1476,9 +1480,8 @@ void Host_Viewframe_f (void)
 
 void PrintFrameName (model_t *m, int frame)
 {
-       int data;
-       if (m->ofs_scenes && (data = (int) Mod_Extradata(m)))
-               Con_Printf("frame %i: %s\n", frame, ((animscene_t *) (m->ofs_scenes + data))[frame].name);
+       if (m->animscenes)
+               Con_Printf("frame %i: %s\n", frame, m->animscenes[frame].name);
        else
                Con_Printf("frame %i\n", frame);
 }
@@ -1604,7 +1607,6 @@ void Host_Stopdemo_f (void)
                return;
        if (!cls.demoplayback)
                return;
-       CL_StopPlayback ();
        CL_Disconnect ();
 }
 
@@ -1664,6 +1666,4 @@ void Host_InitCommands (void)
        Cmd_AddCommand ("viewframe", Host_Viewframe_f);
        Cmd_AddCommand ("viewnext", Host_Viewnext_f);
        Cmd_AddCommand ("viewprev", Host_Viewprev_f);
-
-       Cmd_AddCommand ("mcache", Mod_Print);
 }
diff --git a/image.c b/image.c
index 6023e91b9927b4a358deb58304b49c5f1b62010d..dbad08ff5b69231a6e8255e1faafe393b8efaa11 100644 (file)
--- a/image.c
+++ b/image.c
@@ -54,20 +54,6 @@ void Image_Copy8bitRGBA(byte *in, byte *out, int pixels, int *pal)
                iout[0] = pal[in[0]];
 }
 
-void Image_CopyRGBAGamma(byte *in, byte *out, int pixels)
-{
-       while (pixels--)
-       {
-               out[0] = texgamma[in[0]];
-               out[1] = texgamma[in[1]];
-               out[2] = texgamma[in[2]];
-               out[3] =          in[3] ;
-               in += 4;
-               out += 4;
-       }
-}
-
-
 /*
 =================================================================
 
@@ -106,7 +92,6 @@ byte* LoadPCX (byte *f, int matchwidth, int matchheight)
        if (loadsize < sizeof(pcx) + 768)
        {
                Con_Printf ("Bad pcx file\n");
-               qfree(f);
                return NULL;
        }
 
@@ -128,18 +113,15 @@ byte* LoadPCX (byte *f, int matchwidth, int matchheight)
        if (pcx.manufacturer != 0x0a || pcx.version != 5 || pcx.encoding != 1 || pcx.bits_per_pixel != 8 || pcx.xmax > 320 || pcx.ymax > 256)
        {
                Con_Printf ("Bad pcx file\n");
-               qfree(f);
                return NULL;
        }
 
        if (matchwidth && (pcx.xmax+1) != matchwidth)
        {
-               qfree(f);
                return NULL;
        }
        if (matchheight && (pcx.ymax+1) != matchheight)
        {
-               qfree(f);
                return NULL;
        }
 
@@ -148,11 +130,10 @@ byte* LoadPCX (byte *f, int matchwidth, int matchheight)
 
        palette = f + loadsize - 768;
 
-       image_rgba = qmalloc(image_width*image_height*4);
+       image_rgba = Mem_Alloc(tempmempool, image_width*image_height*4);
        if (!image_rgba)
        {
                Con_Printf("LoadPCX: not enough memory for %i by %i image\n", image_width, image_height);
-               qfree(f);
                return NULL;
        }
        pbuf = image_rgba + image_width*image_height*3;
@@ -194,7 +175,6 @@ byte* LoadPCX (byte *f, int matchwidth, int matchheight)
                *a++ = 255;
        }
 
-       qfree(f);
        return image_rgba;
 }
 
@@ -230,14 +210,11 @@ byte* LoadTGA (byte *f, int matchwidth, int matchheight)
        byte *pixbuf, *image_rgba, *fin, *enddata;
 
        if (loadsize < 18+3)
-       {
-               qfree(f);
                return NULL;
-       }
        targa_header.id_length = f[0];
        targa_header.colormap_type = f[1];
        targa_header.image_type = f[2];
-       
+
        targa_header.colormap_index = f[3] + f[4] * 256;
        targa_header.colormap_length = f[5] + f[6] * 256;
        targa_header.colormap_size = f[7];
@@ -246,29 +223,21 @@ byte* LoadTGA (byte *f, int matchwidth, int matchheight)
        targa_header.width = f[12] + f[13] * 256;
        targa_header.height = f[14] + f[15] * 256;
        if (matchwidth && targa_header.width != matchwidth)
-       {
-               qfree(f);
                return NULL;
-       }
        if (matchheight && targa_header.height != matchheight)
-       {
-               qfree(f);
                return NULL;
-       }
        targa_header.pixel_size = f[16];
        targa_header.attributes = f[17];
 
        if (targa_header.image_type != 2 && targa_header.image_type != 10)
        {
                Con_Printf ("LoadTGA: Only type 2 and 10 targa RGB images supported\n");
-               qfree(f);
                return NULL;
        }
 
        if (targa_header.colormap_type != 0     || (targa_header.pixel_size != 32 && targa_header.pixel_size != 24))
        {
                Con_Printf ("LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n");
-               qfree(f);
                return NULL;
        }
 
@@ -277,11 +246,10 @@ byte* LoadTGA (byte *f, int matchwidth, int matchheight)
        columns = targa_header.width;
        rows = targa_header.height;
 
-       image_rgba = qmalloc(columns * rows * 4);
+       image_rgba = Mem_Alloc(tempmempool, columns * rows * 4);
        if (!image_rgba)
        {
                Con_Printf ("LoadTGA: not enough memory for %i by %i image\n", columns, rows);
-               qfree(f);
                return NULL;
        }
 
@@ -356,7 +324,7 @@ byte* LoadTGA (byte *f, int matchwidth, int matchheight)
                                                alphabyte = *fin++;
                                                break;
                                        }
-       
+
                                        for(j = 0;j < packetSize;j++)
                                        {
                                                *pixbuf++ = red;
@@ -412,7 +380,7 @@ byte* LoadTGA (byte *f, int matchwidth, int matchheight)
                                                        else
                                                                goto breakOut;
                                                        pixbuf = image_rgba + row * columns * 4;
-                                               }                                               
+                                               }
                                        }
                                }
                        }
@@ -423,7 +391,6 @@ outofdata:;
 
        image_width = columns;
        image_height = rows;
-       qfree(f);
        return image_rgba;
 }
 
@@ -436,11 +403,10 @@ byte* LoadLMP (byte *f, int matchwidth, int matchheight)
 {
        byte    *image_rgba;
        int             width, height;
-               
+
        if (loadsize < 9)
        {
                Con_Printf("LoadLMP: invalid LMP file\n");
-               qfree(f);
                return NULL;
        }
 
@@ -450,39 +416,27 @@ byte* LoadLMP (byte *f, int matchwidth, int matchheight)
        if ((unsigned) width > 4096 || (unsigned) height > 4096)
        {
                Con_Printf("LoadLMP: invalid size\n");
-               qfree(f);
                return NULL;
        }
-       if (matchwidth && width != matchwidth)
-       {
-               qfree(f);
+       if ((matchwidth && width != matchwidth) || (matchheight && height != matchheight))
                return NULL;
-       }
-       if (matchheight && height != matchheight)
-       {
-               qfree(f);
-               return NULL;
-       }
 
        if (loadsize < 8 + width * height)
        {
                Con_Printf("LoadLMP: invalid LMP file\n");
-               qfree(f);
                return NULL;
        }
 
        image_width = width;
        image_height = height;
 
-       image_rgba = qmalloc(image_width * image_height * 4);
+       image_rgba = Mem_Alloc(tempmempool, image_width * image_height * 4);
        if (!image_rgba)
        {
                Con_Printf("LoadLMP: not enough memory for %i by %i image\n", image_width, image_height);
-               qfree(f);
                return NULL;
        }
        Image_Copy8bitRGBA(f + 8, image_rgba, image_width * image_height, d_8to24table);
-       qfree(f);
        return image_rgba;
 }
 
@@ -505,34 +459,53 @@ void Image_StripImageExtension (char *in, char *out)
 
 byte* loadimagepixels (char* filename, qboolean complain, int matchwidth, int matchheight)
 {
-       byte    *f;
-       char    basename[256], name[256];
-       byte    *c;
+       byte    *f, *data;
+       char    basename[256], name[256], *c;
        Image_StripImageExtension(filename, basename); // strip .tga, .pcx and .lmp extensions to allow replacement by other types
        // replace *'s with #, so commandline utils don't get confused when dealing with the external files
        for (c = basename;*c;c++)
                if (*c == '*')
                        *c = '#';
        sprintf (name, "textures/%s.tga", basename);
-       f = COM_LoadMallocFile(name, true);
+       f = COM_LoadFile(name, true);
        if (f)
-               return LoadTGA (f, matchwidth, matchheight);
+       {
+               data = LoadTGA (f, matchwidth, matchheight);
+               Mem_Free(f);
+               return data;
+       }
        sprintf (name, "textures/%s.pcx", basename);
-       f = COM_LoadMallocFile(name, true);
+       f = COM_LoadFile(name, true);
        if (f)
-               return LoadPCX (f, matchwidth, matchheight);
+       {
+               data = LoadPCX (f, matchwidth, matchheight);
+               Mem_Free(f);
+               return data;
+       }
        sprintf (name, "%s.tga", basename);
-       f = COM_LoadMallocFile(name, true);
+       f = COM_LoadFile(name, true);
        if (f)
-               return LoadTGA (f, matchwidth, matchheight);
+       {
+               data = LoadTGA (f, matchwidth, matchheight);
+               Mem_Free(f);
+               return data;
+       }
        sprintf (name, "%s.pcx", basename);
-       f = COM_LoadMallocFile(name, true);
+       f = COM_LoadFile(name, true);
        if (f)
-               return LoadPCX (f, matchwidth, matchheight);
+       {
+               data = LoadPCX (f, matchwidth, matchheight);
+               Mem_Free(f);
+               return data;
+       }
        sprintf (name, "%s.lmp", basename);
-       f = COM_LoadMallocFile(name, true);
+       f = COM_LoadFile(name, true);
        if (f)
-               return LoadLMP (f, matchwidth, matchheight);
+       {
+               data = LoadLMP (f, matchwidth, matchheight);
+               Mem_Free(f);
+               return data;
+       }
        if (complain)
                Con_Printf ("Couldn't load %s.tga, .pcx, .lmp\n", filename);
        return NULL;
@@ -564,35 +537,35 @@ byte* loadimagepixelsmask (char* filename, qboolean complain, int matchwidth, in
                return data; // some transparency
        else
        {
-               qfree(data);
+               Mem_Free(data);
                return NULL; // all opaque
        }
 }
 
-rtexture_t *loadtextureimage (char* filename, int matchwidth, int matchheight, qboolean complain, qboolean mipmap, qboolean precache)
+rtexture_t *loadtextureimage (rtexturepool_t *pool, char* filename, int matchwidth, int matchheight, qboolean complain, qboolean mipmap, qboolean precache)
 {
        byte *data;
        rtexture_t *rt;
        if (!(data = loadimagepixels (filename, complain, matchwidth, matchheight)))
                return 0;
-       rt = R_LoadTexture (filename, image_width, image_height, data, TEXF_ALPHA | TEXF_RGBA | (mipmap ? TEXF_MIPMAP : 0) | (mipmap ? TEXF_PRECACHE : 0));
-       qfree(data);
+       rt = R_LoadTexture (pool, filename, image_width, image_height, data, TEXTYPE_RGBA, TEXF_ALPHA | (mipmap ? TEXF_MIPMAP : 0) | (precache ? TEXF_PRECACHE : 0));
+       Mem_Free(data);
        return rt;
 }
 
-rtexture_t *loadtextureimagemask (char* filename, int matchwidth, int matchheight, qboolean complain, qboolean mipmap, qboolean precache)
+rtexture_t *loadtextureimagemask (rtexturepool_t *pool, char* filename, int matchwidth, int matchheight, qboolean complain, qboolean mipmap, qboolean precache)
 {
        byte *data;
        rtexture_t *rt;
        if (!(data = loadimagepixelsmask (filename, complain, matchwidth, matchheight)))
                return 0;
-       rt = R_LoadTexture (filename, image_width, image_height, data, TEXF_ALPHA | TEXF_RGBA | (mipmap ? TEXF_MIPMAP : 0) | (mipmap ? TEXF_PRECACHE : 0));
-       qfree(data);
+       rt = R_LoadTexture (pool, filename, image_width, image_height, data, TEXTYPE_RGBA, TEXF_ALPHA | (mipmap ? TEXF_MIPMAP : 0) | (precache ? TEXF_PRECACHE : 0));
+       Mem_Free(data);
        return rt;
 }
 
 rtexture_t *image_masktex;
-rtexture_t *loadtextureimagewithmask (char* filename, int matchwidth, int matchheight, qboolean complain, qboolean mipmap, qboolean precache)
+rtexture_t *loadtextureimagewithmask (rtexturepool_t *pool, char* filename, int matchwidth, int matchheight, qboolean complain, qboolean mipmap, qboolean precache)
 {
        int count;
        byte *data;
@@ -601,16 +574,16 @@ rtexture_t *loadtextureimagewithmask (char* filename, int matchwidth, int matchh
        image_masktex = NULL;
        if (!(data = loadimagepixels (filename, complain, matchwidth, matchheight)))
                return 0;
-       rt = R_LoadTexture (filename, image_width, image_height, data, TEXF_ALPHA | TEXF_RGBA | (mipmap ? TEXF_MIPMAP : 0) | (mipmap ? TEXF_PRECACHE : 0));
+       rt = R_LoadTexture (pool, filename, image_width, image_height, data, TEXTYPE_RGBA, TEXF_ALPHA | (mipmap ? TEXF_MIPMAP : 0) | (precache ? TEXF_PRECACHE : 0));
        count = image_makemask(data, data, image_width * image_height);
        if (count)
        {
-               filename2 = qmalloc(strlen(filename) + 6);
+               filename2 = Mem_Alloc(tempmempool, strlen(filename) + 6);
                sprintf(filename2, "%s_mask", filename);
-               image_masktex = R_LoadTexture (filename2, image_width, image_height, data, TEXF_ALPHA | TEXF_RGBA | (mipmap ? TEXF_MIPMAP : 0) | (mipmap ? TEXF_PRECACHE : 0));
-               qfree(filename2);
+               image_masktex = R_LoadTexture (pool, filename2, image_width, image_height, data, TEXTYPE_RGBA, TEXF_ALPHA | (mipmap ? TEXF_MIPMAP : 0) | (precache ? TEXF_PRECACHE : 0));
+               Mem_Free(filename2);
        }
-       qfree(data);
+       Mem_Free(data);
        return rt;
 }
 
@@ -618,7 +591,7 @@ void Image_WriteTGARGB_preflipped (char *filename, int width, int height, byte *
 {
        byte *buffer, *in, *out, *end;
 
-       buffer = qmalloc(width*height*3 + 18);
+       buffer = Mem_Alloc(tempmempool, width*height*3 + 18);
 
        memset (buffer, 0, 18);
        buffer[2] = 2;          // uncompressed type
@@ -640,7 +613,7 @@ void Image_WriteTGARGB_preflipped (char *filename, int width, int height, byte *
        }
        COM_WriteFile (filename, buffer, width*height*3 + 18 );
 
-       qfree(buffer);
+       Mem_Free(buffer);
 }
 
 void Image_WriteTGARGB (char *filename, int width, int height, byte *data)
@@ -648,7 +621,7 @@ void Image_WriteTGARGB (char *filename, int width, int height, byte *data)
        int y;
        byte *buffer, *in, *out, *end;
 
-       buffer = qmalloc(width*height*3 + 18);
+       buffer = Mem_Alloc(tempmempool, width*height*3 + 18);
 
        memset (buffer, 0, 18);
        buffer[2] = 2;          // uncompressed type
@@ -673,7 +646,7 @@ void Image_WriteTGARGB (char *filename, int width, int height, byte *data)
        }
        COM_WriteFile (filename, buffer, width*height*3 + 18 );
 
-       qfree(buffer);
+       Mem_Free(buffer);
 }
 
 void Image_WriteTGARGBA (char *filename, int width, int height, byte *data)
@@ -681,7 +654,7 @@ void Image_WriteTGARGBA (char *filename, int width, int height, byte *data)
        int y;
        byte *buffer, *in, *out, *end;
 
-       buffer = qmalloc(width*height*4 + 18);
+       buffer = Mem_Alloc(tempmempool, width*height*4 + 18);
 
        memset (buffer, 0, 18);
        buffer[2] = 2;          // uncompressed type
@@ -707,7 +680,7 @@ void Image_WriteTGARGBA (char *filename, int width, int height, byte *data)
        }
        COM_WriteFile (filename, buffer, width*height*4 + 18 );
 
-       qfree(buffer);
+       Mem_Free(buffer);
 }
 
 qboolean Image_CheckAlpha(byte *data, int size, qboolean rgba)
diff --git a/image.h b/image.h
index 0a1d73fd97bfcee28094a7f2bcdca24510406b2f..c955fafbcf36bf201afc19d6bf05c3862e1ff804 100644 (file)
--- a/image.h
+++ b/image.h
@@ -1,14 +1,13 @@
 
 void Image_GammaRemapRGB(byte *in, byte *out, int pixels, byte *gammar, byte *gammag, byte *gammab);
 void Image_Copy8bitRGBA(byte *in, byte *out, int pixels, int *pal);
-void Image_CopyRGBAGamma(byte *in, byte *out, int pixels);
 int image_makemask (byte *in, byte *out, int size);
 byte* loadimagepixels (char* filename, qboolean complain, int matchwidth, int matchheight);
-rtexture_t *loadtextureimage (char* filename, int matchwidth, int matchheight, qboolean complain, qboolean mipmap, qboolean precache);
+rtexture_t *loadtextureimage (rtexturepool_t *pool, char* filename, int matchwidth, int matchheight, qboolean complain, qboolean mipmap, qboolean precache);
 byte* loadimagepixelsmask (char* filename, qboolean complain, int matchwidth, int matchheight);
-rtexture_t *loadtextureimagemask (char* filename, int matchwidth, int matchheight, qboolean complain, qboolean mipmap, qboolean precache);
+rtexture_t *loadtextureimagemask (rtexturepool_t *pool, char* filename, int matchwidth, int matchheight, qboolean complain, qboolean mipmap, qboolean precache);
 rtexture_t *image_masktex;
-rtexture_t *loadtextureimagewithmask (char* filename, int matchwidth, int matchheight, qboolean complain, qboolean mipmap, qboolean precache);
+rtexture_t *loadtextureimagewithmask (rtexturepool_t *pool, char* filename, int matchwidth, int matchheight, qboolean complain, qboolean mipmap, qboolean precache);
 void Image_WriteTGARGB_preflipped (char *filename, int width, int height, byte *data);
 void Image_WriteTGARGB (char *filename, int width, int height, byte *data);
 void Image_WriteTGARGBA (char *filename, int width, int height, byte *data);
index f585bf7a82cda7acc5d0c3ca8498f0f779276099..971d497fd22ebcd66d0abacfa5e53bd831dba214 100644 (file)
@@ -322,7 +322,7 @@ void IN_Commands(void)
 
 void IN_Move(usercmd_t *cmd)
 {
-       int mouselook = (in_mlook.state & 1) || freelook.value;
+       int mouselook = (in_mlook.state & 1) || freelook.integer;
        if (!UseMouse)
                return;
 
@@ -338,7 +338,7 @@ void IN_Move(usercmd_t *cmd)
        }
        uimx = uimy = 0;
 
-       if (m_filter.value)
+       if (m_filter.integer)
        {
                mouse_x = (mx + old_mouse_x) * 0.5;
                mouse_y = (my + old_mouse_y) * 0.5;
@@ -357,7 +357,7 @@ void IN_Move(usercmd_t *cmd)
        mouse_y *= sensitivity.value;
 
        /* Add mouse X/Y movement to cmd */
-       if ( (in_strafe.state & 1) || (lookstrafe.value && mouselook))
+       if ( (in_strafe.state & 1) || (lookstrafe.integer && mouselook))
                cmd->sidemove += m_side.value * mouse_x;
        else
                cl.viewangles[YAW] -= m_yaw.value * mouse_x;
index d814845f45fa596aede653baa711fc8f100dd977..c6ce7aaa85a298643dd572662be8db6445219af8 100644 (file)
--- a/in_win.c
+++ b/in_win.c
@@ -534,7 +534,7 @@ IN_MouseMove
 */
 void IN_MouseMove (usercmd_t *cmd)
 {
-       int                                     i, mx, my, mouselook = (in_mlook.state & 1) || freelook.value;
+       int                                     i, mx, my, mouselook = (in_mlook.state & 1) || freelook.integer;
        DIDEVICEOBJECTDATA      od;
        DWORD                           dwElements;
        HRESULT                         hr;
@@ -636,7 +636,7 @@ void IN_MouseMove (usercmd_t *cmd)
 //if (mx ||  my)
 //     Con_DPrintf("mx=%d, my=%d\n", mx, my);
 
-       if (m_filter.value)
+       if (m_filter.integer)
        {
                mouse_x = (mx + old_mouse_x) * 0.5;
                mouse_y = (my + old_mouse_y) * 0.5;
@@ -654,7 +654,7 @@ void IN_MouseMove (usercmd_t *cmd)
        mouse_y *= sensitivity.value;
 
 // add mouse X/Y movement to cmd
-       if ( (in_strafe.state & 1) || (lookstrafe.value && mouselook))
+       if ( (in_strafe.state & 1) || (lookstrafe.integer && mouselook))
                cmd->sidemove += m_side.value * mouse_x;
        else
                cl.viewangles[YAW] -= m_yaw.value * mouse_x;
@@ -859,7 +859,7 @@ void Joy_AdvancedUpdate_f (void)
                pdwRawValue[i] = RawValuePointer(i);
        }
 
-       if( joy_advanced.value == 0.0)
+       if( joy_advanced.integer == 0)
        {
                // default joystick initialization
                // 2 axes only with joystick control
@@ -997,7 +997,7 @@ qboolean IN_ReadJoystick (void)
                // this is a hack -- there is a bug in the Logitech WingMan Warrior DirectInput Driver
                // rather than having 32768 be the zero point, they have the zero point at 32668
                // go figure -- anyway, now we get the full resolution out of the device
-               if (joy_wwhack1.value != 0.0)
+               if (joy_wwhack1.integer != 0.0)
                {
                        ji.dwUpos += 100;
                }
@@ -1024,7 +1024,7 @@ void IN_JoyMove (usercmd_t *cmd)
 {
        float   speed, aspeed;
        float   fAxisValue, fTemp;
-       int             i, mouselook = (in_mlook.state & 1) || freelook.value;
+       int             i, mouselook = (in_mlook.state & 1) || freelook.integer;
 
        // complete initialization if first time in
        // this is needed as cvars are not available at initialization time
@@ -1035,11 +1035,11 @@ void IN_JoyMove (usercmd_t *cmd)
        }
 
        // verify joystick is available and that the user wants to use it
-       if (!joy_avail || !in_joystick.value)
+       if (!joy_avail || !in_joystick.integer)
        {
                return; 
        }
+
        // collect the joystick data, if possible
        if (IN_ReadJoystick () != true)
        {
@@ -1060,7 +1060,7 @@ void IN_JoyMove (usercmd_t *cmd)
                // move centerpoint to zero
                fAxisValue -= 32768.0;
 
-               if (joy_wwhack2.value != 0.0)
+               if (joy_wwhack2.integer != 0.0)
                {
                        if (dwAxisMap[i] == AxisTurn)
                        {
@@ -1082,7 +1082,7 @@ void IN_JoyMove (usercmd_t *cmd)
                switch (dwAxisMap[i])
                {
                case AxisForward:
-                       if ((joy_advanced.value == 0.0) && mouselook)
+                       if ((joy_advanced.integer == 0) && mouselook)
                        {
                                // user wants forward control to become look control
                                if (fabs(fAxisValue) > joy_pitchthreshold.value)
@@ -1127,7 +1127,7 @@ void IN_JoyMove (usercmd_t *cmd)
                        break;
 
                case AxisTurn:
-                       if ((in_strafe.state & 1) || (lookstrafe.value && mouselook))
+                       if ((in_strafe.state & 1) || (lookstrafe.integer && mouselook))
                        {
                                // user wants turn control to become side control
                                if (fabs(fAxisValue) > joy_sidethreshold.value)
@@ -1175,7 +1175,7 @@ void IN_JoyMove (usercmd_t *cmd)
                                        // disable pitch return-to-center unless requested by user
                                        // *** this code can be removed when the lookspring bug is fixed
                                        // *** the bug always has the lookspring feature on
-                                       if(lookspring.value == 0.0)
+                                       if(lookspring.integer == 0)
                                                V_StopPitchDrift();
                                }
                        }
index e73961ce4ac2d2208db8d067d3f552f078cde9e5..1599a066690f908dfde05d04a983b1735128485b 100644 (file)
--- a/makefile
+++ b/makefile
@@ -9,7 +9,7 @@ SOUNDLIB=-lasound
 #SND=snd_oss.o
 #SOUNDLIB=
 
-OBJECTS= buildnumber.o cd_linux.o chase.o cl_demo.o cl_input.o cl_main.o cl_parse.o cl_tent.o cmd.o common.o console.o crc.o cvar.o fractalnoise.o gl_draw.o gl_poly.o gl_rmain.o gl_rmisc.o gl_rsurf.o gl_screen.o gl_warp.o host.o host_cmd.o image.o keys.o mathlib.o menu.o model_alias.o model_brush.o model_shared.o model_sprite.o net_bsd.o net_udp.o net_dgrm.o net_loop.o net_main.o pr_cmds.o pr_edict.o pr_exec.o r_light.o r_part.o r_explosion.o sbar.o snd_dma.o snd_mem.o snd_mix.o $(SND) sv_main.o sv_move.o sv_phys.o sv_user.o sv_light.o sys_linux.o transform.o view.o wad.o world.o zone.o vid_shared.o palette.o r_crosshairs.o gl_textures.o gl_models.o r_sprites.o r_modules.o r_explosion.o r_lerpanim.o cl_effects.o r_decals.o protocol.o quakeio.o r_clip.o ui.o portals.o sys_shared.o cl_light.o
+OBJECTS= buildnumber.o cd_linux.o chase.o cl_demo.o cl_input.o cl_main.o cl_parse.o cl_tent.o cmd.o common.o console.o crc.o cvar.o fractalnoise.o gl_draw.o r_sky.o gl_rmain.o gl_rsurf.o gl_screen.o host.o host_cmd.o image.o keys.o mathlib.o menu.o model_alias.o model_brush.o model_shared.o model_sprite.o net_bsd.o net_udp.o net_dgrm.o net_loop.o net_main.o pr_cmds.o pr_edict.o pr_exec.o r_light.o r_particles.o r_explosion.o sbar.o snd_dma.o snd_mem.o snd_mix.o $(SND) sv_main.o sv_move.o sv_phys.o sv_user.o sv_light.o sys_linux.o transform.o view.o wad.o world.o zone.o vid_shared.o palette.o r_crosshairs.o gl_textures.o gl_models.o r_sprites.o r_modules.o r_explosion.o r_lerpanim.o r_decals.o protocol.o quakeio.o r_clip.o ui.o portals.o sys_shared.o cl_light.o gl_backend.o cl_particles.o cl_decals.o
 
 #K6/athlon optimizations
 CPUOPTIMIZATIONS=-march=k6
@@ -34,7 +34,7 @@ CFLAGS= -MD -Wall -Werror -I/usr/X11R6/include -I/usr/include/glide $(OPTIMIZATI
 #OPTIMIZATIONS= -O -g
 #CFLAGS= -MD -Wall -Werror -I/usr/X11R6/include -ggdb $(OPTIMIZATIONS) $(PROFILEOPTION)
 
-LDFLAGS= -L/usr/X11R6/lib -lm -lX11 -lXext -lXIE -lXxf86dga -lXxf86vm -lGL -ldl $(SOUNDLIB) -lz $(PROFILEOPTION)
+LDFLAGS= -L/usr/X11R6/lib -lm -lX11 -lXext -lXIE -lXxf86dga -lXxf86vm -lGL -ldl $(SOUNDLIB) $(PROFILEOPTION)
 
 #most people can't build the -3dfx version (-3dfx version needs some updates for new mesa)
 all: buildnum darkplaces-glx
@@ -42,6 +42,7 @@ all: buildnum darkplaces-glx
 
 buildnum:
        make -C buildnum
+       buildnum/buildnum buildnumber.c
 
 .c.o:
        gcc $(CFLAGS) -c $*.c
index 726cd089590a16dc992d46479d4d74d020c5404e..d528451002f535b93ff6623fd691ab7f1eda60f0 100644 (file)
--- a/mathlib.c
+++ b/mathlib.c
@@ -297,6 +297,22 @@ void VectorVectors(const vec3_t forward, vec3_t right, vec3_t up)
        right[1] = -forward[0];
        right[2] = forward[1];
 
+       d = DotProduct(forward, right);
+       right[0] -= d * forward[0];
+       right[1] -= d * forward[1];
+       right[2] -= d * forward[2];
+       VectorNormalizeFast(right);
+       CrossProduct(right, forward, up);
+}
+
+void VectorVectorsDouble(const double *forward, double *right, double *up)
+{
+       double d;
+
+       right[0] = forward[2];
+       right[1] = -forward[0];
+       right[2] = forward[1];
+
        d = DotProduct(forward, right);
        right[0] -= d * forward[0];
        right[1] -= d * forward[1];
@@ -580,54 +596,111 @@ void PlaneClassify(mplane_t *p)
 
 void AngleVectors (vec3_t angles, vec3_t forward, vec3_t right, vec3_t up)
 {
-       float           angle;
-       float           sr, sp, sy, cr, cp, cy;
-       
+       double angle, sr, sp, sy, cr, cp, cy;
+
        angle = angles[YAW] * (M_PI*2 / 360);
        sy = sin(angle);
        cy = cos(angle);
        angle = angles[PITCH] * (M_PI*2 / 360);
        sp = sin(angle);
        cp = cos(angle);
-       // LordHavoc: this is only to hush up gcc complaining about 'might be used uninitialized' variables
-       // (they are NOT used uninitialized, but oh well)
-       cr = 0;
-       sr = 0;
+       if (forward)
+       {
+               forward[0] = cp*cy;
+               forward[1] = cp*sy;
+               forward[2] = -sp;
+       }
        if (right || up)
        {
                angle = angles[ROLL] * (M_PI*2 / 360);
                sr = sin(angle);
                cr = cos(angle);
+               if (right)
+               {
+                       right[0] = -1*(sr*sp*cy+cr*-sy);
+                       right[1] = -1*(sr*sp*sy+cr*cy);
+                       right[2] = -1*(sr*cp);
+               }
+               if (up)
+               {
+                       up[0] = (cr*sp*cy+-sr*-sy);
+                       up[1] = (cr*sp*sy+-sr*cy);
+                       up[2] = cr*cp;
+               }
        }
+}
+
+void AngleVectorsFLU (vec3_t angles, vec3_t forward, vec3_t left, vec3_t up)
+{
+       double angle, sr, sp, sy, cr, cp, cy;
 
+       angle = angles[YAW] * (M_PI*2 / 360);
+       sy = sin(angle);
+       cy = cos(angle);
+       angle = angles[PITCH] * (M_PI*2 / 360);
+       sp = sin(angle);
+       cp = cos(angle);
        if (forward)
        {
                forward[0] = cp*cy;
                forward[1] = cp*sy;
                forward[2] = -sp;
        }
-       if (right)
-       {
-               right[0] = (-1*sr*sp*cy+-1*cr*-sy);
-               right[1] = (-1*sr*sp*sy+-1*cr*cy);
-               right[2] = -1*sr*cp;
-       }
-       if (up)
+       if (left || up)
        {
-               up[0] = (cr*sp*cy+-sr*-sy);
-               up[1] = (cr*sp*sy+-sr*cy);
-               up[2] = cr*cp;
+               angle = angles[ROLL] * (M_PI*2 / 360);
+               sr = sin(angle);
+               cr = cos(angle);
+               if (left)
+               {
+                       left[0] = sr*sp*cy+cr*-sy;
+                       left[1] = sr*sp*sy+cr*cy;
+                       left[2] = sr*cp;
+               }
+               if (up)
+               {
+                       up[0] = cr*sp*cy+-sr*-sy;
+                       up[1] = cr*sp*sy+-sr*cy;
+                       up[2] = cr*cp;
+               }
        }
 }
 
+void AngleMatrix (vec3_t angles, vec3_t translate, vec_t matrix[][4])
+{
+       double angle, sr, sp, sy, cr, cp, cy;
+
+       angle = angles[YAW] * (M_PI*2 / 360);
+       sy = sin(angle);
+       cy = cos(angle);
+       angle = angles[PITCH] * (M_PI*2 / 360);
+       sp = sin(angle);
+       cp = cos(angle);
+       angle = angles[ROLL] * (M_PI*2 / 360);
+       sr = sin(angle);
+       cr = cos(angle);
+       matrix[0][0] = cp*cy;
+       matrix[0][1] = sr*sp*cy+cr*-sy;
+       matrix[0][2] = cr*sp*cy+-sr*-sy;
+       matrix[0][3] = translate[0];
+       matrix[1][0] = cp*sy;
+       matrix[1][1] = sr*sp*sy+cr*cy;
+       matrix[1][2] = cr*sp*sy+-sr*cy;
+       matrix[1][3] = translate[1];
+       matrix[2][0] = -sp;
+       matrix[2][1] = sr*cp;
+       matrix[2][2] = cr*cp;
+       matrix[2][3] = translate[2];
+}
+
 int VectorCompare (vec3_t v1, vec3_t v2)
 {
        int             i;
-       
+
        for (i=0 ; i<3 ; i++)
                if (v1[i] != v2[i])
                        return 0;
-                       
+
        return 1;
 }
 
index 96497960fb508d9fb55a0528d995363b60354cb0..3588e9cc1e9f1b12c31f085b398483f55eb7867e 100644 (file)
--- a/mathlib.h
+++ b/mathlib.h
@@ -8,7 +8,7 @@ of the License, or (at your option) any later version.
 
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 See the GNU General Public License for more details.
 
@@ -19,6 +19,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
 // mathlib.h
 
+#ifndef M_PI
+#define M_PI           3.14159265358979323846  // matches value in gcc v2 math.h
+#endif
+
 typedef float vec_t;
 typedef vec_t vec2_t[2];
 typedef vec_t vec3_t[3];
@@ -27,28 +31,25 @@ typedef vec_t vec5_t[5];
 typedef vec_t vec6_t[6];
 typedef vec_t vec7_t[7];
 typedef vec_t vec8_t[8];
+struct mplane_s;
+extern vec3_t vec3_origin;
 
-typedef        int     fixed4_t;
-typedef        int     fixed8_t;
-typedef        int     fixed16_t;
+extern int nanmask;
+#define        IS_NAN(x) (((*(int *)&x)&nanmask)==nanmask)
 
-#ifndef M_PI
-#define M_PI           3.14159265358979323846  // matches value in gcc v2 math.h
+#define bound(min,num,max) (num >= min ? (num < max ? num : max) : min)
+
+#ifndef min
+#define min(A,B) (A < B ? A : B)
+#define max(A,B) (A > B ? A : B)
 #endif
 
+#define lhrandom(MIN,MAX) ((rand() & 32767) * (((MAX)-(MIN)) * (1.0f / 32767.0f)) + (MIN))
+
 #define DEG2RAD(a) ((a) * ((float) M_PI / 180.0f))
 #define RAD2DEG(a) ((a) * (180.0f / (float) M_PI))
 #define ANGLEMOD(a) (((int) ((a) * (65536.0f / 360.0f)) & 65535) * (360.0f / 65536.0f))
 
-struct mplane_s;
-
-extern vec3_t vec3_origin;
-extern int nanmask;
-
-#define        IS_NAN(x) (((*(int *)&x)&nanmask)==nanmask)
-
-#define bound(min,num,max) (num >= min ? (num < max ? num : max) : min)
-
 #define VectorNegate(a,b) {b[0] = -(a[0]);b[1] = -(a[1]);b[2] = -(a[2]);}
 #define VectorSet(a,b,c,d) {d[0]=(a);d[1]=(b);d[2]=(c);}
 #define VectorClear(a) {a[0]=a[1]=a[2]=0;}
@@ -59,6 +60,7 @@ extern        int nanmask;
 #define CrossProduct(v1,v2,cross) {cross[0] = v1[1]*v2[2] - v1[2]*v2[1];cross[1] = v1[2]*v2[0] - v1[0]*v2[2];cross[2] = v1[0]*v2[1] - v1[1]*v2[0];}
 #define VectorNormalize(v) {float ilength = 1.0f / (float) sqrt(DotProduct(v,v));v[0] *= ilength;v[1] *= ilength;v[2] *= ilength;}
 #define VectorNormalize2(v,dest) {float ilength = 1.0f / (float) sqrt(DotProduct(v,v));dest[0] = v[0] * ilength;dest[1] = v[1] * ilength;dest[2] = v[2] * ilength;}
+#define VectorNormalizeDouble(v) {double ilength = 1.0 / (float) sqrt(DotProduct(v,v));v[0] *= ilength;v[1] *= ilength;v[2] *= ilength;}
 #define VectorDistance2(a, b) ((a[0] - b[0]) * (a[0] - b[0]) + (a[1] - b[1]) * (a[1] - b[1]) + (a[2] - b[2]) * (a[2] - b[2]))
 #define VectorDistance(a, b) (sqrt(VectorDistance2(a,b)))
 #define VectorLength(a) sqrt(DotProduct(a, a))
@@ -77,6 +79,30 @@ extern       int nanmask;
 }
 #define VectorRandom(v) {do{(v)[0] = lhrandom(-1, 1);(v)[1] = lhrandom(-1, 1);(v)[2] = lhrandom(-1, 1);}while(DotProduct(v, v) > 1);}
 
+// LordHavoc: quaternion math, untested, don't know if these are correct,
+// need to add conversion to/from matrices
+
+// returns length of quaternion
+#define qlen(a) ((float) sqrt(a[0]*a[0]+a[1]*a[1]+a[2]*a[2]+a[3]*a[3]))
+// returns squared length of quaternion
+#define qlen2(a) (a[0]*a[0]+a[1]*a[1]+a[2]*a[2]+a[3]*a[3])
+// makes a quaternion from x, y, z, and a rotation angle
+#define QuatMake(x,y,z,r,c) {if (r2 == 0) {(c)[0]=(float) ((x)*sin(r2));c[1]=(float) ((y)*sin(r2));c[2]=((float) (z)*sin(r2));c[3]=(float) 1;} else {float r2 = (r) * 0.5 * (M_PI / 180);(c)[0]=(float) ((x)*sin(r2));c[1]=(float) ((y)*sin(r2));c[2]=((float) (z)*sin(r2));c[3]=(float) (cos(r2));}}
+// makes a quaternion from a vector and a rotation angle
+#define QuatFromVec(a,r,c) QuatMake((a)[0],(a)[1],(a)[2],(r))
+// copies a quaternion
+#define QuatCopy(a,c) {c[0]=a[0];c[1]=a[1];c[2]=a[2];c[3]=a[3];}
+#define QuatSubtract(a,b,c) {c[0]=a[0]-b[0];c[1]=a[1]-b[1];c[2]=a[2]-b[2];c[3]=a[3]-b[3];}
+#define QuatAdd(a,b,c) {c[0]=a[0]+b[0];c[1]=a[1]+b[1];c[2]=a[2]+b[2];c[3]=a[3]+b[3];}
+#define QuatScale(a,b,c) {c[0]=a[0]*b;c[1]=a[1]*b;c[2]=a[2]*b;c[3]=a[3]*b;}
+// FIXME: this is wrong, do some more research on quaternions
+//#define QuatMultiply(a,b,c) {c[0]=a[0]*b[0];c[1]=a[1]*b[1];c[2]=a[2]*b[2];c[3]=a[3]*b[3];}
+// FIXME: this is wrong, do some more research on quaternions
+//#define QuatMultiplyAdd(a,b,d,c) {c[0]=a[0]*b[0]+d[0];c[1]=a[1]*b[1]+d[1];c[2]=a[2]*b[2]+d[2];c[3]=a[3]*b[3]+d[3];}
+#define qdist(a,b) ((float) sqrt((b[0]-a[0])*(b[0]-a[0])+(b[1]-a[1])*(b[1]-a[1])+(b[2]-a[2])*(b[2]-a[2])+(b[3]-a[3])*(b[3]-a[3])))
+#define qdist2(a,b) ((b[0]-a[0])*(b[0]-a[0])+(b[1]-a[1])*(b[1]-a[1])+(b[2]-a[2])*(b[2]-a[2])+(b[3]-a[3])*(b[3]-a[3]))
+
+#define VectorCopy4(a,b) {b[0]=a[0];b[1]=a[1];b[2]=a[2];b[3]=a[3];}
 
 void VectorMASlow (vec3_t veca, float scale, vec3_t vecb, vec3_t vecc);
 
@@ -109,9 +135,14 @@ void FloorDivMod (double numer, double denom, int *quotient, int *rem);
 int GreatestCommonDivisor (int i1, int i2);
 
 void AngleVectors (vec3_t angles, vec3_t forward, vec3_t right, vec3_t up);
+// LordHavoc: proper matrix version of AngleVectors
+void AngleVectorsFLU (vec3_t angles, vec3_t forward, vec3_t left, vec3_t up);
+// LordHavoc: builds a [3][4] matrix
+void AngleMatrix (vec3_t angles, vec3_t translate, vec_t matrix[][4]);
 
 // LordHavoc: like AngleVectors, but taking a forward vector instead of angles, useful!
 void VectorVectors(const vec3_t forward, vec3_t right, vec3_t up);
+void VectorVectorsDouble(const double *forward, double *right, double *up);
 
 void PlaneClassify(struct mplane_s *p);
 
@@ -136,22 +167,17 @@ void PlaneClassify(struct mplane_s *p);
 //#define PlaneDist(point,plane)  (DotProduct((point), (plane)->normal))
 //#define PlaneDiff(point,plane) (DotProduct((point), (plane)->normal) - (plane)->dist)
 
-#define lhrandom(MIN,MAX) ((rand() & 32767) * (((MAX)-(MIN)) * (1.0f / 32767.0f)) + (MIN))
-
-#ifndef min
-#define min(A,B) (A < B ? A : B)
-#define max(A,B) (A > B ? A : B)
-#endif
-
 // LordHavoc: minimal plane structure
 typedef struct
 {
-       float   normal[3], dist;
-} tinyplane_t;
+       float normal[3], dist;
+}
+tinyplane_t;
 
 typedef struct
 {
-       double  normal[3], dist;
-} tinydoubleplane_t;
+       double normal[3], dist;
+}
+tinydoubleplane_t;
 
-void RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point, float degrees );
+void RotatePointAroundVector(vec3_t dst, const vec3_t dir, const vec3_t point, float degrees);
diff --git a/menu.c b/menu.c
index c4d80a5bee9182a751e85657a1027f6d5abd4b59..2d5ba98e0e80b6214d938e1aa1568145dc98d537 100644 (file)
--- a/menu.c
+++ b/menu.c
@@ -958,8 +958,8 @@ void M_Menu_Setup_f (void)
        m_entersound = true;
        strcpy(setup_myname, cl_name.string);
        strcpy(setup_hostname, hostname.string);
-       setup_top = setup_oldtop = ((int)cl_color.value) >> 4;
-       setup_bottom = setup_oldbottom = ((int)cl_color.value) & 15;
+       setup_top = setup_oldtop = cl_color.integer >> 4;
+       setup_bottom = setup_oldbottom = cl_color.integer & 15;
 }
 
 
@@ -1236,7 +1236,7 @@ again:
 //=============================================================================
 /* OPTIONS MENU */
 
-#define        OPTIONS_ITEMS   (vid_menudrawfn ? 24 : 23)
+#define        OPTIONS_ITEMS   (vid_menudrawfn ? 25 : 24)
 
 #define        SLIDER_RANGE    10
 
@@ -1260,38 +1260,42 @@ void M_AdjustSliders (int dir)
                Cvar_SetValue ("viewsize", bound(30, scr_viewsize.value + dir * 10, 120));
                break;
        case 4:
-               Cvar_SetValue ("r_ser", !r_ser.value);
+               Cvar_SetValue ("r_ser", !r_ser.integer);
                break;
 
        case 5: // overbright rendering
-               Cvar_SetValue ("gl_lightmode", !gl_lightmode.value);
+               Cvar_SetValue ("gl_lightmode", !gl_lightmode.integer);
                break;
 
-       case 6: // sky quality
-               Cvar_SetValue ("r_skyquality", bound(0, r_skyquality.value + dir, 4));
+       case 6: // dithering
+               Cvar_SetValue ("gl_dither", !gl_dither.integer);
                break;
 
-       case 7: // hardware gamma
+       case 7: // sky quality
+               Cvar_SetValue ("r_skyquality", bound(0, r_skyquality.integer + dir, 2));
+               break;
+
+       case 8: // hardware gamma
                Cvar_SetValue ("vid_gamma", bound(1, vid_gamma.value + dir * 0.25, 5));
                break;
 
-       case 8: // hardware brightness
+       case 9: // hardware brightness
                Cvar_SetValue ("vid_brightness", bound(1, vid_brightness.value + dir * 0.25, 5));
                break;
 
-       case 9: // hardware contrast
+       case 10:        // hardware contrast
                Cvar_SetValue ("vid_contrast", bound(0.2, vid_contrast.value + dir * 0.08, 1));
                break;
 
-       case 10:        // software brightness
+       case 11:        // software brightness
                Cvar_SetValue ("r_brightness", bound(1, r_brightness.value + dir * 0.25, 5));
                break;
 
-       case 11: // software base brightness
+       case 12: // software base brightness
                Cvar_SetValue ("r_contrast", bound(0.2, r_contrast.value + dir * 0.08, 1));
                break;
 
-       case 12: // music volume
+       case 13: // music volume
 #ifdef _WIN32
                Cvar_SetValue ("bgmvolume", bound(0, bgmvolume.value + dir * 1.0, 1));
 #else
@@ -1299,11 +1303,11 @@ void M_AdjustSliders (int dir)
 #endif
                break;
 
-       case 13: // sfx volume
+       case 14: // sfx volume
                Cvar_SetValue ("volume", bound(0, volume.value + dir * 0.1, 1));
                break;
 
-       case 14: // always run
+       case 15: // always run
                if (cl_forwardspeed.value > 200)
                {
                        Cvar_SetValue ("cl_forwardspeed", 200);
@@ -1316,36 +1320,36 @@ void M_AdjustSliders (int dir)
                }
                break;
 
-       case 15: // lookspring
-               Cvar_SetValue ("lookspring", !lookspring.value);
+       case 16: // lookspring
+               Cvar_SetValue ("lookspring", !lookspring.integer);
                break;
 
-       case 16: // lookstrafe
-               Cvar_SetValue ("lookstrafe", !lookstrafe.value);
+       case 17: // lookstrafe
+               Cvar_SetValue ("lookstrafe", !lookstrafe.integer);
                break;
 
-       case 17: // mouse speed
+       case 18: // mouse speed
                Cvar_SetValue ("sensitivity", bound(1, sensitivity.value + dir * 0.5, 50));
                break;
 
-       case 18: // mouse look
-               Cvar_SetValue ("freelook", !freelook.value);
+       case 19: // mouse look
+               Cvar_SetValue ("freelook", !freelook.integer);
                break;
 
-       case 19: // invert mouse
+       case 20: // invert mouse
                Cvar_SetValue ("m_pitch", -m_pitch.value);
                break;
 
-       case 20: // windowed mouse
-               Cvar_SetValue ("vid_mouse", !vid_mouse.value);
+       case 21: // windowed mouse
+               Cvar_SetValue ("vid_mouse", !vid_mouse.integer);
                break;
 
-       case 21:
-               Cvar_SetValue ("crosshair", bound(0, crosshair.value + dir, 5));
+       case 22:
+               Cvar_SetValue ("crosshair", bound(0, crosshair.integer + dir, 5));
                break;
 
-       case 22: // show framerate
-               Cvar_SetValue ("showfps", !showfps.value);
+       case 23: // show framerate
+               Cvar_SetValue ("showfps", !showfps.integer);
                break;
        }
 }
@@ -1394,9 +1398,10 @@ void M_Options_Draw (void)
        M_Print(16, y, "         Go to console");y += 8;
        M_Print(16, y, "     Reset to defaults");y += 8;
        M_Print(16, y, "           Screen size");M_DrawSlider(220, y, (scr_viewsize.value - 30) /(120 - 30));y += 8;
-       M_Print(16, y, "Hidden Surface Removal");M_DrawCheckbox(220, y, r_ser.value);y += 8;
-       M_Print(16, y, "  Overbright Rendering");M_DrawCheckbox(220, y, gl_lightmode.value);y += 8;
-       M_Print(16, y, "           Sky Quality");M_DrawSlider(220, y, r_skyquality.value / 4);y += 8;
+       M_Print(16, y, "Hidden Surface Removal");M_DrawCheckbox(220, y, r_ser.integer);y += 8;
+       M_Print(16, y, "  Overbright Rendering");M_DrawCheckbox(220, y, gl_lightmode.integer);y += 8;
+       M_Print(16, y, "             Dithering");M_DrawCheckbox(220, y, gl_dither.integer);y += 8;
+       M_Print(16, y, "           Sky Quality");M_DrawSlider(220, y, r_skyquality.value / 2);y += 8;
        M_Print(16, y, "        Hardware Gamma");M_DrawSlider(220, y, (vid_gamma.value - 1) / 4);y += 8;
        M_Print(16, y, "   Hardware Brightness");M_DrawSlider(220, y, (vid_brightness.value - 1) / 4);y += 8;
        M_Print(16, y, "     Hardware Contrast");M_DrawSlider(220, y, (vid_contrast.value - 0.2) / 0.8);y += 8;
@@ -1405,14 +1410,14 @@ void M_Options_Draw (void)
        M_Print(16, y, "       CD Music Volume");M_DrawSlider(220, y, bgmvolume.value);y += 8;
        M_Print(16, y, "          Sound Volume");M_DrawSlider(220, y, volume.value);y += 8;
        M_Print(16, y, "            Always Run");M_DrawCheckbox(220, y, cl_forwardspeed.value > 200);y += 8;
-       M_Print(16, y, "            Lookspring");M_DrawCheckbox(220, y, lookspring.value);y += 8;
-       M_Print(16, y, "            Lookstrafe");M_DrawCheckbox(220, y, lookstrafe.value);y += 8;
+       M_Print(16, y, "            Lookspring");M_DrawCheckbox(220, y, lookspring.integer);y += 8;
+       M_Print(16, y, "            Lookstrafe");M_DrawCheckbox(220, y, lookstrafe.integer);y += 8;
        M_Print(16, y, "           Mouse Speed");M_DrawSlider(220, y, (sensitivity.value - 1)/50);y += 8;
-       M_Print(16, y, "            Mouse Look");M_DrawCheckbox(220, y, freelook.value);y += 8;
+       M_Print(16, y, "            Mouse Look");M_DrawCheckbox(220, y, freelook.integer);y += 8;
        M_Print(16, y, "          Invert Mouse");M_DrawCheckbox(220, y, m_pitch.value < 0);y += 8;
-       M_Print(16, y, "             Use Mouse");M_DrawCheckbox(220, y, vid_mouse.value);y += 8;
+       M_Print(16, y, "             Use Mouse");M_DrawCheckbox(220, y, vid_mouse.integer);y += 8;
        M_Print(16, y, "             Crosshair");M_DrawSlider(220, y, crosshair.value / 5);y += 8;
-       M_Print(16, y, "        Show Framerate");M_DrawCheckbox(220, y, showfps.value);y += 8;
+       M_Print(16, y, "        Show Framerate");M_DrawCheckbox(220, y, showfps.integer);y += 8;
        if (vid_menudrawfn)
                M_Print(16, y, "         Video Options");
        y += 8;
@@ -2327,9 +2332,9 @@ void M_GameOptions_Draw (void)
        M_Print (160, 56, va("%i", maxplayers) );
 
        M_Print (0, 64, "        Game Type");
-       if (!coop.value && !deathmatch.value)
+       if (!coop.integer && !deathmatch.integer)
                Cvar_SetValue("deathmatch", 1);
-       if (coop.value)
+       if (coop.integer)
                M_Print (160, 64, "Cooperative");
        else
                M_Print (160, 64, "Deathmatch");
@@ -2339,7 +2344,7 @@ void M_GameOptions_Draw (void)
        {
                char *msg;
 
-               switch((int)teamplay.value)
+               switch((int)teamplay.integer)
                {
                        case 1: msg = "No Friendly Fire"; break;
                        case 2: msg = "Friendly Fire"; break;
@@ -2355,7 +2360,7 @@ void M_GameOptions_Draw (void)
        {
                char *msg;
 
-               switch((int)teamplay.value)
+               switch((int)teamplay.integer)
                {
                        case 1: msg = "No Friendly Fire"; break;
                        case 2: msg = "Friendly Fire"; break;
@@ -2365,26 +2370,26 @@ void M_GameOptions_Draw (void)
        }
 
        M_Print (0, 80, "            Skill");
-       if (skill.value == 0)
+       if (skill.integer == 0)
                M_Print (160, 80, "Easy difficulty");
-       else if (skill.value == 1)
+       else if (skill.integer == 1)
                M_Print (160, 80, "Normal difficulty");
-       else if (skill.value == 2)
+       else if (skill.integer == 2)
                M_Print (160, 80, "Hard difficulty");
        else
                M_Print (160, 80, "Nightmare difficulty");
 
        M_Print (0, 88, "       Frag Limit");
-       if (fraglimit.value == 0)
+       if (fraglimit.integer == 0)
                M_Print (160, 88, "none");
        else
-               M_Print (160, 88, va("%i frags", (int)fraglimit.value));
+               M_Print (160, 88, va("%i frags", fraglimit.integer));
 
        M_Print (0, 96, "       Time Limit");
-       if (timelimit.value == 0)
+       if (timelimit.integer == 0)
                M_Print (160, 96, "none");
        else
-               M_Print (160, 96, va("%i minutes", (int)timelimit.value));
+               M_Print (160, 96, va("%i minutes", timelimit.integer));
 
        M_Print (0, 112, "         Episode");
        //MED 01/06/97 added hipnotic episodes
@@ -2470,7 +2475,7 @@ void M_NetStart_Change (int dir)
                break;
 
        case 2:
-               if (deathmatch.value) // changing from deathmatch to coop
+               if (deathmatch.integer) // changing from deathmatch to coop
                {
                        Cvar_SetValue ("coop", 1);
                        Cvar_SetValue ("deathmatch", 0);
@@ -2488,26 +2493,26 @@ void M_NetStart_Change (int dir)
                else
                        count = 2;
 
-               Cvar_SetValue ("teamplay", teamplay.value + dir);
-               if (teamplay.value > count)
+               Cvar_SetValue ("teamplay", teamplay.integer + dir);
+               if (teamplay.integer > count)
                        Cvar_SetValue ("teamplay", 0);
-               else if (teamplay.value < 0)
+               else if (teamplay.integer < 0)
                        Cvar_SetValue ("teamplay", count);
                break;
 
        case 4:
-               Cvar_SetValue ("skill", skill.value + dir);
-               if (skill.value > 3)
+               Cvar_SetValue ("skill", skill.integer + dir);
+               if (skill.integer > 3)
                        Cvar_SetValue ("skill", 0);
-               if (skill.value < 0)
+               if (skill.integer < 0)
                        Cvar_SetValue ("skill", 3);
                break;
 
        case 5:
-               Cvar_SetValue ("fraglimit", fraglimit.value + dir*10);
-               if (fraglimit.value > 100)
+               Cvar_SetValue ("fraglimit", fraglimit.integer + dir*10);
+               if (fraglimit.integer > 100)
                        Cvar_SetValue ("fraglimit", 0);
-               if (fraglimit.value < 0)
+               if (fraglimit.integer < 0)
                        Cvar_SetValue ("fraglimit", 100);
                break;
 
@@ -2530,7 +2535,7 @@ void M_NetStart_Change (int dir)
                        count = 4;
                else if (gamemode == GAME_NEHAHRA)
                        count = 4;
-               else if (registered.value)
+               else if (registered.integer)
                        count = 7;
                else
                        count = 2;
index ee6fe6abe1e4905db3e3192874597be7329bca3f..793299d8a5616a3821c8469cc85885bead2e6513 100644 (file)
@@ -22,11 +22,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 static cvar_t r_mipskins = {CVAR_SAVE, "r_mipskins", "0"};
 
-/*
-===============
-Mod_AliasInit
-===============
-*/
 void Mod_AliasInit (void)
 {
        Cvar_RegisterVariable(&r_mipskins);
@@ -37,8 +32,6 @@ static void Mod_Alias_SERAddEntity(void)
        R_Clip_AddBox(currentrenderentity->mins, currentrenderentity->maxs, R_Entity_Callback, currentrenderentity, NULL);
 }
 
-static int posenum;
-
 // LordHavoc: proper bounding box considerations
 static float aliasbboxmin[3], aliasbboxmax[3], modelyawradius, modelradius;
 
@@ -46,7 +39,7 @@ static float vertst[MAXALIASVERTS][2];
 static int vertusage[MAXALIASVERTS];
 static int vertonseam[MAXALIASVERTS];
 static int vertremap[MAXALIASVERTS];
-static unsigned short temptris[MAXALIASTRIS][3];
+static int temptris[MAXALIASTRIS][3];
 
 static void Mod_ConvertAliasVerts (int inverts, vec3_t scale, vec3_t translate, trivertx_t *v, trivertx_t *out)
 {
@@ -57,6 +50,7 @@ static void Mod_ConvertAliasVerts (int inverts, vec3_t scale, vec3_t translate,
        {
                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];
@@ -73,6 +67,7 @@ static void Mod_ConvertAliasVerts (int inverts, vec3_t scale, vec3_t translate,
                dist += temp[2]*temp[2];
                if (modelradius < dist)
                        modelradius = dist;
+
                j = vertremap[i]; // not onseam
                if (j >= 0)
                {
@@ -97,78 +92,75 @@ static void Mod_ConvertAliasVerts (int inverts, vec3_t scale, vec3_t translate,
                }
        }
        if (invalidnormals)
-               Con_Printf("Mod_ConvertAliasVerts: \"%s\", %i invalid normal indices found\n", loadname, invalidnormals);
+               Con_Printf("Mod_ConvertAliasVerts: \"%s\", %i invalid normal indices found\n", loadmodel->name, invalidnormals);
 }
 
-/*
-=================
-Mod_LoadAliasFrame
-=================
-*/
-static void * Mod_LoadAliasFrame (void *pin, maliashdr_t *mheader, int inverts, int outverts, trivertx_t **posevert, animscene_t *scene)
+static void Mod_MDL_LoadFrames (long datapointer, int inverts, int outverts, vec3_t scale, vec3_t translate)
 {
-       trivertx_t              *pinframe;
-       daliasframe_t   *pdaliasframe;
-
-       pdaliasframe = (daliasframe_t *)pin;
-
-       strcpy(scene->name, pdaliasframe->name);
-       scene->firstframe = posenum;
-       scene->framecount = 1;
-       scene->framerate = 10.0f; // unnecessary but...
-       scene->loop = true;
-
-       pinframe = (trivertx_t *)(pdaliasframe + 1);
-
-       Mod_ConvertAliasVerts(inverts, mheader->scale, mheader->scale_origin, pinframe, *posevert);
-       *posevert += outverts;
-       posenum++;
-
-       pinframe += inverts;
-
-       return (void *)pinframe;
-}
-
+       daliasframetype_t       *pframetype;
+       daliasframe_t           *pinframe;
+       daliasgroup_t           *group;
+       daliasinterval_t        *intervals;
+       int                                     i, f, pose, groupframes;
+       float                           interval;
+       animscene_t                     *scene;
+       pose = 0;
+       scene = loadmodel->animscenes;
+       for (f = 0;f < loadmodel->numframes;f++)
+       {
+               pframetype = (daliasframetype_t *)datapointer;
+               datapointer += sizeof(daliasframetype_t);
+               if (LittleLong (pframetype->type) == ALIAS_SINGLE)
+               {
+                       // a single frame is still treated as a group
+                       interval = 0.1f;
+                       groupframes = 1;
+               }
+               else
+               {
+                       // read group header
+                       group = (daliasgroup_t *)datapointer;
+                       datapointer += sizeof(daliasgroup_t);
+                       groupframes = LittleLong (group->numframes);
+
+                       // intervals (time per frame)
+                       intervals = (daliasinterval_t *)datapointer;
+                       datapointer += sizeof(daliasinterval_t) * groupframes;
+
+                       interval = LittleFloat (intervals->interval); // FIXME: support variable framerate groups
+                       if (interval < 0.01f)
+                               Host_Error("Mod_LoadAliasGroup: invalid interval");
+               }
 
-/*
-=================
-Mod_LoadAliasGroup
-=================
-*/
-static void *Mod_LoadAliasGroup (void *pin, maliashdr_t *mheader, int inverts, int outverts, trivertx_t **posevert, animscene_t *scene)
-{
-       int             i, numframes;
-       void    *ptemp;
-       float   interval;
+               // get scene name from first frame
+               pinframe = (daliasframe_t *)datapointer;
 
-       numframes = LittleLong (((daliasgroup_t *)pin)->numframes);
+               strcpy(scene->name, pinframe->name);
+               scene->firstframe = pose;
+               scene->framecount = groupframes;
+               scene->framerate = 1.0f / interval;
+               scene->loop = true;
+               scene++;
 
-       strcpy(scene->name, ((daliasframe_t *) (sizeof(daliasinterval_t) * numframes + sizeof(daliasgroup_t) + (int) pin))->name);
-       scene->firstframe = posenum;
-       scene->framecount = 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");
-       scene->framerate = 1.0f / interval;
-       scene->loop = true;
+               // read frames
+               for (i = 0;i < groupframes;i++)
+               {
+                       pinframe = (daliasframe_t *)datapointer;
+                       datapointer += sizeof(daliasframe_t);
 
-       ptemp = (void *)(((daliasinterval_t *)(((daliasgroup_t *)pin) + 1)) + numframes);
+                       // convert to MD2 frame headers
+                       strcpy(loadmodel->mdlmd2data_frames[pose].name, pinframe->name);
+                       VectorCopy(scale, loadmodel->mdlmd2data_frames[pose].scale);
+                       VectorCopy(translate, loadmodel->mdlmd2data_frames[pose].translate);
 
-       for (i=0 ; i<numframes ; i++)
-       {
-               ((daliasframe_t *)ptemp)++;
-               Mod_ConvertAliasVerts(inverts, mheader->scale, mheader->scale_origin, ptemp, *posevert);
-               *posevert += outverts;
-               posenum++;
-               ptemp = (trivertx_t *)ptemp + inverts;
+                       Mod_ConvertAliasVerts(inverts, scale, translate, (trivertx_t *)datapointer, loadmodel->mdlmd2data_pose + pose * outverts);
+                       datapointer += sizeof(trivertx_t) * inverts;
+                       pose++;
+               }
        }
-
-       return ptemp;
 }
 
-//=========================================================
-
-static rtexture_t *GL_SkinSplitShirt(byte *in, byte *out, int width, int height, unsigned short bits, char *name, int precache)
+static rtexture_t *GL_SkinSplitShirt(byte *in, byte *out, int width, int height, int bits, char *name, int precache)
 {
        int i, pixels, passed;
        byte pixeltest[16];
@@ -193,12 +185,12 @@ static rtexture_t *GL_SkinSplitShirt(byte *in, byte *out, int width, int height,
                out++;
        }
        if (passed)
-               return R_LoadTexture (name, width, height, out - width*height, (r_mipskins.value ? TEXF_MIPMAP : 0) | (precache ? TEXF_PRECACHE : 0));
+               return R_LoadTexture (loadmodel->texturepool, name, width, height, out - width*height, TEXTYPE_QPALETTE, (r_mipskins.integer ? TEXF_MIPMAP : 0) | (precache ? TEXF_PRECACHE : 0));
        else
                return NULL;
 }
 
-static rtexture_t *GL_SkinSplit(byte *in, byte *out, int width, int height, unsigned short bits, char *name, int precache)
+static rtexture_t *GL_SkinSplit(byte *in, byte *out, int width, int height, int bits, char *name, int precache)
 {
        int i, pixels, passed;
        byte pixeltest[16];
@@ -219,253 +211,204 @@ static rtexture_t *GL_SkinSplit(byte *in, byte *out, int width, int height, unsi
                out++;
        }
        if (passed)
-               return R_LoadTexture (name, width, height, out - width*height, (r_mipskins.value ? TEXF_MIPMAP : 0) | (precache ? TEXF_PRECACHE : 0));
+               return R_LoadTexture (loadmodel->texturepool, name, width, height, out - width*height, TEXTYPE_QPALETTE, (r_mipskins.integer ? TEXF_MIPMAP : 0) | (precache ? TEXF_PRECACHE : 0));
        else
                return NULL;
 }
 
-
-static void Mod_LoadSkin (maliashdr_t *mheader, char *basename, byte *skindata, byte *skintemp, int width, int height, rtexture_t **skintex)
+static void Mod_LoadSkin (char *basename, byte *skindata, byte *skintemp, int width, int height, skinframe_t *skinframe)
 {
-       skintex[0] = loadtextureimage(va("%s_normal", basename), 0, 0, false, r_mipskins.value, true);
-       skintex[1] = NULL;
-       skintex[2] = NULL;
-       skintex[3] = loadtextureimage(va("%s_glow"  , basename), 0, 0, false, r_mipskins.value, true);
-       skintex[4] = NULL;
-       if (skintex[0])
+       skinframe->base   = loadtextureimagewithmask(loadmodel->texturepool, va("%s_normal", basename), 0, 0, false, r_mipskins.integer, true);
+       skinframe->fog    = image_masktex;
+       skinframe->pants  = NULL;
+       skinframe->shirt  = NULL;
+       skinframe->glow   = loadtextureimage(loadmodel->texturepool, va("%s_glow"  , basename), 0, 0, false, r_mipskins.integer, true);
+       skinframe->merged = NULL;
+       if (skinframe->base)
        {
-               skintex[1] = loadtextureimage(va("%s_pants" , basename), 0, 0, false, r_mipskins.value, true);
-               skintex[2] = loadtextureimage(va("%s_shirt" , basename), 0, 0, false, r_mipskins.value, true);
+               skinframe->pants  = loadtextureimage(loadmodel->texturepool, va("%s_pants" , basename), 0, 0, false, r_mipskins.integer, true);
+               skinframe->shirt  = loadtextureimage(loadmodel->texturepool, va("%s_shirt" , basename), 0, 0, false, r_mipskins.integer, true);
        }
        else
        {
-               skintex[0] = loadtextureimage(basename, 0, 0, false, true, true);
-               if (!skintex[0])
+               skinframe->base   = loadtextureimagewithmask(loadmodel->texturepool, basename, 0, 0, false, true, true);
+               skinframe->fog    = image_masktex;
+               if (!skinframe->base)
                {
-                       skintex[1] = GL_SkinSplitShirt(skindata, skintemp, width, height, 0x0040, va("%s_pants", basename), false); // pants
-                       skintex[2] = GL_SkinSplitShirt(skindata, skintemp, width, height, 0x0002, va("%s_shirt", basename), false); // shirt
-                       skintex[3] = GL_SkinSplit(skindata, skintemp, width, height, 0xC000, va("%s_glow", basename), true); // glow
-                       if (skintex[1] || skintex[2])
+                       skinframe->pants  = GL_SkinSplitShirt(skindata, skintemp, width, height, 0x0040, va("%s_pants", basename), false); // pants
+                       skinframe->shirt  = GL_SkinSplitShirt(skindata, skintemp, width, height, 0x0002, va("%s_shirt", basename), false); // shirt
+                       skinframe->glow   = GL_SkinSplit     (skindata, skintemp, width, height, 0xC000, va("%s_glow", basename), true); // glow
+                       if (skinframe->pants || skinframe->shirt)
                        {
-                               skintex[0] = GL_SkinSplit(skindata, skintemp, width, height, 0x3FBD, va("%s_normal", basename), false); // normal (no special colors)
-                               skintex[4] = GL_SkinSplit(skindata, skintemp, width, height, 0x3FFF, va("%s_body", basename), true); // body (normal + pants + shirt, but not glow)
+                               skinframe->base   = GL_SkinSplit (skindata, skintemp, width, height, 0x3FBD, va("%s_normal", basename), false); // normal (no special colors)
+                               skinframe->merged = GL_SkinSplit (skindata, skintemp, width, height, 0x3FFF, va("%s_body", basename), true); // body (normal + pants + shirt, but not glow)
                        }
                        else
-                               skintex[0] = GL_SkinSplit(skindata, skintemp, width, height, 0x3FFF, va("%s_base", basename), true); // no special colors
+                               skinframe->base   = GL_SkinSplit (skindata, skintemp, width, height, 0x3FFF, va("%s_base", basename), true); // no special colors
+                       // quake model skins don't have alpha
+                       skinframe->fog = NULL;
                }
        }
-       if (R_TextureHasAlpha(skintex[0]))
-               loadmodel->flags2 |= MODF_TRANSPARENT;
 }
 
-/*
-===============
-Mod_LoadAllSkins
-===============
-*/
-static void *Mod_LoadAllSkins (maliashdr_t *mheader, int numskins, daliasskintype_t *pskintype, int width, int height)
+#define BOUNDI(VALUE,MIN,MAX) if (VALUE < MIN || VALUE >= MAX) Host_Error("model %s has an invalid ##VALUE (%d exceeds %d - %d)\n", loadmodel->name, VALUE, MIN, MAX);
+#define BOUNDF(VALUE,MIN,MAX) if (VALUE < MIN || VALUE >= MAX) Host_Error("model %s has an invalid ##VALUE (%f exceeds %f - %f)\n", loadmodel->name, VALUE, MIN, MAX);
+void Mod_LoadAliasModel (model_t *mod, void *buffer)
 {
-       int             i, j;
-       char    name[32];
-       int             s;
-       byte    *skin;
+       int                                             i, j, version, numverts, totalposes, totalskins, skinwidth, skinheight, totalverts, groupframes, groupskins;
+       mdl_t                                   *pinmodel;
+       stvert_t                                *pinstverts;
+       dtriangle_t                             *pintriangles;
+       daliasskintype_t                *pinskintype;
        daliasskingroup_t               *pinskingroup;
-       int             groupskins;
        daliasskininterval_t    *pinskinintervals;
-       int             skinranges, skincount, *skinrange, skinnum;
-       rtexture_t **skintex;
-       void    *temp;
-       byte    *skintemp = NULL;
+       daliasframetype_t               *pinframetype;
+       daliasgroup_t                   *pinframegroup;
+       float                                   scales, scalet, scale[3], translate[3], interval;
+       long                                    datapointer, startframes, startskins;
+       char                                    name[MAX_QPATH];
+       byte                                    *skintemp = NULL;
+       modelyawradius = 0;
+       modelradius = 0;
 
-       skin = (byte *)(pskintype + 1);
+       datapointer = (long) buffer;
+       pinmodel = (mdl_t *)datapointer;
+       datapointer += sizeof(mdl_t);
 
-       if (numskins < 1 || numskins > MAX_SKINS)
-               Host_Error ("Mod_LoadAliasModel: Invalid # of skins: %d\n", numskins);
+       version = LittleLong (pinmodel->version);
+       if (version != ALIAS_VERSION)
+               Host_Error ("%s has wrong version number (%i should be %i)",
+                                loadmodel->name, version, ALIAS_VERSION);
 
-       s = width * height;
-       skintemp = qmalloc(s);
+       loadmodel->type = mod_alias;
+       loadmodel->aliastype = ALIASTYPE_MDL;
 
-       // 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++)
+       loadmodel->numskins = LittleLong(pinmodel->numskins);
+       BOUNDI(loadmodel->numskins,0,256);
+       skinwidth = LittleLong (pinmodel->skinwidth);
+       BOUNDI(skinwidth,0,4096);
+       skinheight = LittleLong (pinmodel->skinheight);
+       BOUNDI(skinheight,0,4096);
+       loadmodel->numverts = numverts = LittleLong(pinmodel->numverts);
+       BOUNDI(loadmodel->numverts,0,MAXALIASVERTS);
+       loadmodel->numtris = LittleLong(pinmodel->numtris);
+       BOUNDI(loadmodel->numtris,0,MAXALIASTRIS);
+       loadmodel->numframes = LittleLong(pinmodel->numframes);
+       BOUNDI(loadmodel->numframes,0,65536);
+       loadmodel->synctype = LittleLong (pinmodel->synctype);
+       BOUNDI(loadmodel->synctype,0,2);
+       loadmodel->flags = LittleLong (pinmodel->flags);
+
+       for (i = 0;i < 3;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);
-               }
+               scale[i] = LittleFloat (pinmodel->scale[i]);
+               translate[i] = LittleFloat (pinmodel->scale_origin[i]);
        }
-       pskintype = temp;
-
-       skinrange = loadmodel->skinanimrange;
-       skintex = 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++)
+
+       startskins = datapointer;
+       totalskins = 0;
+       for (i = 0;i < loadmodel->numskins;i++)
        {
-               *skinrange++ = skinnum; // start of the range
-               pskintype++;
-               if (pskintype[-1].type == ALIAS_SKIN_SINGLE)
-               {
-                       *skinrange++ = 1; // single skin
-                       skinnum++;
-                       sprintf (name, "%s_%i", loadmodel->name, i);
-                       Mod_LoadSkin(mheader, name, (byte *)pskintype, skintemp, width, height, skintex);
-                       skintex += 5;
-                       pskintype = (daliasskintype_t *)((byte *)(pskintype) + s);
-               }
+               pinskintype = (daliasskintype_t *)datapointer;
+               datapointer += sizeof(daliasskintype_t);
+               if (LittleLong(pinskintype->type) == ALIAS_SKIN_SINGLE)
+                       groupskins = 1;
                else
                {
-                       // animating skin group.  yuck.
-                       pinskingroup = (daliasskingroup_t *)pskintype;
-                       groupskins = LittleLong (pinskingroup->numskins);
-                       pinskinintervals = (daliasskininterval_t *)(pinskingroup + 1);
-
-                       pskintype = (void *)(pinskinintervals + groupskins);
+                       pinskingroup = (daliasskingroup_t *)datapointer;
+                       datapointer += sizeof(daliasskingroup_t);
+                       groupskins = LittleLong(pinskingroup->numskins);
+                       datapointer += sizeof(daliasskininterval_t) * groupskins;
+               }
 
-                       *skinrange++ = groupskins; // number of skins
-                       skinnum += groupskins;
-                       for (j = 0;j < groupskins;j++)
-                       {
-                               sprintf (name, "%s_%i_%i", loadmodel->name, i, j);
-                               Mod_LoadSkin(mheader, name, (byte *)pskintype, skintemp, width, height, skintex);
-                               skintex += 5;
-                               pskintype = (daliasskintype_t *)((byte *)(pskintype) + s);
-                       }
+               for (j = 0;j < groupskins;j++)
+               {
+                       datapointer += skinwidth * skinheight;
+                       totalskins++;
                }
        }
-       loadmodel->numskins = numskins;
-       qfree(skintemp);
 
-       return (void *)pskintype;
-}
+       pinstverts = (stvert_t *)datapointer;
+       datapointer += sizeof(stvert_t) * numverts;
 
-static void *Mod_SkipAllSkins (int numskins, daliasskintype_t *pskintype, int skinsize)
-{
-       int             i;
-       for (i = 0;i < numskins;i++)
+       pintriangles = (dtriangle_t *)datapointer;
+       datapointer += sizeof(dtriangle_t) * loadmodel->numtris;
+
+       startframes = datapointer;
+       totalposes = 0;
+       for (i = 0;i < loadmodel->numframes;i++)
        {
-               pskintype++;
-               if (pskintype[-1].type == ALIAS_SKIN_SINGLE)
-                       (byte *)pskintype += skinsize;
+               pinframetype = (daliasframetype_t *)datapointer;
+               datapointer += sizeof(daliasframetype_t);
+               if (LittleLong (pinframetype->type) == ALIAS_SINGLE)
+                       groupframes = 1;
                else
-                       (byte *)pskintype += (skinsize + sizeof(daliasskininterval_t)) * LittleLong (((daliasskingroup_t *)pskintype)->numskins) + sizeof(daliasskingroup_t);
-       }
-       return pskintype;
-}
-
-//=========================================================================
+               {
+                       pinframegroup = (daliasgroup_t *)datapointer;
+                       datapointer += sizeof(daliasgroup_t);
+                       groupframes = LittleLong(pinframegroup->numframes);
+                       datapointer += sizeof(daliasinterval_t) * groupframes;
+               }
 
-//void GL_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr);
+               for (j = 0;j < groupframes;j++)
+               {
+                       datapointer += sizeof(daliasframe_t);
+                       datapointer += sizeof(trivertx_t) * numverts;
+                       totalposes++;
+               }
+       }
 
-/*
-=================
-Mod_LoadAliasModel
-=================
-*/
-#define BOUNDI(VALUE,MIN,MAX) if (VALUE < MIN || VALUE >= MAX) Host_Error("model %s has an invalid ##VALUE (%d exceeds %d - %d)\n", mod->name, VALUE, MIN, MAX);
-#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, 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;
-       float                           *pouttexcoords, scales, scalet;
-       maliashdr_t                     *mheader;
-       unsigned short          *pouttris;
-       trivertx_t                      *posevert;
-       animscene_t                     *animscenes;
+       // load the skins
+       skintemp = Mem_Alloc(tempmempool, skinwidth * skinheight);
+       loadmodel->skinscenes = Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
+       loadmodel->skinframes = Mem_Alloc(loadmodel->mempool, totalskins * sizeof(skinframe_t));
+       totalskins = 0;
+       datapointer = startskins;
+       for (i = 0;i < loadmodel->numskins;i++)
+       {
+               pinskintype = (daliasskintype_t *)datapointer;
+               datapointer += sizeof(daliasskintype_t);
 
-       modelyawradius = 0;
-       modelradius = 0;
+               if (pinskintype->type == ALIAS_SKIN_SINGLE)
+               {
+                       groupskins = 1;
+                       interval = 0.1f;
+               }
+               else
+               {
+                       pinskingroup = (daliasskingroup_t *)datapointer;
+                       datapointer += sizeof(daliasskingroup_t);
 
-       start = Hunk_LowMark ();
+                       groupskins = LittleLong (pinskingroup->numskins);
 
-       pinmodel = (mdl_t *)buffer;
+                       pinskinintervals = (daliasskininterval_t *)datapointer;
+                       datapointer += sizeof(daliasskininterval_t) * groupskins;
 
-       version = LittleLong (pinmodel->version);
-       if (version != ALIAS_VERSION)
-               Host_Error ("%s has wrong version number (%i should be %i)",
-                                mod->name, version, ALIAS_VERSION);
-
-       mod->type = mod_alias;
-       mod->aliastype = ALIASTYPE_MDL;
-
-       numframes = LittleLong(pinmodel->numframes);
-       BOUNDI(numframes,0,65536);
-       numverts = LittleLong(pinmodel->numverts);
-       BOUNDI(numverts,0,MAXALIASVERTS);
-       numtris = LittleLong(pinmodel->numtris);
-       BOUNDI(numtris,0,MAXALIASTRIS);
-       numskins = LittleLong(pinmodel->numskins);
-       BOUNDI(numskins,0,256);
-       skinwidth = LittleLong (pinmodel->skinwidth);
-       BOUNDI(skinwidth,0,4096);
-       skinheight = LittleLong (pinmodel->skinheight);
-       BOUNDI(skinheight,0,1024);
+                       interval = LittleFloat(pinskinintervals[0].interval);
+                       if (interval < 0.01f)
+                               Host_Error("Mod_LoadAliasModel: invalid interval\n");
+               }
 
-       pskintype = (daliasskintype_t *)&pinmodel[1];
-       pinstverts = (stvert_t *)Mod_SkipAllSkins (numskins, pskintype, skinwidth * skinheight);
-       pintriangles = (dtriangle_t *)&pinstverts[numverts];
-       pframetype = (daliasframetype_t *)&pintriangles[numtris];
+               sprintf(loadmodel->skinscenes[i].name, "skin %i", i);
+               loadmodel->skinscenes[i].firstframe = totalskins;
+               loadmodel->skinscenes[i].framecount = groupskins;
+               loadmodel->skinscenes[i].framerate = 1.0f / interval;
+               loadmodel->skinscenes[i].loop = true;
 
-       numposes = 0;
-       for (i=0 ; i<numframes ; i++)
-       {
-               if ((aliasframetype_t) LittleLong (pframetype->type) == ALIAS_SINGLE)
+               for (j = 0;j < groupskins;j++)
                {
-                       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);
+                       if (groupskins > 1)
+                               sprintf (name, "%s_%i_%i", loadmodel->name, i, j);
+                       else
+                               sprintf (name, "%s_%i", loadmodel->name, i);
+                       Mod_LoadSkin(name, (byte *)datapointer, skintemp, skinwidth, skinheight, loadmodel->skinframes + totalskins);
+                       datapointer += skinwidth * skinheight;
+                       totalskins++;
                }
        }
-
-       // rebuild the model
-       mheader = Hunk_AllocName (sizeof(maliashdr_t), va("%s model header", loadname));
-       mod->flags = LittleLong (pinmodel->flags);
-// endian-adjust and copy the data, starting with the alias model header
-       mheader->numverts = numverts;
-       mod->numtris = mheader->numtris = numtris;
-       mod->numframes = mheader->numframes = numframes;
-       mod->synctype = LittleLong (pinmodel->synctype);
-       BOUNDI(mod->synctype,0,2);
-
-       for (i=0 ; i<3 ; i++)
-       {
-               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
-       pskintype = (daliasskintype_t *)&pinmodel[1];
-       pskintype = Mod_LoadAllSkins(mheader, numskins, pskintype, skinwidth, skinheight);
+       Mem_Free(skintemp);
 
        // store texture coordinates into temporary array, they will be stored after usage is determined (triangle data)
-       pinstverts = (stvert_t *)pskintype;
-
-       // LordHavoc: byteswap and convert stvert data
        scales = 1.0 / skinwidth;
        scalet = 1.0 / skinheight;
        for (i = 0;i < numverts;i++)
@@ -480,14 +423,12 @@ void Mod_LoadAliasModel (model_t *mod, void *buffer)
        }
 
 // load triangle data
-       pouttris = Hunk_AllocName(sizeof(unsigned short[3]) * numtris, va("%s triangles", loadname));
-       mheader->tridata = (int) pouttris - (int) mheader;
-       pintriangles = (dtriangle_t *)&pinstverts[mheader->numverts];
+       loadmodel->mdldata_indices = Mem_Alloc(loadmodel->mempool, sizeof(int[3]) * loadmodel->numtris);
 
        // count the vertices used
        for (i = 0;i < numverts*2;i++)
                vertusage[i] = 0;
-       for (i = 0;i < numtris;i++)
+       for (i = 0;i < loadmodel->numtris;i++)
        {
                temptris[i][0] = LittleLong(pintriangles[i].vertindex[0]);
                temptris[i][1] = LittleLong(pintriangles[i].vertindex[1]);
@@ -516,80 +457,57 @@ void Mod_LoadAliasModel (model_t *mod, void *buffer)
                else
                        vertremap[i] = -1; // not used at all
        }
-       mheader->numverts = totalverts;
+       loadmodel->numverts = totalverts;
        // remap the triangle references
-       for (i = 0;i < numtris;i++)
+       for (i = 0;i < loadmodel->numtris;i++)
        {
-               *pouttris++ = vertremap[temptris[i][0]];
-               *pouttris++ = vertremap[temptris[i][1]];
-               *pouttris++ = vertremap[temptris[i][2]];
+               loadmodel->mdldata_indices[i*3+0] = vertremap[temptris[i][0]];
+               loadmodel->mdldata_indices[i*3+1] = vertremap[temptris[i][1]];
+               loadmodel->mdldata_indices[i*3+2] = vertremap[temptris[i][2]];
        }
        // store the texture coordinates
-       pouttexcoords = Hunk_AllocName(sizeof(float[2]) * totalverts, va("%s texcoords", loadname));
-       mheader->texdata = (int) pouttexcoords - (int) mheader;
+       loadmodel->mdldata_texcoords = Mem_Alloc(loadmodel->mempool, sizeof(float[2]) * totalverts);
        for (i = 0;i < totalverts;i++)
        {
-               *pouttexcoords++ = vertst[i][0];
-               *pouttexcoords++ = vertst[i][1];
+               loadmodel->mdldata_texcoords[i*2+0] = vertst[i][0];
+               loadmodel->mdldata_texcoords[i*2+1] = vertst[i][1];
        }
 
 // load the frames
-       posenum = 0;
-       posevert = Hunk_AllocName(sizeof(trivertx_t) * numposes * totalverts, va("%s vertex data", loadname));
-       mheader->posedata = (int) posevert - (int) mheader;
-       pframetype = (daliasframetype_t *)&pintriangles[numtris];
+       loadmodel->animscenes = Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
+       loadmodel->mdlmd2data_frames = Mem_Alloc(loadmodel->mempool, sizeof(md2frame_t) * totalposes);
+       loadmodel->mdlmd2data_pose = Mem_Alloc(loadmodel->mempool, sizeof(trivertx_t) * totalposes * totalverts);
 
        // LordHavoc: doing proper bbox for model
        aliasbboxmin[0] = aliasbboxmin[1] = aliasbboxmin[2] = 1000000000;
        aliasbboxmax[0] = aliasbboxmax[1] = aliasbboxmax[2] = -1000000000;
 
-       animscenes = Hunk_AllocName(sizeof(animscene_t) * mod->numframes, va("%s sceneinfo", loadname));
-
-       for (i = 0;i < numframes;i++)
-       {
-               if ((aliasframetype_t) LittleLong (pframetype->type) == ALIAS_SINGLE)
-                       pframetype = (daliasframetype_t *) Mod_LoadAliasFrame (pframetype + 1, mheader, numverts, totalverts, &posevert, animscenes + i);
-               else
-                       pframetype = (daliasframetype_t *) Mod_LoadAliasGroup (pframetype + 1, mheader, numverts, totalverts, &posevert, animscenes + i);
-       }
-
-       mod->ofs_scenes = (int) animscenes - (int) mheader;
+       Mod_MDL_LoadFrames (startframes, numverts, totalverts, scale, translate);
 
        // 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;
+       //loadmodel->mins[0] = loadmodel->mins[1] = loadmodel->mins[2] = -16;
+       //loadmodel->maxs[0] = loadmodel->maxs[1] = loadmodel->maxs[2] = 16;
        modelyawradius = sqrt(modelyawradius);
        modelradius = sqrt(modelradius);
-//     mod->modelradius = modelradius;
+//     loadmodel->modelradius = modelradius;
        for (j = 0;j < 3;j++)
        {
-               mod->normalmins[j] = aliasbboxmin[j];
-               mod->normalmaxs[j] = aliasbboxmax[j];
-               mod->rotatedmins[j] = -modelradius;
-               mod->rotatedmaxs[j] = modelradius;
+               loadmodel->normalmins[j] = aliasbboxmin[j];
+               loadmodel->normalmaxs[j] = aliasbboxmax[j];
+               loadmodel->rotatedmins[j] = -modelradius;
+               loadmodel->rotatedmaxs[j] = modelradius;
        }
-       mod->yawmins[0] = mod->yawmins[1] = -(mod->yawmaxs[0] = mod->yawmaxs[1] = modelyawradius);
-       mod->yawmins[2] = mod->normalmins[2];
-       mod->yawmaxs[2] = mod->normalmaxs[2];
-
-       mod->SERAddEntity = Mod_Alias_SERAddEntity;
-       mod->DrawEarly = NULL;
-       mod->DrawLate = R_DrawAliasModel;
-       mod->DrawShadow = NULL;
-
-// move the complete, relocatable alias model to the cache
-       end = Hunk_LowMark ();
-       mod->cachesize = total = end - start;
-
-       Cache_Alloc (&mod->cache, total, loadname);
-       if (!mod->cache.data)
-               return;
-       memcpy (mod->cache.data, mheader, total);
-
-       Hunk_FreeToLowMark (start);
+       loadmodel->yawmins[0] = loadmodel->yawmins[1] = -(loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = modelyawradius);
+       loadmodel->yawmins[2] = loadmodel->normalmins[2];
+       loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
+
+       loadmodel->SERAddEntity = Mod_Alias_SERAddEntity;
+       loadmodel->Draw = R_DrawAliasModel;
+       loadmodel->DrawSky = NULL;
+       loadmodel->DrawShadow = NULL;
 }
 
-static void Mod_ConvertQ2AliasVerts (int numverts, vec3_t scale, vec3_t translate, trivertx_t *v, trivertx_t *out)
+static void Mod_MD2_ConvertVerts (int numverts, vec3_t scale, vec3_t translate, trivertx_t *v, trivertx_t *out)
 {
        int i, invalidnormals = 0;
        float dist;
@@ -621,208 +539,180 @@ static void Mod_ConvertQ2AliasVerts (int numverts, vec3_t scale, vec3_t translat
                }
        }
        if (invalidnormals)
-               Con_Printf("Mod_ConvertQ2AliasVerts: \"%s\", %i invalid normal indices found\n", loadname, invalidnormals);
+               Con_Printf("Mod_MD2_ConvertVerts: \"%s\", %i invalid normal indices found\n", loadmodel->name, invalidnormals);
 }
 
-/*
-=================
-Mod_LoadQ2AliasModel
-=================
-*/
-void Mod_LoadQ2AliasModel (model_t *mod, void *buffer)
+void Mod_MD2_ReadHeader(md2_t *in, int *numglcmds)
 {
-       int                                     i, j, version, size, *pinglcmd, *poutglcmd, start, end, total, framesize;
-       md2_t                           *pinmodel;
-       md2mem_t                        *pheader;
-       md2triangle_t           *pintriangles, *pouttriangles;
-       md2frame_t                      *pinframe;
-       md2frame_t                      *poutframe;
-       char                            *pinskins;
-//     temptris_t                      *tris;
-       animscene_t                     *animscenes;
-
-       modelyawradius = 0;
-       modelradius = 0;
+       int version, end;
 
-       start = Hunk_LowMark ();
-
-//     if (!temptris)
-//             temptris = qmalloc(sizeof(temptris_t) * MD2MAX_TRIANGLES);
-
-       pinmodel = (md2_t *)buffer;
-
-       version = LittleLong (pinmodel->version);
+       version = LittleLong (in->version);
        if (version != MD2ALIAS_VERSION)
                Host_Error ("%s has wrong version number (%i should be %i)",
-                       mod->name, version, MD2ALIAS_VERSION);
-
-       mod->type = mod_alias;
-       mod->aliastype = ALIASTYPE_MD2;
-
-       framesize = sizeof(md2framesize_t) + LittleLong(pinmodel->num_xyz) * sizeof(trivertx_t);
-       // LordHavoc: calculate size for in memory version
-       size = sizeof(md2mem_t)
-                + LittleLong(pinmodel->num_st) * sizeof(md2stvert_t)
-                + LittleLong(pinmodel->num_tris) * sizeof(md2triangle_t)
-                + LittleLong(pinmodel->num_frames) * framesize
-                + LittleLong(pinmodel->num_glcmds) * sizeof(int);
-       if (size <= 0 || size >= MD2MAX_SIZE)
-               Host_Error ("%s is not a valid model", mod->name);
-       pheader = Hunk_AllocName (size, va("%s Quake2 model", loadname));
-
-       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);
-       if (LittleLong(pinmodel->ofs_st <= 0) || LittleLong(pinmodel->ofs_st) >= LittleLong(pinmodel->ofs_end))
-               Host_Error ("%s is not a valid model", mod->name);
-       if (LittleLong(pinmodel->ofs_tris <= 0) || LittleLong(pinmodel->ofs_tris) >= LittleLong(pinmodel->ofs_end))
-               Host_Error ("%s is not a valid model", mod->name);
-       if (LittleLong(pinmodel->ofs_frames <= 0) || LittleLong(pinmodel->ofs_frames) >= LittleLong(pinmodel->ofs_end))
-               Host_Error ("%s is not a valid model", mod->name);
-       if (LittleLong(pinmodel->ofs_glcmds <= 0) || LittleLong(pinmodel->ofs_glcmds) >= LittleLong(pinmodel->ofs_end))
-               Host_Error ("%s is not a valid model", mod->name);
-
-       if (LittleLong(pinmodel->num_tris < 1) || LittleLong(pinmodel->num_tris) > MD2MAX_TRIANGLES)
-               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) > 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) > MAX_SKINS)
-               Host_Error ("%s has invalid number of skins: %i", mod->name, LittleLong(pinmodel->num_skins));
-
-       pheader->framesize = framesize;
-       pheader->num_skins = LittleLong(pinmodel->num_skins);
-       pheader->num_xyz = LittleLong(pinmodel->num_xyz);
-       pheader->num_st = LittleLong(pinmodel->num_st);
-       pheader->num_tris = LittleLong(pinmodel->num_tris);
-       pheader->num_frames = LittleLong(pinmodel->num_frames);
-       pheader->num_glcmds = LittleLong(pinmodel->num_glcmds);
+                       loadmodel->name, version, MD2ALIAS_VERSION);
+
+       loadmodel->type = mod_alias;
+       loadmodel->aliastype = ALIASTYPE_MD2;
+       loadmodel->SERAddEntity = Mod_Alias_SERAddEntity;
+       loadmodel->Draw = R_DrawAliasModel;
+       loadmodel->DrawSky = NULL;
+       loadmodel->DrawShadow = NULL;
+
+       if (LittleLong(in->num_tris < 1) || LittleLong(in->num_tris) > MD2MAX_TRIANGLES)
+               Host_Error ("%s has invalid number of triangles: %i", loadmodel->name, LittleLong(in->num_tris));
+       if (LittleLong(in->num_xyz < 1) || LittleLong(in->num_xyz) > MD2MAX_VERTS)
+               Host_Error ("%s has invalid number of vertices: %i", loadmodel->name, LittleLong(in->num_xyz));
+       if (LittleLong(in->num_frames < 1) || LittleLong(in->num_frames) > MD2MAX_FRAMES)
+               Host_Error ("%s has invalid number of frames: %i", loadmodel->name, LittleLong(in->num_frames));
+       if (LittleLong(in->num_skins < 0) || LittleLong(in->num_skins) > MAX_SKINS)
+               Host_Error ("%s has invalid number of skins: %i", loadmodel->name, LittleLong(in->num_skins));
+
+       end = LittleLong(in->ofs_end);
+       if (LittleLong(in->num_skins) >= 1 && (LittleLong(in->ofs_skins <= 0) || LittleLong(in->ofs_skins) >= end))
+               Host_Error ("%s is not a valid model", loadmodel->name);
+       if (LittleLong(in->ofs_st <= 0) || LittleLong(in->ofs_st) >= end)
+               Host_Error ("%s is not a valid model", loadmodel->name);
+       if (LittleLong(in->ofs_tris <= 0) || LittleLong(in->ofs_tris) >= end)
+               Host_Error ("%s is not a valid model", loadmodel->name);
+       if (LittleLong(in->ofs_frames <= 0) || LittleLong(in->ofs_frames) >= end)
+               Host_Error ("%s is not a valid model", loadmodel->name);
+       if (LittleLong(in->ofs_glcmds <= 0) || LittleLong(in->ofs_glcmds) >= end)
+               Host_Error ("%s is not a valid model", loadmodel->name);
+
+       loadmodel->numskins = LittleLong(in->num_skins);
+       loadmodel->numverts = LittleLong(in->num_xyz);
+//     loadmodel->md2num_st = LittleLong(in->num_st);
+       loadmodel->numtris = LittleLong(in->num_tris);
+       loadmodel->numframes = LittleLong(in->num_frames);
+       *numglcmds = LittleLong(in->num_glcmds);
+
+       loadmodel->flags = 0; // there are no MD2 flags
+       loadmodel->synctype = ST_RAND;
+}
 
+void Mod_MD2_LoadSkins(char *in)
+{
+       int i;
 // load the skins
-       if (pheader->num_skins)
+       if (loadmodel->numskins)
        {
-               rtexture_t **skin;
-               int *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++)
+               loadmodel->skinscenes = Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
+               loadmodel->skinframes = Mem_Alloc(loadmodel->mempool, sizeof(skinframe_t) * loadmodel->numskins);
+               for (i = 0;i < loadmodel->numskins;i++)
                {
-                       *skinrange++ = i;
-                       *skinrange++ = 1;
-                       *skin++ = loadtextureimage (pinskins, 0, 0, true, r_mipskins.value, true);
-                       *skin++ = NULL; // the extra 4 layers are currently unused
-                       *skin++ = NULL;
-                       *skin++ = NULL;
-                       *skin++ = NULL;
-                       pinskins += MD2MAX_SKINNAME;
+                       loadmodel->skinscenes[i].firstframe = i;
+                       loadmodel->skinscenes[i].framecount = 1;
+                       loadmodel->skinscenes[i].loop = true;
+                       loadmodel->skinscenes[i].framerate = 10;
+                       loadmodel->skinframes[i].base = loadtextureimagewithmask (loadmodel->texturepool, in, 0, 0, true, r_mipskins.integer, true);
+                       loadmodel->skinframes[i].fog = image_masktex;
+                       loadmodel->skinframes[i].pants = NULL;
+                       loadmodel->skinframes[i].shirt = NULL;
+                       loadmodel->skinframes[i].glow = NULL;
+                       loadmodel->skinframes[i].merged = NULL;
+                       in += 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;
+/*
+void Mod_MD2_LoadTriangles(md2triangle_t *in)
+{
+       int i, j;
+       loadmodel->md2data_tris = Mem_Alloc(loadmodel->mempool, loadmodel->numtris * sizeof(md2triangle_t));
        // swap the triangle list
-       for (i = 0;i < pheader->num_tris;i++)
+       for (i = 0;i < loadmodel->numtris;i++)
        {
                for (j = 0;j < 3;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);
-                       if (pouttriangles->index_st[j] >= pheader->num_st)
-                               Host_Error ("%s has invalid vertex indices", mod->name);
+                       loadmodel->md2data_tris[i].index_xyz[j] = LittleShort (in[i].index_xyz[j]);
+                       loadmodel->md2data_tris[i].index_st[j] = LittleShort (in[i].index_st[j]);
+                       if (loadmodel->md2data_tris[i].index_xyz[j] >= loadmodel->md2num_xyz)
+                               Host_Error ("%s has invalid vertex indices", loadmodel->name);
+                       if (loadmodel->md2data_tris[i].index_st[j] >= loadmodel->md2num_st)
+                               Host_Error ("%s has invalid vertex indices", loadmodel->name);
                }
-               pintriangles++;
-               pouttriangles++;
        }
+}
+*/
 
+void Mod_MD2_LoadFrames(void *start)
+{
+       int i, j;
+       long datapointer;
+       md2frame_t *pinframe;
        // LordHavoc: doing proper bbox for model
        aliasbboxmin[0] = aliasbboxmin[1] = aliasbboxmin[2] = 1000000000;
        aliasbboxmax[0] = aliasbboxmax[1] = aliasbboxmax[2] = -1000000000;
+       modelyawradius = 0;
+       modelradius = 0;
 
+       datapointer = (long) start;
 // load the frames
-       pinframe = (void*) ((int) pinmodel + LittleLong(pinmodel->ofs_frames));
-       poutframe = (void*) pouttriangles;
-       pheader->ofs_frames = (int) poutframe - (int) pheader;
+       loadmodel->animscenes = Mem_Alloc(loadmodel->mempool, loadmodel->numframes * sizeof(animscene_t));
+       loadmodel->mdlmd2data_frames = Mem_Alloc(loadmodel->mempool, loadmodel->numframes * sizeof(md2frame_t));
+       loadmodel->mdlmd2data_pose = Mem_Alloc(loadmodel->mempool, loadmodel->numverts * loadmodel->numframes * sizeof(trivertx_t));
 
-       animscenes = Hunk_AllocName(sizeof(animscene_t) * mod->numframes, va("%s sceneinfo", loadname));
-
-       for (i = 0;i < pheader->num_frames;i++)
+       for (i = 0;i < loadmodel->numframes;i++)
        {
-               strcpy(poutframe->name, pinframe->name);
+               pinframe = (md2frame_t *)datapointer;
+               datapointer += sizeof(md2frame_t);
+               strcpy(loadmodel->mdlmd2data_frames[i].name, pinframe->name);
                for (j = 0;j < 3;j++)
                {
-                       poutframe->scale[j] = LittleFloat(pinframe->scale[j]);
-                       poutframe->translate[j] = LittleFloat(pinframe->translate[j]);
+                       loadmodel->mdlmd2data_frames[i].scale[j] = LittleFloat(pinframe->scale[j]);
+                       loadmodel->mdlmd2data_frames[i].translate[j] = LittleFloat(pinframe->translate[j]);
                }
-               Mod_ConvertQ2AliasVerts (pheader->num_xyz, poutframe->scale, poutframe->translate, &pinframe->verts[0], &poutframe->verts[0]);
-
-               strcpy(animscenes[i].name, poutframe->name);
-               animscenes[i].firstframe = i;
-               animscenes[i].framecount = 1;
-               animscenes[i].framerate = 10;
-               animscenes[i].loop = true;
-
-               pinframe = (void*) &pinframe->verts[j];
-               poutframe = (void*) &poutframe->verts[j];
+               Mod_MD2_ConvertVerts (loadmodel->numverts, loadmodel->mdlmd2data_frames[i].scale, loadmodel->mdlmd2data_frames[i].translate, (void *)datapointer, &loadmodel->mdlmd2data_pose[i * loadmodel->numverts]);
+               datapointer += loadmodel->numverts * sizeof(trivertx_t);
+
+               strcpy(loadmodel->animscenes[i].name, loadmodel->mdlmd2data_frames[i].name);
+               loadmodel->animscenes[i].firstframe = i;
+               loadmodel->animscenes[i].framecount = 1;
+               loadmodel->animscenes[i].framerate = 10;
+               loadmodel->animscenes[i].loop = true;
        }
 
-       mod->ofs_scenes = (int) animscenes - (int) pheader;
-
        // LordHavoc: model bbox
        modelyawradius = sqrt(modelyawradius);
        modelradius = sqrt(modelradius);
-//     mod->modelradius = modelradius;
+//     loadmodel->modelradius = modelradius;
        for (j = 0;j < 3;j++)
        {
-               mod->normalmins[j] = aliasbboxmin[j];
-               mod->normalmaxs[j] = aliasbboxmax[j];
-               mod->rotatedmins[j] = -modelradius;
-               mod->rotatedmaxs[j] = modelradius;
+               loadmodel->normalmins[j] = aliasbboxmin[j];
+               loadmodel->normalmaxs[j] = aliasbboxmax[j];
+               loadmodel->rotatedmins[j] = -modelradius;
+               loadmodel->rotatedmaxs[j] = modelradius;
        }
-       mod->yawmins[0] = mod->yawmins[1] = -(mod->yawmaxs[0] = mod->yawmaxs[1] = modelyawradius);
-       mod->yawmins[2] = mod->normalmins[2];
-       mod->yawmaxs[2] = mod->normalmaxs[2];
+       loadmodel->yawmins[0] = loadmodel->yawmins[1] = -(loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = modelyawradius);
+       loadmodel->yawmins[2] = loadmodel->normalmins[2];
+       loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
+}
 
+void Mod_MD2_LoadGLCmds(int *in, int numglcmds)
+{
+       int i;
        // load the draw list
-       pinglcmd = (void*) ((int) pinmodel + LittleLong(pinmodel->ofs_glcmds));
-       poutglcmd = (void*) poutframe;
-       pheader->ofs_glcmds = (int) poutglcmd - (int) pheader;
-       for (i = 0;i < pheader->num_glcmds;i++)
-               *poutglcmd++ = LittleLong(*pinglcmd++);
-
-       mod->SERAddEntity = Mod_Alias_SERAddEntity;
-       mod->DrawEarly = NULL;
-       mod->DrawLate = R_DrawAliasModel;
-       mod->DrawShadow = NULL;
-
-// move the complete, relocatable alias model to the cache
-       end = Hunk_LowMark ();
-       mod->cachesize = total = end - start;
-
-       Cache_Alloc (&mod->cache, total, loadname);
-       if (!mod->cache.data)
-               return;
-       memcpy (mod->cache.data, pheader, total);
-
-       Hunk_FreeToLowMark (start);
+       loadmodel->md2data_glcmds = Mem_Alloc(loadmodel->mempool, numglcmds * sizeof(int));
+       for (i = 0;i < numglcmds;i++)
+               loadmodel->md2data_glcmds[i] = LittleLong(in[i]);
 }
 
-static void swapintblock(int *m, int size)
+void Mod_LoadQ2AliasModel (model_t *mod, void *buffer)
+{
+       md2_t *pinmodel;
+       int numglcmds;
+       long base;
+       pinmodel = buffer;
+       base = (long) buffer;
+       Mod_MD2_ReadHeader(pinmodel, &numglcmds);
+       Mod_MD2_LoadSkins((void*)(base + LittleLong(pinmodel->ofs_skins)));
+//     Mod_MD2_LoadTriangles((void*)(base + LittleLong(pinmodel->ofs_tris)));
+       Mod_MD2_LoadFrames((void*)(base + LittleLong(pinmodel->ofs_frames)));
+       Mod_MD2_LoadGLCmds((void*)(base + LittleLong(pinmodel->ofs_glcmds)), numglcmds);
+}
+
+static void zymswapintblock(int *m, int size)
 {
        size /= 4;
        while(size--)
@@ -832,19 +722,16 @@ static void swapintblock(int *m, int size)
        }
 }
 
-void Mod_LoadZymoticModel (model_t *mod, void *buffer)
+void Mod_LoadZymoticModel(model_t *mod, void *buffer)
 {
-       int i, pbase, start, end, total, *skinrange;
-       rtexture_t **texture, **skin;
+       int i, pbase, *bonecount;
+       rtexture_t **texture;
        char *shadername;
        zymtype1header_t *pinmodel, *pheader;
        zymscene_t *scene;
        zymbone_t *bone;
-       animscene_t *animscenes;
        float corner[2], modelradius;
 
-       start = Hunk_LowMark ();
-
        pinmodel = (void *)buffer;
 
        if (memcmp(pinmodel->id, "ZYMOTICMODEL", 12))
@@ -853,117 +740,113 @@ void Mod_LoadZymoticModel (model_t *mod, void *buffer)
        if (BigLong(pinmodel->type) != 1)
                Host_Error ("Mod_LoadZymoticModel: only type 1 (skeletal pose) models are currently supported\n");
 
-       mod->type = mod_alias;
-       mod->aliastype = ALIASTYPE_ZYM;
+       loadmodel->type = mod_alias;
+       loadmodel->aliastype = ALIASTYPE_ZYM;
 
-       pheader = Hunk_AllocName (BigLong(pinmodel->filesize), va("%s Zymotic model", loadname));
+       loadmodel->zymdata_header = pheader = Mem_Alloc(loadmodel->mempool, BigLong(pinmodel->filesize));
 
        pbase = (int) pheader;
 
        memcpy(pheader, pinmodel, BigLong(pinmodel->filesize));
 
        // byteswap header
-       memcpy(pheader->id, pinmodel->id, 12);
-       pheader->type = BigLong(pheader->type);
-       pheader->filesize = BigLong(pheader->filesize);
-       pheader->mins[0] = BigFloat(pheader->mins[0]);
-       pheader->mins[1] = BigFloat(pheader->mins[1]);
-       pheader->mins[2] = BigFloat(pheader->mins[2]);
-       pheader->maxs[0] = BigFloat(pheader->maxs[0]);
-       pheader->maxs[1] = BigFloat(pheader->maxs[1]);
-       pheader->maxs[2] = BigFloat(pheader->maxs[2]);
-       pheader->radius = BigFloat(pheader->radius);
-       pheader->numverts = BigLong(pheader->numverts);
-       pheader->numtris = BigLong(pheader->numtris);
-       pheader->numshaders = BigLong(pheader->numshaders);
-       pheader->numbones = BigLong(pheader->numbones);
-       pheader->numscenes = BigLong(pheader->numscenes);
-
-
-       pheader->lump_scenes.start = BigLong(pheader->lump_scenes.start);pheader->lump_scenes.length = BigLong(pheader->lump_scenes.length);
-       pheader->lump_poses.start = BigLong(pheader->lump_poses.start);pheader->lump_poses.length = BigLong(pheader->lump_poses.length);
-       pheader->lump_bones.start = BigLong(pheader->lump_bones.start);pheader->lump_bones.length = BigLong(pheader->lump_bones.length);
-       pheader->lump_vertbonecounts.start = BigLong(pheader->lump_vertbonecounts.start);pheader->lump_vertbonecounts.length = BigLong(pheader->lump_vertbonecounts.length);
-       pheader->lump_verts.start = BigLong(pheader->lump_verts.start);pheader->lump_verts.length = BigLong(pheader->lump_verts.length);
-       pheader->lump_texcoords.start = BigLong(pheader->lump_texcoords.start);pheader->lump_texcoords.length = BigLong(pheader->lump_texcoords.length);
-       pheader->lump_render.start = BigLong(pheader->lump_render.start);pheader->lump_render.length = BigLong(pheader->lump_render.length);
-       pheader->lump_shaders.start = BigLong(pheader->lump_shaders.start);pheader->lump_shaders.length = BigLong(pheader->lump_shaders.length);
-       pheader->lump_trizone.start = BigLong(pheader->lump_trizone.start);pheader->lump_trizone.length = BigLong(pheader->lump_trizone.length);
-
-       mod->flags = 0; // there are no flags
-       mod->numframes = pheader->numscenes;
-       mod->synctype = ST_SYNC;
-       mod->numtris = pheader->numtris;
+#define SWAPLONG(var) var = BigLong(var)
+#define SWAPFLOAT(var) var = BigFloat(var)
+#define SWAPVEC(var) SWAPFLOAT(var[0]);SWAPFLOAT(var[1]);SWAPFLOAT(var[2])
+       SWAPLONG(pheader->type);
+       SWAPLONG(pheader->filesize);
+       SWAPVEC(pheader->mins);
+       SWAPVEC(pheader->maxs);
+       SWAPFLOAT(pheader->radius);
+       SWAPLONG(pheader->numverts);
+       SWAPLONG(pheader->numtris);
+       SWAPLONG(pheader->numshaders);
+       SWAPLONG(pheader->numbones);
+       SWAPLONG(pheader->numscenes);
+
+#define SWAPLUMPINFO(var) SWAPLONG(pheader->lump_##var.start);SWAPLONG(pheader->lump_##var.length)
+       SWAPLUMPINFO(scenes);
+       SWAPLUMPINFO(poses);
+       SWAPLUMPINFO(bones);
+       SWAPLUMPINFO(vertbonecounts);
+       SWAPLUMPINFO(verts);
+       SWAPLUMPINFO(texcoords);
+       SWAPLUMPINFO(render);
+       SWAPLUMPINFO(shaders);
+       SWAPLUMPINFO(trizone);
+
+       loadmodel->flags = 0; // there are no flags
+       loadmodel->numframes = pheader->numscenes;
+       loadmodel->synctype = ST_SYNC;
+       loadmodel->numtris = pheader->numtris;
 
        // FIXME: add skin support and texturing and shaders and...
-// load the skins
-       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;
-       *skinrange++ = 0;
-       *skinrange++ = 1;
-       *skin++ = NULL;
-       *skin++ = NULL;
-       *skin++ = NULL;
-       *skin++ = NULL;
-       *skin++ = NULL;
+       loadmodel->skinscenes = Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) + sizeof(skinframe_t));
+       loadmodel->skinscenes[0].firstframe = 0;
+       loadmodel->skinscenes[0].framecount = 1;
+       loadmodel->skinscenes[0].loop = true;
+       loadmodel->skinscenes[0].framerate = 10;
+       loadmodel->skinframes = (void *)(loadmodel->skinscenes + 1);
+       loadmodel->skinframes->base = NULL;
+       loadmodel->skinframes->fog = NULL;
+       loadmodel->skinframes->pants = NULL;
+       loadmodel->skinframes->shirt = NULL;
+       loadmodel->skinframes->glow = NULL;
+       loadmodel->skinframes->merged = NULL;
        loadmodel->numskins = 1;
 
        // go through the lumps, swapping things
 
 //     zymlump_t lump_scenes; // zymscene_t scene[numscenes]; // name and other information for each scene (see zymscene struct)
        scene = (void *) (pheader->lump_scenes.start + pbase);
-       animscenes = Hunk_AllocName(sizeof(animscene_t) * mod->numframes, va("%s sceneinfo", loadname));
+       loadmodel->animscenes = Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
        for (i = 0;i < pheader->numscenes;i++)
        {
-               scene->mins[0] = BigFloat(scene->mins[0]);
-               scene->mins[1] = BigFloat(scene->mins[1]);
-               scene->mins[2] = BigFloat(scene->mins[2]);
-               scene->maxs[0] = BigFloat(scene->maxs[0]);
-               scene->maxs[1] = BigFloat(scene->maxs[1]);
-               scene->maxs[2] = BigFloat(scene->maxs[2]);
-               scene->radius = BigFloat(scene->radius);
-               scene->framerate = BigFloat(scene->framerate);
-               scene->flags = BigLong(scene->flags);
-               scene->start = BigLong(scene->start);
-               scene->length = BigLong(scene->length);
-
-               memcpy(animscenes[i].name, scene->name, 32);
-               animscenes[i].firstframe = scene->start;
-               animscenes[i].framecount = scene->length;
-               animscenes[i].framerate = scene->framerate;
-               animscenes[i].loop = (scene->flags & ZYMSCENEFLAG_NOLOOP) == 0;
+               SWAPVEC(scene->mins);
+               SWAPVEC(scene->maxs);
+               SWAPFLOAT(scene->radius);
+               SWAPFLOAT(scene->framerate);
+               SWAPLONG(scene->flags);
+               SWAPLONG(scene->start);
+               SWAPLONG(scene->length);
+
+               memcpy(loadmodel->animscenes[i].name, scene->name, 32);
+               loadmodel->animscenes[i].firstframe = scene->start;
+               loadmodel->animscenes[i].framecount = scene->length;
+               loadmodel->animscenes[i].framerate = scene->framerate;
+               loadmodel->animscenes[i].loop = (scene->flags & ZYMSCENEFLAG_NOLOOP) == 0;
 
                scene++;
        }
-       mod->ofs_scenes = (int) animscenes - pbase;
 
 //     zymlump_t lump_poses; // float pose[numposes][numbones][3][4]; // animation data
-       swapintblock((void *) (pheader->lump_poses.start + pbase), pheader->lump_poses.length);
+       zymswapintblock((void *) (pheader->lump_poses.start + pbase), pheader->lump_poses.length);
 
 //     zymlump_t lump_bones; // zymbone_t bone[numbones];
        bone = (void *) (pheader->lump_bones.start + pbase);
        for (i = 0;i < pheader->numbones;i++)
        {
-               bone->flags = BigLong(bone->flags);
-               bone->parent = BigLong(bone->parent);
-               bone++;
+               SWAPLONG(bone[i].flags);
+               SWAPLONG(bone[i].parent);
+               if (bone[i].parent >= i)
+                       Host_Error("Mod_LoadZymoticModel: bone[i].parent >= i\n");
        }
 
 //     zymlump_t lump_vertbonecounts; // int vertbonecounts[numvertices]; // how many bones influence each vertex (separate mainly to make this compress better)
-       swapintblock((void *) (pheader->lump_vertbonecounts.start + pbase), pheader->lump_vertbonecounts.length);
+       zymswapintblock((void *) (pheader->lump_vertbonecounts.start + pbase), pheader->lump_vertbonecounts.length);
+       bonecount = (void *) (pheader->lump_vertbonecounts.start + pbase);
+       for (i = 0;i < pheader->numbones;i++)
+               if (bonecount[i] < 1)
+                       Host_Error("Mod_LoadZymoticModel: bone vertex count < 1\n");
 
 //     zymlump_t lump_verts; // zymvertex_t vert[numvertices]; // see vertex struct
-       swapintblock((void *) (pheader->lump_verts.start + pbase), pheader->lump_verts.length);
+       zymswapintblock((void *) (pheader->lump_verts.start + pbase), pheader->lump_verts.length);
 
 //     zymlump_t lump_texcoords; // float texcoords[numvertices][2];
-       swapintblock((void *) (pheader->lump_texcoords.start + pbase), pheader->lump_texcoords.length);
+       zymswapintblock((void *) (pheader->lump_texcoords.start + pbase), pheader->lump_texcoords.length);
 
 //     zymlump_t lump_render; // int renderlist[rendersize]; // sorted by shader with run lengths (int count), shaders are sequentially used, each run can be used with glDrawElements (each triangle is 3 int indices)
-       swapintblock((void *) (pheader->lump_render.start + pbase), pheader->lump_render.length);
+       zymswapintblock((void *) (pheader->lump_render.start + pbase), pheader->lump_render.length);
 
 //     zymlump_t lump_shaders; // char shadername[numshaders][32]; // shaders used on this model
        shadername = (void *) (pheader->lump_shaders.start + pbase);
@@ -971,46 +854,35 @@ void Mod_LoadZymoticModel (model_t *mod, void *buffer)
        for (i = 0;i < pheader->numshaders;i++)
        {
                rtexture_t *rt;
-               rt = loadtextureimage(shadername, 0, 0, true, r_mipskins.value, true);
+               rt = loadtextureimage(loadmodel->texturepool, shadername, 0, 0, true, r_mipskins.integer, true);
                shadername += 32;
                *texture++ = rt; // reuse shader name list for texture pointers
        }
 
 //     zymlump_t lump_trizone; // byte trizone[numtris]; // see trizone explanation
-       swapintblock((void *) (pheader->lump_trizone.start + pbase), pheader->lump_trizone.length);
+       zymswapintblock((void *) (pheader->lump_trizone.start + pbase), pheader->lump_trizone.length);
 
        // model bbox
        modelradius = pheader->radius;
-//     mod->modelradius = pheader->radius;
+//     loadmodel->modelradius = pheader->radius;
        for (i = 0;i < 3;i++)
        {
-               mod->normalmins[i] = pheader->mins[i];
-               mod->normalmaxs[i] = pheader->maxs[i];
-               mod->rotatedmins[i] = -modelradius;
-               mod->rotatedmaxs[i] = modelradius;
+               loadmodel->normalmins[i] = pheader->mins[i];
+               loadmodel->normalmaxs[i] = pheader->maxs[i];
+               loadmodel->rotatedmins[i] = -modelradius;
+               loadmodel->rotatedmaxs[i] = modelradius;
        }
-       corner[0] = max(fabs(mod->normalmins[0]), fabs(mod->normalmaxs[0]));
-       corner[1] = max(fabs(mod->normalmins[1]), fabs(mod->normalmaxs[1]));
-       mod->yawmaxs[0] = mod->yawmaxs[1] = sqrt(corner[0]*corner[0]+corner[1]*corner[1]);
-       if (mod->yawmaxs[0] > modelradius)
-               mod->yawmaxs[0] = mod->yawmaxs[1] = modelradius;
-       mod->yawmins[0] = mod->yawmins[1] = -mod->yawmaxs[0];
-       mod->yawmins[2] = mod->normalmins[2];
-       mod->yawmaxs[2] = mod->normalmaxs[2];
-
-       mod->SERAddEntity = Mod_Alias_SERAddEntity;
-       mod->DrawEarly = NULL;
-       mod->DrawLate = R_DrawAliasModel;
-       mod->DrawShadow = NULL;
-
-// move the complete, relocatable alias model to the cache
-       end = Hunk_LowMark ();
-       mod->cachesize = total = end - start;
-
-       Cache_Alloc (&mod->cache, total, loadname);
-       if (!mod->cache.data)
-               return;
-       memcpy (mod->cache.data, pheader, total);
-
-       Hunk_FreeToLowMark (start);
+       corner[0] = max(fabs(loadmodel->normalmins[0]), fabs(loadmodel->normalmaxs[0]));
+       corner[1] = max(fabs(loadmodel->normalmins[1]), fabs(loadmodel->normalmaxs[1]));
+       loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = sqrt(corner[0]*corner[0]+corner[1]*corner[1]);
+       if (loadmodel->yawmaxs[0] > modelradius)
+               loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = modelradius;
+       loadmodel->yawmins[0] = loadmodel->yawmins[1] = -loadmodel->yawmaxs[0];
+       loadmodel->yawmins[2] = loadmodel->normalmins[2];
+       loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
+
+       loadmodel->SERAddEntity = Mod_Alias_SERAddEntity;
+       loadmodel->Draw = R_DrawAliasModel;
+       loadmodel->DrawSky = NULL;
+       loadmodel->DrawShadow = NULL;
 }
index 3d628cd2d642be929964ad39d4841bf1956363ad..935bd5467697dbe5d9fef4ba5fc5a050ab61d21c 100644 (file)
@@ -79,19 +79,6 @@ typedef struct {
        float           size;
 } daliashdr_t;
 
-typedef struct
-{
-       vec3_t          scale;
-       vec3_t          scale_origin;
-       int                     numverts;
-       int                     numtris;
-       int                     numframes;
-       int                     numposes;
-       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
@@ -107,7 +94,6 @@ typedef struct
 // LordHavoc: grabbed this from the Q2 utility source,
 // renamed a things to avoid conflicts
 
-#define MD2IDALIASHEADER               (('2'<<24)+('P'<<16)+('D'<<8)+'I')
 #define MD2ALIAS_VERSION       8
 
 #define        MD2MAX_TRIANGLES        4096
@@ -134,17 +120,8 @@ 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[1];       // variable sized
 } md2frame_t;
 
-// must match md2frame_t, this is just used for sizeof()
-typedef struct
-{
-       float           scale[3];       // multiply byte verts by this
-       float           translate[3];   // then add this
-} md2framesize_t;
-
-
 // the glcmd format:
 // a positive integer starts a tristrip command, followed by that many
 // vertex structures.
@@ -174,26 +151,10 @@ typedef struct
        int                     ofs_st;                 // byte offset from start for stverts
        int                     ofs_tris;               // offset for dtriangles
        int                     ofs_frames;             // offset for first frame
-       int                     ofs_glcmds;     
+       int                     ofs_glcmds;
        int                     ofs_end;                // end of file
 } md2_t;
 
-typedef struct
-{
-       int                     framesize;              // byte size of each frame
-
-       int                     num_skins;
-       int                     num_xyz;
-       int                     num_st;                 // greater than num_xyz for seams
-       int                     num_tris;
-       int                     num_glcmds;             // dwords in strip/fan command list
-       int                     num_frames;
-
-       int                     ofs_tris;               // offset for dtriangles
-       int                     ofs_frames;             // offset for first frame
-       int                     ofs_glcmds;     
-} md2mem_t;
-
 #define ALIASTYPE_MDL 1
 #define ALIASTYPE_MD2 2
 #define ALIASTYPE_ZYM 3
index b005563b02b4630bdd9d04c91a5c7e9c5de5c697..54324fabacbed2f224ccb97efaf3a41633def2f4 100644 (file)
@@ -22,11 +22,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 byte mod_novis[(MAX_MAP_LEAFS + 7)/ 8];
 
-qboolean       hlbsp; // LordHavoc: true if it is a HalfLife BSP file (version 30)
-
-cvar_t gl_subdivide_size = {CVAR_SAVE, "gl_subdivide_size", "128"};
+cvar_t r_subdivide_size = {CVAR_SAVE, "r_subdivide_size", "128"};
 cvar_t halflifebsp = {0, "halflifebsp", "0"};
 cvar_t r_novis = {0, "r_novis", "0"};
+cvar_t r_miplightmaps = {CVAR_SAVE, "r_miplightmaps", "0"};
+cvar_t r_lightmaprgba = {0, "r_lightmaprgba", "1"};
+cvar_t r_vertexsurfacesthreshold = {CVAR_SAVE, "r_vertexsurfacesthreshold", "48"};
 
 /*
 ===============
@@ -35,9 +36,12 @@ Mod_BrushInit
 */
 void Mod_BrushInit (void)
 {
-       Cvar_RegisterVariable (&gl_subdivide_size);
-       Cvar_RegisterVariable (&halflifebsp);
-       Cvar_RegisterVariable (&r_novis);
+       Cvar_RegisterVariable(&r_subdivide_size);
+       Cvar_RegisterVariable(&halflifebsp);
+       Cvar_RegisterVariable(&r_novis);
+       Cvar_RegisterVariable(&r_miplightmaps);
+       Cvar_RegisterVariable(&r_lightmaprgba);
+       Cvar_RegisterVariable(&r_vertexsurfacesthreshold);
        memset(mod_novis, 0xff, sizeof(mod_novis));
 }
 
@@ -55,16 +59,33 @@ mleaf_t *Mod_PointInLeaf (vec3_t p, model_t *model)
 {
        mnode_t         *node;
 
+       Mod_CheckLoaded(model);
 //     if (!model || !model->nodes)
 //             Sys_Error ("Mod_PointInLeaf: bad model");
 
-       node = model->nodes;
-       do
+       // LordHavoc: modified to start at first clip node,
+       // in other words: first node of the (sub)model
+       node = model->nodes + model->hulls[0].firstclipnode;
+       while (node->contents == 0)
                node = node->children[(node->plane->type < 3 ? p[node->plane->type] : DotProduct (p,node->plane->normal)) < node->plane->dist];
-       while (node->contents == 0);
 
        return (mleaf_t *)node;
 }
+
+void Mod_FindNonSolidLocation(vec3_t pos, model_t *mod)
+{
+       if (Mod_PointInLeaf(pos, mod)->contents != CONTENTS_SOLID) return;
+       pos[0]-=1;if (Mod_PointInLeaf(pos, mod)->contents != CONTENTS_SOLID) return;
+       pos[0]+=2;if (Mod_PointInLeaf(pos, mod)->contents != CONTENTS_SOLID) return;
+       pos[0]-=1;
+       pos[1]-=1;if (Mod_PointInLeaf(pos, mod)->contents != CONTENTS_SOLID) return;
+       pos[1]+=2;if (Mod_PointInLeaf(pos, mod)->contents != CONTENTS_SOLID) return;
+       pos[1]-=1;
+       pos[2]-=1;if (Mod_PointInLeaf(pos, mod)->contents != CONTENTS_SOLID) return;
+       pos[2]+=2;if (Mod_PointInLeaf(pos, mod)->contents != CONTENTS_SOLID) return;
+       pos[2]-=1;
+}
+
 /*
 mleaf_t *Mod_PointInLeaf (vec3_t p, model_t *model)
 {
@@ -141,21 +162,16 @@ static byte *Mod_DecompressVis (byte *in, model_t *model)
 
 byte *Mod_LeafPVS (mleaf_t *leaf, model_t *model)
 {
-       if (r_novis.value || leaf == model->leafs || leaf->compressed_vis == NULL)
+       if (r_novis.integer || leaf == model->leafs || leaf->compressed_vis == NULL)
                return mod_novis;
        return Mod_DecompressVis (leaf->compressed_vis, model);
 }
 
-rtexture_t *r_notexture;
-texture_t r_notexture_mip;
-
 void Mod_SetupNoTexture(void)
 {
        int             x, y;
        byte    pix[16][16][4];
 
-       // create a simple checkerboard texture for the default
-       // LordHavoc: redesigned this to remove reliance on the palette and texture_t
        for (y = 0;y < 16;y++)
        {
                for (x = 0;x < 16;x++)
@@ -177,14 +193,12 @@ void Mod_SetupNoTexture(void)
                }
        }
 
-       r_notexture = R_LoadTexture("notexture", 16, 16, &pix[0][0][0], TEXF_MIPMAP | TEXF_RGBA);
-
-       strcpy(r_notexture_mip.name, "notexture");
-       r_notexture_mip.width = 16;
-       r_notexture_mip.height = 16;
-       r_notexture_mip.transparent = false;
-       r_notexture_mip.texture = r_notexture;
-       r_notexture_mip.glowtexture = NULL;
+       memset(&loadmodel->notexture, 0, sizeof(texture_t));
+       strcpy(loadmodel->notexture.name, "notexture");
+       loadmodel->notexture.width = 16;
+       loadmodel->notexture.height = 16;
+       loadmodel->notexture.flags = 0;
+       loadmodel->notexture.texture = R_LoadTexture(loadmodel->texturepool, "notexture", 16, 16, &pix[0][0][0], TEXTYPE_RGBA, TEXF_MIPMAP);
 }
 
 /*
@@ -198,7 +212,10 @@ static void Mod_LoadTextures (lump_t *l)
        miptex_t                *dmiptex;
        texture_t               *tx, *tx2, *anims[10], *altanims[10];
        dmiptexlump_t   *m;
-       byte                    *data, *mtdata;
+       byte                    *data, *mtdata, *data2;
+       char                    name[256];
+
+       Mod_SetupNoTexture();
 
        if (!l->filelen)
        {
@@ -207,11 +224,11 @@ static void Mod_LoadTextures (lump_t *l)
        }
 
        m = (dmiptexlump_t *)(mod_base + l->fileofs);
-       
+
        m->nummiptex = LittleLong (m->nummiptex);
 
        loadmodel->numtextures = m->nummiptex;
-       loadmodel->textures = Hunk_AllocName (m->nummiptex * sizeof(*loadmodel->textures), va("%s texture headers", loadname));
+       loadmodel->textures = Mem_Alloc(loadmodel->mempool, m->nummiptex * sizeof(*loadmodel->textures));
 
        // just to work around bounds checking when debugging with it (array index out of bounds error thing)
        dofs = m->dataofs;
@@ -236,7 +253,7 @@ static void Mod_LoadTextures (lump_t *l)
                if ((mtwidth & 15) || (mtheight & 15))
                        Host_Error ("Texture %s is not 16 aligned", dmiptex->name);
                // LordHavoc: rewriting the map texture loader for GLQuake
-               tx = Hunk_AllocName (sizeof(texture_t), va("%s textures", loadname));
+               tx = Mem_Alloc(loadmodel->mempool, sizeof(texture_t));
                memset(tx, 0, sizeof(texture_t));
                tx->anim_total = 0;
                tx->alternate_anims = NULL;
@@ -255,137 +272,146 @@ static void Mod_LoadTextures (lump_t *l)
 
                if (!tx->name[0])
                {
-                       Con_Printf("warning: unnamed texture in %s\n", loadname);
+                       Con_Printf("warning: unnamed texture in %s\n", loadmodel->name);
                        sprintf(tx->name, "unnamed%i", i);
                }
 
-               tx->transparent = false;
-               data = loadimagepixels(tx->name, false, 0, 0);
-               if (data)
+               tx->width = mtwidth;
+               tx->height = mtheight;
+               tx->texture = NULL;
+               tx->glowtexture = NULL;
+               tx->fogtexture = NULL;
+
+               if (!loadmodel->ishlbsp && !strncmp(tx->name,"sky",3) && mtwidth == 256 && mtheight == 128) // LordHavoc: HL sky textures are entirely unrelated
                {
-                       if (!hlbsp && !strncmp(tx->name,"sky",3) && image_width == 256 && image_height == 128) // LordHavoc: HL sky textures are entirely unrelated
-                       {
-                               tx->width = 0;
-                               tx->height = 0;
-                               tx->transparent = false;
-                               tx->texture = NULL;
-                               tx->glowtexture = NULL;
-                               R_InitSky (data, 4);
-                       }
-                       else
+                       data = loadimagepixels(tx->name, false, 0, 0);
+                       if (data)
                        {
-                               tx->width = mtwidth;
-                               tx->height = mtheight;
-                               tx->transparent = Image_CheckAlpha(data, image_width * image_height, true);
-                               tx->texture = R_LoadTexture (tx->name, image_width, image_height, data, TEXF_MIPMAP | (tx->transparent ? TEXF_ALPHA : 0) | TEXF_RGBA | TEXF_PRECACHE);
-                               tx->glowtexture = NULL;
+                               if (image_width == 256 && image_height == 128)
+                               {
+                                       if (loadmodel->isworldmodel)
+                                               R_InitSky (data, 4);
+                                       Mem_Free(data);
+                               }
+                               else
+                               {
+                                       Mem_Free(data);
+                                       Host_Error("Mod_LoadTextures: replacement sky image must be 256x128 pixels\n");
+                               }
                        }
-                       qfree(data);
+                       else if (loadmodel->isworldmodel)
+                               R_InitSky (mtdata, 1);
+               }
+               else if ((tx->texture = loadtextureimagewithmask(loadmodel->texturepool, tx->name, 0, 0, false, true, true)))
+               {
+                       tx->fogtexture = image_masktex;
+                       strcpy(name, tx->name);
+                       strcat(name, "_glow");
+                       tx->glowtexture = loadtextureimage(loadmodel->texturepool, name, 0, 0, false, true, true);
                }
                else
                {
-                       if (hlbsp)
+                       if (loadmodel->ishlbsp)
                        {
-                               if (mtdata) // texture included
+                               if (mtdata && (data = W_ConvertWAD3Texture(dmiptex)))
                                {
-                                       data = W_ConvertWAD3Texture(dmiptex);
-                                       if (data)
+                                       // texture included
+                                       tx->texture = R_LoadTexture (loadmodel->texturepool, tx->name, image_width, image_height, data, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE);
+                                       if (R_TextureHasAlpha(tx->texture))
                                        {
-                                               tx->width = mtwidth;
-                                               tx->height = mtheight;
-                                               tx->transparent = Image_CheckAlpha(data, mtwidth * mtheight, true);
-                                               tx->texture = R_LoadTexture (tx->name, mtwidth, mtheight, data, TEXF_MIPMAP | (tx->transparent ? TEXF_ALPHA : 0) | TEXF_RGBA | TEXF_PRECACHE);
-                                               tx->glowtexture = NULL;
-                                               qfree(data);
+                                               // make mask texture
+                                               for (j = 0;j < image_width * image_height;j++)
+                                                       data[j*4+0] = data[j*4+1] = data[j*4+2] = 255;
+                                               strcpy(name, tx->name);
+                                               strcat(name, "_fog");
+                                               tx->fogtexture = R_LoadTexture (loadmodel->texturepool, name, image_width, image_height, data, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE);
                                        }
+                                       Mem_Free(data);
                                }
-                               if (!data)
+                               else if ((data = W_GetTexture(tx->name)))
                                {
-                                       data = W_GetTexture(tx->name);
                                        // get the size from the wad texture
-                                       if (data)
+                                       tx->width = image_width;
+                                       tx->height = image_height;
+                                       tx->texture = R_LoadTexture (loadmodel->texturepool, tx->name, image_width, image_height, data, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE);
+                                       if (R_TextureHasAlpha(tx->texture))
                                        {
-                                               tx->width = image_width;
-                                               tx->height = image_height;
-                                               tx->transparent = Image_CheckAlpha(data, image_width * image_height, true);
-                                               tx->texture = R_LoadTexture (tx->name, image_width, image_height, data, TEXF_MIPMAP | (tx->transparent ? TEXF_ALPHA : 0) | TEXF_RGBA | TEXF_PRECACHE);
-                                               tx->glowtexture = NULL;
-                                               qfree(data);
+                                               // make mask texture
+                                               for (j = 0;j < image_width * image_height;j++)
+                                                       data[j*4+0] = data[j*4+1] = data[j*4+2] = 255;
+                                               strcpy(name, tx->name);
+                                               strcat(name, "_fog");
+                                               tx->fogtexture = R_LoadTexture (loadmodel->texturepool, name, image_width, image_height, data, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE);
                                        }
+                                       Mem_Free(data);
                                }
-                               if (!data)
+                               else
                                {
                                        tx->width = 16;
                                        tx->height = 16;
-                                       tx->transparent = false;
-                                       tx->texture = r_notexture;
-                                       tx->glowtexture = NULL;
+                                       tx->texture = loadmodel->notexture.texture;
                                }
                        }
                        else
                        {
-                               if (!strncmp(tx->name,"sky",3) && mtwidth == 256 && mtheight == 128)
-                               {
-                                       tx->width = mtwidth;
-                                       tx->height = mtheight;
-                                       tx->transparent = false;
-                                       tx->texture = NULL;
-                                       tx->glowtexture = NULL;
-                                       R_InitSky (mtdata, 1);
-                               }
-                               else
+                               if (mtdata) // texture included
                                {
-                                       if (mtdata) // texture included
+                                       int fullbrights;
+                                       data = mtdata;
+                                       fullbrights = false;
+                                       if (r_fullbrights.value && tx->name[0] != '*')
                                        {
-                                               int fullbrights;
-                                               data = mtdata;
-                                               tx->width = mtwidth;
-                                               tx->height = mtheight;
-                                               tx->transparent = false;
-                                               fullbrights = false;
-                                               if (r_fullbrights.value && tx->name[0] != '*')
+                                               for (j = 0;j < tx->width*tx->height;j++)
                                                {
-                                                       for (j = 0;j < tx->width*tx->height;j++)
+                                                       if (data[j] >= 224) // fullbright
                                                        {
-                                                               if (data[j] >= 224) // fullbright
-                                                               {
-                                                                       fullbrights = true;
-                                                                       break;
-                                                               }
+                                                               fullbrights = true;
+                                                               break;
                                                        }
                                                }
-                                               if (fullbrights)
-                                               {
-                                                       char name[64];
-                                                       byte *data2;
-                                                       data2 = qmalloc(tx->width*tx->height);
-                                                       for (j = 0;j < tx->width*tx->height;j++)
-                                                               data2[j] = data[j] >= 224 ? 0 : data[j]; // no fullbrights
-                                                       tx->texture = R_LoadTexture (tx->name, tx->width, tx->height, data2, TEXF_MIPMAP | TEXF_PRECACHE);
-                                                       strcpy(name, tx->name);
-                                                       strcat(name, "_glow");
-                                                       for (j = 0;j < tx->width*tx->height;j++)
-                                                               data2[j] = data[j] >= 224 ? data[j] : 0; // only fullbrights
-                                                       tx->glowtexture = R_LoadTexture (name, tx->width, tx->height, data2, TEXF_MIPMAP | TEXF_PRECACHE);
-                                                       qfree(data2);
-                                               }
-                                               else
-                                               {
-                                                       tx->texture = R_LoadTexture (tx->name, tx->width, tx->height, data, TEXF_MIPMAP | TEXF_PRECACHE);
-                                                       tx->glowtexture = NULL;
-                                               }
                                        }
-                                       else // no texture, and no external replacement texture was found
+                                       if (fullbrights)
                                        {
-                                               tx->width = 16;
-                                               tx->height = 16;
-                                               tx->transparent = false;
-                                               tx->texture = r_notexture;
-                                               tx->glowtexture = NULL;
+                                               data2 = Mem_Alloc(tempmempool, tx->width*tx->height);
+                                               for (j = 0;j < tx->width*tx->height;j++)
+                                                       data2[j] = data[j] >= 224 ? 0 : data[j]; // no fullbrights
+                                               tx->texture = R_LoadTexture (loadmodel->texturepool, tx->name, tx->width, tx->height, data2, TEXTYPE_QPALETTE, TEXF_MIPMAP | TEXF_PRECACHE);
+                                               strcpy(name, tx->name);
+                                               strcat(name, "_glow");
+                                               for (j = 0;j < tx->width*tx->height;j++)
+                                                       data2[j] = data[j] >= 224 ? data[j] : 0; // only fullbrights
+                                               tx->glowtexture = R_LoadTexture (loadmodel->texturepool, name, tx->width, tx->height, data2, TEXTYPE_QPALETTE, TEXF_MIPMAP | TEXF_PRECACHE);
+                                               Mem_Free(data2);
                                        }
+                                       else
+                                               tx->texture = R_LoadTexture (loadmodel->texturepool, tx->name, tx->width, tx->height, data, TEXTYPE_QPALETTE, TEXF_MIPMAP | TEXF_PRECACHE);
+                               }
+                               else // no texture, and no external replacement texture was found
+                               {
+                                       tx->width = 16;
+                                       tx->height = 16;
+                                       tx->texture = loadmodel->notexture.texture;
                                }
                        }
                }
+
+               if (tx->name[0] == '*')
+               {
+                       tx->flags |= (SURF_DRAWTURB | SURF_LIGHTBOTHSIDES);
+                       // LordHavoc: some turbulent textures should be fullbright and solid
+                       if (!strncmp(tx->name,"*lava",5)
+                        || !strncmp(tx->name,"*teleport",9)
+                        || !strncmp(tx->name,"*rift",5)) // Scourge of Armagon texture
+                               tx->flags |= (SURF_DRAWFULLBRIGHT | SURF_DRAWNOALPHA | SURF_CLIPSOLID);
+               }
+               else if (tx->name[0] == 's' && tx->name[1] == 'k' && tx->name[2] == 'y')
+                       tx->flags |= (SURF_DRAWSKY | SURF_CLIPSOLID);
+               else
+               {
+                       tx->flags |= SURF_LIGHTMAP;
+                       if (!R_TextureHasAlpha(tx->texture))
+                               tx->flags |= SURF_CLIPSOLID;
+               }
        }
 
 //
@@ -464,9 +490,9 @@ static void Mod_LoadLighting (lump_t *l)
        byte d;
        char litfilename[1024];
        loadmodel->lightdata = NULL;
-       if (hlbsp) // LordHavoc: load the colored lighting data straight
+       if (loadmodel->ishlbsp) // LordHavoc: load the colored lighting data straight
        {
-               loadmodel->lightdata = Hunk_AllocName ( l->filelen, va("%s lightmaps", loadname));
+               loadmodel->lightdata = Mem_Alloc(loadmodel->mempool, l->filelen);
                memcpy (loadmodel->lightdata, mod_base + l->fileofs, l->filelen);
        }
        else // LordHavoc: bsp version 29 (normal white lighting)
@@ -475,28 +501,39 @@ static void Mod_LoadLighting (lump_t *l)
                strcpy(litfilename, loadmodel->name);
                COM_StripExtension(litfilename, litfilename);
                strcat(litfilename, ".lit");
-               data = (byte*) COM_LoadHunkFile (litfilename, false);
+               data = (byte*) COM_LoadFile (litfilename, false);
                if (data)
                {
-                       if (data[0] == 'Q' && data[1] == 'L' && data[2] == 'I' && data[3] == 'T')
+                       if (loadsize > 8 && data[0] == 'Q' && data[1] == 'L' && data[2] == 'I' && data[3] == 'T')
                        {
                                i = LittleLong(((int *)data)[1]);
                                if (i == 1)
                                {
                                        Con_DPrintf("%s loaded", litfilename);
-                                       loadmodel->lightdata = data + 8;
+                                       loadmodel->lightdata = Mem_Alloc(loadmodel->mempool, loadsize - 8);
+                                       memcpy(loadmodel->lightdata, data + 8, loadsize - 8);
+                                       Mem_Free(data);
                                        return;
                                }
                                else
+                               {
                                        Con_Printf("Unknown .lit file version (%d)\n", i);
+                                       Mem_Free(data);
+                               }
                        }
                        else
-                               Con_Printf("Corrupt .lit file (old version?), ignoring\n");
+                       {
+                               if (loadsize == 8)
+                                       Con_Printf("Empty .lit file, ignoring\n");
+                               else
+                                       Con_Printf("Corrupt .lit file (old version?), ignoring\n");
+                               Mem_Free(data);
+                       }
                }
                // LordHavoc: oh well, expand the white lighting data
                if (!l->filelen)
                        return;
-               loadmodel->lightdata = Hunk_AllocName ( l->filelen*3, va("%s lightmaps", loadname));
+               loadmodel->lightdata = Mem_Alloc(loadmodel->mempool, l->filelen*3);
                in = loadmodel->lightdata + l->filelen*2; // place the file at the end, so it will not be overwritten until the very last write
                out = loadmodel->lightdata;
                memcpy (in, mod_base + l->fileofs, l->filelen);
@@ -523,10 +560,73 @@ static void Mod_LoadVisibility (lump_t *l)
                loadmodel->visdata = NULL;
                return;
        }
-       loadmodel->visdata = Hunk_AllocName ( l->filelen, va("%s visdata", loadname));
+       loadmodel->visdata = Mem_Alloc(loadmodel->mempool, l->filelen);
        memcpy (loadmodel->visdata, mod_base + l->fileofs, l->filelen);
 }
 
+// used only for HalfLife maps
+void Mod_ParseWadsFromEntityLump(char *data)
+{
+       char key[128], value[4096];
+       char wadname[128];
+       int i, j, k;
+       if (!data)
+               return;
+       data = COM_Parse(data);
+       if (!data)
+               return; // error
+       if (com_token[0] != '{')
+               return; // error
+       while (1)
+       {
+               data = COM_Parse(data);
+               if (!data)
+                       return; // error
+               if (com_token[0] == '}')
+                       break; // end of worldspawn
+               if (com_token[0] == '_')
+                       strcpy(key, com_token + 1);
+               else
+                       strcpy(key, com_token);
+               while (key[strlen(key)-1] == ' ') // remove trailing spaces
+                       key[strlen(key)-1] = 0;
+               data = COM_Parse(data);
+               if (!data)
+                       return; // error
+               strcpy(value, com_token);
+               if (!strcmp("wad", key)) // for HalfLife maps
+               {
+                       if (loadmodel->ishlbsp)
+                       {
+                               j = 0;
+                               for (i = 0;i < 4096;i++)
+                                       if (value[i] != ';' && value[i] != '\\' && value[i] != '/' && value[i] != ':')
+                                               break;
+                               if (value[i])
+                               {
+                                       for (;i < 4096;i++)
+                                       {
+                                               // ignore path - the \\ check is for HalfLife... stupid windoze 'programmers'...
+                                               if (value[i] == '\\' || value[i] == '/' || value[i] == ':')
+                                                       j = i+1;
+                                               else if (value[i] == ';' || value[i] == 0)
+                                               {
+                                                       k = value[i];
+                                                       value[i] = 0;
+                                                       strcpy(wadname, "textures/");
+                                                       strcat(wadname, &value[j]);
+                                                       W_LoadTextureWadFile (wadname, false);
+                                                       j = i+1;
+                                                       if (!k)
+                                                               break;
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+}
+
 /*
 =================
 Mod_LoadEntities
@@ -539,11 +639,10 @@ static void Mod_LoadEntities (lump_t *l)
                loadmodel->entities = NULL;
                return;
        }
-       loadmodel->entities = Hunk_AllocName ( l->filelen, va("%s entities", loadname));
+       loadmodel->entities = Mem_Alloc(loadmodel->mempool, l->filelen);
        memcpy (loadmodel->entities, mod_base + l->fileofs, l->filelen);
-
-       if (isworldmodel)
-               CL_ParseEntityLump(loadmodel->entities);
+       if (loadmodel->ishlbsp)
+               Mod_ParseWadsFromEntityLump(loadmodel->entities);
 }
 
 
@@ -562,7 +661,7 @@ static void Mod_LoadVertexes (lump_t *l)
        if (l->filelen % sizeof(*in))
                Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
        count = l->filelen / sizeof(*in);
-       out = Hunk_AllocName ( count*sizeof(*out), va("%s vertices", loadname));
+       out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
 
        loadmodel->vertexes = out;
        loadmodel->numvertexes = count;
@@ -590,7 +689,7 @@ static void Mod_LoadSubmodels (lump_t *l)
        if (l->filelen % sizeof(*in))
                Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
        count = l->filelen / sizeof(*in);
-       out = Hunk_AllocName ( count*sizeof(*out), va("%s submodels", loadname));
+       out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
 
        loadmodel->submodels = out;
        loadmodel->numsubmodels = count;
@@ -627,7 +726,7 @@ static void Mod_LoadEdges (lump_t *l)
        if (l->filelen % sizeof(*in))
                Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
        count = l->filelen / sizeof(*in);
-       out = Hunk_AllocName ( (count + 1) * sizeof(*out), va("%s edges", loadname));
+       out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
 
        loadmodel->edges = out;
        loadmodel->numedges = count;
@@ -655,36 +754,32 @@ static void Mod_LoadTexinfo (lump_t *l)
        if (l->filelen % sizeof(*in))
                Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
        count = l->filelen / sizeof(*in);
-       out = Hunk_AllocName ( count*sizeof(*out), va("%s texinfo", loadname));
+       out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
 
        loadmodel->texinfo = out;
        loadmodel->numtexinfo = count;
 
-       for ( i=0 ; i<count ; i++, in++, out++)
+       for (i = 0;i < count;i++, in++, out++)
        {
-               for (k=0 ; k<2 ; k++)
-                       for (j=0 ; j<4 ; j++)
+               for (k = 0;k < 2;k++)
+                       for (j = 0;j < 4;j++)
                                out->vecs[k][j] = LittleFloat (in->vecs[k][j]);
 
                miptex = LittleLong (in->miptex);
                out->flags = LittleLong (in->flags);
 
                if (!loadmodel->textures)
-               {
-                       out->texture = &r_notexture_mip;        // checkerboard texture
-                       out->flags = 0;
-               }
+                       out->texture = &loadmodel->notexture;
                else
                {
+                       if (miptex < 0)
+                               Host_Error ("miptex < 0");
                        if (miptex >= loadmodel->numtextures)
                                Host_Error ("miptex >= loadmodel->numtextures");
                        out->texture = loadmodel->textures[miptex];
-                       if (!out->texture)
-                       {
-                               out->texture = &r_notexture_mip; // checkerboard texture
-                               out->flags = 0;
-                       }
                }
+               if (!out->texture)
+                       out->texture = &loadmodel->notexture;
        }
 }
 
@@ -703,8 +798,8 @@ static void CalcSurfaceExtents (msurface_t *s)
        mtexinfo_t      *tex;
        int             bmins[2], bmaxs[2];
 
-       mins[0] = mins[1] = 999999;
-       maxs[0] = maxs[1] = -99999;
+       mins[0] = mins[1] = 999999999;
+       maxs[0] = maxs[1] = -999999999;
 
        tex = s->texinfo;
 
@@ -715,10 +810,10 @@ static void CalcSurfaceExtents (msurface_t *s)
                        v = &loadmodel->vertexes[loadmodel->edges[e].v[0]];
                else
                        v = &loadmodel->vertexes[loadmodel->edges[-e].v[1]];
-               
+
                for (j=0 ; j<2 ; j++)
                {
-                       val = v->position[0] * tex->vecs[j][0] + 
+                       val = v->position[0] * tex->vecs[j][0] +
                                v->position[1] * tex->vecs[j][1] +
                                v->position[2] * tex->vecs[j][2] +
                                tex->vecs[j][3];
@@ -730,7 +825,7 @@ static void CalcSurfaceExtents (msurface_t *s)
        }
 
        for (i=0 ; i<2 ; i++)
-       {       
+       {
                bmins[i] = floor(mins[i]/16);
                bmaxs[i] = ceil(maxs[i]/16);
 
@@ -742,7 +837,311 @@ static void CalcSurfaceExtents (msurface_t *s)
        }
 }
 
-void GL_SubdivideSurface (msurface_t *fa);
+
+void BoundPoly (int numverts, float *verts, vec3_t mins, vec3_t maxs)
+{
+       int             i, j;
+       float   *v;
+
+       mins[0] = mins[1] = mins[2] = 9999;
+       maxs[0] = maxs[1] = maxs[2] = -9999;
+       v = verts;
+       for (i = 0;i < numverts;i++)
+       {
+               for (j = 0;j < 3;j++, v++)
+               {
+                       if (*v < mins[j])
+                               mins[j] = *v;
+                       if (*v > maxs[j])
+                               maxs[j] = *v;
+               }
+       }
+}
+
+#define MAX_SUBDIVPOLYTRIANGLES 4096
+#define MAX_SUBDIVPOLYVERTS (MAX_SUBDIVPOLYTRIANGLES * 3)
+
+static int subdivpolyverts, subdivpolytriangles;
+static int subdivpolyindex[MAX_SUBDIVPOLYTRIANGLES][3];
+static float subdivpolyvert[MAX_SUBDIVPOLYVERTS][3];
+
+static int subdivpolylookupvert(vec3_t v)
+{
+       int i;
+       for (i = 0;i < subdivpolyverts;i++)
+               if (subdivpolyvert[i][0] == v[0]
+                && subdivpolyvert[i][1] == v[1]
+                && subdivpolyvert[i][2] == v[2])
+                       return i;
+       if (subdivpolyverts >= MAX_SUBDIVPOLYVERTS)
+               Host_Error("SubDividePolygon: ran out of vertices in buffer, please increase your r_subdivide_size");
+       VectorCopy(v, subdivpolyvert[subdivpolyverts]);
+       return subdivpolyverts++;
+}
+
+static void SubdividePolygon (int numverts, float *verts)
+{
+       int             i, i1, i2, i3, f, b, c, p;
+       vec3_t  mins, maxs, front[256], back[256];
+       float   m, *pv, *cv, dist[256], frac;
+
+       if (numverts > 250)
+               Host_Error ("SubdividePolygon: ran out of verts in buffer");
+
+       BoundPoly (numverts, verts, mins, maxs);
+
+       for (i = 0;i < 3;i++)
+       {
+               m = (mins[i] + maxs[i]) * 0.5;
+               m = r_subdivide_size.value * floor (m/r_subdivide_size.value + 0.5);
+               if (maxs[i] - m < 8)
+                       continue;
+               if (m - mins[i] < 8)
+                       continue;
+
+               // cut it
+               for (cv = verts, c = 0;c < numverts;c++, cv += 3)
+                       dist[c] = cv[i] - m;
+
+               f = b = 0;
+               for (p = numverts - 1, c = 0, pv = verts + p * 3, cv = verts;c < numverts;p = c, c++, pv = cv, cv += 3)
+               {
+                       if (dist[p] >= 0)
+                       {
+                               VectorCopy (pv, front[f]);
+                               f++;
+                       }
+                       if (dist[p] <= 0)
+                       {
+                               VectorCopy (pv, back[b]);
+                               b++;
+                       }
+                       if (dist[p] == 0 || dist[c] == 0)
+                               continue;
+                       if ( (dist[p] > 0) != (dist[c] > 0) )
+                       {
+                               // clip point
+                               frac = dist[p] / (dist[p] - dist[c]);
+                               front[f][0] = back[b][0] = pv[0] + frac * (cv[0] - pv[0]);
+                               front[f][1] = back[b][1] = pv[1] + frac * (cv[1] - pv[1]);
+                               front[f][2] = back[b][2] = pv[2] + frac * (cv[2] - pv[2]);
+                               f++;
+                               b++;
+                       }
+               }
+
+               SubdividePolygon (f, front[0]);
+               SubdividePolygon (b, back[0]);
+               return;
+       }
+
+       i1 = subdivpolylookupvert(verts);
+       i2 = subdivpolylookupvert(verts + 3);
+       for (i = 2;i < numverts;i++)
+       {
+               if (subdivpolytriangles >= MAX_SUBDIVPOLYTRIANGLES)
+               {
+                       Con_Printf("SubdividePolygon: ran out of triangles in buffer, please increase your r_subdivide_size\n");
+                       return;
+               }
+
+               i3 = subdivpolylookupvert(verts + i * 3);
+               subdivpolyindex[subdivpolytriangles][0] = i1;
+               subdivpolyindex[subdivpolytriangles][1] = i2;
+               subdivpolyindex[subdivpolytriangles][2] = i3;
+               i2 = i3;
+               subdivpolytriangles++;
+       }
+}
+
+/*
+================
+Mod_GenerateWarpMesh
+
+Breaks a polygon up along axial 64 unit
+boundaries so that turbulent and sky warps
+can be done reasonably.
+================
+*/
+void Mod_GenerateWarpMesh (msurface_t *surf)
+{
+       int                             i, j;
+       surfvertex_t    *v;
+       surfmesh_t              *mesh;
+
+       subdivpolytriangles = 0;
+       subdivpolyverts = 0;
+       SubdividePolygon (surf->poly_numverts, surf->poly_verts);
+
+       mesh = &surf->mesh;
+       mesh->numverts = subdivpolyverts;
+       mesh->numtriangles = subdivpolytriangles;
+       if (mesh->numtriangles < 1)
+               Host_Error("Mod_GenerateWarpMesh: no triangles?\n");
+       mesh->index = Mem_Alloc(loadmodel->mempool, mesh->numtriangles * sizeof(int[3]) + mesh->numverts * sizeof(surfvertex_t));
+       mesh->vertex = (surfvertex_t *)((long) mesh->index + mesh->numtriangles * sizeof(int[3]));
+       memset(mesh->vertex, 0, mesh->numverts * sizeof(surfvertex_t));
+
+       for (i = 0;i < mesh->numtriangles;i++)
+       {
+               for (j = 0;j < 3;j++)
+               {
+                       mesh->index[i*3+j] = subdivpolyindex[i][j];
+                       //if (mesh->index[i] < 0 || mesh->index[i] >= mesh->numverts)
+                       //      Host_Error("Mod_GenerateWarpMesh: invalid index generated\n");
+               }
+       }
+
+       for (i = 0, v = mesh->vertex;i < subdivpolyverts;i++, v++)
+       {
+               VectorCopy(subdivpolyvert[i], v->v);
+               v->st[0] = DotProduct (v->v, surf->texinfo->vecs[0]);
+               v->st[1] = DotProduct (v->v, surf->texinfo->vecs[1]);
+       }
+}
+
+void Mod_GenerateVertexLitMesh (msurface_t *surf)
+{
+       int                             i, is, it, *index, smax, tmax;
+       float                   *in, s, t;
+       surfvertex_t    *out;
+       surfmesh_t              *mesh;
+
+       //surf->flags |= SURF_LIGHTMAP;
+       smax = surf->extents[0] >> 4;
+       tmax = surf->extents[1] >> 4;
+       surf->lightmaptexturestride = 0;
+       surf->lightmaptexture = NULL;
+
+       mesh = &surf->mesh;
+       mesh->numverts = surf->poly_numverts;
+       mesh->numtriangles = surf->poly_numverts - 2;
+       mesh->index = Mem_Alloc(loadmodel->mempool, mesh->numtriangles * sizeof(int[3]) + mesh->numverts * sizeof(surfvertex_t));
+       mesh->vertex = (surfvertex_t *)((long) mesh->index + mesh->numtriangles * sizeof(int[3]));
+       memset(mesh->vertex, 0, mesh->numverts * sizeof(surfvertex_t));
+
+       index = mesh->index;
+       for (i = 0;i < mesh->numtriangles;i++)
+       {
+               *index++ = 0;
+               *index++ = i + 1;
+               *index++ = i + 2;
+       }
+
+       for (i = 0, in = surf->poly_verts, out = mesh->vertex;i < mesh->numverts;i++, in += 3, out++)
+       {
+               VectorCopy (in, out->v);
+
+               s = DotProduct (out->v, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3];
+               t = DotProduct (out->v, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3];
+
+               out->st[0] = s / surf->texinfo->texture->width;
+               out->st[1] = t / surf->texinfo->texture->height;
+
+               s = (s + 8 - surf->texturemins[0]) * (1.0 / 16.0);
+               t = (t + 8 - surf->texturemins[1]) * (1.0 / 16.0);
+
+               // lightmap coordinates
+               out->uv[0] = 0;
+               out->uv[1] = 0;
+
+               // LordHavoc: calc lightmap data offset for vertex lighting to use
+               is = (int) s;
+               it = (int) t;
+               is = bound(0, is, smax);
+               it = bound(0, it, tmax);
+               out->lightmapoffset = ((it * (smax+1) + is) * 3);
+       }
+}
+
+void Mod_GenerateLightmappedMesh (msurface_t *surf)
+{
+       int                             i, is, it, *index, smax, tmax;
+       float                   *in, s, t, xbase, ybase, xscale, yscale;
+       surfvertex_t    *out;
+       surfmesh_t              *mesh;
+
+       surf->flags |= SURF_LIGHTMAP;
+       smax = surf->extents[0] >> 4;
+       tmax = surf->extents[1] >> 4;
+       if (r_miplightmaps.integer)
+       {
+               surf->lightmaptexturestride = (surf->extents[0]>>4)+1;
+               surf->lightmaptexture = R_ProceduralTexture(loadmodel->texturepool, NULL, surf->lightmaptexturestride, (surf->extents[1]>>4)+1, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_MIPMAP/* | TEXF_PRECACHE*/, NULL, NULL, 0);
+       }
+       else
+       {
+               surf->lightmaptexturestride = R_CompatibleFragmentWidth((surf->extents[0]>>4)+1, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, 0);
+               surf->lightmaptexture = R_ProceduralTexture(loadmodel->texturepool, NULL, surf->lightmaptexturestride, (surf->extents[1]>>4)+1, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_FRAGMENT/* | TEXF_PRECACHE*/, NULL, NULL, 0);
+       }
+//     surf->lightmaptexture = R_LoadTexture(loadmodel->texturepool, va("lightmap%08x", lightmapnum), surf->lightmaptexturestride, (surf->extents[1]>>4)+1, NULL, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_FRAGMENT | TEXF_PRECACHE);
+//     surf->lightmaptexture = R_LoadTexture(loadmodel->texturepool, va("lightmap%08x", lightmapnum), surf->lightmaptexturestride, (surf->extents[1]>>4)+1, NULL, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_PRECACHE);
+       R_GetFragmentLocation(surf->lightmaptexture, NULL, NULL, &xbase, &ybase, &xscale, &yscale);
+       xscale = (xscale - xbase) * 16.0 / ((surf->extents[0] & ~15) + 16);
+       yscale = (yscale - ybase) * 16.0 / ((surf->extents[1] & ~15) + 16);
+
+       mesh = &surf->mesh;
+       mesh->numverts = surf->poly_numverts;
+       mesh->numtriangles = surf->poly_numverts - 2;
+       mesh->index = Mem_Alloc(loadmodel->mempool, mesh->numtriangles * sizeof(int[3]) + mesh->numverts * sizeof(surfvertex_t));
+       mesh->vertex = (surfvertex_t *)((long) mesh->index + mesh->numtriangles * sizeof(int[3]));
+       memset(mesh->vertex, 0, mesh->numverts * sizeof(surfvertex_t));
+
+       index = mesh->index;
+       for (i = 0;i < mesh->numtriangles;i++)
+       {
+               *index++ = 0;
+               *index++ = i + 1;
+               *index++ = i + 2;
+       }
+
+       for (i = 0, in = surf->poly_verts, out = mesh->vertex;i < mesh->numverts;i++, in += 3, out++)
+       {
+               VectorCopy (in, out->v);
+
+               s = DotProduct (out->v, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3];
+               t = DotProduct (out->v, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3];
+
+               out->st[0] = s / surf->texinfo->texture->width;
+               out->st[1] = t / surf->texinfo->texture->height;
+
+               s = (s + 8 - surf->texturemins[0]) * (1.0 / 16.0);
+               t = (t + 8 - surf->texturemins[1]) * (1.0 / 16.0);
+
+               // lightmap coordinates
+               out->uv[0] = s * xscale + xbase;
+               out->uv[1] = t * yscale + ybase;
+
+               // LordHavoc: calc lightmap data offset for vertex lighting to use
+               is = (int) s;
+               it = (int) t;
+               is = bound(0, is, smax);
+               it = bound(0, it, tmax);
+               out->lightmapoffset = ((it * (smax+1) + is) * 3);
+       }
+}
+
+void Mod_GenerateSurfacePolygon (msurface_t *surf)
+{
+       float           *vert;
+       int                     i;
+       int                     lindex;
+       float           *vec;
+
+       // convert edges back to a normal polygon
+       surf->poly_numverts = surf->numedges;
+       vert = surf->poly_verts = Mem_Alloc(loadmodel->mempool, sizeof(float[3]) * surf->numedges);
+       for (i = 0;i < surf->numedges;i++)
+       {
+               lindex = loadmodel->surfedges[surf->firstedge + i];
+               if (lindex > 0)
+                       vec = loadmodel->vertexes[loadmodel->edges[lindex].v[0]].position;
+               else
+                       vec = loadmodel->vertexes[loadmodel->edges[-lindex].v[1]].position;
+               VectorCopy (vec, vert);
+               vert += 3;
+       }
+}
 
 /*
 =================
@@ -760,16 +1159,19 @@ static void Mod_LoadFaces (lump_t *l)
        if (l->filelen % sizeof(*in))
                Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
        count = l->filelen / sizeof(*in);
-       out = Hunk_AllocName ( count*sizeof(*out), va("%s faces", loadname));
+       out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
 
        loadmodel->surfaces = out;
        loadmodel->numsurfaces = count;
 
-       for ( surfnum=0 ; surfnum<count ; surfnum++, in++, out++)
+       for (surfnum = 0;surfnum < count;surfnum++, in++, out++)
        {
+               // FIXME: validate edges, texinfo, etc?
                out->firstedge = LittleLong(in->firstedge);
                out->numedges = LittleShort(in->numedges);
-               out->flags = 0;
+
+               out->texinfo = loadmodel->texinfo + LittleShort (in->texinfo);
+               out->flags = out->texinfo->texture->flags;
 
                planenum = LittleShort(in->planenum);
                side = LittleShort(in->side);
@@ -778,59 +1180,100 @@ static void Mod_LoadFaces (lump_t *l)
 
                out->plane = loadmodel->planes + planenum;
 
-               out->texinfo = loadmodel->texinfo + LittleShort (in->texinfo);
+               // clear lightmap (filled in later)
+               out->lightmaptexture = NULL;
 
-               CalcSurfaceExtents (out);
+               // force lightmap upload on first time seeing the surface
+               out->cached_dlight = true;
+               out->cached_ambient = -1000;
+               out->cached_lightscalebit = -1000;
+               out->cached_light[0] = -1000;
+               out->cached_light[1] = -1000;
+               out->cached_light[2] = -1000;
+               out->cached_light[3] = -1000;
 
-       // lighting info
+               CalcSurfaceExtents (out);
 
-               for (i=0 ; i<MAXLIGHTMAPS ; i++)
+               // lighting info
+               for (i = 0;i < MAXLIGHTMAPS;i++)
                        out->styles[i] = in->styles[i];
                i = LittleLong(in->lightofs);
                if (i == -1)
                        out->samples = NULL;
-               else if (hlbsp) // LordHavoc: HalfLife map (bsp version 30)
+               else if (loadmodel->ishlbsp) // LordHavoc: HalfLife map (bsp version 30)
                        out->samples = loadmodel->lightdata + i;
                else // LordHavoc: white lighting (bsp version 29)
                        out->samples = loadmodel->lightdata + (i * 3);
 
-       // set the drawing flags flag
+               Mod_GenerateSurfacePolygon(out);
 
-//             if (!strncmp(out->texinfo->texture->name,"sky",3))      // sky
-               // LordHavoc: faster check
-               if ((out->texinfo->texture->name[0] == 's' || out->texinfo->texture->name[0] == 'S')
-                && (out->texinfo->texture->name[1] == 'k' || out->texinfo->texture->name[1] == 'K')
-                && (out->texinfo->texture->name[2] == 'y' || out->texinfo->texture->name[2] == 'Y'))
+               if (out->texinfo->texture->flags & SURF_DRAWSKY)
                {
-                       // LordHavoc: for consistency reasons, mark sky as fullbright and solid as well
-                       out->flags |= (SURF_DRAWSKY | SURF_DRAWTILED | SURF_DRAWFULLBRIGHT | SURF_DRAWNOALPHA | SURF_CLIPSOLID);
-                       GL_SubdivideSurface (out);      // cut up polygon for warps
+                       out->shader = &Cshader_sky;
+                       Mod_GenerateWarpMesh (out);
                        continue;
                }
 
-//             if (!strncmp(out->texinfo->texture->name,"*",1))                // turbulent
-               if (out->texinfo->texture->name[0] == '*') // LordHavoc: faster check
+               if (out->texinfo->texture->flags & SURF_DRAWTURB)
                {
-                       out->flags |= (SURF_DRAWTURB | SURF_DRAWTILED | SURF_LIGHTBOTHSIDES);
-                       // LordHavoc: some turbulent textures should be fullbright and solid
-                       if (!strncmp(out->texinfo->texture->name,"*lava",5)
-                        || !strncmp(out->texinfo->texture->name,"*teleport",9)
-                        || !strncmp(out->texinfo->texture->name,"*rift",5)) // Scourge of Armagon texture
-                               out->flags |= (SURF_DRAWFULLBRIGHT | SURF_DRAWNOALPHA | SURF_CLIPSOLID);
+                       out->shader = &Cshader_water;
+                       /*
                        for (i=0 ; i<2 ; i++)
                        {
-                               out->extents[i] = 16384;
-                               out->texturemins[i] = -8192;
+                               out->extents[i] = 16384*1024;
+                               out->texturemins[i] = -8192*1024;
                        }
-                       GL_SubdivideSurface (out);      // cut up polygon for warps
+                       */
+                       Mod_GenerateWarpMesh (out);
                        continue;
                }
 
-               if (!out->texinfo->texture->transparent)
+               if (!R_TextureHasAlpha(out->texinfo->texture->texture))
                        out->flags |= SURF_CLIPSOLID;
+               if (out->texinfo->flags & TEX_SPECIAL)
+               {
+                       // qbsp couldn't find the texture for this surface, but it was either turb or sky...  assume turb
+                       out->shader = &Cshader_water;
+                       Mod_GenerateWarpMesh (out);
+               }
+               else if (out->extents[0] < r_vertexsurfacesthreshold.integer && out->extents[1] < r_vertexsurfacesthreshold.integer)
+               {
+                       out->shader = &Cshader_wall_vertex;
+                       Mod_GenerateVertexLitMesh(out);
+               }
+               else
+               {
+                       out->shader = &Cshader_wall_lightmap;
+                       Mod_GenerateLightmappedMesh(out);
+               }
        }
 }
 
+static model_t *sortmodel;
+
+static int Mod_SurfaceQSortCompare(const void *voida, const void *voidb)
+{
+       const msurface_t *a, *b;
+       a = *((const msurface_t **)voida);
+       b = *((const msurface_t **)voidb);
+       if (a->shader != b->shader)
+               return (long) a->shader - (long) b->shader;
+       if (a->texinfo->texture != b->texinfo->texture);
+               return a->texinfo->texture - b->texinfo->texture;
+       return 0;
+}
+
+static void Mod_BrushSortedSurfaces(model_t *model, mempool_t *pool)
+{
+       int surfnum;
+       sortmodel = model;
+       sortmodel->modelsortedsurfaces = Mem_Alloc(pool, sortmodel->nummodelsurfaces * sizeof(msurface_t *));
+       for (surfnum = 0;surfnum < sortmodel->nummodelsurfaces;surfnum++)
+               sortmodel->modelsortedsurfaces[surfnum] = &sortmodel->surfaces[surfnum + sortmodel->firstmodelsurface];
+
+       qsort(sortmodel->modelsortedsurfaces, sortmodel->nummodelsurfaces, sizeof(msurface_t *), Mod_SurfaceQSortCompare);
+}
+
 
 /*
 =================
@@ -861,7 +1304,7 @@ static void Mod_LoadNodes (lump_t *l)
        if (l->filelen % sizeof(*in))
                Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
        count = l->filelen / sizeof(*in);
-       out = Hunk_AllocName ( count*sizeof(*out), va("%s nodes", loadname));
+       out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
 
        loadmodel->nodes = out;
        loadmodel->numnodes = count;
@@ -873,13 +1316,13 @@ static void Mod_LoadNodes (lump_t *l)
                        out->mins[j] = LittleShort (in->mins[j]);
                        out->maxs[j] = LittleShort (in->maxs[j]);
                }
-       
+
                p = LittleLong(in->planenum);
                out->plane = loadmodel->planes + p;
 
                out->firstsurface = LittleShort (in->firstface);
                out->numsurfaces = LittleShort (in->numfaces);
-               
+
                for (j=0 ; j<2 ; j++)
                {
                        p = LittleShort (in->children[j]);
@@ -889,7 +1332,7 @@ static void Mod_LoadNodes (lump_t *l)
                                out->children[j] = (mnode_t *)(loadmodel->leafs + (-1 - p));
                }
        }
-       
+
        Mod_SetParent (loadmodel->nodes, NULL); // sets nodes and leafs
 }
 
@@ -908,7 +1351,7 @@ static void Mod_LoadLeafs (lump_t *l)
        if (l->filelen % sizeof(*in))
                Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
        count = l->filelen / sizeof(*in);
-       out = Hunk_AllocName ( count*sizeof(*out), va("%s leafs", loadname));
+       out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
 
        loadmodel->leafs = out;
        loadmodel->numleafs = count;
@@ -933,7 +1376,7 @@ static void Mod_LoadLeafs (lump_t *l)
                        out->compressed_vis = NULL;
                else
                        out->compressed_vis = loadmodel->visdata + p;
-               
+
                for (j=0 ; j<4 ; j++)
                        out->ambient_sound_level[j] = in->ambient_level[j];
 
@@ -946,7 +1389,7 @@ static void Mod_LoadLeafs (lump_t *l)
                                out->firstmarksurface[j]->flags |= SURF_UNDERWATER;
                }
                */
-       }       
+       }
 }
 
 /*
@@ -964,12 +1407,12 @@ static void Mod_LoadClipnodes (lump_t *l)
        if (l->filelen % sizeof(*in))
                Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
        count = l->filelen / sizeof(*in);
-       out = Hunk_AllocName ( count*sizeof(*out), va("%s clipnodes", loadname));
+       out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
 
        loadmodel->clipnodes = out;
        loadmodel->numclipnodes = count;
 
-       if (hlbsp)
+       if (loadmodel->ishlbsp)
        {
                hull = &loadmodel->hulls[1];
                hull->clipnodes = out;
@@ -1055,21 +1498,20 @@ static void Mod_MakeHull0 (void)
 {
        mnode_t         *in;
        dclipnode_t *out;
-       int                     i, count;
+       int                     i;
        hull_t          *hull;
-       
-       hull = &loadmodel->hulls[0];    
+
+       hull = &loadmodel->hulls[0];
 
        in = loadmodel->nodes;
-       count = loadmodel->numnodes;
-       out = Hunk_AllocName ( count*sizeof(*out), va("%s hull0", loadname));
+       out = Mem_Alloc(loadmodel->mempool, loadmodel->numnodes * sizeof(dclipnode_t));
 
        hull->clipnodes = out;
        hull->firstclipnode = 0;
-       hull->lastclipnode = count - 1;
+       hull->lastclipnode = loadmodel->numnodes - 1;
        hull->planes = loadmodel->planes;
 
-       for (i = 0;i < count;i++, out++, in++)
+       for (i = 0;i < loadmodel->numnodes;i++, out++, in++)
        {
                out->planenum = in->plane - loadmodel->planes;
                out->children[0] = in->children[0]->contents < 0 ? in->children[0]->contents : in->children[0] - loadmodel->nodes;
@@ -1084,25 +1526,21 @@ Mod_LoadMarksurfaces
 */
 static void Mod_LoadMarksurfaces (lump_t *l)
 {
-       int             i, j, count;
-       short           *in;
-       msurface_t **out;
+       int             i, j;
+       short   *in;
 
        in = (void *)(mod_base + l->fileofs);
        if (l->filelen % sizeof(*in))
                Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
-       count = l->filelen / sizeof(*in);
-       out = Hunk_AllocName ( count*sizeof(*out), va("%s marksurfaces", loadname));
-
-       loadmodel->marksurfaces = out;
-       loadmodel->nummarksurfaces = count;
+       loadmodel->nummarksurfaces = l->filelen / sizeof(*in);
+       loadmodel->marksurfaces = Mem_Alloc(loadmodel->mempool, loadmodel->nummarksurfaces * sizeof(msurface_t *));
 
-       for ( i=0 ; i<count ; i++)
+       for (i = 0;i < loadmodel->nummarksurfaces;i++)
        {
-               j = LittleShort(in[i]);
+               j = (unsigned) LittleShort(in[i]);
                if (j >= loadmodel->numsurfaces)
                        Host_Error ("Mod_ParseMarksurfaces: bad surface number");
-               out[i] = loadmodel->surfaces + j;
+               loadmodel->marksurfaces[i] = loadmodel->surfaces + j;
        }
 }
 
@@ -1113,20 +1551,17 @@ Mod_LoadSurfedges
 */
 static void Mod_LoadSurfedges (lump_t *l)
 {
-       int             i, count;
-       int             *in, *out;
-       
+       int             i;
+       int             *in;
+
        in = (void *)(mod_base + l->fileofs);
        if (l->filelen % sizeof(*in))
                Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
-       count = l->filelen / sizeof(*in);
-       out = Hunk_AllocName ( count*sizeof(*out), va("%s surfedges", loadname));
+       loadmodel->numsurfedges = l->filelen / sizeof(*in);
+       loadmodel->surfedges = Mem_Alloc(loadmodel->mempool, loadmodel->numsurfedges * sizeof(int));
 
-       loadmodel->surfedges = out;
-       loadmodel->numsurfedges = count;
-
-       for ( i=0 ; i<count ; i++)
-               out[i] = LittleLong (in[i]);
+       for (i = 0;i < loadmodel->numsurfedges;i++)
+               loadmodel->surfedges[i] = LittleLong (in[i]);
 }
 
 
@@ -1137,26 +1572,24 @@ Mod_LoadPlanes
 */
 static void Mod_LoadPlanes (lump_t *l)
 {
-       int                     i, j;
+       int                     i;
        mplane_t        *out;
        dplane_t        *in;
-       int                     count;
 
        in = (void *)(mod_base + l->fileofs);
        if (l->filelen % sizeof(*in))
-               Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
-       count = l->filelen / sizeof(*in);
-       out = Hunk_AllocName ( count*2*sizeof(*out), va("%s planes", loadname));
+               Host_Error ("MOD_LoadBmodel: funny lump size in %s", loadmodel->name);
 
-       loadmodel->planes = out;
-       loadmodel->numplanes = count;
+       loadmodel->numplanes = l->filelen / sizeof(*in);
+       loadmodel->planes = out = Mem_Alloc(loadmodel->mempool, loadmodel->numplanes * sizeof(*out));
 
-       for ( i=0 ; i<count ; i++, in++, out++)
+       for (i = 0;i < loadmodel->numplanes;i++, in++, out++)
        {
-               for (j=0 ; j<3 ; j++)
-                       out->normal[j] = LittleFloat (in->normal[j]);
-
+               out->normal[0] = LittleFloat (in->normal[0]);
+               out->normal[1] = LittleFloat (in->normal[1]);
+               out->normal[2] = LittleFloat (in->normal[2]);
                out->dist = LittleFloat (in->dist);
+
                // LordHavoc: recalculated by PlaneClassify, FIXME: validate type and report error if type does not match normal?
 //             out->type = LittleLong (in->type);
                PlaneClassify(out);
@@ -1168,10 +1601,16 @@ static void Mod_LoadPlanes (lump_t *l)
 typedef struct
 {
        int numpoints;
-       vec3_t points[8]; // variable sized
+       double points[8][3]; // variable sized
 }
 winding_t;
 
+typedef struct
+{
+       int numpoints;
+}
+windingsizeof_t;
+
 /*
 ==================
 NewWinding
@@ -1185,8 +1624,8 @@ static winding_t *NewWinding (int points)
        if (points > MAX_POINTS_ON_WINDING)
                Host_Error("NewWinding: too many points\n");
 
-       size = (int)((winding_t *)0)->points[points];
-       w = qmalloc (size);
+       size = sizeof(windingsizeof_t) + sizeof(double[3]) * points;
+       w = Mem_Alloc(tempmempool, size);
        memset (w, 0, size);
 
        return w;
@@ -1194,7 +1633,7 @@ static winding_t *NewWinding (int points)
 
 static void FreeWinding (winding_t *w)
 {
-       qfree (w);
+       Mem_Free(w);
 }
 
 /*
@@ -1204,13 +1643,14 @@ BaseWindingForPlane
 */
 static winding_t *BaseWindingForPlane (mplane_t *p)
 {
-       vec3_t  org, vright, vup;
-       winding_t       *w;
+       double org[3], vright[3], vup[3], normal[3];
+       winding_t *w;
 
-       VectorVectors(p->normal, vright, vup);
+       VectorCopy(p->normal, normal);
+       VectorVectorsDouble(normal, vright, vup);
 
-       VectorScale (vup, 65536, vup);
-       VectorScale (vright, 65536, vright);
+       VectorScale (vup, 1024.0*1024.0*1024.0, vup);
+       VectorScale (vright, 1024.0*1024.0*1024.0, vright);
 
        // project a really big axis aligned box onto the plane
        w = NewWinding (4);
@@ -1231,7 +1671,7 @@ static winding_t *BaseWindingForPlane (mplane_t *p)
 
        w->numpoints = 4;
 
-       return w;       
+       return w;
 }
 
 /*
@@ -1246,13 +1686,13 @@ it will be clipped away.
 */
 static winding_t *ClipWinding (winding_t *in, mplane_t *split, int keepon)
 {
-       vec_t   dists[MAX_POINTS_ON_WINDING + 1];
+       double  dists[MAX_POINTS_ON_WINDING + 1];
        int             sides[MAX_POINTS_ON_WINDING + 1];
        int             counts[3];
-       vec_t   dot;
+       double  dot;
        int             i, j;
-       vec_t   *p1, *p2;
-       vec3_t  mid;
+       double  *p1, *p2;
+       double  mid[3];
        winding_t       *neww;
        int             maxpts;
 
@@ -1347,13 +1787,13 @@ new windings will be created.
 */
 static void DivideWinding (winding_t *in, mplane_t *split, winding_t **front, winding_t **back)
 {
-       vec_t   dists[MAX_POINTS_ON_WINDING + 1];
+       double  dists[MAX_POINTS_ON_WINDING + 1];
        int             sides[MAX_POINTS_ON_WINDING + 1];
        int             counts[3];
-       vec_t   dot;
+       double  dot;
        int             i, j;
-       vec_t   *p1, *p2;
-       vec3_t  mid;
+       double  *p1, *p2;
+       double  mid[3];
        winding_t       *f, *b;
        int             maxpts;
 
@@ -1446,7 +1886,7 @@ typedef struct portal_s
 {
        mplane_t plane;
        mnode_t *nodes[2];              // [0] = front side of plane
-       struct portal_s *next[2];       
+       struct portal_s *next[2];
        winding_t *winding;
        struct portal_s *chain; // all portals are linked into a list
 }
@@ -1462,13 +1902,18 @@ AllocPortal
 static portal_t *AllocPortal (void)
 {
        portal_t *p;
-       p = qmalloc(sizeof(portal_t));
-       memset(p, 0, sizeof(portal_t));
+       p = Mem_Alloc(tempmempool, sizeof(portal_t));
+       //memset(p, 0, sizeof(portal_t));
        p->chain = portalchain;
        portalchain = p;
        return p;
 }
 
+static void FreePortal(portal_t *p)
+{
+       Mem_Free(p);
+}
+
 static void Mod_RecursiveRecalcNodeBBox(mnode_t *node)
 {
        // calculate children first
@@ -1526,19 +1971,15 @@ static void Mod_FinalizePortals(void)
                p = p->chain;
        }
 
-//     Hunk_Check();
-
        Mod_RecursiveRecalcNodeBBox(loadmodel->nodes);
 
-//     Hunk_Check();
-
        // tally up portal and point counts
        p = portalchain;
        numportals = 0;
        numpoints = 0;
        while(p)
        {
-               // note: this check must match the one below or it will usually corrupt the hunk
+               // note: this check must match the one below or it will usually corrupt memory
                // the nodes[0] != nodes[1] check is because leaf 0 is the shared solid leaf, it can have many portals inside with leaf 0 on both sides
                if (p->winding && p->nodes[0] != p->nodes[1]
                 && p->nodes[0]->contents != CONTENTS_SOLID && p->nodes[1]->contents != CONTENTS_SOLID
@@ -1549,9 +1990,9 @@ static void Mod_FinalizePortals(void)
                }
                p = p->chain;
        }
-       loadmodel->portals = Hunk_AllocName(numportals * sizeof(mportal_t), va("%s portals", loadmodel->name));
+       loadmodel->portals = Mem_Alloc(loadmodel->mempool, numportals * sizeof(mportal_t) + numpoints * sizeof(mvertex_t));
        loadmodel->numportals = numportals;
-       loadmodel->portalpoints = Hunk_AllocName(numpoints * sizeof(mvertex_t), va("%s portals", loadmodel->name));
+       loadmodel->portalpoints = (void *) ((long) loadmodel->portals + numportals * sizeof(mportal_t));
        loadmodel->numportalpoints = numpoints;
        // clear all leaf portal chains
        for (i = 0;i < loadmodel->numleafs;i++)
@@ -1567,7 +2008,7 @@ static void Mod_FinalizePortals(void)
 
                if (p->winding)
                {
-                       // note: this check must match the one below or it will usually corrupt the hunk
+                       // note: this check must match the one above or it will usually corrupt memory
                        // the nodes[0] != nodes[1] check is because leaf 0 is the shared solid leaf, it can have many portals inside with leaf 0 on both sides
                        if (p->nodes[0] != p->nodes[1]
                         && p->nodes[0]->contents != CONTENTS_SOLID && p->nodes[1]->contents != CONTENTS_SOLID
@@ -1619,7 +2060,7 @@ static void Mod_FinalizePortals(void)
                        }
                        FreeWinding(p->winding);
                }
-               qfree(p);
+               FreePortal(p);
                p = pnext;
        }
 }
@@ -1725,7 +2166,7 @@ static void Mod_RecursiveNodePortals (mnode_t *node)
 
        nodeportalwinding = BaseWindingForPlane (node->plane);
        side = 0;       // shut up compiler warning
-       for (portal = (portal_t *)node->portals;portal;portal = portal->next[side])     
+       for (portal = (portal_t *)node->portals;portal;portal = portal->next[side])
        {
                clipplane = portal->plane;
                if (portal->nodes[0] == portal->nodes[1])
@@ -1825,7 +2266,7 @@ void Mod_MakeOutsidePortals(mnode_t *node)
        portal_t        *p, *portals[6];
        mnode_t         *outside_node;
 
-       outside_node = Hunk_AllocName(sizeof(mnode_t), loadmodel->name);
+       outside_node = Mem_Alloc(loadmodel->mempool, sizeof(mnode_t));
        outside_node->contents = CONTENTS_SOLID;
        outside_node->portals = NULL;
 
@@ -1878,16 +2319,18 @@ void Mod_LoadBrushModel (model_t *mod, void *buffer)
        int                     i, j;
        dheader_t       *header;
        dmodel_t        *bm;
+       mempool_t       *mainmempool;
 
-       loadmodel->type = mod_brush;
+       mod->type = mod_brush;
 
        header = (dheader_t *)buffer;
 
        i = LittleLong (header->version);
        if (i != BSPVERSION && i != 30)
                Host_Error ("Mod_LoadBrushModel: %s has wrong version number (%i should be %i or 30 (HalfLife))", mod->name, i, BSPVERSION);
-       hlbsp = i == 30;
-       halflifebsp.value = hlbsp;
+       mod->ishlbsp = i == 30;
+       if (loadmodel->isworldmodel)
+               Cvar_SetValue("halflifebsp", mod->ishlbsp);
 
 // swap all the lumps
        mod_base = (byte *)header;
@@ -1897,31 +2340,52 @@ void Mod_LoadBrushModel (model_t *mod, void *buffer)
 
 // load into heap
 
+       // store which lightmap format to use
+       mod->lightmaprgba = r_lightmaprgba.integer;
+
+//     Mem_CheckSentinelsGlobal();
        // LordHavoc: had to move entity loading above everything to allow parsing various settings from worldspawn
        Mod_LoadEntities (&header->lumps[LUMP_ENTITIES]);
-
+//     Mem_CheckSentinelsGlobal();
        Mod_LoadVertexes (&header->lumps[LUMP_VERTEXES]);
+//     Mem_CheckSentinelsGlobal();
        Mod_LoadEdges (&header->lumps[LUMP_EDGES]);
+//     Mem_CheckSentinelsGlobal();
        Mod_LoadSurfedges (&header->lumps[LUMP_SURFEDGES]);
+//     Mem_CheckSentinelsGlobal();
        Mod_LoadTextures (&header->lumps[LUMP_TEXTURES]);
+//     Mem_CheckSentinelsGlobal();
        Mod_LoadLighting (&header->lumps[LUMP_LIGHTING]);
+//     Mem_CheckSentinelsGlobal();
        Mod_LoadPlanes (&header->lumps[LUMP_PLANES]);
+//     Mem_CheckSentinelsGlobal();
        Mod_LoadTexinfo (&header->lumps[LUMP_TEXINFO]);
+//     Mem_CheckSentinelsGlobal();
        Mod_LoadFaces (&header->lumps[LUMP_FACES]);
+//     Mem_CheckSentinelsGlobal();
        Mod_LoadMarksurfaces (&header->lumps[LUMP_MARKSURFACES]);
+//     Mem_CheckSentinelsGlobal();
        Mod_LoadVisibility (&header->lumps[LUMP_VISIBILITY]);
+//     Mem_CheckSentinelsGlobal();
        Mod_LoadLeafs (&header->lumps[LUMP_LEAFS]);
+//     Mem_CheckSentinelsGlobal();
        Mod_LoadNodes (&header->lumps[LUMP_NODES]);
+//     Mem_CheckSentinelsGlobal();
        Mod_LoadClipnodes (&header->lumps[LUMP_CLIPNODES]);
+//     Mem_CheckSentinelsGlobal();
 //     Mod_LoadEntities (&header->lumps[LUMP_ENTITIES]);
        Mod_LoadSubmodels (&header->lumps[LUMP_MODELS]);
+//     Mem_CheckSentinelsGlobal();
 
        Mod_MakeHull0 ();
-
+//     Mem_CheckSentinelsGlobal();
        Mod_MakePortals();
+//     Mem_CheckSentinelsGlobal();
 
        mod->numframes = 2;             // regular and alternate animation
 
+       mainmempool = mod->mempool;
+
 //
 // set up the submodels (FIXME: this is confusing)
 //
@@ -1948,9 +2412,13 @@ void Mod_LoadBrushModel (model_t *mod, void *buffer)
                mod->firstmodelsurface = bm->firstface;
                mod->nummodelsurfaces = bm->numfaces;
 
+               mod->DrawSky = NULL;
                // LordHavoc: calculate bmodel bounding box rather than trusting what it says
                for (j = 0, surf = &mod->surfaces[mod->firstmodelsurface];j < mod->nummodelsurfaces;j++, surf++)
                {
+                       // we only need to have a drawsky function if it is used (usually only on world model)
+                       if (surf->shader == &Cshader_sky)
+                               mod->DrawSky = R_DrawBrushModelSky;
                        for (k = 0;k < surf->numedges;k++)
                        {
                                l = mod->surfedges[k + surf->firstedge];
@@ -1989,19 +2457,26 @@ void Mod_LoadBrushModel (model_t *mod, void *buffer)
                mod->numleafs = bm->visleafs;
 
                mod->SERAddEntity = Mod_Brush_SERAddEntity;
-               mod->DrawEarly = R_DrawBrushModel;
-               mod->DrawLate = NULL;
+               mod->Draw = R_DrawBrushModelNormal;
                mod->DrawShadow = NULL;
 
-               if (isworldmodel && i < (mod->numsubmodels - 1)) // LordHavoc: only register submodels if it is the world (prevents bsp models from replacing world submodels)
-               {       // duplicate the basic information
-                       char    name[10];
+               Mod_BrushSortedSurfaces(mod, mainmempool);
 
+               // LordHavoc: only register submodels if it is the world
+               // (prevents bsp models from replacing world submodels)
+               if (loadmodel->isworldmodel && i < (mod->numsubmodels - 1))
+               {
+                       char    name[10];
+                       // duplicate the basic information
                        sprintf (name, "*%i", i+1);
                        loadmodel = Mod_FindName (name);
                        *loadmodel = *mod;
                        strcpy (loadmodel->name, name);
+                       // textures and memory belong to the main model
+                       loadmodel->texturepool = NULL;
+                       loadmodel->mempool = NULL;
                        mod = loadmodel;
                }
        }
+//     Mem_CheckSentinelsGlobal();
 }
index 15f73d9c1d215e29de869d0f1087b6bcb809ccec..c172a07d00ebc4fadf48d4a0cba1c0443e580d5e 100644 (file)
@@ -8,7 +8,7 @@ of the License, or (at your option) any later version.
 
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 See the GNU General Public License for more details.
 
@@ -33,7 +33,8 @@ BRUSH MODELS
 typedef struct
 {
        vec3_t          position;
-} mvertex_t;
+}
+mvertex_t;
 
 #define        SIDE_FRONT      0
 #define        SIDE_BACK       1
@@ -48,27 +49,32 @@ typedef struct mplane_s
        int             type;                   // for texture axis selection and fast side tests
        // LordHavoc: faster than id's signbits system
        int (*BoxOnPlaneSideFunc) (vec3_t emins, vec3_t emaxs, struct mplane_s *p);
-} mplane_t;
+}
+mplane_t;
 
 typedef struct texture_s
 {
        char                            name[16];
        unsigned                        width, height;
+       int                                     flags;                          // LordHavoc: SURF_ flags
+
        rtexture_t                      *texture;
-       rtexture_t                      *glowtexture;           // LordHavoc: fullbrights on walls
-       int                                     anim_total;                     // total frames in sequence (0 = not animated)
+       rtexture_t                      *glowtexture;
+       rtexture_t                      *fogtexture;            // alpha-only version of main texture
+
+       int                                     anim_total;                     // total frames in sequence (< 2 = not animated)
        struct texture_s        *anim_frames[10];       // LordHavoc: direct pointers to each of the frames in the sequence
        struct texture_s        *alternate_anims;       // bmodels in frame 1 use these
-       int                                     transparent;            // LordHavoc: transparent texture support
-texture_t;
+}
+texture_t;
 
 
 #define        SURF_PLANEBACK          2
 #define        SURF_DRAWSKY            4
-#define SURF_DRAWSPRITE                8
+//#define SURF_DRAWSPRITE              8
 #define SURF_DRAWTURB          0x10
-#define SURF_DRAWTILED         0x20
-#define SURF_DRAWBACKGROUND    0x40
+#define SURF_LIGHTMAP          0x20
+//#define SURF_DRAWBACKGROUND  0x40
 //#define SURF_UNDERWATER              0x80
 #define SURF_DRAWNOALPHA       0x100
 #define SURF_DRAWFULLBRIGHT    0x200
@@ -78,117 +84,172 @@ typedef struct texture_s
 typedef struct
 {
        unsigned short  v[2];
-} medge_t;
+}
+medge_t;
 
 typedef struct
 {
        float           vecs[2][4];
        texture_t       *texture;
        int                     flags;
-} mtexinfo_t;
-
-// LordHavoc: was 7, I added one more for raw lightmap position
-// (xyz st uv l)
-#define        VERTEXSIZE      8
+}
+mtexinfo_t;
 
-typedef struct glpoly_s
+typedef struct surfvertex_s
 {
-       struct  glpoly_s        *next;
-       int             numverts;
-       float   verts[4][VERTEXSIZE];   // variable sized
-} glpoly_t;
+       // position
+       float v[3];
+       // offset into lightmap (used by vertex lighting)
+       int lightmapoffset;
+       // texture coordinates
+       float st[2];
+       // lightmap coordinates
+       float uv[2];
+}
+surfvertex_t;
 
-typedef struct glpolysizeof_s
+// LordHavoc: replaces glpoly, triangle mesh
+typedef struct surfmesh_s
 {
-       struct  glpoly_s        *next;
-       int             numverts;
-} glpolysizeof_t;
+       int numverts;
+       int numtriangles;
+       surfvertex_t *vertex;
+       int *index;
+}
+surfmesh_t;
 
 typedef struct msurface_s
 {
-       int                     visframe;               // should be drawn when node is crossed
+       // should be drawn if visframe == r_framecount (set by WorldNode functions)
+       int                     visframe;
 
+       // the node plane this is on, backwards if SURF_PLANEBACK flag set
        mplane_t        *plane;
+       // SURF_ flags
        int                     flags;
+       struct Cshader_s        *shader;
+       struct msurface_s       *chain; // shader rendering chain
 
-       int                     firstedge;      // look up in model->surfedges[], negative numbers
-       int                     numedges;       // are backwards edges
+       // look up in model->surfedges[], negative numbers are backwards edges
+       int                     firstedge;
+       int                     numedges;
 
        short           texturemins[2];
        short           extents[2];
 
-       short           light_s, light_t;       // gl lightmap coordinates
-
-       glpoly_t        *polys;                         // multiple if warped
-
        mtexinfo_t      *texinfo;
+       texture_t       *currenttexture; // updated (animated) during early surface processing each frame
 
-// lighting info
+       // index into d_lightstylevalue array, 255 means not used (black)
+       byte            styles[MAXLIGHTMAPS];
+       // RGB lighting data [numstyles][height][width][3]
+       byte            *samples;
+
+       // these fields are generated during model loading
+       // the lightmap texture fragment to use on the surface
+       rtexture_t *lightmaptexture;
+       // the stride when building lightmaps to comply with fragment update
+       int                     lightmaptexturestride;
+       // mesh for rendering
+       surfmesh_t      mesh;
+
+       // these are just 3D points defining the outline of the polygon,
+       // no texcoord info (that can be generated from these)
+       int                     poly_numverts;
+       float           *poly_verts;
+
+       // these are regenerated every frame
+       // lighting info
        int                     dlightframe;
        int                     dlightbits[8];
+       // avoid redundent addition of dlights
+       int                     lightframe;
+       // only render each surface once
+       int                     worldnodeframe;
+       // marked when surface is prepared for the frame
+       int                     insertframe;
+
+       // these cause lightmap updates if regenerated
+       // values currently used in lightmap
+       unsigned short cached_light[MAXLIGHTMAPS];
+       // if lightmap was lit by dynamic lights, force update on next frame
+       short           cached_dlight;
+       // to cause lightmap to be rerendered when lighthalf changes
+       short           cached_lightscalebit;
+       // rerender lightmaps when r_ambient changes
+       float           cached_ambient;
+}
+msurface_t;
 
-       int                     lightframe; // avoid redundent addition of dlights
-       int                     worldnodeframe; // only render each surface once
+#define SHADERSTAGE_SKY 0
+#define SHADERSTAGE_NORMAL 1
+#define SHADERSTAGE_FOG 2
+#define SHADERSTAGE_COUNT 3
 
-       int                     lightmaptexturenum;
-       byte            styles[MAXLIGHTMAPS];
-       unsigned short cached_light[MAXLIGHTMAPS];      // values currently used in lightmap
-       short           cached_dlight;                          // LordHavoc: if lightmap was lit by dynamic lights, update on frame after end of effect to erase it
-       short           cached_lightscalebit;           // LordHavoc: to cause lightmap to be rerendered when lighthalf changes
-       float           cached_ambient;                         // LordHavoc: rerender lightmaps when r_ambient changes
-       byte            *samples;               // [numstyles*surfsize]
-} msurface_t;
+// change this stuff when real shaders are added
+typedef struct Cshader_s
+{
+       int (*shaderfunc[SHADERSTAGE_COUNT])(int stage, msurface_t *s);
+       // list of surfaces using this shader (used during surface rendering)
+       msurface_t *chain;
+}
+Cshader_t;
+
+extern Cshader_t Cshader_wall_vertex;
+extern Cshader_t Cshader_wall_lightmap;
+extern Cshader_t Cshader_water;
+extern Cshader_t Cshader_sky;
 
 // warning: if this is changed, references must be updated in cpu_* assembly files
 typedef struct mnode_s
 {
 // common with leaf
-       int                     contents;               // 0, to differentiate from leafs
+       int                                     contents;               // 0, to differentiate from leafs
 
-       struct mnode_s  *parent;
-       struct mportal_s *portals;
+       struct mnode_s          *parent;
+       struct mportal_s        *portals;
 
        // for bounding box culling
-       vec3_t          mins;
-       vec3_t          maxs;
+       vec3_t                          mins;
+       vec3_t                          maxs;
 
 // node specific
-       mplane_t        *plane;
-       struct mnode_s  *children[2];
+       mplane_t                        *plane;
+       struct mnode_s          *children[2];
 
        unsigned short          firstsurface;
        unsigned short          numsurfaces;
-} mnode_t;
-
-
+}
+mnode_t;
 
 typedef struct mleaf_s
 {
 // common with node
-       int                     contents;               // will be a negative contents number
+       int                                     contents;               // will be a negative contents number
 
-       struct mnode_s  *parent;
-       struct mportal_s *portals;
+       struct mnode_s          *parent;
+       struct mportal_s        *portals;
 
        // for bounding box culling
-       vec3_t          mins;
-       vec3_t          maxs;
+       vec3_t                          mins;
+       vec3_t                          maxs;
 
 // leaf specific
-       int                     visframe;               // visible if current (r_framecount)
-       int                     worldnodeframe; // used by certain worldnode variants to avoid processing the same leaf twice in a frame
-       int                     portalmarkid;   // used by polygon-through-portals visibility checker
+       int                                     visframe;               // visible if current (r_framecount)
+       int                                     worldnodeframe; // used by certain worldnode variants to avoid processing the same leaf twice in a frame
+       int                                     portalmarkid;   // used by polygon-through-portals visibility checker
 
        // LordHavoc: leaf based dynamic lighting
-       int                     dlightbits[8];
-       int                     dlightframe;
+       int                                     dlightbits[8];
+       int                                     dlightframe;
 
-       byte            *compressed_vis;
+       byte                            *compressed_vis;
 
-       msurface_t      **firstmarksurface;
-       int                     nummarksurfaces;
-       byte            ambient_sound_level[NUM_AMBIENTS];
-} mleaf_t;
+       msurface_t                      **firstmarksurface;
+       int                                     nummarksurfaces;
+       byte                            ambient_sound_level[NUM_AMBIENTS];
+}
+mleaf_t;
 
 typedef struct
 {
@@ -198,7 +259,8 @@ typedef struct
        int                     lastclipnode;
        vec3_t          clip_mins;
        vec3_t          clip_maxs;
-} hull_t;
+}
+hull_t;
 
 typedef struct mportal_s
 {
@@ -212,10 +274,10 @@ typedef struct mportal_s
 }
 mportal_t;
 
-extern void CL_ParseEntityLump(char *entdata);
 extern rtexture_t *r_notexture;
 extern texture_t r_notexture_mip;
 
 struct model_s;
-extern void Mod_LoadBrushModel (struct model_s *mod, void *buffer);
-extern void Mod_BrushInit(void);
+void Mod_LoadBrushModel (struct model_s *mod, void *buffer);
+void Mod_BrushInit(void);
+void Mod_FindNonSolidLocation(vec3_t pos, struct model_s *mod);
index 6209ace388328f1c5d0ef7b8ea6b2d2158906a88..d892a36d3b5aeac9dc9640e41a196677e99af3bc 100644 (file)
@@ -8,7 +8,7 @@ of the License, or (at your option) any later version.
 
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 See the GNU General Public License for more details.
 
@@ -25,45 +25,180 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #include "quakedef.h"
 
 model_t        *loadmodel;
-char   loadname[32];   // for hunk tags
 
 // LordHavoc: increased from 512 to 2048
 #define        MAX_MOD_KNOWN   2048
 model_t        mod_known[MAX_MOD_KNOWN];
-int            mod_numknown;
+
+void mod_start()
+{
+       int i;
+       for (i = 0;i < MAX_MOD_KNOWN;i++)
+               if (mod_known[i].name[0])
+                       Mod_UnloadModel(&mod_known[i]);
+}
+
+void mod_shutdown()
+{
+       int i;
+       for (i = 0;i < MAX_MOD_KNOWN;i++)
+               if (mod_known[i].name[0])
+                       Mod_UnloadModel(&mod_known[i]);
+}
+
+void mod_newmap()
+{
+}
 
 /*
 ===============
 Mod_Init
 ===============
 */
+static void Mod_Print (void);
+static void Mod_Flush (void);
 void Mod_Init (void)
 {
        Mod_BrushInit();
        Mod_AliasInit();
        Mod_SpriteInit();
+
+       Cmd_AddCommand ("modellist", Mod_Print);
+       Cmd_AddCommand ("modelflush", Mod_Flush);
+}
+
+void Mod_RenderInit(void)
+{
+       R_RegisterModule("Models", mod_start, mod_shutdown, mod_newmap);
+}
+
+void Mod_FreeModel (model_t *mod)
+{
+       R_FreeTexturePool(&mod->texturepool);
+       Mem_FreePool(&mod->mempool);
+
+       // clear the struct to make it available
+       memset(mod, 0, sizeof(model_t));
+}
+
+void Mod_UnloadModel (model_t *mod)
+{
+       char name[MAX_QPATH];
+       qboolean isworldmodel;
+       strcpy(name, mod->name);
+       isworldmodel = mod->isworldmodel;
+       Mod_FreeModel(mod);
+       strcpy(mod->name, name);
+       mod->isworldmodel = isworldmodel;
+       mod->needload = true;
 }
 
 /*
-===============
-Mod_Init
+==================
+Mod_LoadModel
 
-Caches the data if needed
-===============
+Loads a model
+==================
 */
-void *Mod_Extradata (model_t *mod)
+static model_t *Mod_LoadModel (model_t *mod, qboolean crash, qboolean checkdisk, qboolean isworldmodel)
 {
-       void    *r;
+       int crc;
+       void *buf;
+       char tempname[MAX_QPATH];
+
+       mod->used = true;
+
+       if (mod->name[0] == '*') // submodel
+               return mod;
 
-       r = Cache_Check (&mod->cache);
-       if (r)
-               return r;
+       if (checkdisk)
+       {
+               // load the file
+               buf = COM_LoadFile (mod->name, false);
+               if (!buf)
+               {
+                       if (crash)
+                               Host_Error ("Mod_LoadModel: %s not found", mod->name); // LordHavoc: Sys_Error was *ANNOYING*
+                       return NULL;
+               }
 
-       Mod_LoadModel (mod, true);
+               crc = CRC_Block(buf, com_filesize);
 
-       if (!mod->cache.data)
-               Host_Error ("Mod_Extradata: caching failed");
-       return mod->cache.data;
+               if (!mod->needload && mod->crc == crc && mod->isworldmodel == isworldmodel)
+               {
+                       Mem_Free(buf);
+                       return mod; // already loaded
+               }
+
+               Con_DPrintf("loading model %s\n", mod->name);
+       }
+       else
+       {
+               if (!mod->needload && mod->isworldmodel == isworldmodel)
+                       return mod; // already loaded
+
+               Con_DPrintf("loading model %s\n", mod->name);
+
+               buf = COM_LoadFile (mod->name, false);
+               if (!buf)
+               {
+                       if (crash)
+                               Host_Error ("Mod_LoadModel: %s not found", mod->name); // LordHavoc: Sys_Error was *ANNOYING*
+                       return NULL;
+               }
+               crc = CRC_Block(buf, com_filesize);
+       }
+
+       // make sure nothing got trashed
+       Mem_CheckSentinelsGlobal();
+
+       // allocate a new model
+       loadmodel = mod;
+
+       // LordHavoc: clear the model struct
+       strcpy(tempname, mod->name);
+       Mod_FreeModel(mod);
+
+       strcpy(mod->name, tempname);
+       mod->isworldmodel = isworldmodel;
+       mod->needload = false;
+       mod->used = true;
+       mod->crc = crc;
+
+       // all models use memory, so allocate a memory pool
+       mod->mempool = Mem_AllocPool(mod->name);
+       // all models load textures, so allocate a texture pool
+       mod->texturepool = R_AllocTexturePool();
+
+       // call the apropriate loader
+            if (!memcmp(buf, "IDPO"    , 4)) Mod_LoadAliasModel  (mod, buf);
+       else if (!memcmp(buf, "IDP2"    , 4)) Mod_LoadQ2AliasModel(mod, buf);
+       else if (!memcmp(buf, "ZYMOTIC" , 7)) Mod_LoadZymoticModel(mod, buf);
+       else if (!memcmp(buf, "IDSP"    , 4)) Mod_LoadSpriteModel (mod, buf);
+       else                                  Mod_LoadBrushModel  (mod, buf);
+
+       Mem_Free(buf);
+
+       // make sure nothing got trashed
+       Mem_CheckSentinelsGlobal();
+
+       return mod;
+}
+
+void Mod_CheckLoaded (model_t *mod)
+{
+       if (mod)
+       {
+               if (!mod->needload)
+               {
+                       if (mod->type == mod_invalid)
+                               Host_Error("Mod_CheckLoaded: invalid model\n");
+                       mod->used = true;
+                       return;
+               }
+
+               Mod_LoadModel(mod, true, true, mod->isworldmodel);
+       }
 }
 
 /*
@@ -73,12 +208,36 @@ Mod_ClearAll
 */
 void Mod_ClearAll (void)
 {
+       /*
        int             i;
        model_t *mod;
 
-       for (i=0 , mod=mod_known ; i<mod_numknown ; i++, mod++)
-               if (!mod->cachesize)
-                       mod->needload = true;
+       for (i = 0, mod = mod_known;i < MAX_MOD_KNOWN;i++, mod++)
+               if (mod->name[0])
+                       if (mod->usesheap)
+                               Mod_FreeModel(mod);
+       */
+}
+
+void Mod_ClearUsed(void)
+{
+       int             i;
+       model_t *mod;
+
+       for (i = 0, mod = mod_known;i < MAX_MOD_KNOWN;i++, mod++)
+               if (mod->name[0])
+                       mod->used = false;
+}
+
+void Mod_PurgeUnused(void)
+{
+       int             i;
+       model_t *mod;
+
+       for (i = 0, mod = mod_known;i < MAX_MOD_KNOWN;i++, mod++)
+               if (mod->name[0])
+                       if (!mod->used)
+                               Mod_FreeModel(mod);
 }
 
 /*
@@ -90,28 +249,38 @@ Mod_FindName
 model_t *Mod_FindName (char *name)
 {
        int             i;
-       model_t *mod;
+       model_t *mod, *freemod;
 
        if (!name[0])
                Host_Error ("Mod_ForName: NULL name");
 
-//
 // search the currently loaded models
-//
-       for (i=0 , mod=mod_known ; i<mod_numknown ; i++, mod++)
-               if (!strcmp (mod->name, name) )
-                       break;
+       freemod = NULL;
+       for (i = 0, mod = mod_known;i < MAX_MOD_KNOWN;i++, mod++)
+       {
+               if (mod->name[0])
+               {
+                       if (!strcmp (mod->name, name))
+                       {
+                               mod->used = true;
+                               return mod;
+                       }
+               }
+               else if (freemod == NULL)
+                       freemod = mod;
+       }
 
-       if (i == mod_numknown)
+       if (freemod)
        {
-               if (mod_numknown == MAX_MOD_KNOWN)
-                       Host_Error ("mod_numknown == MAX_MOD_KNOWN");
+               mod = freemod;
                strcpy (mod->name, name);
                mod->needload = true;
-               mod_numknown++;
+               mod->used = true;
+               return mod;
        }
 
-       return mod;
+       Host_Error ("Mod_FindName: ran out of models\n");
+       return NULL;
 }
 
 /*
@@ -125,85 +294,7 @@ void Mod_TouchModel (char *name)
        model_t *mod;
 
        mod = Mod_FindName (name);
-
-       if (!mod->needload)
-               if (mod->cachesize)
-                       Cache_Check (&mod->cache);
-}
-
-/*
-==================
-Mod_LoadModel
-
-Loads a model into the cache
-==================
-*/
-model_t *Mod_LoadModel (model_t *mod, qboolean crash)
-{
-       void    *d;
-       unsigned *buf;
-
-       if (!mod->needload)
-       {
-               if (mod->cachesize)
-               {
-                       d = Cache_Check (&mod->cache);
-                       if (d)
-                               return mod;
-               }
-               else
-                       return mod;             // not cached at all
-       }
-
-       Con_DPrintf("loading model %s\n", mod->name);
-
-// load the file
-       buf = (unsigned *)COM_LoadMallocFile (mod->name, false);
-       if (!buf)
-       {
-               if (crash)
-                       Host_Error ("Mod_NumForName: %s not found", mod->name); // LordHavoc: Sys_Error was *ANNOYING*
-               return NULL;
-       }
-
-// allocate a new model
-//     COM_FileBase (mod->name, loadname);
-       strcpy(loadname, mod->name);
-
-       loadmodel = mod;
-
-// call the apropriate loader
-       mod->needload = false;
-
-       // LordHavoc: clear some important stuff in the model_t structure
-       mod->flags = 0;
-       mod->flags2 = 0;
-
-       switch (LittleLong(*(unsigned *)buf))
-       {
-       case IDPOLYHEADER:
-               Mod_LoadAliasModel (mod, buf);
-               break;
-
-       case MD2IDALIASHEADER: // LordHavoc: added Quake2 model support
-               Mod_LoadQ2AliasModel (mod, buf);
-               break;
-
-       case (('O'<<24)+('M'<<16)+('Y'<<8)+'Z'):
-               Mod_LoadZymoticModel(mod, buf);
-               break;
-
-       case IDSPRITEHEADER:
-               Mod_LoadSpriteModel (mod, buf);
-               break;
-       
-       default:
-               Mod_LoadBrushModel (mod, buf);
-               break;
-       }
-       qfree(buf);
-
-       return mod;
+       mod->used = true;
 }
 
 /*
@@ -213,13 +304,14 @@ Mod_ForName
 Loads in a model for the given name
 ==================
 */
-model_t *Mod_ForName (char *name, qboolean crash)
+model_t *Mod_ForName (char *name, qboolean crash, qboolean checkdisk, qboolean isworldmodel)
 {
        model_t *mod;
-       
+
        mod = Mod_FindName (name);
-       
-       return Mod_LoadModel (mod, crash);
+       mod->used = true;
+
+       return Mod_LoadModel (mod, crash, checkdisk, isworldmodel);
 }
 
 byte   *mod_base;
@@ -229,6 +321,7 @@ byte        *mod_base;
 RadiusFromBounds
 =================
 */
+/*
 float RadiusFromBounds (vec3_t mins, vec3_t maxs)
 {
        int             i;
@@ -239,6 +332,7 @@ float RadiusFromBounds (vec3_t mins, vec3_t maxs)
 
        return Length (corner);
 }
+*/
 
 //=============================================================================
 
@@ -247,16 +341,24 @@ float RadiusFromBounds (vec3_t mins, vec3_t maxs)
 Mod_Print
 ================
 */
-void Mod_Print (void)
+static void Mod_Print (void)
 {
        int             i;
        model_t *mod;
 
-       Con_Printf ("Cached models:\n");
-       for (i=0, mod=mod_known ; i < mod_numknown ; i++, mod++)
-       {
-               Con_Printf ("%4iK : %8p : %s\n", (mod->cachesize + 1023) / 1024, mod->cache.data, mod->name);
-       }
+       Con_Printf ("Loaded models:\n");
+       for (i = 0, mod = mod_known;i < MAX_MOD_KNOWN;i++, mod++)
+               if (mod->name[0])
+                       Con_Printf ("%4iK %s\n", mod->mempool ? (mod->mempool->totalsize + 1023) / 1024 : 0, mod->name);
 }
 
+static void Mod_Flush (void)
+{
+       int             i;
+
+       Con_Printf ("Unloading models\n");
+       for (i = 0;i < MAX_MOD_KNOWN;i++)
+               if (mod_known[i].name[0])
+                       Mod_UnloadModel(&mod_known[i]);
+}
 
index 4160766475f58f7f3345c743050c83456ca81a52..1fe9adcc0f81f09c13d4774603573c045de69bf0 100644 (file)
@@ -33,7 +33,7 @@ m*_t structures are in-memory
 
 */
 
-typedef enum {mod_brush, mod_sprite, mod_alias} modtype_t;
+typedef enum {mod_invalid, mod_brush, mod_sprite, mod_alias} modtype_t;
 
 typedef struct animscene_s
 {
@@ -45,6 +45,17 @@ typedef struct animscene_s
 }
 animscene_t;
 
+typedef struct skinframe_s
+{
+       rtexture_t *base; // original texture minus pants/shirt/glow
+       rtexture_t *pants; // pants only (in greyscale)
+       rtexture_t *shirt; // shirt only (in greyscale)
+       rtexture_t *glow; // glow only
+       rtexture_t *merged; // original texture minus glow
+       rtexture_t *fog; // white texture with alpha of the base texture, NULL if not transparent
+}
+skinframe_t;
+
 #define MAX_SKINS 256
 
 
@@ -52,110 +63,157 @@ animscene_t;
 #include "model_sprite.h"
 #include "model_alias.h"
 
-#define MODF_TRANSPARENT 1
-
 typedef struct model_s
 {
-       char            name[MAX_QPATH];
-       qboolean        needload;               // bmodels don't cache normally
-
-       modtype_t       type;
-       int                     aliastype; // LordHavoc: Q2 model support
-       int                     fullbright; // LordHavoc: if true (normally only for sprites) the model/sprite/bmodel is always rendered fullbright
-       int                     numframes;
-       synctype_t      synctype;
-
-       int                     flags;
-       int                     flags2; // engine calculated flags, ones that can not be set in the file
-
-// volume occupied by the model graphics
-       vec3_t          normalmins, normalmaxs; // bounding box at angles '0 0 0'
-       vec3_t          yawmins, yawmaxs; // bounding box if yaw angle is not 0, but pitch and roll are
-       vec3_t          rotatedmins, rotatedmaxs; // bounding box if pitch or roll are used
-//     float           modelradius; // usable at any angles
-
-// solid volume for clipping
-       qboolean        clipbox;
-       vec3_t          clipmins, clipmaxs;
-
-// brush model
-       int                     firstmodelsurface, nummodelsurfaces;
-
-       int                     numsubmodels;
-       dmodel_t        *submodels;
-
-       int                     numplanes;
-       mplane_t        *planes;
-
-       int                     numleafs;               // number of visible leafs, not counting 0
-       mleaf_t         *leafs;
-
-       int                     numvertexes;
-       mvertex_t       *vertexes;
+       char                    name[MAX_QPATH];
+       // model needs to be loaded if this is true
+       qboolean                needload;
+       // set if the model is used in current map, models which are not, are purged
+       qboolean                used;
+       // CRC of the file this model was loaded from, to reload if changed
+       qboolean                crc;
+       // true if this is the world model (I.E. defines what sky to use, and may contain submodels)
+       qboolean                isworldmodel;
+       // true if this model is a HalfLife .bsp file
+       qboolean                ishlbsp;
+
+       // mod_brush, mod_alias, mod_sprite
+       modtype_t               type;
+       // LordHavoc: Q2/ZYM model support
+       int                             aliastype;
+       // LordHavoc: if true (normally only for sprites) the model/sprite/bmodel is always rendered fullbright
+       int                             fullbright;
+       // number of QC accessable frame(group)s in the model
+       int                             numframes;
+       // whether to randomize animated framegroups
+       synctype_t              synctype;
+
+       // used for sprites and models
+       int                             numtris;
+       // used for models
+       int                             numskins;
+       // used by models
+       int                             numverts;
+
+       // flags from the model file
+       int                             flags;
+       // engine calculated flags, ones that can not be set in the file
+       int                             flags2;
+
+       // all models use textures...
+       rtexturepool_t  *texturepool;
+
+       // volume occupied by the model
+       // bounding box at angles '0 0 0'
+       vec3_t                  normalmins, normalmaxs;
+       // bounding box if yaw angle is not 0, but pitch and roll are
+       vec3_t                  yawmins, yawmaxs;
+       // bounding box if pitch or roll are used
+       vec3_t                  rotatedmins, rotatedmaxs;
+       // usable at any angles
+//     float                   modelradius;
+
+       // brush model specific
+       int                             firstmodelsurface, nummodelsurfaces;
+       // LordHavoc: sorted surface pointer array, sorted by shader type and then by texture
+       msurface_t              **modelsortedsurfaces; // [nummodelsurfaces]
+
+       // used for surfaces without a valid texture
+       texture_t               notexture;
+
+       // lightmap format, set to r_lightmaprgba when model is loaded
+       int                             lightmaprgba;
+
+       int                             numsubmodels;
+       dmodel_t                *submodels;
+
+       int                             numplanes;
+       mplane_t                *planes;
+
+       // number of visible leafs, not counting 0 (solid)
+       int                             numleafs;
+       mleaf_t                 *leafs;
+
+       int                             numvertexes;
+       mvertex_t               *vertexes;
+
+       int                             numedges;
+       medge_t                 *edges;
+
+       int                             numnodes;
+       mnode_t                 *nodes;
+
+       int                             numtexinfo;
+       mtexinfo_t              *texinfo;
+
+       int                             numsurfaces;
+       msurface_t              *surfaces;
+
+       int                             numsurfedges;
+       int                             *surfedges;
+
+       int                             numclipnodes;
+       dclipnode_t             *clipnodes;
+
+       int                             nummarksurfaces;
+       msurface_t              **marksurfaces;
+
+       hull_t                  hulls[MAX_MAP_HULLS];
+
+       int                             numtextures;
+       texture_t               **textures;
+
+       byte                    *visdata;
+       byte                    *lightdata;
+       char                    *entities;
+
+       int                             numportals;
+       mportal_t               *portals;
+
+       int                             numportalpoints;
+       mvertex_t               *portalpoints;
+
+       // skin animation info
+       animscene_t             *skinscenes; // [numskins]
+       // skin frame info
+       skinframe_t             *skinframes;
+
+       animscene_t             *animscenes; // [numframes]
 
-       int                     numedges;
-       medge_t         *edges;
+       // Q2 model information
+//     md2triangle_t   *md2data_tris;
+       // FIXME: redesign to use triangle mesh
+       int                             *md2data_glcmds;
 
-       int                     numnodes;
-       mnode_t         *nodes;
+       float                   *mdldata_texcoords;
+       int                             *mdldata_indices;
 
-       int                     numtexinfo;
-       mtexinfo_t      *texinfo;
+       md2frame_t              *mdlmd2data_frames;
+       trivertx_t              *mdlmd2data_pose;
 
-       int                     numsurfaces;
-       msurface_t      *surfaces;
+       // for Zymotic models
+       void                    *zymdata_header;
 
-       int                     numsurfedges;
-       int                     *surfedges;
+       int                             sprnum_type;
+       mspriteframe_t  *sprdata_frames;
 
-       int                     numclipnodes;
-       dclipnode_t     *clipnodes;
+       // adds a box (or individual polygons) to the clipping engine,
+       // which will mark the entity visible if seen
+       void(*SERAddEntity)(void);
+       // draw the model
+       void(*Draw)(void);
+       // draw the model's sky polygons (only used by brush models)
+       void(*DrawSky)(void);
+       // draw the model's shadows
+       void(*DrawShadow)(void);
 
-       int                     nummarksurfaces;
-       msurface_t      **marksurfaces;
-
-       hull_t          hulls[MAX_MAP_HULLS];
-
-       int                     numtextures;
-       texture_t       **textures;
-
-       byte            *visdata;
-       byte            *lightdata;
-       char            *entities;
-
-       int                     numportals;
-       mportal_t       *portals;
-
-       int                     numportalpoints;
-       mvertex_t       *portalpoints;
-
-       // LordHavoc: useful for sprites and models
-       int                     numtris;
-       int                     numskins;
-
-       int                     skinanimrange[MAX_SKINS*2]; // array of start and length pairs
-       rtexture_t      *skinanim[MAX_SKINS*5]; // texture numbers for each frame (indexed by animrange), note: normal pants shirt glow body (normal contains no shirt/pants/glow colors and body is normal + pants + shirt, but not glow)
-
-       int                     ofs_scenes; // offset from Mod_ExtraData(model) memory to array of animscene_t structs
-       // these are used simply to simplify model/sprite/whatever processing and are specific to each type
-       int                     ofs_frames; // offset from Mod_ExtraData(model) memory to array of model specific frame structs
-       int                     framesize; // size of model specific frame structs
-
-       void (*SERAddEntity)(void);
-       void (*DrawEarly)(void);
-       void (*DrawLate)(void);
-       void (*DrawShadow)(void);
-
-// additional model data
-       cache_user_t    cache;          // only access through Mod_Extradata
-       int                     cachesize;              // size of cached data (zero if not cached)
-
-} model_t;
+       // memory pool for allocations
+       mempool_t               *mempool;
+}
+model_t;
 
 //============================================================================
 
-// used to avoid setting up submodels in non-world bmodels
-extern qboolean isworldmodel;
 // model loading
 extern model_t *loadmodel;
 extern byte    *mod_base;
@@ -165,20 +223,24 @@ extern cvar_t gl_subdivide_size;
 extern cvar_t r_fullbrights;
 
 void Mod_Init (void);
+void Mod_CheckLoaded (model_t *mod);
 void Mod_ClearAll (void);
-model_t *Mod_ForName (char *name, qboolean crash);
-void *Mod_Extradata (model_t *mod);    // handles caching
+model_t *Mod_ForName (char *name, qboolean crash, qboolean checkdisk, qboolean isworldmodel);
 void Mod_TouchModel (char *name);
+void Mod_UnloadModel (model_t *mod);
 
 mleaf_t *Mod_PointInLeaf (float *p, model_t *model);
 byte *Mod_LeafPVS (mleaf_t *leaf, model_t *model);
 
+void Mod_ClearUsed(void);
+void Mod_PurgeUnused(void);
+
 extern model_t *loadmodel;
 extern char loadname[32];      // for hunk tags
 
-extern model_t *Mod_LoadModel (model_t *mod, qboolean crash);
+//extern model_t *Mod_LoadModel (model_t *mod, qboolean crash);
 
-extern float RadiusFromBounds (vec3_t mins, vec3_t maxs);
+//extern float RadiusFromBounds (vec3_t mins, vec3_t maxs);
 extern model_t *Mod_FindName (char *name);
 
 #endif // __MODEL__
index 53dbb7c97162b8e2447eddeae37425188fb6555d..22140efad857fbdfb8eea059284b0f672fc394cb 100644 (file)
@@ -8,7 +8,7 @@ of the License, or (at your option) any later version.
 
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 See the GNU General Public License for more details.
 
@@ -51,436 +51,178 @@ void Mod_Sprite_StripExtension(char *in, char *out)
        *out++ = 0;
 }
 
-/*
-=================
-Mod_LoadSpriteFrame
-=================
-*/
-void * Mod_LoadSpriteFrame (void * pin, mspriteframe_t *frame, int framenum, int bytesperpixel, byte *palette, float *modelradius)
+void Mod_Sprite_SharedSetup(long datapointer, int version, int *palette)
 {
+       int                                     i, j, k, groupframes, realframes, x, y, origin[2], width, height;
+       dspriteframetype_t      *pinframetype;
        dspriteframe_t          *pinframe;
-       mspriteframe_t          *pspriteframe;
-       float                           dist;
-       int                                     i, width, height, size, origin[2];
-       char                            name[256], tempname[256];
-       byte                            *pixbuf, *pixel, *inpixel;
-
-       pinframe = (dspriteframe_t *)pin;
-
-       origin[0] = LittleLong (pinframe->origin[0]);
-       origin[1] = LittleLong (pinframe->origin[1]);
-       width = LittleLong (pinframe->width);
-       height = LittleLong (pinframe->height);
-       size = width * height * bytesperpixel;
-
-       pspriteframe = frame;
-
-       memset (pspriteframe, 0, sizeof (mspriteframe_t));
-
-       pspriteframe->left = origin[0];
-       pspriteframe->right = origin[0] + width;
-       pspriteframe->up = origin[1];
-       pspriteframe->down = origin[1] - height;
-
-       dist = pspriteframe->left*pspriteframe->left+pspriteframe->up*pspriteframe->up;
-       if (*modelradius < dist)
-               *modelradius = dist;
-       dist = pspriteframe->right*pspriteframe->right+pspriteframe->down*pspriteframe->down;
-       if (*modelradius < dist)
-               *modelradius = dist;
+       dspritegroup_t          *pingroup;
+       dspriteinterval_t       *pinintervals;
+       float                           modelradius, interval;
+       char                            tempname[MAX_QPATH], name[MAX_QPATH];
+       byte                            *pixbuf;
+       long                            startframes;
+       modelradius = 0;
 
        Mod_Sprite_StripExtension(loadmodel->name, tempname);
-       sprintf (name, "%s_%i", tempname, framenum);
-       pspriteframe->texture = loadtextureimagewithmask(name, 0, 0, false, r_mipsprites.value, true);
-       pspriteframe->fogtexture = image_masktex;
 
-       pixbuf = qmalloc(width*height*4);
+       if (loadmodel->numframes < 1)
+               Host_Error ("Mod_Sprite_SharedSetup: Invalid # of frames: %d\n", loadmodel->numframes);
 
-       inpixel = (byte *)(pinframe + 1);
-       pixel = pixbuf;
-       if (bytesperpixel == 1)
-       {
-               for (i = 0;i < width * height;i++)
-               {
-                       *pixel++ = palette[inpixel[i]*4+0];
-                       *pixel++ = palette[inpixel[i]*4+1];
-                       *pixel++ = palette[inpixel[i]*4+2];
-                       *pixel++ = palette[inpixel[i]*4+3];
-               }
-       }
-       else
-               memcpy(pixel, inpixel, width*height*4);
-
-       if (!pspriteframe->texture)
-       {
-               pspriteframe->texture = R_LoadTexture (name, width, height, pixbuf, TEXF_ALPHA | TEXF_RGBA | (r_mipsprites.value ? TEXF_MIPMAP : 0) | TEXF_PRECACHE);
-               // make fog version (just alpha)
-               pixel = pixbuf;
-               for (i = 0;i < width*height;i++)
-               {
-                       *pixel++ = 255;
-                       *pixel++ = 255;
-                       *pixel++ = 255;
-                       pixel++;
-               }
-               sprintf (name, "%s_%ifog", loadmodel->name, framenum);
-               pspriteframe->fogtexture = R_LoadTexture (name, width, height, pixbuf, TEXF_ALPHA | TEXF_RGBA | (r_mipsprites.value ? TEXF_MIPMAP : 0) | TEXF_PRECACHE);
-       }
-
-       qfree(pixbuf);
-
-       return (void *)((byte *)pinframe + sizeof (dspriteframe_t) + size);
-}
-
-
-/*
-=================
-Mod_LoadSpriteGroup
-=================
-*/
-/*
-void *Mod_LoadSpriteGroup (void * pin, mspriteframe_t *frame, int numframes, int framenum, int bytesperpixel)
-{
-       int i;
-       void *ptemp;
-
-       ptemp = (void *)(sizeof(dspriteinterval_t) * numframes + sizeof(dspritegroup_t) + (int) pin);
-
-       for (i = 0;i < numframes;i++)
-               ptemp = Mod_LoadSpriteFrame (ptemp, frame++, framenum * 100 + i, bytesperpixel);
-
-       return ptemp;
-}
-*/
+       loadmodel->type = mod_sprite;
+       loadmodel->flags = EF_FULLBRIGHT;
 
-// this actually handles both quake sprite and darkplaces sprite32
-void Mod_LoadQuakeSprite (model_t *mod, void *buffer)
-{
-       int                                     i, j, version, numframes, realframes, size, bytesperpixel, start, end, total;
-       dsprite_t                       *pin;
-       msprite_t                       *psprite;
-       dspriteframetype_t      *pframetype;
-       dspriteframe_t          *pframe;
-       animscene_t                     *animscenes;
-       mspriteframe_t          *frames;
-       dspriteframe_t          **framedata;
-       float                           modelradius;
-
-       modelradius = 0;
-
-       start = Hunk_LowMark ();
-
-       mod->flags = EF_FULLBRIGHT;
        // LordHavoc: hack to allow sprites to be non-fullbright
-       for (i = 0;i < MAX_QPATH && mod->name[i];i++)
+       for (i = 0;i < MAX_QPATH && loadmodel->name[i];i++)
        {
-               if (mod->name[i] == '!')
+               if (loadmodel->name[i] == '!')
                {
-                       mod->flags &= ~EF_FULLBRIGHT;
+                       loadmodel->flags &= ~EF_FULLBRIGHT;
                        break;
                }
        }
 
-       // build a list of frames while parsing
-       framedata = qmalloc(65536*sizeof(dspriteframe_t));
-
-       pin = (dsprite_t *)buffer;
-
-       version = LittleLong (pin->version);
        // LordHavoc: 32bit textures
-       bytesperpixel = 1;
-       if (version == SPRITE32_VERSION)
-               bytesperpixel = 4;
-
-       numframes = LittleLong (pin->numframes);
-
-       psprite = Hunk_AllocName (sizeof(msprite_t), va("%s info", loadname));
-
-//     mod->cache.data = psprite;
-
-       psprite->type = LittleLong (pin->type);
-//     maxwidth = LittleLong (pin->width);
-//     maxheight = LittleLong (pin->height);
-//     psprite->beamlength = LittleFloat (pin->beamlength);
-       mod->synctype = LittleLong (pin->synctype);
-//     psprite->numframes = numframes;
-
-//     mod->mins[0] = mod->mins[1] = -maxwidth/2;
-//     mod->maxs[0] = mod->maxs[1] = maxwidth/2;
-//     mod->mins[2] = -maxheight/2;
-//     mod->maxs[2] = maxheight/2;
+       if (version != SPRITE_VERSION && version != SPRITE32_VERSION && version != SPRITEHL_VERSION)
+               Host_Error("Mod_Sprite_SharedSetup: unsupported version %i, only %i (quake), %i (HalfLife), and %i (sprite32) supported", version, SPRITE_VERSION, SPRITEHL_VERSION, SPRITE32_VERSION);
 
 //
 // load the frames
 //
-       if (numframes < 1)
-               Host_Error ("Mod_LoadQuakeSprite: Invalid # of frames: %d\n", numframes);
-
-       mod->numframes = numframes;
-
-       pframetype = (dspriteframetype_t *)(pin + 1);
-
-       animscenes = Hunk_AllocName(sizeof(animscene_t) * mod->numframes, va("%s sceneinfo", loadname));
-
+       startframes = datapointer;
        realframes = 0;
-
-       for (i = 0;i < numframes;i++)
+       for (i = 0;i < loadmodel->numframes;i++)
        {
-               spriteframetype_t       frametype;
-
-               frametype = LittleLong (pframetype->type);
+               pinframetype = (dspriteframetype_t *)datapointer;
+               datapointer += sizeof(dspriteframetype_t);
 
-               sprintf(animscenes[i].name, "frame%i", i);
-               animscenes[i].firstframe = realframes;
-               animscenes[i].loop = true;
-               if (frametype == SPR_SINGLE)
-               {
-                       animscenes[i].framecount = 1;
-                       animscenes[i].framerate = 10;
-                       pframe = (dspriteframe_t *) (pframetype + 1);
-                       framedata[realframes] = pframe;
-                       size = LittleLong(pframe->width) * LittleLong(pframe->height) * bytesperpixel;
-                       pframetype = (dspriteframetype_t *) (size + sizeof(dspriteframe_t) + (int) pframe);
-                       realframes++;
-               }
+               if (LittleLong (pinframetype->type) == SPR_SINGLE)
+                       groupframes = 1;
                else
                {
-                       j = LittleLong(((dspritegroup_t *) (sizeof(dspriteframetype_t) + (int) pframetype))->numframes);
-                       animscenes[i].framecount = j;
-                       // FIXME: support variable framerate?
-                       animscenes[i].framerate = 1.0f / LittleFloat(((dspriteinterval_t *) (sizeof(dspritegroup_t) + sizeof(dspriteframetype_t) + (int) pframetype))->interval);
-                       pframe = (dspriteframe_t *) (sizeof(dspriteinterval_t) * j + sizeof(dspritegroup_t) + sizeof(dspriteframetype_t) + (int) pframetype);
-                       while (j--)
-                       {
-                               framedata[realframes] = pframe;
-                               size = LittleLong(pframe->width) * LittleLong(pframe->height) * bytesperpixel;
-                               pframe = (dspriteframe_t *) (size + sizeof(dspriteframe_t) + (int) pframe);
-                               realframes++;
-                       }
-                       pframetype = (dspriteframetype_t *) pframe;
-               }
-       }
+                       pingroup = (dspritegroup_t *)datapointer;
+                       datapointer += sizeof(dspritegroup_t);
 
-       mod->ofs_scenes = (int) animscenes - (int) psprite;
+                       groupframes = LittleLong(pingroup->numframes);
 
-       frames = Hunk_AllocName(sizeof(mspriteframe_t) * realframes, va("%s frames", loadname));
+                       datapointer += sizeof(dspriteinterval_t) * groupframes;
+               }
 
-       realframes = 0;
-       for (i = 0;i < numframes;i++)
-       {
-               for (j = 0;j < animscenes[i].framecount;j++)
+               for (j = 0;j < groupframes;j++)
                {
-                       Mod_LoadSpriteFrame (framedata[realframes], frames + realframes, i, bytesperpixel, (byte *)&d_8to24table, &modelradius);
-                       realframes++;
+                       pinframe = (dspriteframe_t *)datapointer;
+                       if (version == SPRITE32_VERSION)
+                               datapointer += sizeof(dspriteframe_t) + LittleLong(pinframe->width) * LittleLong(pinframe->height) * 4;
+                       else //if (version == SPRITE_VERSION || version == SPRITEHL_VERSION)
+                               datapointer += sizeof(dspriteframe_t) + LittleLong(pinframe->width) * LittleLong(pinframe->height);
                }
+               realframes += groupframes;
        }
 
-       psprite->ofs_frames = (int) frames - (int) psprite;
-
-       qfree(framedata);
+       loadmodel->animscenes = Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
+       loadmodel->sprdata_frames = Mem_Alloc(loadmodel->mempool, sizeof(mspriteframe_t) * realframes);
 
-       mod->type = mod_sprite;
-
-       modelradius = sqrt(modelradius);
-       for (i = 0;i < 3;i++)
+       datapointer = startframes;
+       realframes = 0;
+       for (i = 0;i < loadmodel->numframes;i++)
        {
-               mod->normalmins[i] = mod->yawmins[i] = mod->rotatedmins[i] = -modelradius;
-               mod->normalmaxs[i] = mod->yawmaxs[i] = mod->rotatedmaxs[i] = modelradius;
-       }
-//     mod->modelradius = modelradius;
-
-// move the complete, relocatable sprite model to the cache
-       end = Hunk_LowMark ();
-       mod->cachesize = total = end - start;
+               pinframetype = (dspriteframetype_t *)datapointer;
+               datapointer += sizeof(dspriteframetype_t);
 
-       Cache_Alloc (&mod->cache, total, loadname);
-       if (!mod->cache.data)
-               return;
-       memcpy (mod->cache.data, psprite, total);
-
-       Hunk_FreeToLowMark (start);
-}
-
-void Mod_LoadHLSprite (model_t *mod, void *buffer)
-{
-       int                                     i, j, numframes, realframes, size, start, end, total, rendermode;
-       byte                            palette[256][4], *in;
-       dspritehl_t                     *pin;
-       msprite_t                       *psprite;
-       dspriteframetype_t      *pframetype;
-       dspriteframe_t          *pframe;
-       animscene_t                     *animscenes;
-       mspriteframe_t          *frames;
-       dspriteframe_t          **framedata;
-       float                           modelradius;
-
-       modelradius = 0;
-
-       start = Hunk_LowMark ();
-
-       mod->flags = EF_FULLBRIGHT;
-
-       // build a list of frames while parsing
-       framedata = qmalloc(65536*sizeof(dspriteframe_t));
-
-       pin = (dspritehl_t *)buffer;
-
-       numframes = LittleLong (pin->numframes);
-
-       psprite = Hunk_AllocName (sizeof(msprite_t), va("%s info", loadname));
-
-       psprite->type = LittleLong (pin->type);
-//     maxwidth = LittleLong (pin->width);
-//     maxheight = LittleLong (pin->height);
-       mod->synctype = LittleLong (pin->synctype);
-       rendermode = pin->rendermode;
-
-//     mod->mins[0] = mod->mins[1] = -maxwidth/2;
-//     mod->maxs[0] = mod->maxs[1] = maxwidth/2;
-//     mod->mins[2] = -maxheight/2;
-//     mod->maxs[2] = maxheight/2;
-
-//
-// load the frames
-//
-       if (numframes < 1)
-               Host_Error ("Mod_LoadHLSprite: Invalid # of frames: %d\n", numframes);
-
-       mod->numframes = numframes;
-
-       in = (byte *)(pin + 1);
-       i = in[0] + in[1] * 256;
-       if (i != 256)
-               Host_Error ("Mod_LoadHLSprite: unexpected number of palette colors %i (should be 256)", i);
-       in += 2;
-       switch(rendermode)
-       {
-       case SPRHL_NORMAL:
-               for (i = 0;i < 256;i++)
-               {
-                       palette[i][0] = *in++;
-                       palette[i][1] = *in++;
-                       palette[i][2] = *in++;
-                       palette[i][3] = 255;
-               }
-               palette[255][0] = palette[255][1] = palette[255][2] = palette[255][3] = 0;
-               break;
-       case SPRHL_ADDITIVE:
-               for (i = 0;i < 256;i++)
+               if (LittleLong (pinframetype->type) == SPR_SINGLE)
                {
-                       palette[i][0] = *in++;
-                       palette[i][1] = *in++;
-                       palette[i][2] = *in++;
-                       palette[i][3] = 255;
+                       groupframes = 1;
+                       interval = 0.1f;
                }
-//             palette[255][0] = palette[255][1] = palette[255][2] = palette[255][3] = 0;
-               mod->flags |= EF_ADDITIVE;
-               break;
-       case SPRHL_INDEXALPHA:
-               for (i = 0;i < 256;i++)
-               {
-                       palette[i][0] = 255;
-                       palette[i][1] = 255;
-                       palette[i][2] = 255;
-                       palette[i][3] = i;
-                       in += 3;
-               }
-               break;
-       case SPRHL_ALPHATEST:
-               for (i = 0;i < 256;i++)
+               else
                {
-                       palette[i][0] = *in++;
-                       palette[i][1] = *in++;
-                       palette[i][2] = *in++;
-                       palette[i][3] = 255;
-               }
-               palette[0][0] = palette[0][1] = palette[0][2] = palette[0][3] = 0;
-               break;
-       default:
-               Host_Error("Mod_LoadHLSprite: unknown texFormat (%i, should be 0, 1, 2, or 3)\n", i);
-               return;
-       }
-
-       pframetype = (dspriteframetype_t *)in;
+                       pingroup = (dspritegroup_t *)datapointer;
+                       datapointer += sizeof(dspritegroup_t);
 
-       animscenes = Hunk_AllocName(sizeof(animscene_t) * mod->numframes, va("%s sceneinfo", loadname));
+                       groupframes = LittleLong(pingroup->numframes);
 
-       realframes = 0;
+                       pinintervals = (dspriteinterval_t *)datapointer;
+                       datapointer += sizeof(dspriteinterval_t) * groupframes;
 
-       for (i = 0;i < numframes;i++)
-       {
-               spriteframetype_t       frametype;
+                       interval = LittleFloat(pinintervals[0].interval);
+                       if (interval < 0.01f)
+                               Host_Error("Mod_Sprite_SharedSetup: invalid interval");
+               }
 
-               frametype = LittleLong (pframetype->type);
+               sprintf(loadmodel->animscenes[i].name, "frame %i", i);
+               loadmodel->animscenes[i].firstframe = realframes;
+               loadmodel->animscenes[i].framecount = groupframes;
+               loadmodel->animscenes[i].framerate = 1.0f / interval;
+               loadmodel->animscenes[i].loop = true;
 
-               sprintf(animscenes[i].name, "frame%i", i);
-               animscenes[i].firstframe = realframes;
-               animscenes[i].loop = true;
-               if (frametype == SPR_SINGLE)
-               {
-                       animscenes[i].framecount = 1;
-                       animscenes[i].framerate = 10;
-                       pframe = (dspriteframe_t *) (pframetype + 1);
-                       framedata[realframes] = pframe;
-                       size = LittleLong(pframe->width) * LittleLong(pframe->height);
-                       pframetype = (dspriteframetype_t *) (size + sizeof(dspriteframe_t) + (int) pframe);
-                       realframes++;
-               }
-               else
+               for (j = 0;j < groupframes;j++)
                {
-                       j = LittleLong(((dspritegroup_t *) (sizeof(dspriteframetype_t) + (int) pframetype))->numframes);
-                       animscenes[i].framecount = j;
-                       // FIXME: support variable framerate?
-                       animscenes[i].framerate = 1.0f / LittleFloat(((dspriteinterval_t *) (sizeof(dspritegroup_t) + sizeof(dspriteframetype_t) + (int) pframetype))->interval);
-                       pframe = (dspriteframe_t *) (sizeof(dspriteinterval_t) * j + sizeof(dspritegroup_t) + sizeof(dspriteframetype_t) + (int) pframetype);
-                       while (j--)
+                       pinframe = (dspriteframe_t *)datapointer;
+                       datapointer += sizeof(dspriteframe_t);
+
+                       origin[0] = LittleLong (pinframe->origin[0]);
+                       origin[1] = LittleLong (pinframe->origin[1]);
+                       width = LittleLong (pinframe->width);
+                       height = LittleLong (pinframe->height);
+
+                       loadmodel->sprdata_frames[realframes].left = origin[0];
+                       loadmodel->sprdata_frames[realframes].right = origin[0] + width;
+                       loadmodel->sprdata_frames[realframes].up = origin[1];
+                       loadmodel->sprdata_frames[realframes].down = origin[1] - height;
+
+                       x = max(loadmodel->sprdata_frames[realframes].left * loadmodel->sprdata_frames[realframes].left, loadmodel->sprdata_frames[realframes].right * loadmodel->sprdata_frames[realframes].right);
+                       y = max(loadmodel->sprdata_frames[realframes].up * loadmodel->sprdata_frames[realframes].up, loadmodel->sprdata_frames[realframes].down * loadmodel->sprdata_frames[realframes].down);
+                       if (modelradius < x + y)
+                               modelradius = x + y;
+
+                       if (groupframes > 1)
+                               sprintf (name, "%s_%i_%i", tempname, i, j);
+                       else
+                               sprintf (name, "%s_%i", tempname, i);
+                       loadmodel->sprdata_frames[realframes].texture = loadtextureimagewithmask(loadmodel->texturepool, name, 0, 0, false, r_mipsprites.integer, true);
+                       loadmodel->sprdata_frames[realframes].fogtexture = image_masktex;
+
+                       if (!loadmodel->sprdata_frames[realframes].texture)
                        {
-                               framedata[realframes] = pframe;
-                               size = LittleLong(pframe->width) * LittleLong(pframe->height);
-                               pframe = (dspriteframe_t *) (size + sizeof(dspriteframe_t) + (int) pframe);
-                               realframes++;
+                               pixbuf = Mem_Alloc(tempmempool, width*height*4);
+                               if (version == SPRITE32_VERSION)
+                                       memcpy(pixbuf, (byte *)datapointer, width*height*4);
+                               else //if (version == SPRITE_VERSION || version == SPRITEHL_VERSION)
+                                       Image_Copy8bitRGBA((byte *)datapointer, pixbuf, width*height, palette);
+
+                               loadmodel->sprdata_frames[realframes].texture = R_LoadTexture (loadmodel->texturepool, name, width, height, pixbuf, TEXTYPE_RGBA, TEXF_ALPHA | (r_mipsprites.integer ? TEXF_MIPMAP : 0) | TEXF_PRECACHE);
+
+                               // make fog version (just alpha)
+                               for (k = 0;k < width*height;k++)
+                               {
+                                       pixbuf[k*4+0] = 255;
+                                       pixbuf[k*4+1] = 255;
+                                       pixbuf[k*4+2] = 255;
+                               }
+                               if (groupframes > 1)
+                                       sprintf (name, "%s_%i_%ifog", tempname, i, j);
+                               else
+                                       sprintf (name, "%s_%ifog", tempname, i);
+                               loadmodel->sprdata_frames[realframes].fogtexture = R_LoadTexture (loadmodel->texturepool, name, width, height, pixbuf, TEXTYPE_RGBA, TEXF_ALPHA | (r_mipsprites.integer ? TEXF_MIPMAP : 0) | TEXF_PRECACHE);
+
+                               Mem_Free(pixbuf);
                        }
-                       pframetype = (dspriteframetype_t *) pframe;
-               }
-       }
-
-       mod->ofs_scenes = (int) animscenes - (int) psprite;
 
-       frames = Hunk_AllocName(sizeof(mspriteframe_t) * realframes, va("%s frames", loadname));
-
-       realframes = 0;
-       for (i = 0;i < numframes;i++)
-       {
-               for (j = 0;j < animscenes[i].framecount;j++)
-               {
-                       Mod_LoadSpriteFrame (framedata[realframes], frames + realframes, i, 1, &palette[0][0], &modelradius);
+                       if (version == SPRITE32_VERSION)
+                               datapointer += width * height * 4;
+                       else //if (version == SPRITE_VERSION || version == SPRITEHL_VERSION)
+                               datapointer += width * height;
                        realframes++;
                }
        }
 
-       psprite->ofs_frames = (int) frames - (int) psprite;
-
-       qfree(framedata);
-
-       mod->type = mod_sprite;
-
        modelradius = sqrt(modelradius);
        for (i = 0;i < 3;i++)
        {
-               mod->normalmins[i] = mod->yawmins[i] = mod->rotatedmins[i] = -modelradius;
-               mod->normalmaxs[i] = mod->yawmaxs[i] = mod->rotatedmaxs[i] = modelradius;
+               loadmodel->normalmins[i] = loadmodel->yawmins[i] = loadmodel->rotatedmins[i] = -modelradius;
+               loadmodel->normalmaxs[i] = loadmodel->yawmaxs[i] = loadmodel->rotatedmaxs[i] = modelradius;
        }
-
-// move the complete, relocatable sprite model to the cache
-       end = Hunk_LowMark ();
-       mod->cachesize = total = end - start;
-
-       Cache_Alloc (&mod->cache, total, loadname);
-       if (!mod->cache.data)
-               return;
-       memcpy (mod->cache.data, psprite, total);
-
-       Hunk_FreeToLowMark (start);
+//     loadmodel->modelradius = modelradius;
 }
 
 void Mod_Sprite_SERAddEntity(void)
@@ -497,22 +239,102 @@ Mod_LoadSpriteModel
 void Mod_LoadSpriteModel (model_t *mod, void *buffer)
 {
        int version;
-       version = ((dsprite_t *)buffer)->version;
-       switch(version)
+       loadmodel->SERAddEntity = Mod_Sprite_SERAddEntity;
+       loadmodel->Draw = R_DrawSpriteModel;
+       loadmodel->DrawSky = NULL;
+       loadmodel->DrawShadow = NULL;
+
+       version = LittleLong(((dsprite_t *)buffer)->version);
+       if (version == SPRITE_VERSION || SPRITE32_VERSION)
+       {
+               dsprite_t                       *pinsprite;
+               long                            datapointer;
+
+               datapointer = (long) buffer;
+
+               pinsprite = (dsprite_t *)datapointer;
+               datapointer += sizeof(dsprite_t);
+
+               loadmodel->numframes = LittleLong (pinsprite->numframes);
+               loadmodel->sprnum_type = LittleLong (pinsprite->type);
+               loadmodel->synctype = LittleLong (pinsprite->synctype);
+
+               Mod_Sprite_SharedSetup(datapointer, LittleLong (pinsprite->version), d_8to24table);
+       }
+       else if (version == SPRITEHL_VERSION)
        {
-       case SPRITEHL_VERSION:
-               Mod_LoadHLSprite (mod, buffer);
-               break;
-       case SPRITE_VERSION:
-       case SPRITE32_VERSION:
-               Mod_LoadQuakeSprite(mod, buffer);
-               break;
-       default:
-               Host_Error ("Mod_LoadSpriteModel: %s has wrong version number (%i should be 1 (quake) or 32 (sprite32) or 2 (halflife)", mod->name, version);
-               break;
+               int                                     i, rendermode;
+               byte                            palette[256][4], *in;
+               dspritehl_t                     *pinsprite;
+               long                            datapointer;
+
+               datapointer = (long) buffer;
+
+               pinsprite = (dspritehl_t *)datapointer;
+               datapointer += sizeof(dspritehl_t);
+
+               loadmodel->numframes = LittleLong (pinsprite->numframes);
+               loadmodel->sprnum_type = LittleLong (pinsprite->type);
+               loadmodel->synctype = LittleLong (pinsprite->synctype);
+               rendermode = pinsprite->rendermode;
+
+               in = (byte *)datapointer;
+               datapointer += 2;
+               i = in[0] + in[1] * 256;
+               if (i != 256)
+                       Host_Error ("Mod_LoadHLSprite: unexpected number of palette colors %i (should be 256)", i);
+               in = (byte *)datapointer;
+               datapointer += 768;
+               switch(rendermode)
+               {
+               case SPRHL_NORMAL:
+                       for (i = 0;i < 255;i++)
+                       {
+                               palette[i][0] = *in++;
+                               palette[i][1] = *in++;
+                               palette[i][2] = *in++;
+                               palette[i][3] = 255;
+                       }
+                       palette[255][0] = palette[255][1] = palette[255][2] = palette[255][3] = 0;
+                       break;
+               case SPRHL_ADDITIVE:
+                       for (i = 0;i < 256;i++)
+                       {
+                               palette[i][0] = *in++;
+                               palette[i][1] = *in++;
+                               palette[i][2] = *in++;
+                               palette[i][3] = 255;
+                       }
+       //              palette[255][0] = palette[255][1] = palette[255][2] = palette[255][3] = 0;
+                       loadmodel->flags |= EF_ADDITIVE;
+                       break;
+               case SPRHL_INDEXALPHA:
+                       for (i = 0;i < 256;i++)
+                       {
+                               palette[i][0] = 255;
+                               palette[i][1] = 255;
+                               palette[i][2] = 255;
+                               palette[i][3] = i;
+                               in += 3;
+                       }
+                       break;
+               case SPRHL_ALPHATEST:
+                       for (i = 0;i < 255;i++)
+                       {
+                               palette[i][0] = *in++;
+                               palette[i][1] = *in++;
+                               palette[i][2] = *in++;
+                               palette[i][3] = 255;
+                       }
+                       palette[0][0] = palette[0][1] = palette[0][2] = palette[0][3] = 0;
+                       break;
+               default:
+                       Host_Error("Mod_LoadHLSprite: unknown texFormat (%i, should be 0, 1, 2, or 3)\n", i);
+                       return;
+               }
+
+               Mod_Sprite_SharedSetup(datapointer, LittleLong (pinsprite->version), (int *)(&palette[0][0]));
        }
-       mod->SERAddEntity = Mod_Sprite_SERAddEntity;
-       mod->DrawEarly = R_DrawSpriteModel;
-       mod->DrawLate = NULL;
-       mod->DrawShadow = NULL;
+       else
+               Host_Error ("Mod_LoadSpriteModel: %s has wrong version number (%i should be 1 (quake) or 32 (sprite32) or 2 (halflife)", loadmodel->name, version);
 }
index 05b0dce3c9484ebeaa79c6ecf4b4bf0f4bb71368..394fb830c3c52c48d83542cfb488cc6a208f6776 100644 (file)
@@ -31,22 +31,9 @@ SPRITE MODELS
 // FIXME: shorten these?
 typedef struct mspriteframe_s
 {
-//     int             width;
-//     int             height;
        float   up, down, left, right;
        rtexture_t *texture, *fogtexture;
 } mspriteframe_t;
 
-typedef struct
-{
-       int                                     type;
-//     int                                     maxwidth;
-//     int                                     maxheight;
-//     int                                     numframes;
-//     float                           beamlength;             // remove?
-//     void                            *cachespot;             // remove?
-       int                                     ofs_frames;
-} msprite_t;
-
 extern void Mod_LoadSpriteModel (struct model_s *mod, void *buffer);
 extern void Mod_SpriteInit(void);
index 41691072378464104843128017d8ac166f00b579..951ed91fedebbafcf3393bf16236c014aef226fe 100644 (file)
@@ -107,7 +107,3 @@ typedef struct {
 typedef struct {
        aliasskintype_t type;
 } daliasskintype_t;
-
-#define IDPOLYHEADER   (('O'<<24)+('P'<<16)+('D'<<8)+'I')
-                                                                                                               // little-endian "IDPO"
-
index b457a672da4c659c0f7e792981083f3c9e16468f..df40cad6b5dbd21c74218c5673b6a4e8dba0cbcc 100644 (file)
@@ -691,6 +691,8 @@ NET_Init
 ====================
 */
 
+static mempool_t *net_mempool;
+
 void NET_Init (void)
 {
        int                     i;
@@ -720,16 +722,18 @@ void NET_Init (void)
 
        SetNetTime();
 
+       net_mempool = Mem_AllocPool("qsocket");
+       s = Mem_Alloc(net_mempool, net_numsockets * sizeof(qsocket_t));
        for (i = 0; i < net_numsockets; i++)
        {
-               s = (qsocket_t *)Hunk_AllocName(sizeof(qsocket_t), "qsocket");
                s->next = net_freeSockets;
                net_freeSockets = s;
                s->disconnected = true;
+               s++;
        }
 
        // allocate space for network message buffer
-       SZ_Alloc (&net_message, NET_MAXMESSAGE);
+       SZ_Alloc (&net_message, NET_MAXMESSAGE, "net_message");
 
        Cvar_RegisterVariable (&net_messagetimeout);
        Cvar_RegisterVariable (&hostname);
@@ -783,6 +787,8 @@ void                NET_Shutdown (void)
                        net_drivers[net_driverlevel].initialized = false;
                }
        }
+
+       Mem_FreePool(&net_mempool);
 }
 
 
index 1de9ec732e677bcb9f78328845fa014073f0bcca..cdcbd1e7144fa0c3972e47e6395952888a9bd26a 100644 (file)
--- a/palette.c
+++ b/palette.c
@@ -6,8 +6,6 @@ unsigned int d_8to24table[256];
 byte host_basepal[768];
 byte texgamma[256];
 
-static float texture_gamma = 1.0;
-
 cvar_t vid_gamma = {CVAR_SAVE, "vid_gamma", "1"};
 cvar_t vid_brightness = {CVAR_SAVE, "vid_brightness", "1"};
 cvar_t vid_contrast = {CVAR_SAVE, "vid_contrast", "1"};
@@ -116,32 +114,6 @@ void BuildGammaTable16(float prescale, float gamma, float scale, float base, uns
        }
 }
 
-void Texture_Gamma (void)
-{
-       int i, adjusted;
-       double invgamma;
-
-       texture_gamma = 1;
-       if ((i = COM_CheckParm("-gamma")))
-               texture_gamma = atof(com_argv[i+1]);
-       texture_gamma = bound(0.1, texture_gamma, 5.0);
-
-       if (texture_gamma == 1) // LordHavoc: dodge the math
-       {
-               for (i = 0;i < 256;i++)
-                       texgamma[i] = i;
-       }
-       else
-       {
-               invgamma = 1.0 / texture_gamma;
-               for (i = 0;i < 256;i++)
-               {
-                       adjusted = (int) ((255.0 * pow((double) i / 255.0, invgamma)) + 0.5);
-                       texgamma[i] = bound(0, adjusted, 255);
-               }
-       }
-}
-
 qboolean hardwaregammasupported = false;
 void VID_UpdateGamma(qboolean force)
 {
@@ -189,13 +161,12 @@ void Gamma_Init(void)
 void Palette_Init(void)
 {
        byte *pal;
-       pal = (byte *)COM_LoadMallocFile ("gfx/palette.lmp", false);
+       pal = (byte *)COM_LoadFile ("gfx/palette.lmp", false);
        if (!pal)
                Sys_Error ("Couldn't load gfx/palette.lmp");
        memcpy(host_basepal, pal, 765);
-       qfree(pal);
+       Mem_Free(pal);
        host_basepal[765] = host_basepal[766] = host_basepal[767] = 0; // LordHavoc: force the transparent color to black
        Palette_Setup8to24();
 //     Palette_Setup15to8();
-       Texture_Gamma();
 }
index 9fd075c1b14061cd17dabe75c84fdaf5272011d8..d12c40a8db976d40231f00b756e091e98c958a9c 100644 (file)
--- a/palette.h
+++ b/palette.h
@@ -5,7 +5,6 @@ extern cvar_t vid_contrast;
 
 extern unsigned int d_8to24table[256];
 //extern byte d_15to8table[32768];
-extern byte texgamma[256];
 
 extern qboolean hardwaregammasupported;
 
index 3575298868ee88bd1d2bd16673c597f0b7b57661..1ad130c2c08525f0d668eb44c5bc620dfdbf3933 100644 (file)
--- a/portals.c
+++ b/portals.c
@@ -203,6 +203,7 @@ int Portal_CheckPolygon(model_t *model, vec3_t eye, float *polypoints, int numpo
 
        portal_markid++;
 
+       Mod_CheckLoaded(model);
        Portal_PolygonRecursiveMarkLeafs(model->nodes, polypoints, numpoints);
 
        eyeleaf = Mod_PointInLeaf(eye, model);
index d5ba332975b11b4b8803da9959995014b2b8001d..08a1368efcc24e45b7bad39162740e9f93375f61 100644 (file)
--- a/pr_cmds.c
+++ b/pr_cmds.c
@@ -646,7 +646,7 @@ void PF_ambientsound (void)
        for (soundnum=0, check = sv.sound_precache ; *check ; check++, soundnum++)
                if (!strcmp(*check,samp))
                        break;
-                       
+
        if (!*check)
        {
                Con_Printf ("no precache: %s\n", samp);
@@ -1006,7 +1006,7 @@ localcmd (string)
 void PF_localcmd (void)
 {
        char    *str;
-       
+
        str = G_STRING(OFS_PARM0);      
        Cbuf_AddText (str);
 }
@@ -1326,7 +1326,7 @@ void PF_precache_model (void)
                PR_RunError ("PF_Precache_*: Precache can only be done in spawn functions");
                
        s = G_STRING(OFS_PARM0);
-       if (hlbsp && ((!s) || (!s[0])))
+       if (sv.worldmodel->ishlbsp && ((!s) || (!s[0])))
                return;
        G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
        PR_CheckEmptyString (s);
@@ -1336,7 +1336,7 @@ void PF_precache_model (void)
                if (!sv.model_precache[i])
                {
                        sv.model_precache[i] = s;
-                       sv.models[i] = Mod_ForName (s, true);
+                       sv.models[i] = Mod_ForName (s, true, true, false);
                        return;
                }
                if (!strcmp(sv.model_precache[i], s))
@@ -1571,7 +1571,7 @@ void PF_aim (void)
        VectorMA (start, 2048, dir, end);
        tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
        if (tr.ent && tr.ent->v.takedamage == DAMAGE_AIM
-       && (!teamplay.value || ent->v.team <=0 || ent->v.team != tr.ent->v.team) )
+       && (!teamplay.integer || ent->v.team <=0 || ent->v.team != tr.ent->v.team) )
        {
                VectorCopy (pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
                return;
@@ -1590,7 +1590,7 @@ void PF_aim (void)
                        continue;
                if (check == ent)
                        continue;
-               if (teamplay.value && ent->v.team > 0 && ent->v.team == check->v.team)
+               if (teamplay.integer && ent->v.team > 0 && ent->v.team == check->v.team)
                        continue;       // don't aim at teammate
                for (j=0 ; j<3 ; j++)
                        end[j] = check->v.origin[j]
index 5b348ff59e464fc91427082cccd82d824aaff481..dc4166ad8647e50406ff86cb71a499a1c6186532 100644 (file)
@@ -8,7 +8,7 @@ of the License, or (at your option) any later version.
 
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 See the GNU General Public License for more details.
 
@@ -32,7 +32,10 @@ float                        *pr_globals;                    // same as pr_global_struct
 int                            pr_edict_size;                  // in bytes
 int                            pr_edictareasize;               // LordHavoc: in bytes
 
-unsigned short         pr_crc;
+unsigned short pr_crc;
+
+mempool_t              *progs_mempool;
+mempool_t              *edictstring_mempool;
 
 int            type_size[8] = {1,sizeof(string_t)/4,1,3,1,1,sizeof(func_t)/4,sizeof(void *)/4};
 
@@ -109,7 +112,6 @@ int eval_viewmodelforclient;
 int eval_nodrawtoclient;
 int eval_exteriormodeltoclient;
 int eval_drawonlytoclient;
-int eval_colormod;
 int eval_ping;
 int eval_movement;
 int eval_pmodel;
@@ -158,7 +160,6 @@ void FindEdictFieldOffsets(void)
        eval_nodrawtoclient = FindFieldOffset("nodrawtoclient");
        eval_exteriormodeltoclient = FindFieldOffset("exteriormodeltoclient");
        eval_drawonlytoclient = FindFieldOffset("drawonlytoclient");
-       eval_colormod = FindFieldOffset("colormod");
        eval_ping = FindFieldOffset("ping");
        eval_movement = FindFieldOffset("movement");
        eval_pmodel = FindFieldOffset("pmodel");
@@ -297,7 +298,7 @@ ddef_t *ED_FindField (char *name)
 {
        ddef_t          *def;
        int                     i;
-       
+
        for (i=0 ; i<progs->numfielddefs ; i++)
        {
                def = &pr_fielddefs[i];
@@ -387,12 +388,14 @@ PR_ValueString
 Returns a string describing *data in a type specific manner
 =============
 */
+int NoCrash_NUM_FOR_EDICT(edict_t *e);
 char *PR_ValueString (etype_t type, eval_t *val)
 {
-       static char     line[1024]; // LordHavoc: enlarged a bit (was 256)
-       ddef_t          *def;
-       dfunction_t     *f;
-       
+       static char line[1024]; // LordHavoc: enlarged a bit (was 256)
+       ddef_t *def;
+       dfunction_t *f;
+       int n;
+
        type &= ~DEF_SAVEGLOBAL;
 
        switch (type)
@@ -400,8 +403,12 @@ char *PR_ValueString (etype_t type, eval_t *val)
        case ev_string:
                sprintf (line, "%s", pr_strings + val->string);
                break;
-       case ev_entity: 
-               sprintf (line, "entity %i", NUM_FOR_EDICT(PROG_TO_EDICT(val->edict)) );
+       case ev_entity:
+               n = NoCrash_NUM_FOR_EDICT(PROG_TO_EDICT(val->edict));
+               if (n < 0 || n >= MAX_EDICTS)
+                       sprintf (line, "entity %i (invalid!)", n);
+               else
+                       sprintf (line, "entity %i", n);
                break;
        case ev_function:
                f = pr_functions + val->function;
@@ -575,7 +582,7 @@ void ED_Print (edict_t *ed)
 
        // if the value is still all 0, skip the field
                type = d->type & ~DEF_SAVEGLOBAL;
-               
+
                for (j=0 ; j<type_size[type] ; j++)
                        if (v[j])
                                break;
@@ -643,7 +650,7 @@ void ED_Write (QFile *f, edict_t *ed)
                name = pr_strings + d->s_name;
                if (name[strlen(name)-2] == '_')
                        continue;       // skip _x, _y, _z vars
-                       
+
                v = (int *)((char *)&ed->v + d->ofs*4);
 
        // if the value is still all 0, skip the field
@@ -653,9 +660,9 @@ void ED_Write (QFile *f, edict_t *ed)
                                break;
                if (j == type_size[type])
                        continue;
-       
+
                Qprintf (f,"\"%s\" ",name);
-               Qprintf (f,"\"%s\"\n", PR_UglyValueString(d->type, (eval_t *)v));               
+               Qprintf (f,"\"%s\"\n", PR_UglyValueString(d->type, (eval_t *)v));
        }
 
        Qprintf (f, "}\n");
@@ -799,7 +806,7 @@ void ED_ParseGlobals (char *data)
 
                strcpy (keyname, com_token);
 
-       // parse value  
+       // parse value
                data = COM_Parse (data);
                if (!data)
                        Host_Error ("ED_ParseEntity: EOF without closing brace");
@@ -831,9 +838,9 @@ char *ED_NewString (char *string)
 {
        char    *new, *new_p;
        int             i,l;
-       
+
        l = strlen(string) + 1;
-       new = Hunk_AllocName (l, "edict string");
+       new = Mem_Alloc(edictstring_mempool, l);
        new_p = new;
 
        for (i=0 ; i< l ; i++)
@@ -896,7 +903,7 @@ qboolean    ED_ParseEpair (void *base, ddef_t *key, char *s)
                        w = v = v+1;
                }
                break;
-               
+
        case ev_entity:
                *(int *)d = EDICT_TO_PROG(EDICT_NUM(atoi (s)));
                break;
@@ -922,7 +929,7 @@ qboolean    ED_ParseEpair (void *base, ddef_t *key, char *s)
                }
                *(func_t *)d = func - pr_functions;
                break;
-               
+
        default:
                break;
        }
@@ -954,27 +961,27 @@ char *ED_ParseEdict (char *data, edict_t *ent)
 
 // go through all the dictionary pairs
        while (1)
-       {       
+       {
        // parse key
                data = COM_Parse (data);
                if (com_token[0] == '}')
                        break;
                if (!data)
                        Host_Error ("ED_ParseEntity: EOF without closing brace");
-               
-// anglehack is to allow QuakeEd to write single scalar angles
-// and allow them to be turned into vectors. (FIXME...)
-if (!strcmp(com_token, "angle"))
-{
-       strcpy (com_token, "angles");
-       anglehack = true;
-}
-else
-       anglehack = false;
 
-// FIXME: change light to _light to get rid of this hack
-if (!strcmp(com_token, "light"))
-       strcpy (com_token, "light_lev");        // hack for single light def
+               // anglehack is to allow QuakeEd to write single scalar angles
+               // and allow them to be turned into vectors. (FIXME...)
+               if (!strcmp(com_token, "angle"))
+               {
+                       strcpy (com_token, "angles");
+                       anglehack = true;
+               }
+               else
+                       anglehack = false;
+
+               // FIXME: change light to _light to get rid of this hack
+               if (!strcmp(com_token, "light"))
+                       strcpy (com_token, "light_lev");        // hack for single light def
 
                strcpy (keyname, com_token);
 
@@ -994,13 +1001,13 @@ if (!strcmp(com_token, "light"))
                if (com_token[0] == '}')
                        Host_Error ("ED_ParseEntity: closing brace without data");
 
-               init = true;    
+               init = true;
 
 // keynames with a leading underscore are used for utility comments,
 // and are immediately discarded by quake
                if (keyname[0] == '_')
                        continue;
-               
+
                key = ED_FindField (keyname);
                if (!key)
                {
@@ -1008,12 +1015,12 @@ if (!strcmp(com_token, "light"))
                        continue;
                }
 
-if (anglehack)
-{
-char   temp[32];
-strcpy (temp, com_token);
-sprintf (com_token, "0 %s 0", temp);
-}
+               if (anglehack)
+               {
+                       char    temp[32];
+                       strcpy (temp, com_token);
+                       sprintf (com_token, "0 %s 0", temp);
+               }
 
                if (!ED_ParseEpair ((void *)&ent->v, key, com_token))
                        Host_Error ("ED_ParseEdict: parse error");
@@ -1046,7 +1053,7 @@ void ED_LoadFromFile (char *data)
        edict_t         *ent;
        int                     inhibit;
        dfunction_t     *func;
-       
+
        ent = NULL;
        inhibit = 0;
        pr_global_struct->time = sv.time;
@@ -1068,7 +1075,7 @@ void ED_LoadFromFile (char *data)
                data = ED_ParseEdict (data, ent);
 
 // remove things from different skill levels or deathmatch
-               if (deathmatch.value)
+               if (deathmatch.integer)
                {
                        if (((int)ent->v.spawnflags & SPAWNFLAG_NOT_DEATHMATCH))
                        {
@@ -1102,7 +1109,7 @@ void ED_LoadFromFile (char *data)
 
                if (!func)
                {
-                       if (developer.value) // don't confuse non-developers with errors
+                       if (developer.integer) // don't confuse non-developers with errors
                        {
                                Con_Printf ("No spawn function for:\n");
                                ED_Print (ent);
@@ -1159,7 +1166,6 @@ dpfield_t dpfields[] =
        {ev_entity, "nodrawtoclient"},
        {ev_entity, "exteriormodeltoclient"},
        {ev_entity, "drawonlytoclient"},
-       {ev_vector, "colormod"},
        {ev_float, "ping"},
        {ev_vector, "movement"},
        {ev_float, "pmodel"},
@@ -1176,14 +1182,24 @@ void PR_LoadProgs (void)
        int i;
        dstatement_t *st;
        ddef_t *infielddefs;
+       void *temp;
 
 // flush the non-C variable lookup cache
        for (i=0 ; i<GEFV_CACHESIZE ; i++)
                gefvCache[i].field[0] = 0;
 
-       progs = (dprograms_t *)COM_LoadHunkFile ("progs.dat", false);
-       if (!progs)
+       Mem_EmptyPool(progs_mempool);
+       Mem_EmptyPool(edictstring_mempool);
+
+       temp = COM_LoadFile ("progs.dat", false);
+       if (!temp)
                Host_Error ("PR_LoadProgs: couldn't load progs.dat");
+
+       progs = (dprograms_t *)Mem_Alloc(progs_mempool, com_filesize);
+
+       memcpy(progs, temp, com_filesize);
+       Mem_Free(temp);
+
        Con_DPrintf ("Programs occupy %iK.\n", com_filesize/1024);
 
        pr_crc = CRC_Block((byte *)progs, com_filesize);
@@ -1204,7 +1220,7 @@ void PR_LoadProgs (void)
        // we need to expand the fielddefs list to include all the engine fields,
        // so allocate a new place for it
        infielddefs = (ddef_t *)((byte *)progs + progs->ofs_fielddefs);
-       pr_fielddefs = Hunk_AllocName((progs->numfielddefs + DPFIELDS) * sizeof(ddef_t), "progs fields\n");
+       pr_fielddefs = Mem_Alloc(progs_mempool, (progs->numfielddefs + DPFIELDS) * sizeof(ddef_t));
 
        pr_statements = (dstatement_t *)((byte *)progs + progs->ofs_statements);
 
@@ -1443,6 +1459,9 @@ void PR_Init (void)
        Cvar_RegisterVariable (&cutscene); // for Nehahra but useful to other mods as well
        // LordHavoc: optional runtime bounds checking (speed drain, but worth it for security, on by default - breaks most QCCX features (used by CRMod and others))
        Cvar_RegisterVariable (&pr_boundscheck);
+
+       progs_mempool = Mem_AllocPool("progs.dat");
+       edictstring_mempool = Mem_AllocPool("edict strings");
 }
 
 // LordHavoc: turned EDICT_NUM into a #define for speed reasons
@@ -1463,11 +1482,20 @@ edict_t *EDICT_NUM(int n)
 int NUM_FOR_EDICT(edict_t *e)
 {
        int             b;
-       
+
        b = (byte *)e - (byte *)sv.edicts;
        b = b / pr_edict_size;
-       
+
        if (b < 0 || b >= sv.num_edicts)
                Host_Error ("NUM_FOR_EDICT: bad pointer");
        return b;
 }
+
+int NoCrash_NUM_FOR_EDICT(edict_t *e)
+{
+       int             b;
+
+       b = (byte *)e - (byte *)sv.edicts;
+       b = b / pr_edict_size;
+       return b;
+}
index e70f158159ddc69e9cfca1e51d6a07fce6669c19..1db112819c19c121a32bacaae609c2a3b2a12a29 100644 (file)
--- a/pr_exec.c
+++ b/pr_exec.c
@@ -33,7 +33,7 @@ typedef struct
 
 #define        MAX_STACK_DEPTH         32
 prstack_t      pr_stack[MAX_STACK_DEPTH];
-int                    pr_depth;
+int                    pr_depth = 0;
 
 #define        LOCALSTACK_SIZE         2048
 int                    localstack[LOCALSTACK_SIZE];
@@ -126,7 +126,7 @@ char *pr_opnames[] =
 "CALL8",
   
 "STATE",
-  
+
 "GOTO", 
   
 "AND",
@@ -191,24 +191,17 @@ void PR_StackTrace (void)
 {
        dfunction_t     *f;
        int                     i;
-       
-       if (pr_depth == 0)
-       {
-               Con_Printf ("<NO STACK>\n");
-               return;
-       }
-       
+
+       pr_stack[pr_depth].s = pr_xstatement;
        pr_stack[pr_depth].f = pr_xfunction;
-       for (i=pr_depth ; i>=0 ; i--)
+       for (i = pr_depth;i > 0;i--)
        {
                f = pr_stack[i].f;
-               
+
                if (!f)
-               {
-                       Con_Printf ("<NO FUNCTION>\n");
-               }
+                       Con_Printf ("<NULL FUNCTION>\n");
                else
-                       Con_Printf ("%12s : %s\n", pr_strings + f->s_file, pr_strings + f->s_name);             
+                       Con_Printf ("%12s : %s : statement %i\n", pr_strings + f->s_file, pr_strings + f->s_name, pr_stack[i].s - f->first_statement);
        }
 }
 
@@ -225,8 +218,8 @@ void PR_Profile_f (void)
        int                     max;
        int                     num;
        int                     i;
-       
-       num = 0;        
+
+       num = 0;
        do
        {
                max = 0;
@@ -260,6 +253,7 @@ Aborts the currently executing function
 */
 void PR_RunError (char *error, ...)
 {
+       int                     i;
        va_list         argptr;
        char            string[1024];
 
@@ -267,10 +261,17 @@ void PR_RunError (char *error, ...)
        vsprintf (string,error,argptr);
        va_end (argptr);
 
-       PR_PrintStatement (pr_statements + pr_xstatement);
+       if (pr_xfunction)
+       {
+               for (i = -4;i <= 0;i++)
+                       if (pr_xstatement + i >= pr_xfunction->first_statement)
+                               PR_PrintStatement (pr_statements + pr_xstatement + i);
+       }
+       else
+               Con_Printf("null function executing??\n");
        PR_StackTrace ();
        Con_Printf ("%s\n", string);
-       
+
        pr_depth = 0;           // dump the stack so host_error can shutdown functions
 
        Host_Error ("Program error");
@@ -295,8 +296,11 @@ int PR_EnterFunction (dfunction_t *f)
 {
        int             i, j, c, o;
 
+       if (!f)
+               PR_RunError ("PR_EnterFunction: NULL function\n");
+
        pr_stack[pr_depth].s = pr_xstatement;
-       pr_stack[pr_depth].f = pr_xfunction;    
+       pr_stack[pr_depth].f = pr_xfunction;
        pr_depth++;
        if (pr_depth >= MAX_STACK_DEPTH)
                PR_RunError ("stack overflow");
@@ -337,6 +341,8 @@ int PR_LeaveFunction (void)
        if (pr_depth <= 0)
                Host_Error ("prog stack underflow");
 
+       if (!pr_xfunction)
+               PR_RunError ("PR_LeaveFunction: NULL function\n");
 // restore locals from the stack
        c = pr_xfunction->locals;
        localstack_used -= c;
@@ -352,7 +358,6 @@ int PR_LeaveFunction (void)
        return pr_stack[pr_depth].s;
 }
 
-
 /*
 ====================
 PR_ExecuteProgram
@@ -368,9 +373,8 @@ void PR_ExecuteProgram (func_t fnum, char *errormessage)
        dstatement_t    *st;
        dfunction_t     *f, *newf;
        edict_t *ed;
-       int             exitdepth;
        eval_t  *ptr;
-       int             profile, startprofile;
+       int             profile, startprofile, cachedpr_trace, exitdepth;
 
        if (!fnum || fnum >= progs->numfunctions)
        {
@@ -378,881 +382,46 @@ void PR_ExecuteProgram (func_t fnum, char *errormessage)
                        ED_Print (PROG_TO_EDICT(pr_global_struct->self));
                Host_Error ("PR_ExecuteProgram: %s", errormessage);
        }
-       
+
        f = &pr_functions[fnum];
 
        pr_trace = false;
 
-// make a stack frame
+       // we know we're done when pr_depth drops to this
        exitdepth = pr_depth;
 
+// make a stack frame
        st = &pr_statements[PR_EnterFunction (f)];
        startprofile = profile = 0;
 
-       if (pr_boundscheck.value)
+chooseexecprogram:
+       cachedpr_trace = pr_trace;
+       if (pr_boundscheck.integer)
        {
-               while (1)
+#define PRBOUNDSCHECK 1
+               if (pr_trace)
                {
-                       st++;
-                       if (++profile > 1000000) // LordHavoc: increased runaway loop limit 10x
-                       {
-                               pr_xstatement = st - pr_statements;
-                               PR_RunError ("runaway loop error");
-                       }
-                       
-                       if (pr_trace)
-                               PR_PrintStatement (st);
-
-                       switch (st->op)
-                       {
-                       case OP_ADD_F:
-                               OPC->_float = OPA->_float + OPB->_float;
-                               break;
-                       case OP_ADD_V:
-                               OPC->vector[0] = OPA->vector[0] + OPB->vector[0];
-                               OPC->vector[1] = OPA->vector[1] + OPB->vector[1];
-                               OPC->vector[2] = OPA->vector[2] + OPB->vector[2];
-                               break;
-                       case OP_SUB_F:
-                               OPC->_float = OPA->_float - OPB->_float;
-                               break;
-                       case OP_SUB_V:
-                               OPC->vector[0] = OPA->vector[0] - OPB->vector[0];
-                               OPC->vector[1] = OPA->vector[1] - OPB->vector[1];
-                               OPC->vector[2] = OPA->vector[2] - OPB->vector[2];
-                               break;
-                       case OP_MUL_F:
-                               OPC->_float = OPA->_float * OPB->_float;
-                               break;
-                       case OP_MUL_V:
-                               OPC->_float = OPA->vector[0]*OPB->vector[0] + OPA->vector[1]*OPB->vector[1] + OPA->vector[2]*OPB->vector[2];
-                               break;
-                       case OP_MUL_FV:
-                               OPC->vector[0] = OPA->_float * OPB->vector[0];
-                               OPC->vector[1] = OPA->_float * OPB->vector[1];
-                               OPC->vector[2] = OPA->_float * OPB->vector[2];
-                               break;
-                       case OP_MUL_VF:
-                               OPC->vector[0] = OPB->_float * OPA->vector[0];
-                               OPC->vector[1] = OPB->_float * OPA->vector[1];
-                               OPC->vector[2] = OPB->_float * OPA->vector[2];
-                               break;
-                       case OP_DIV_F:
-                               OPC->_float = OPA->_float / OPB->_float;
-                               break;
-                       case OP_BITAND:
-                               OPC->_float = (int)OPA->_float & (int)OPB->_float;
-                               break;
-                       case OP_BITOR:
-                               OPC->_float = (int)OPA->_float | (int)OPB->_float;
-                               break;
-                       case OP_GE:
-                               OPC->_float = OPA->_float >= OPB->_float;
-                               break;
-                       case OP_LE:
-                               OPC->_float = OPA->_float <= OPB->_float;
-                               break;
-                       case OP_GT:
-                               OPC->_float = OPA->_float > OPB->_float;
-                               break;
-                       case OP_LT:
-                               OPC->_float = OPA->_float < OPB->_float;
-                               break;
-                       case OP_AND:
-                               OPC->_float = OPA->_float && OPB->_float;
-                               break;
-                       case OP_OR:
-                               OPC->_float = OPA->_float || OPB->_float;
-                               break;
-                       case OP_NOT_F:
-                               OPC->_float = !OPA->_float;
-                               break;
-                       case OP_NOT_V:
-                               OPC->_float = !OPA->vector[0] && !OPA->vector[1] && !OPA->vector[2];
-                               break;
-                       case OP_NOT_S:
-                               OPC->_float = !OPA->string || !pr_strings[OPA->string];
-                               break;
-                       case OP_NOT_FNC:
-                               OPC->_float = !OPA->function;
-                               break;
-                       case OP_NOT_ENT:
-                               OPC->_float = (PROG_TO_EDICT(OPA->edict) == sv.edicts);
-                               break;
-                       case OP_EQ_F:
-                               OPC->_float = OPA->_float == OPB->_float;
-                               break;
-                       case OP_EQ_V:
-                               OPC->_float = (OPA->vector[0] == OPB->vector[0]) && (OPA->vector[1] == OPB->vector[1]) && (OPA->vector[2] == OPB->vector[2]);
-                               break;
-                       case OP_EQ_S:
-                               OPC->_float = !strcmp(pr_strings+OPA->string,pr_strings+OPB->string);
-                               break;
-                       case OP_EQ_E:
-                               OPC->_float = OPA->_int == OPB->_int;
-                               break;
-                       case OP_EQ_FNC:
-                               OPC->_float = OPA->function == OPB->function;
-                               break;
-                       case OP_NE_F:
-                               OPC->_float = OPA->_float != OPB->_float;
-                               break;
-                       case OP_NE_V:
-                               OPC->_float = (OPA->vector[0] != OPB->vector[0]) || (OPA->vector[1] != OPB->vector[1]) || (OPA->vector[2] != OPB->vector[2]);
-                               break;
-                       case OP_NE_S:
-                               OPC->_float = strcmp(pr_strings+OPA->string,pr_strings+OPB->string);
-                               break;
-                       case OP_NE_E:
-                               OPC->_float = OPA->_int != OPB->_int;
-                               break;
-                       case OP_NE_FNC:
-                               OPC->_float = OPA->function != OPB->function;
-                               break;
-
-               //==================
-                       case OP_STORE_F:
-                       case OP_STORE_ENT:
-                       case OP_STORE_FLD:              // integers
-                       case OP_STORE_S:
-                       case OP_STORE_FNC:              // pointers
-                               OPB->_int = OPA->_int;
-                               break;
-                       case OP_STORE_V:
-                               OPB->vector[0] = OPA->vector[0];
-                               OPB->vector[1] = OPA->vector[1];
-                               OPB->vector[2] = OPA->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
-                               if (OPB->_int < 0 || OPB->_int + 4 > pr_edictareasize)
-                               {
-                                       pr_xstatement = st - pr_statements;
-                                       PR_RunError("Progs attempted to write to an out of bounds edict\n");
-                                       return;
-                               }
-                               if (OPB->_int % pr_edict_size < ((byte *)&sv.edicts->v - (byte *)sv.edicts))
-                               {
-                                       pr_xstatement = st - pr_statements;
-                                       PR_RunError("Progs attempted to write to an engine edict field\n");
-                                       return;
-                               }
-                               ptr = (eval_t *)((byte *)sv.edicts + OPB->_int);
-                               ptr->_int = OPA->_int;
-                               break;
-                       case OP_STOREP_V:
-                               if (OPB->_int < 0 || OPB->_int + 12 > pr_edictareasize)
-                               {
-                                       pr_xstatement = st - pr_statements;
-                                       PR_RunError("Progs attempted to write to an out of bounds edict\n");
-                                       return;
-                               }
-                               ptr = (eval_t *)((byte *)sv.edicts + OPB->_int);
-                               ptr->vector[0] = OPA->vector[0];
-                               ptr->vector[1] = OPA->vector[1];
-                               ptr->vector[2] = OPA->vector[2];
-                               break;
-                               
-                       case OP_ADDRESS:
-                               if (OPA->edict < 0 || OPA->edict >= pr_edictareasize)
-                               {
-                                       pr_xstatement = st - pr_statements;
-                                       PR_RunError("Progs attempted to address an out of bounds edict\n");
-                                       return;
-                               }
-                               if (OPA->edict == 0 && sv.state == ss_active)
-                               {
-                                       pr_xstatement = st - pr_statements;
-                                       PR_RunError ("assignment to world entity");
-                                       return;
-                               }
-                               if (OPB->_int < 0 || OPB->_int >= progs->entityfields)
-                               {
-                                       pr_xstatement = st - pr_statements;
-                                       PR_RunError("Progs attempted to address an invalid field in an edict\n");
-                                       return;
-                               }
-                               ed = PROG_TO_EDICT(OPA->edict);
-                               OPC->_int = (byte *)((int *)&ed->v + OPB->_int) - (byte *)sv.edicts;
-                               break;
-                               
-                       case OP_LOAD_F:
-                       case OP_LOAD_FLD:
-                       case OP_LOAD_ENT:
-                       case OP_LOAD_S:
-                       case OP_LOAD_FNC:
-                               if (OPA->edict < 0 || OPA->edict >= pr_edictareasize)
-                               {
-                                       pr_xstatement = st - pr_statements;
-                                       PR_RunError("Progs attempted to read an out of bounds edict number\n");
-                                       return;
-                               }
-                               if (OPB->_int < 0 || OPB->_int >= progs->entityfields)
-                               {
-                                       pr_xstatement = st - pr_statements;
-                                       PR_RunError("Progs attempted to read an invalid field in an edict\n");
-                                       return;
-                               }
-                               ed = PROG_TO_EDICT(OPA->edict);
-                               OPC->_int = ((eval_t *)((int *)&ed->v + OPB->_int))->_int;
-                               break;
-
-                       case OP_LOAD_V:
-                               if (OPA->edict < 0 || OPA->edict >= pr_edictareasize)
-                               {
-                                       pr_xstatement = st - pr_statements;
-                                       PR_RunError("Progs attempted to read an out of bounds edict number\n");
-                                       return;
-                               }
-                               if (OPB->_int < 0 || OPB->_int + 2 >= progs->entityfields)
-                               {
-                                       pr_xstatement = st - pr_statements;
-                                       PR_RunError("Progs attempted to read an invalid field in an edict\n");
-                                       return;
-                               }
-                               ed = PROG_TO_EDICT(OPA->edict);
-                               OPC->vector[0] = ((eval_t *)((int *)&ed->v + OPB->_int))->vector[0];
-                               OPC->vector[1] = ((eval_t *)((int *)&ed->v + OPB->_int))->vector[1];
-                               OPC->vector[2] = ((eval_t *)((int *)&ed->v + OPB->_int))->vector[2];
-                               break;
-                               
-               //==================
-
-                       case OP_IFNOT:
-                               if (!OPA->_int)
-                                       st += st->b - 1;        // offset the s++
-                               break;
-                               
-                       case OP_IF:
-                               if (OPA->_int)
-                                       st += st->b - 1;        // offset the s++
-                               break;
-                               
-                       case OP_GOTO:
-                               st += st->a - 1;        // offset the s++
-                               break;
-                               
-                       case OP_CALL0:
-                       case OP_CALL1:
-                       case OP_CALL2:
-                       case OP_CALL3:
-                       case OP_CALL4:
-                       case OP_CALL5:
-                       case OP_CALL6:
-                       case OP_CALL7:
-                       case OP_CALL8:
-                               pr_xfunction->profile += profile - startprofile;
-                               startprofile = profile;
-                               pr_xstatement = st - pr_statements;
-                               pr_argc = st->op - OP_CALL0;
-                               if (!OPA->function)
-                                       PR_RunError ("NULL function");
-
-                               newf = &pr_functions[OPA->function];
-
-                               if (newf->first_statement < 0)
-                               {       // negative statements are built in functions
-                                       int i = -newf->first_statement;
-                                       if (i >= pr_numbuiltins)
-                                               PR_RunError ("Bad builtin call number");
-                                       pr_builtins[i] ();
-                                       break;
-                               }
-
-                               st = &pr_statements[PR_EnterFunction (newf)];
-                               break;
-
-                       case OP_DONE:
-                       case OP_RETURN:
-                               pr_globals[OFS_RETURN] = pr_globals[(unsigned short) st->a];
-                               pr_globals[OFS_RETURN+1] = pr_globals[(unsigned short) st->a+1];
-                               pr_globals[OFS_RETURN+2] = pr_globals[(unsigned short) st->a+2];
-                       
-                               st = &pr_statements[PR_LeaveFunction ()];
-                               if (pr_depth == exitdepth)
-                                       return;         // all done
-                               break;
-                               
-                       case OP_STATE:
-                               ed = PROG_TO_EDICT(pr_global_struct->self);
-                               ed->v.nextthink = pr_global_struct->time + 0.1;
-                               ed->v.frame = OPA->_float;
-                               ed->v.think = OPB->function;
-                               break;
-                               
-                       default:
-                               pr_xstatement = st - pr_statements;
-                               PR_RunError ("Bad opcode %i", st->op);
-                       }
+#define PRTRACE 1
+#include "pr_execprogram.h"
+               }
+               else
+               {
+#undef PRTRACE
+#include "pr_execprogram.h"
                }
        }
        else
        {
-               while (1)
+#undef PRBOUNDSCHECK
+               if (pr_trace)
                {
-                       st++;
-                       if (++profile > 1000000) // LordHavoc: increased runaway loop limit 10x
-                       {
-                               pr_xstatement = st - pr_statements;
-                               PR_RunError ("runaway loop error");
-                       }
-                       
-                       if (pr_trace)
-                               PR_PrintStatement (st);
-
-                       switch (st->op)
-                       {
-                       case OP_ADD_F:
-                               OPC->_float = OPA->_float + OPB->_float;
-                               break;
-                       case OP_ADD_V:
-                               OPC->vector[0] = OPA->vector[0] + OPB->vector[0];
-                               OPC->vector[1] = OPA->vector[1] + OPB->vector[1];
-                               OPC->vector[2] = OPA->vector[2] + OPB->vector[2];
-                               break;
-                       case OP_SUB_F:
-                               OPC->_float = OPA->_float - OPB->_float;
-                               break;
-                       case OP_SUB_V:
-                               OPC->vector[0] = OPA->vector[0] - OPB->vector[0];
-                               OPC->vector[1] = OPA->vector[1] - OPB->vector[1];
-                               OPC->vector[2] = OPA->vector[2] - OPB->vector[2];
-                               break;
-                       case OP_MUL_F:
-                               OPC->_float = OPA->_float * OPB->_float;
-                               break;
-                       case OP_MUL_V:
-                               OPC->_float = OPA->vector[0]*OPB->vector[0] + OPA->vector[1]*OPB->vector[1] + OPA->vector[2]*OPB->vector[2];
-                               break;
-                       case OP_MUL_FV:
-                               OPC->vector[0] = OPA->_float * OPB->vector[0];
-                               OPC->vector[1] = OPA->_float * OPB->vector[1];
-                               OPC->vector[2] = OPA->_float * OPB->vector[2];
-                               break;
-                       case OP_MUL_VF:
-                               OPC->vector[0] = OPB->_float * OPA->vector[0];
-                               OPC->vector[1] = OPB->_float * OPA->vector[1];
-                               OPC->vector[2] = OPB->_float * OPA->vector[2];
-                               break;
-                       case OP_DIV_F:
-                               OPC->_float = OPA->_float / OPB->_float;
-                               break;
-                       case OP_BITAND:
-                               OPC->_float = (int)OPA->_float & (int)OPB->_float;
-                               break;
-                       case OP_BITOR:
-                               OPC->_float = (int)OPA->_float | (int)OPB->_float;
-                               break;
-                       case OP_GE:
-                               OPC->_float = OPA->_float >= OPB->_float;
-                               break;
-                       case OP_LE:
-                               OPC->_float = OPA->_float <= OPB->_float;
-                               break;
-                       case OP_GT:
-                               OPC->_float = OPA->_float > OPB->_float;
-                               break;
-                       case OP_LT:
-                               OPC->_float = OPA->_float < OPB->_float;
-                               break;
-                       case OP_AND:
-                               OPC->_float = OPA->_float && OPB->_float;
-                               break;
-                       case OP_OR:
-                               OPC->_float = OPA->_float || OPB->_float;
-                               break;
-                       case OP_NOT_F:
-                               OPC->_float = !OPA->_float;
-                               break;
-                       case OP_NOT_V:
-                               OPC->_float = !OPA->vector[0] && !OPA->vector[1] && !OPA->vector[2];
-                               break;
-                       case OP_NOT_S:
-                               OPC->_float = !OPA->string || !pr_strings[OPA->string];
-                               break;
-                       case OP_NOT_FNC:
-                               OPC->_float = !OPA->function;
-                               break;
-                       case OP_NOT_ENT:
-                               OPC->_float = (PROG_TO_EDICT(OPA->edict) == sv.edicts);
-                               break;
-                       case OP_EQ_F:
-                               OPC->_float = OPA->_float == OPB->_float;
-                               break;
-                       case OP_EQ_V:
-                               OPC->_float = (OPA->vector[0] == OPB->vector[0]) && (OPA->vector[1] == OPB->vector[1]) && (OPA->vector[2] == OPB->vector[2]);
-                               break;
-                       case OP_EQ_S:
-                               OPC->_float = !strcmp(pr_strings+OPA->string,pr_strings+OPB->string);
-                               break;
-                       case OP_EQ_E:
-                               OPC->_float = OPA->_int == OPB->_int;
-                               break;
-                       case OP_EQ_FNC:
-                               OPC->_float = OPA->function == OPB->function;
-                               break;
-                       case OP_NE_F:
-                               OPC->_float = OPA->_float != OPB->_float;
-                               break;
-                       case OP_NE_V:
-                               OPC->_float = (OPA->vector[0] != OPB->vector[0]) || (OPA->vector[1] != OPB->vector[1]) || (OPA->vector[2] != OPB->vector[2]);
-                               break;
-                       case OP_NE_S:
-                               OPC->_float = strcmp(pr_strings+OPA->string,pr_strings+OPB->string);
-                               break;
-                       case OP_NE_E:
-                               OPC->_float = OPA->_int != OPB->_int;
-                               break;
-                       case OP_NE_FNC:
-                               OPC->_float = OPA->function != OPB->function;
-                               break;
-
-               //==================
-                       case OP_STORE_F:
-                       case OP_STORE_ENT:
-                       case OP_STORE_FLD:              // integers
-                       case OP_STORE_S:
-                       case OP_STORE_FNC:              // pointers
-                               OPB->_int = OPA->_int;
-                               break;
-                       case OP_STORE_V:
-                               OPB->vector[0] = OPA->vector[0];
-                               OPB->vector[1] = OPA->vector[1];
-                               OPB->vector[2] = OPA->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
-                               if (OPB->_int < 0 || OPB->_int + 4 > pr_edictareasize)
-                               {
-                                       pr_xstatement = st - pr_statements;
-                                       PR_RunError("Progs attempted to write to an out of bounds edict\n");
-                                       return;
-                               }
-                               if (OPB->_int % pr_edict_size < ((byte *)&sv.edicts->v - (byte *)sv.edicts))
-                               {
-                                       pr_xstatement = st - pr_statements;
-                                       PR_RunError("Progs attempted to write to an engine edict field\n");
-                                       return;
-                               }
-                               ptr = (eval_t *)((byte *)sv.edicts + OPB->_int);
-                               ptr->_int = OPA->_int;
-                               break;
-                       case OP_STOREP_V:
-                               if (OPB->_int < 0 || OPB->_int + 12 > pr_edictareasize)
-                               {
-                                       pr_xstatement = st - pr_statements;
-                                       PR_RunError("Progs attempted to write to an out of bounds edict\n");
-                                       return;
-                               }
-                               ptr = (eval_t *)((byte *)sv.edicts + OPB->_int);
-                               ptr->vector[0] = OPA->vector[0];
-                               ptr->vector[1] = OPA->vector[1];
-                               ptr->vector[2] = OPA->vector[2];
-                               break;
-                               
-                       case OP_ADDRESS:
-                               if (OPA->edict < 0 || OPA->edict >= pr_edictareasize)
-                               {
-                                       pr_xstatement = st - pr_statements;
-                                       PR_RunError("Progs attempted to address an out of bounds edict\n");
-                                       return;
-                               }
-                               if (OPA->edict == 0 && sv.state == ss_active)
-                               {
-                                       pr_xstatement = st - pr_statements;
-                                       PR_RunError ("assignment to world entity");
-                                       return;
-                               }
-                               if (OPB->_int < 0 || OPB->_int >= progs->entityfields)
-                               {
-                                       pr_xstatement = st - pr_statements;
-                                       PR_RunError("Progs attempted to address an invalid field in an edict\n");
-                                       return;
-                               }
-                               ed = PROG_TO_EDICT(OPA->edict);
-                               OPC->_int = (byte *)((int *)&ed->v + OPB->_int) - (byte *)sv.edicts;
-                               break;
-                               
-                       case OP_LOAD_F:
-                       case OP_LOAD_FLD:
-                       case OP_LOAD_ENT:
-                       case OP_LOAD_S:
-                       case OP_LOAD_FNC:
-                               if (OPA->edict < 0 || OPA->edict >= pr_edictareasize)
-                               {
-                                       pr_xstatement = st - pr_statements;
-                                       PR_RunError("Progs attempted to read an out of bounds edict number\n");
-                                       return;
-                               }
-                               if (OPB->_int < 0 || OPB->_int >= progs->entityfields)
-                               {
-                                       pr_xstatement = st - pr_statements;
-                                       PR_RunError("Progs attempted to read an invalid field in an edict\n");
-                                       return;
-                               }
-                               ed = PROG_TO_EDICT(OPA->edict);
-                               OPC->_int = ((eval_t *)((int *)&ed->v + OPB->_int))->_int;
-                               break;
-
-                       case OP_LOAD_V:
-                               if (OPA->edict < 0 || OPA->edict >= pr_edictareasize)
-                               {
-                                       pr_xstatement = st - pr_statements;
-                                       PR_RunError("Progs attempted to read an out of bounds edict number\n");
-                                       return;
-                               }
-                               if (OPB->_int < 0 || OPB->_int + 2 >= progs->entityfields)
-                               {
-                                       pr_xstatement = st - pr_statements;
-                                       PR_RunError("Progs attempted to read an invalid field in an edict\n");
-                                       return;
-                               }
-                               ed = PROG_TO_EDICT(OPA->edict);
-                               OPC->vector[0] = ((eval_t *)((int *)&ed->v + OPB->_int))->vector[0];
-                               OPC->vector[1] = ((eval_t *)((int *)&ed->v + OPB->_int))->vector[1];
-                               OPC->vector[2] = ((eval_t *)((int *)&ed->v + OPB->_int))->vector[2];
-                               break;
-                               
-               //==================
-
-                       case OP_IFNOT:
-                               if (!OPA->_int)
-                                       st += st->b - 1;        // offset the s++
-                               break;
-                               
-                       case OP_IF:
-                               if (OPA->_int)
-                                       st += st->b - 1;        // offset the s++
-                               break;
-                               
-                       case OP_GOTO:
-                               st += st->a - 1;        // offset the s++
-                               break;
-                               
-                       case OP_CALL0:
-                       case OP_CALL1:
-                       case OP_CALL2:
-                       case OP_CALL3:
-                       case OP_CALL4:
-                       case OP_CALL5:
-                       case OP_CALL6:
-                       case OP_CALL7:
-                       case OP_CALL8:
-                               pr_xfunction->profile += profile - startprofile;
-                               startprofile = profile;
-                               pr_xstatement = st - pr_statements;
-                               pr_argc = st->op - OP_CALL0;
-                               if (!OPA->function)
-                                       PR_RunError ("NULL function");
-
-                               newf = &pr_functions[OPA->function];
-
-                               if (newf->first_statement < 0)
-                               {       // negative statements are built in functions
-                                       int i = -newf->first_statement;
-                                       if (i >= pr_numbuiltins)
-                                               PR_RunError ("Bad builtin call number");
-                                       pr_builtins[i] ();
-                                       break;
-                               }
-
-                               st = &pr_statements[PR_EnterFunction (newf)];
-                               break;
-
-                       case OP_DONE:
-                       case OP_RETURN:
-                               pr_globals[OFS_RETURN] = pr_globals[(unsigned short) st->a];
-                               pr_globals[OFS_RETURN+1] = pr_globals[(unsigned short) st->a+1];
-                               pr_globals[OFS_RETURN+2] = pr_globals[(unsigned short) st->a+2];
-                       
-                               st = &pr_statements[PR_LeaveFunction ()];
-                               if (pr_depth == exitdepth)
-                                       return;         // all done
-                               break;
-                               
-                       case OP_STATE:
-                               ed = PROG_TO_EDICT(pr_global_struct->self);
-                               ed->v.nextthink = pr_global_struct->time + 0.1;
-                               ed->v.frame = OPA->_float;
-                               ed->v.think = OPB->function;
-                               break;
-                               
-               //==================
-
-// LordHavoc: to be enabled when Progs version 7 (or whatever it will be numbered) is finalized
-/*
-                       case OP_ADD_I:
-                               OPC->_int = OPA->_int + OPB->_int;
-                               break;
-                       case OP_ADD_IF:
-                               OPC->_int = OPA->_int + (int) OPB->_float;
-                               break;
-                       case OP_ADD_FI:
-                               OPC->_float = OPA->_float + (float) OPB->_int;
-                               break;
-                       case OP_SUB_I:
-                               OPC->_int = OPA->_int - OPB->_int;
-                               break;
-                       case OP_SUB_IF:
-                               OPC->_int = OPA->_int - (int) OPB->_float;
-                               break;
-                       case OP_SUB_FI:
-                               OPC->_float = OPA->_float - (float) OPB->_int;
-                               break;
-                       case OP_MUL_I:
-                               OPC->_int = OPA->_int * OPB->_int;
-                               break;
-                       case OP_MUL_IF:
-                               OPC->_int = OPA->_int * (int) OPB->_float;
-                               break;
-                       case OP_MUL_FI:
-                               OPC->_float = OPA->_float * (float) OPB->_int;
-                               break;
-                       case OP_MUL_VI:
-                               OPC->vector[0] = (float) OPB->_int * OPA->vector[0];
-                               OPC->vector[1] = (float) OPB->_int * OPA->vector[1];
-                               OPC->vector[2] = (float) OPB->_int * OPA->vector[2];
-                               break;
-                       case OP_DIV_VF:
-                               {
-                                       float temp = 1.0f / OPB->_float;
-                                       OPC->vector[0] = temp * OPA->vector[0];
-                                       OPC->vector[1] = temp * OPA->vector[1];
-                                       OPC->vector[2] = temp * OPA->vector[2];
-                               }
-                               break;
-                       case OP_DIV_I:
-                               OPC->_int = OPA->_int / OPB->_int;
-                               break;
-                       case OP_DIV_IF:
-                               OPC->_int = OPA->_int / (int) OPB->_float;
-                               break;
-                       case OP_DIV_FI:
-                               OPC->_float = OPA->_float / (float) OPB->_int;
-                               break;
-                       case OP_CONV_IF:
-                               OPC->_float = OPA->_int;
-                               break;
-                       case OP_CONV_FI:
-                               OPC->_int = OPA->_float;
-                               break;
-                       case OP_BITAND_I:
-                               OPC->_int = OPA->_int & OPB->_int;
-                               break;
-                       case OP_BITOR_I:
-                               OPC->_int = OPA->_int | OPB->_int;
-                               break;
-                       case OP_BITAND_IF:
-                               OPC->_int = OPA->_int & (int)OPB->_float;
-                               break;
-                       case OP_BITOR_IF:
-                               OPC->_int = OPA->_int | (int)OPB->_float;
-                               break;
-                       case OP_BITAND_FI:
-                               OPC->_float = (int)OPA->_float & OPB->_int;
-                               break;
-                       case OP_BITOR_FI:
-                               OPC->_float = (int)OPA->_float | OPB->_int;
-                               break;
-                       case OP_GE_I:
-                               OPC->_float = OPA->_int >= OPB->_int;
-                               break;
-                       case OP_LE_I:
-                               OPC->_float = OPA->_int <= OPB->_int;
-                               break;
-                       case OP_GT_I:
-                               OPC->_float = OPA->_int > OPB->_int;
-                               break;
-                       case OP_LT_I:
-                               OPC->_float = OPA->_int < OPB->_int;
-                               break;
-                       case OP_AND_I:
-                               OPC->_float = OPA->_int && OPB->_int;
-                               break;
-                       case OP_OR_I:
-                               OPC->_float = OPA->_int || OPB->_int;
-                               break;
-                       case OP_GE_IF:
-                               OPC->_float = (float)OPA->_int >= OPB->_float;
-                               break;
-                       case OP_LE_IF:
-                               OPC->_float = (float)OPA->_int <= OPB->_float;
-                               break;
-                       case OP_GT_IF:
-                               OPC->_float = (float)OPA->_int > OPB->_float;
-                               break;
-                       case OP_LT_IF:
-                               OPC->_float = (float)OPA->_int < OPB->_float;
-                               break;
-                       case OP_AND_IF:
-                               OPC->_float = (float)OPA->_int && OPB->_float;
-                               break;
-                       case OP_OR_IF:
-                               OPC->_float = (float)OPA->_int || OPB->_float;
-                               break;
-                       case OP_GE_FI:
-                               OPC->_float = OPA->_float >= (float)OPB->_int;
-                               break;
-                       case OP_LE_FI:
-                               OPC->_float = OPA->_float <= (float)OPB->_int;
-                               break;
-                       case OP_GT_FI:
-                               OPC->_float = OPA->_float > (float)OPB->_int;
-                               break;
-                       case OP_LT_FI:
-                               OPC->_float = OPA->_float < (float)OPB->_int;
-                               break;
-                       case OP_AND_FI:
-                               OPC->_float = OPA->_float && (float)OPB->_int;
-                               break;
-                       case OP_OR_FI:
-                               OPC->_float = OPA->_float || (float)OPB->_int;
-                               break;
-                       case OP_NOT_I:
-                               OPC->_float = !OPA->_int;
-                               break;
-                       case OP_EQ_I:
-                               OPC->_float = OPA->_int == OPB->_int;
-                               break;
-                       case OP_EQ_IF:
-                               OPC->_float = (float)OPA->_int == OPB->_float;
-                               break;
-                       case OP_EQ_FI:
-                               OPC->_float = OPA->_float == (float)OPB->_int;
-                               break;
-                       case OP_NE_I:
-                               OPC->_float = OPA->_int != OPB->_int;
-                               break;
-                       case OP_NE_IF:
-                               OPC->_float = (float)OPA->_int != OPB->_float;
-                               break;
-                       case OP_NE_FI:
-                               OPC->_float = OPA->_float != (float)OPB->_int;
-                               break;
-                       case OP_STORE_I:
-                               OPB->_int = OPA->_int;
-                               break;
-                       case OP_STOREP_I:
-                               if (OPB->_int < 0 || OPB->_int + 4 > pr_edictareasize)
-                               {
-                                       pr_xstatement = st - pr_statements;
-                                       PR_RunError("Progs attempted to write to an out of bounds edict\n");
-                                       return;
-                               }
-                               if (OPB->_int % pr_edict_size < ((byte *)&sv.edicts->v - (byte *)sv.edicts))
-                               {
-                                       pr_xstatement = st - pr_statements;
-                                       PR_RunError("Progs attempted to write to an engine edict field\n");
-                                       return;
-                               }
-                               ptr = (eval_t *)((byte *)sv.edicts + OPB->_int);
-                               ptr->_int = OPA->_int;
-                               break;
-                       case OP_LOAD_I:
-                               if (OPA->edict < 0 || OPA->edict >= pr_edictareasize)
-                               {
-                                       pr_xstatement = st - pr_statements;
-                                       PR_RunError("Progs attempted to read an out of bounds edict number\n");
-                                       return;
-                               }
-                               if (OPB->_int < 0 || OPB->_int >= progs->entityfields)
-                               {
-                                       pr_xstatement = st - pr_statements;
-                                       PR_RunError("Progs attempted to read an invalid field in an edict\n");
-                                       return;
-                               }
-                               ed = PROG_TO_EDICT(OPA->edict);
-                               OPC->_int = ((eval_t *)((int *)&ed->v + OPB->_int))->_int;
-                               break;
-
-                       case OP_GSTOREP_I:
-                       case OP_GSTOREP_F:
-                       case OP_GSTOREP_ENT:
-                       case OP_GSTOREP_FLD:            // integers
-                       case OP_GSTOREP_S:
-                       case OP_GSTOREP_FNC:            // pointers
-                               if (OPB->_int < 0 || OPB->_int >= pr_globaldefs)
-                               {
-                                       pr_xstatement = st - pr_statements;
-                                       PR_RunError("Progs attempted to write to an invalid indexed global\n");
-                                       return;
-                               }
-                               pr_globals[OPB->_int] = OPA->_float;
-                               break;
-                       case OP_GSTOREP_V:
-                               if (OPB->_int < 0 || OPB->_int + 2 >= pr_globaldefs)
-                               {
-                                       pr_xstatement = st - pr_statements;
-                                       PR_RunError("Progs attempted to write to an invalid indexed global\n");
-                                       return;
-                               }
-                               pr_globals[OPB->_int  ] = OPA->vector[0];
-                               pr_globals[OPB->_int+1] = OPA->vector[1];
-                               pr_globals[OPB->_int+2] = OPA->vector[2];
-                               break;
-                               
-                       case OP_GADDRESS:
-                               i = OPA->_int + (int) OPB->_float;
-                               if (i < 0 || i >= pr_globaldefs)
-                               {
-                                       pr_xstatement = st - pr_statements;
-                                       PR_RunError("Progs attempted to address an out of bounds global\n");
-                                       return;
-                               }
-                               OPC->_float = pr_globals[i];
-                               break;
-                               
-                       case OP_GLOAD_I:
-                       case OP_GLOAD_F:
-                       case OP_GLOAD_FLD:
-                       case OP_GLOAD_ENT:
-                       case OP_GLOAD_S:
-                       case OP_GLOAD_FNC:
-                               if (OPA->_int < 0 || OPA->_int >= pr_globaldefs)
-                               {
-                                       pr_xstatement = st - pr_statements;
-                                       PR_RunError("Progs attempted to read an invalid indexed global\n");
-                                       return;
-                               }
-                               OPC->_float = pr_globals[OPA->_int];
-                               break;
-
-                       case OP_GLOAD_V:
-                               if (OPA->_int < 0 || OPA->_int + 2 >= pr_globaldefs)
-                               {
-                                       pr_xstatement = st - pr_statements;
-                                       PR_RunError("Progs attempted to read an invalid indexed global\n");
-                                       return;
-                               }
-                               OPC->vector[0] = pr_globals[OPA->_int  ];
-                               OPC->vector[1] = pr_globals[OPA->_int+1];
-                               OPC->vector[2] = pr_globals[OPA->_int+2];
-                               break;
-
-                       case OP_BOUNDCHECK:
-                               if (OPA->_int < 0 || OPA->_int >= st->b)
-                               {
-                                       pr_xstatement = st - pr_statements;
-                                       PR_RunError("Progs boundcheck failed at line number %d, value is < 0 or >= %d\n", st->b, st->c);
-                                       return;
-                               }
-                               break;
-
-*/
-               //==================
-
-                       default:
-                               pr_xstatement = st - pr_statements;
-                               PR_RunError ("Bad opcode %i", st->op);
-                       }
+#define PRTRACE 1
+#include "pr_execprogram.h"
+               }
+               else
+               {
+#undef PRTRACE
+#include "pr_execprogram.h"
                }
        }
 }
diff --git a/pr_execprogram.h b/pr_execprogram.h
new file mode 100644 (file)
index 0000000..524ca44
--- /dev/null
@@ -0,0 +1,601 @@
+               while (1)
+               {
+                       st++;
+                       if (++profile > 1000000) // LordHavoc: increased runaway loop limit 10x
+                       {
+                               pr_xstatement = st - pr_statements;
+                               PR_RunError ("runaway loop error");
+                       }
+
+#if PRTRACE
+                       PR_PrintStatement (st);
+#endif
+
+                       switch (st->op)
+                       {
+                       case OP_ADD_F:
+                               OPC->_float = OPA->_float + OPB->_float;
+                               break;
+                       case OP_ADD_V:
+                               OPC->vector[0] = OPA->vector[0] + OPB->vector[0];
+                               OPC->vector[1] = OPA->vector[1] + OPB->vector[1];
+                               OPC->vector[2] = OPA->vector[2] + OPB->vector[2];
+                               break;
+                       case OP_SUB_F:
+                               OPC->_float = OPA->_float - OPB->_float;
+                               break;
+                       case OP_SUB_V:
+                               OPC->vector[0] = OPA->vector[0] - OPB->vector[0];
+                               OPC->vector[1] = OPA->vector[1] - OPB->vector[1];
+                               OPC->vector[2] = OPA->vector[2] - OPB->vector[2];
+                               break;
+                       case OP_MUL_F:
+                               OPC->_float = OPA->_float * OPB->_float;
+                               break;
+                       case OP_MUL_V:
+                               OPC->_float = OPA->vector[0]*OPB->vector[0] + OPA->vector[1]*OPB->vector[1] + OPA->vector[2]*OPB->vector[2];
+                               break;
+                       case OP_MUL_FV:
+                               OPC->vector[0] = OPA->_float * OPB->vector[0];
+                               OPC->vector[1] = OPA->_float * OPB->vector[1];
+                               OPC->vector[2] = OPA->_float * OPB->vector[2];
+                               break;
+                       case OP_MUL_VF:
+                               OPC->vector[0] = OPB->_float * OPA->vector[0];
+                               OPC->vector[1] = OPB->_float * OPA->vector[1];
+                               OPC->vector[2] = OPB->_float * OPA->vector[2];
+                               break;
+                       case OP_DIV_F:
+                               OPC->_float = OPA->_float / OPB->_float;
+                               break;
+                       case OP_BITAND:
+                               OPC->_float = (int)OPA->_float & (int)OPB->_float;
+                               break;
+                       case OP_BITOR:
+                               OPC->_float = (int)OPA->_float | (int)OPB->_float;
+                               break;
+                       case OP_GE:
+                               OPC->_float = OPA->_float >= OPB->_float;
+                               break;
+                       case OP_LE:
+                               OPC->_float = OPA->_float <= OPB->_float;
+                               break;
+                       case OP_GT:
+                               OPC->_float = OPA->_float > OPB->_float;
+                               break;
+                       case OP_LT:
+                               OPC->_float = OPA->_float < OPB->_float;
+                               break;
+                       case OP_AND:
+                               OPC->_float = OPA->_float && OPB->_float;
+                               break;
+                       case OP_OR:
+                               OPC->_float = OPA->_float || OPB->_float;
+                               break;
+                       case OP_NOT_F:
+                               OPC->_float = !OPA->_float;
+                               break;
+                       case OP_NOT_V:
+                               OPC->_float = !OPA->vector[0] && !OPA->vector[1] && !OPA->vector[2];
+                               break;
+                       case OP_NOT_S:
+                               OPC->_float = !OPA->string || !pr_strings[OPA->string];
+                               break;
+                       case OP_NOT_FNC:
+                               OPC->_float = !OPA->function;
+                               break;
+                       case OP_NOT_ENT:
+                               OPC->_float = (PROG_TO_EDICT(OPA->edict) == sv.edicts);
+                               break;
+                       case OP_EQ_F:
+                               OPC->_float = OPA->_float == OPB->_float;
+                               break;
+                       case OP_EQ_V:
+                               OPC->_float = (OPA->vector[0] == OPB->vector[0]) && (OPA->vector[1] == OPB->vector[1]) && (OPA->vector[2] == OPB->vector[2]);
+                               break;
+                       case OP_EQ_S:
+                               OPC->_float = !strcmp(pr_strings+OPA->string,pr_strings+OPB->string);
+                               break;
+                       case OP_EQ_E:
+                               OPC->_float = OPA->_int == OPB->_int;
+                               break;
+                       case OP_EQ_FNC:
+                               OPC->_float = OPA->function == OPB->function;
+                               break;
+                       case OP_NE_F:
+                               OPC->_float = OPA->_float != OPB->_float;
+                               break;
+                       case OP_NE_V:
+                               OPC->_float = (OPA->vector[0] != OPB->vector[0]) || (OPA->vector[1] != OPB->vector[1]) || (OPA->vector[2] != OPB->vector[2]);
+                               break;
+                       case OP_NE_S:
+                               OPC->_float = strcmp(pr_strings+OPA->string,pr_strings+OPB->string);
+                               break;
+                       case OP_NE_E:
+                               OPC->_float = OPA->_int != OPB->_int;
+                               break;
+                       case OP_NE_FNC:
+                               OPC->_float = OPA->function != OPB->function;
+                               break;
+
+               //==================
+                       case OP_STORE_F:
+                       case OP_STORE_ENT:
+                       case OP_STORE_FLD:              // integers
+                       case OP_STORE_S:
+                       case OP_STORE_FNC:              // pointers
+                               OPB->_int = OPA->_int;
+                               break;
+                       case OP_STORE_V:
+                               OPB->vector[0] = OPA->vector[0];
+                               OPB->vector[1] = OPA->vector[1];
+                               OPB->vector[2] = OPA->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
+#if PRBOUNDSCHECK
+                               if (OPB->_int < 0 || OPB->_int + 4 > pr_edictareasize)
+                               {
+                                       pr_xstatement = st - pr_statements;
+                                       PR_RunError("Progs attempted to write to an out of bounds edict\n");
+                                       return;
+                               }
+                               if (OPB->_int % pr_edict_size < ((byte *)&sv.edicts->v - (byte *)sv.edicts))
+                               {
+                                       pr_xstatement = st - pr_statements;
+                                       PR_RunError("Progs attempted to write to an engine edict field\n");
+                                       return;
+                               }
+#endif
+                               ptr = (eval_t *)((byte *)sv.edicts + OPB->_int);
+                               ptr->_int = OPA->_int;
+                               break;
+                       case OP_STOREP_V:
+#if PRBOUNDSCHECK
+                               if (OPB->_int < 0 || OPB->_int + 12 > pr_edictareasize)
+                               {
+                                       pr_xstatement = st - pr_statements;
+                                       PR_RunError("Progs attempted to write to an out of bounds edict\n");
+                                       return;
+                               }
+#endif
+                               ptr = (eval_t *)((byte *)sv.edicts + OPB->_int);
+                               ptr->vector[0] = OPA->vector[0];
+                               ptr->vector[1] = OPA->vector[1];
+                               ptr->vector[2] = OPA->vector[2];
+                               break;
+
+                       case OP_ADDRESS:
+#if PRBOUNDSCHECK
+                               if (OPA->edict <= 0)
+                               {
+                                       if (OPA->edict == 0 && sv.state == ss_active)
+                                       {
+                                               pr_xstatement = st - pr_statements;
+                                               PR_RunError ("assignment to world entity");
+                                               return;
+                                       }
+                                       else
+                                       {
+                                               pr_xstatement = st - pr_statements;
+                                               PR_RunError("Progs attempted to address an out of bounds edict\n");
+                                               return;
+                                       }
+                               }
+                               else if (OPA->edict >= pr_edictareasize)
+                               {
+                                       pr_xstatement = st - pr_statements;
+                                       PR_RunError("Progs attempted to address an out of bounds edict\n");
+                                       return;
+                               }
+                               if (OPB->_int < 0 || OPB->_int >= progs->entityfields)
+                               {
+                                       pr_xstatement = st - pr_statements;
+                                       PR_RunError("Progs attempted to address an invalid field in an edict\n");
+                                       return;
+                               }
+#else
+                               if (OPA->edict == 0 && sv.state == ss_active)
+                               {
+                                       pr_xstatement = st - pr_statements;
+                                       PR_RunError ("assignment to world entity");
+                                       return;
+                               }
+#endif
+                               ed = PROG_TO_EDICT(OPA->edict);
+                               OPC->_int = (byte *)((int *)&ed->v + OPB->_int) - (byte *)sv.edicts;
+                               break;
+
+                       case OP_LOAD_F:
+                       case OP_LOAD_FLD:
+                       case OP_LOAD_ENT:
+                       case OP_LOAD_S:
+                       case OP_LOAD_FNC:
+#if PRBOUNDSCHECK
+                               if (OPA->edict < 0 || OPA->edict >= pr_edictareasize)
+                               {
+                                       pr_xstatement = st - pr_statements;
+                                       PR_RunError("Progs attempted to read an out of bounds edict number\n");
+                                       return;
+                               }
+                               if (OPB->_int < 0 || OPB->_int >= progs->entityfields)
+                               {
+                                       pr_xstatement = st - pr_statements;
+                                       PR_RunError("Progs attempted to read an invalid field in an edict\n");
+                                       return;
+                               }
+#endif
+                               ed = PROG_TO_EDICT(OPA->edict);
+                               OPC->_int = ((eval_t *)((int *)&ed->v + OPB->_int))->_int;
+                               break;
+
+                       case OP_LOAD_V:
+#if PRBOUNDSCHECK
+                               if (OPA->edict < 0 || OPA->edict >= pr_edictareasize)
+                               {
+                                       pr_xstatement = st - pr_statements;
+                                       PR_RunError("Progs attempted to read an out of bounds edict number\n");
+                                       return;
+                               }
+                               if (OPB->_int < 0 || OPB->_int + 2 >= progs->entityfields)
+                               {
+                                       pr_xstatement = st - pr_statements;
+                                       PR_RunError("Progs attempted to read an invalid field in an edict\n");
+                                       return;
+                               }
+#endif
+                               ed = PROG_TO_EDICT(OPA->edict);
+                               OPC->vector[0] = ((eval_t *)((int *)&ed->v + OPB->_int))->vector[0];
+                               OPC->vector[1] = ((eval_t *)((int *)&ed->v + OPB->_int))->vector[1];
+                               OPC->vector[2] = ((eval_t *)((int *)&ed->v + OPB->_int))->vector[2];
+                               break;
+
+               //==================
+
+                       case OP_IFNOT:
+                               if (!OPA->_int)
+                                       st += st->b - 1;        // offset the s++
+                               break;
+
+                       case OP_IF:
+                               if (OPA->_int)
+                                       st += st->b - 1;        // offset the s++
+                               break;
+
+                       case OP_GOTO:
+                               st += st->a - 1;        // offset the s++
+                               break;
+
+                       case OP_CALL0:
+                       case OP_CALL1:
+                       case OP_CALL2:
+                       case OP_CALL3:
+                       case OP_CALL4:
+                       case OP_CALL5:
+                       case OP_CALL6:
+                       case OP_CALL7:
+                       case OP_CALL8:
+                               pr_xfunction->profile += profile - startprofile;
+                               startprofile = profile;
+                               pr_xstatement = st - pr_statements;
+                               pr_argc = st->op - OP_CALL0;
+                               if (!OPA->function)
+                                       PR_RunError ("NULL function");
+
+                               newf = &pr_functions[OPA->function];
+
+                               if (newf->first_statement < 0)
+                               {
+                                       // negative statements are built in functions
+                                       if ((-newf->first_statement) >= pr_numbuiltins)
+                                               PR_RunError ("Bad builtin call number");
+                                       pr_builtins[-newf->first_statement] ();
+                               }
+                               else
+                                       st = pr_statements + PR_EnterFunction(newf);
+                               break;
+
+                       case OP_DONE:
+                       case OP_RETURN:
+                               pr_globals[OFS_RETURN] = pr_globals[(unsigned short) st->a];
+                               pr_globals[OFS_RETURN+1] = pr_globals[(unsigned short) st->a+1];
+                               pr_globals[OFS_RETURN+2] = pr_globals[(unsigned short) st->a+2];
+
+                               st = pr_statements + PR_LeaveFunction();
+                               if (pr_depth <= exitdepth)
+                                       return;         // all done
+                               if (pr_trace != cachedpr_trace)
+                                       goto chooseexecprogram;
+                               break;
+
+                       case OP_STATE:
+                               ed = PROG_TO_EDICT(pr_global_struct->self);
+                               ed->v.nextthink = pr_global_struct->time + 0.1;
+                               ed->v.frame = OPA->_float;
+                               ed->v.think = OPB->function;
+                               break;
+
+// LordHavoc: to be enabled when Progs version 7 (or whatever it will be numbered) is finalized
+/*
+                       case OP_ADD_I:
+                               OPC->_int = OPA->_int + OPB->_int;
+                               break;
+                       case OP_ADD_IF:
+                               OPC->_int = OPA->_int + (int) OPB->_float;
+                               break;
+                       case OP_ADD_FI:
+                               OPC->_float = OPA->_float + (float) OPB->_int;
+                               break;
+                       case OP_SUB_I:
+                               OPC->_int = OPA->_int - OPB->_int;
+                               break;
+                       case OP_SUB_IF:
+                               OPC->_int = OPA->_int - (int) OPB->_float;
+                               break;
+                       case OP_SUB_FI:
+                               OPC->_float = OPA->_float - (float) OPB->_int;
+                               break;
+                       case OP_MUL_I:
+                               OPC->_int = OPA->_int * OPB->_int;
+                               break;
+                       case OP_MUL_IF:
+                               OPC->_int = OPA->_int * (int) OPB->_float;
+                               break;
+                       case OP_MUL_FI:
+                               OPC->_float = OPA->_float * (float) OPB->_int;
+                               break;
+                       case OP_MUL_VI:
+                               OPC->vector[0] = (float) OPB->_int * OPA->vector[0];
+                               OPC->vector[1] = (float) OPB->_int * OPA->vector[1];
+                               OPC->vector[2] = (float) OPB->_int * OPA->vector[2];
+                               break;
+                       case OP_DIV_VF:
+                               {
+                                       float temp = 1.0f / OPB->_float;
+                                       OPC->vector[0] = temp * OPA->vector[0];
+                                       OPC->vector[1] = temp * OPA->vector[1];
+                                       OPC->vector[2] = temp * OPA->vector[2];
+                               }
+                               break;
+                       case OP_DIV_I:
+                               OPC->_int = OPA->_int / OPB->_int;
+                               break;
+                       case OP_DIV_IF:
+                               OPC->_int = OPA->_int / (int) OPB->_float;
+                               break;
+                       case OP_DIV_FI:
+                               OPC->_float = OPA->_float / (float) OPB->_int;
+                               break;
+                       case OP_CONV_IF:
+                               OPC->_float = OPA->_int;
+                               break;
+                       case OP_CONV_FI:
+                               OPC->_int = OPA->_float;
+                               break;
+                       case OP_BITAND_I:
+                               OPC->_int = OPA->_int & OPB->_int;
+                               break;
+                       case OP_BITOR_I:
+                               OPC->_int = OPA->_int | OPB->_int;
+                               break;
+                       case OP_BITAND_IF:
+                               OPC->_int = OPA->_int & (int)OPB->_float;
+                               break;
+                       case OP_BITOR_IF:
+                               OPC->_int = OPA->_int | (int)OPB->_float;
+                               break;
+                       case OP_BITAND_FI:
+                               OPC->_float = (int)OPA->_float & OPB->_int;
+                               break;
+                       case OP_BITOR_FI:
+                               OPC->_float = (int)OPA->_float | OPB->_int;
+                               break;
+                       case OP_GE_I:
+                               OPC->_float = OPA->_int >= OPB->_int;
+                               break;
+                       case OP_LE_I:
+                               OPC->_float = OPA->_int <= OPB->_int;
+                               break;
+                       case OP_GT_I:
+                               OPC->_float = OPA->_int > OPB->_int;
+                               break;
+                       case OP_LT_I:
+                               OPC->_float = OPA->_int < OPB->_int;
+                               break;
+                       case OP_AND_I:
+                               OPC->_float = OPA->_int && OPB->_int;
+                               break;
+                       case OP_OR_I:
+                               OPC->_float = OPA->_int || OPB->_int;
+                               break;
+                       case OP_GE_IF:
+                               OPC->_float = (float)OPA->_int >= OPB->_float;
+                               break;
+                       case OP_LE_IF:
+                               OPC->_float = (float)OPA->_int <= OPB->_float;
+                               break;
+                       case OP_GT_IF:
+                               OPC->_float = (float)OPA->_int > OPB->_float;
+                               break;
+                       case OP_LT_IF:
+                               OPC->_float = (float)OPA->_int < OPB->_float;
+                               break;
+                       case OP_AND_IF:
+                               OPC->_float = (float)OPA->_int && OPB->_float;
+                               break;
+                       case OP_OR_IF:
+                               OPC->_float = (float)OPA->_int || OPB->_float;
+                               break;
+                       case OP_GE_FI:
+                               OPC->_float = OPA->_float >= (float)OPB->_int;
+                               break;
+                       case OP_LE_FI:
+                               OPC->_float = OPA->_float <= (float)OPB->_int;
+                               break;
+                       case OP_GT_FI:
+                               OPC->_float = OPA->_float > (float)OPB->_int;
+                               break;
+                       case OP_LT_FI:
+                               OPC->_float = OPA->_float < (float)OPB->_int;
+                               break;
+                       case OP_AND_FI:
+                               OPC->_float = OPA->_float && (float)OPB->_int;
+                               break;
+                       case OP_OR_FI:
+                               OPC->_float = OPA->_float || (float)OPB->_int;
+                               break;
+                       case OP_NOT_I:
+                               OPC->_float = !OPA->_int;
+                               break;
+                       case OP_EQ_I:
+                               OPC->_float = OPA->_int == OPB->_int;
+                               break;
+                       case OP_EQ_IF:
+                               OPC->_float = (float)OPA->_int == OPB->_float;
+                               break;
+                       case OP_EQ_FI:
+                               OPC->_float = OPA->_float == (float)OPB->_int;
+                               break;
+                       case OP_NE_I:
+                               OPC->_float = OPA->_int != OPB->_int;
+                               break;
+                       case OP_NE_IF:
+                               OPC->_float = (float)OPA->_int != OPB->_float;
+                               break;
+                       case OP_NE_FI:
+                               OPC->_float = OPA->_float != (float)OPB->_int;
+                               break;
+                       case OP_STORE_I:
+                               OPB->_int = OPA->_int;
+                               break;
+                       case OP_STOREP_I:
+#if PRBOUNDSCHECK
+                               if (OPB->_int < 0 || OPB->_int + 4 > pr_edictareasize)
+                               {
+                                       pr_xstatement = st - pr_statements;
+                                       PR_RunError("Progs attempted to write to an out of bounds edict\n");
+                                       return;
+                               }
+                               if (OPB->_int % pr_edict_size < ((byte *)&sv.edicts->v - (byte *)sv.edicts))
+                               {
+                                       pr_xstatement = st - pr_statements;
+                                       PR_RunError("Progs attempted to write to an engine edict field\n");
+                                       return;
+                               }
+#endif
+                               ptr = (eval_t *)((byte *)sv.edicts + OPB->_int);
+                               ptr->_int = OPA->_int;
+                               break;
+                       case OP_LOAD_I:
+#if PRBOUNDSCHECK
+                               if (OPA->edict < 0 || OPA->edict >= pr_edictareasize)
+                               {
+                                       pr_xstatement = st - pr_statements;
+                                       PR_RunError("Progs attempted to read an out of bounds edict number\n");
+                                       return;
+                               }
+                               if (OPB->_int < 0 || OPB->_int >= progs->entityfields)
+                               {
+                                       pr_xstatement = st - pr_statements;
+                                       PR_RunError("Progs attempted to read an invalid field in an edict\n");
+                                       return;
+                               }
+#endif
+                               ed = PROG_TO_EDICT(OPA->edict);
+                               OPC->_int = ((eval_t *)((int *)&ed->v + OPB->_int))->_int;
+                               break;
+
+                       case OP_GSTOREP_I:
+                       case OP_GSTOREP_F:
+                       case OP_GSTOREP_ENT:
+                       case OP_GSTOREP_FLD:            // integers
+                       case OP_GSTOREP_S:
+                       case OP_GSTOREP_FNC:            // pointers
+#if PRBOUNDSCHECK
+                               if (OPB->_int < 0 || OPB->_int >= pr_globaldefs)
+                               {
+                                       pr_xstatement = st - pr_statements;
+                                       PR_RunError("Progs attempted to write to an invalid indexed global\n");
+                                       return;
+                               }
+#endif
+                               pr_globals[OPB->_int] = OPA->_float;
+                               break;
+                       case OP_GSTOREP_V:
+#if PRBOUNDSCHECK
+                               if (OPB->_int < 0 || OPB->_int + 2 >= pr_globaldefs)
+                               {
+                                       pr_xstatement = st - pr_statements;
+                                       PR_RunError("Progs attempted to write to an invalid indexed global\n");
+                                       return;
+                               }
+#endif
+                               pr_globals[OPB->_int  ] = OPA->vector[0];
+                               pr_globals[OPB->_int+1] = OPA->vector[1];
+                               pr_globals[OPB->_int+2] = OPA->vector[2];
+                               break;
+
+                       case OP_GADDRESS:
+                               i = OPA->_int + (int) OPB->_float;
+#if PRBOUNDSCHECK
+                               if (i < 0 || i >= pr_globaldefs)
+                               {
+                                       pr_xstatement = st - pr_statements;
+                                       PR_RunError("Progs attempted to address an out of bounds global\n");
+                                       return;
+                               }
+#endif
+                               OPC->_float = pr_globals[i];
+                               break;
+
+                       case OP_GLOAD_I:
+                       case OP_GLOAD_F:
+                       case OP_GLOAD_FLD:
+                       case OP_GLOAD_ENT:
+                       case OP_GLOAD_S:
+                       case OP_GLOAD_FNC:
+#if PRBOUNDSCHECK
+                               if (OPA->_int < 0 || OPA->_int >= pr_globaldefs)
+                               {
+                                       pr_xstatement = st - pr_statements;
+                                       PR_RunError("Progs attempted to read an invalid indexed global\n");
+                                       return;
+                               }
+#endif
+                               OPC->_float = pr_globals[OPA->_int];
+                               break;
+
+                       case OP_GLOAD_V:
+#if PRBOUNDSCHECK
+                               if (OPA->_int < 0 || OPA->_int + 2 >= pr_globaldefs)
+                               {
+                                       pr_xstatement = st - pr_statements;
+                                       PR_RunError("Progs attempted to read an invalid indexed global\n");
+                                       return;
+                               }
+#endif
+                               OPC->vector[0] = pr_globals[OPA->_int  ];
+                               OPC->vector[1] = pr_globals[OPA->_int+1];
+                               OPC->vector[2] = pr_globals[OPA->_int+2];
+                               break;
+
+                       case OP_BOUNDCHECK:
+                               if (OPA->_int < 0 || OPA->_int >= st->b)
+                               {
+                                       pr_xstatement = st - pr_statements;
+                                       PR_RunError("Progs boundcheck failed at line number %d, value is < 0 or >= %d\n", st->b, st->c);
+                                       return;
+                               }
+                               break;
+
+*/
+
+                       default:
+                               pr_xstatement = st - pr_statements;
+                               PR_RunError ("Bad opcode %i", st->op);
+                       }
+               }
diff --git a/progs.h b/progs.h
index a77faafe8f0a60aa4cc506ce3ebb79dcfa1923c1..2b7b35060d8516dee3ba4cf3c89e7d66d7a1002f 100644 (file)
--- a/progs.h
+++ b/progs.h
@@ -89,7 +89,6 @@ extern int eval_viewmodelforclient;
 extern int eval_nodrawtoclient;
 extern int eval_exteriormodeltoclient;
 extern int eval_drawonlytoclient;
-extern int eval_colormod;
 extern int eval_ping;
 extern int eval_movement;
 extern int eval_pmodel;
index 7d21297fa66070f2cbd7246e82c07c06bfaab58c..20cf850d5ed787c5721313a1d01b092120f7ef29 100644 (file)
@@ -15,7 +15,6 @@ void ClearStateToDefault(entity_state_t *s)
        s->scale = 16;
        s->glowsize = 0;
        s->glowcolor = 254;
-       s->colormod = 255;
        s->flags = 0;
        s->active = 0;
 }
index e7b494b2fde02b719180a39a4dc8d65c1414e3f4..639221ec84fd6787d7700d5beab2515b145f5b34 100644 (file)
@@ -77,6 +77,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #define U_EFFECTS2             (1<<19) // 1 byte, this is .effects & 0xFF00 (second byte)
 #define U_GLOWSIZE             (1<<20) // 1 byte, encoding is float/8.0, signed (negative is darklight), not sent if 0
 #define U_GLOWCOLOR            (1<<21) // 1 byte, palette index, default is 254 (white), this IS used for darklight (allowing colored darklight), however the particles from a darklight are always black, not sent if default value (even if glowsize or glowtrail is set)
+// LordHavoc: colormod feature has been removed, because no one used it
 #define U_COLORMOD             (1<<22) // 1 byte, 3 bit red, 3 bit green, 2 bit blue, this lets you tint an object artifically, so you could make a red rocket, or a blue fiend...
 #define U_EXTEND2              (1<<23) // another byte to follow
 // LordHavoc: second extend byte
@@ -270,11 +271,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #define RENDER_VIEWMODEL 4
 #define RENDER_EXTERIORMODEL 8
 
-// LordHavoc: made this more compact, and added some more fields
 typedef struct
 {
-       double  time; // time this state was updated
-       unsigned short active;
+       double  time; // time this state was built
+       unsigned short active; // true if a valid state
        unsigned short modelindex;
        unsigned short frame;
        unsigned short effects;
@@ -286,8 +286,8 @@ typedef struct
        byte    scale;
        byte    glowsize;
        byte    glowcolor;
-       byte    colormod;
        byte    flags;
-} entity_state_t;
+}
+entity_state_t;
 
 void ClearStateToDefault(entity_state_t *s);
index f9fbe204e860afb2fcee50b6f5d5e61bb1d27c0d..bba4b2383b6a49bc918cf2c33c010159748468a1 100644 (file)
@@ -23,6 +23,20 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 extern int buildnumber;
 
+#if !defined BYTE_DEFINED
+typedef unsigned char          byte;
+#define BYTE_DEFINED 1
+#endif
+
+#undef true
+#undef false
+
+typedef enum {false, true} qboolean;
+
+#ifndef NULL
+#define NULL ((void *)0)
+#endif
+
 #ifndef FALSE
 #define FALSE 0
 #define TRUE 1
@@ -35,7 +49,7 @@ extern int buildnumber;
 #define ASSERT(condition)
 #endif
 
-#define        GAMENAME        "id1"
+#define GAMENAME "id1"
 
 #include <math.h>
 #include <string.h>
@@ -44,13 +58,6 @@ extern int buildnumber;
 #include <stdlib.h>
 #include <setjmp.h>
 
-#define UNUSED(x)      (x = x) // for pesky compiler / lint warnings
-
-// LordHavoc: default heap size (unless -heapsize, -mem, or -winmem is used), in megabytes
-#define DEFAULTMEM 24
-//#define      MINIMUM_MEMORY                  0x550000
-//#define      MINIMUM_MEMORY_LEVELPAK (MINIMUM_MEMORY + 0x100000)
-
 #define MAX_NUM_ARGVS  50
 
 // up / down
@@ -179,12 +186,13 @@ extern int buildnumber;
 
 #define        SOUND_CHANNELS          8
 
+#include "zone.h"
+#include "quakeio.h"
 #include "common.h"
 #include "cvar.h"
 #include "bspfile.h"
 #include "vid.h"
 #include "sys.h"
-#include "zone.h"
 #include "mathlib.h"
 
 #include "r_textures.h"
@@ -198,8 +206,8 @@ extern int buildnumber;
 #include "sbar.h"
 #include "sound.h"
 #include "model_shared.h"
-#include "render.h"
 #include "client.h"
+#include "render.h"
 #include "progs.h"
 #include "server.h"
 
@@ -232,8 +240,6 @@ typedef struct
 #endif
        int             argc;
        char    **argv;
-       void    *membase;
-       int             memsize;
 } quakeparms_t;
 
 
index 2610e45026209c40b091c45ad8ea8601197edcd4..f297e0e679bab8176d11ac47392a5f3758dd38c8 100644 (file)
--- a/quakeio.c
+++ b/quakeio.c
@@ -60,6 +60,8 @@
 # endif
 #endif
 
+mempool_t *quakeio_mempool;
+
 void
 Qexpand_squiggle (const char *path, char *dest)
 {
@@ -132,7 +134,7 @@ Qopen (const char *path, const char *mode)
        }
        *p = 0;
 
-       file = qmalloc (sizeof (*file));
+       file = Mem_Alloc(quakeio_mempool, sizeof (*file));
        memset(file, 0, sizeof(*file));
        if (!file)
                return 0;
@@ -140,7 +142,7 @@ Qopen (const char *path, const char *mode)
        if (zip) {
                file->gzfile = gzopen (path, m);
                if (!file->gzfile) {
-                       qfree (file);
+                       Mem_Free(file);
                        return 0;
                }
        } else
@@ -148,7 +150,7 @@ Qopen (const char *path, const char *mode)
        {
                file->file = fopen (path, m);
                if (!file->file) {
-                       qfree (file);
+                       Mem_Free(file);
                        return 0;
                }
        }
@@ -172,7 +174,7 @@ Qdopen (int fd, const char *mode)
 
        *p = 0;
 
-       file = qmalloc (sizeof (*file));
+       file = Mem_Alloc(quakeio_mempool, sizeof (*file));
        memset(file, 0, sizeof(*file));
        if (!file)
                return 0;
@@ -180,7 +182,7 @@ Qdopen (int fd, const char *mode)
        if (zip) {
                file->gzfile = gzdopen (fd, m);
                if (!file->gzfile) {
-                       qfree (file);
+                       Mem_Free(file);
                        return 0;
                }
        } else
@@ -188,7 +190,7 @@ Qdopen (int fd, const char *mode)
        {
                file->file = fdopen (fd, m);
                if (!file->file) {
-                       qfree (file);
+                       Mem_Free(file);
                        return 0;
                }
        }
@@ -208,7 +210,7 @@ Qclose (QFile *file)
        else
                gzclose (file->gzfile);
 #endif
-       qfree (file);
+       Mem_Free(file);
 }
 
 int
@@ -370,22 +372,23 @@ Qgetline (QFile *file)
 {
        static int  size = 256;
        static char *buf = 0;
+       char        *t;
        int         len;
 
        if (!buf)
-               buf = malloc (size);
+               buf = Mem_Alloc(quakeio_mempool, size);
 
        if (!Qgets (file, buf, size))
                return 0;
 
        len = strlen (buf);
-       while (buf[len - 1] != '\n' && buf[len - 1] != '\r') {
-               char       *t = realloc (buf, size + 256);
-
-               if (!t)
-                       Host_Error("Qgetline: realloc failed, out of memory?\n");
-               buf = t;
+       while (buf[len - 1] != '\n' && buf[len - 1] != '\r')
+       {
+               t = Mem_Alloc(quakeio_mempool, size + 256);
+               memcpy(t, buf, size);
+               Mem_Free(buf);
                size += 256;
+               buf = t;
                if (!Qgets (file, buf + len, size - len))
                        break;
                len = strlen (buf);
@@ -394,3 +397,8 @@ Qgetline (QFile *file)
                buf[len - 1] = 0;
        return buf;
 }
+
+void QuakeIO_Init(void)
+{
+       quakeio_mempool = Mem_AllocPool("file management");
+}
index eb5f6fa6f5da91f5af21e737a933791f62f9eb84..d0134e03ad69fbe351658e5b8fbe709f44e6c5b2 100644 (file)
--- a/r_clip.c
+++ b/r_clip.c
@@ -65,6 +65,8 @@ float r_clip_viewmatrix[3][3], r_clip_viewmulx, r_clip_viewmuly, r_clip_viewcent
 //float r_clip_nearclipdist, r_clip_nearclipdist2;
 tinyplane_t r_clip_viewplane[5];
 
+mempool_t *r_clip_mempool;
+
 void R_Clip_MakeViewMatrix(void)
 {
        float pixelaspect, screenaspect, horizontalfieldofview, verticalfieldofview;
@@ -100,35 +102,35 @@ void R_Clip_StartFrame(void)
 {
        int i;
        int newwidth, newheight, newmaxedges, newmaxsurfs;
-       newwidth = bound(80, (int) r_clipwidth.value, vid.realwidth * 2);
-       newheight = bound(60, (int) r_clipheight.value, vid.realheight * 2);
-       newmaxedges = bound(128, (int) r_clipedges.value, 262144);
-       newmaxsurfs = bound(32, (int) r_clipsurfaces.value, 65536);
+       newwidth = bound(80, r_clipwidth.integer, vid.realwidth * 2);
+       newheight = bound(60, r_clipheight.integer, vid.realheight * 2);
+       newmaxedges = bound(128, r_clipedges.integer, 262144);
+       newmaxsurfs = bound(32, r_clipsurfaces.integer, 65536);
        if (newwidth != clipwidth || newheight != clipheight || maxclipedges != newmaxedges || maxclipsurfs != newmaxsurfs)
        {
 #if CLIPTEST
                if (clipbuffer)
-                       qfree(clipbuffer);
+                       Mem_Free(clipbuffer);
 #endif
                if (clipedges)
-                       qfree(clipedges);
+                       Mem_Free(clipedges);
                if (clipsurfs)
-                       qfree(clipsurfs);
+                       Mem_Free(clipsurfs);
                if (newedges)
-                       qfree(newedges);
+                       Mem_Free(newedges);
                if (removeedges)
-                       qfree(removeedges);
+                       Mem_Free(removeedges);
                clipwidth = newwidth;
                clipheight = newheight;
                maxclipedges = newmaxedges;
                maxclipsurfs = newmaxsurfs;
 #if CLIPTEST
-               clipbuffer = qmalloc(clipwidth * clipheight * sizeof(clippixel_t));
+               clipbuffer = Mem_Alloc(r_clip_mempool, clipwidth * clipheight * sizeof(clippixel_t));
 #endif
-               clipedges = qmalloc(maxclipedges * sizeof(clipedge_t));
-               clipsurfs = qmalloc(maxclipsurfs * sizeof(clipsurf_t));
-               newedges = qmalloc(clipheight * sizeof(clipedge_t));
-               removeedges = qmalloc(clipheight * sizeof(clipedge_t *));
+               clipedges = Mem_Alloc(r_clip_mempool, maxclipedges * sizeof(clipedge_t));
+               clipsurfs = Mem_Alloc(r_clip_mempool, maxclipsurfs * sizeof(clipsurf_t));
+               newedges = Mem_Alloc(r_clip_mempool, clipheight * sizeof(clipedge_t));
+               removeedges = Mem_Alloc(r_clip_mempool, clipheight * sizeof(clipedge_t *));
                clipedgesend = clipedges + maxclipedges;
                clipsurfsend = clipsurfs + maxclipsurfs;
        }
@@ -169,26 +171,18 @@ void R_Clip_EndFrame(void)
 
 void r_clip_start(void)
 {
+       r_clip_mempool = Mem_AllocPool("R_Clip");
 }
 
 void r_clip_shutdown(void)
 {
+       Mem_FreePool(&r_clip_mempool);
 #if CLIPTEST
-       if (clipbuffer)
-               qfree(clipbuffer);
        clipbuffer = NULL;
 #endif
-       if (clipsurfs)
-               qfree(clipsurfs);
        clipsurfs = NULL;
-       if (clipedges)
-               qfree(clipedges);
        clipedges = NULL;
-       if (newedges)
-               qfree(newedges);
        newedges = NULL;
-       if (removeedges)
-               qfree(removeedges);
        removeedges = NULL;
        clipwidth = -1;
        clipheight = -1;
@@ -881,7 +875,7 @@ void R_Clip_DisplayBuffer(void)
        int i;
        static int firstupload = true;
        byte clipbuffertex[256*256], *b;
-       if (!r_render.value)
+       if (!r_render.integer)
                return;
        if (clipwidth > 256 || clipheight > 256)
                return;
index 5872d5697a287416338b054c717eae911e6c7410..a628b71d6aa96c301baacfd98aaf1aec6f2f2a61 100644 (file)
@@ -7,9 +7,11 @@ cvar_t crosshair_flashrange = {CVAR_SAVE, "crosshair_flashrange", "0.1"};
 
 #define NUMCROSSHAIRS 5
 
-rtexture_t *crosshairtex[NUMCROSSHAIRS];
+static rtexturepool_t *crosshairtexturepool;
 
-byte *crosshairtexdata[NUMCROSSHAIRS] =
+static rtexture_t *crosshairtex[NUMCROSSHAIRS];
+
+static byte *crosshairtexdata[NUMCROSSHAIRS] =
 {
        "0000000000000000"
        "0000000000000000"
@@ -97,7 +99,7 @@ byte *crosshairtexdata[NUMCROSSHAIRS] =
        "0000000000000000"
 };
 
-void crosshairload(int num, byte *in)
+static void crosshairload(int num, byte *in)
 {
        int i;
        byte data[16*16][4];
@@ -106,22 +108,24 @@ void crosshairload(int num, byte *in)
                data[i][0] = data[i][1] = data[i][2] = 255;
                data[i][3] = (in[i] - '0') * 255 / 7;
        }
-       crosshairtex[num] = R_LoadTexture(va("crosshair%02d", num), 16, 16, &data[0][0], TEXF_ALPHA | TEXF_RGBA | TEXF_PRECACHE);
+       crosshairtex[num] = R_LoadTexture(crosshairtexturepool, va("crosshair%02d", num), 16, 16, &data[0][0], TEXTYPE_RGBA, TEXF_ALPHA | TEXF_PRECACHE);
 }
 
-void r_crosshairs_start(void)
+static void r_crosshairs_start(void)
 {
        int i;
+       crosshairtexturepool = R_AllocTexturePool();
        for (i = 0;i < NUMCROSSHAIRS;i++)
                crosshairload(i, crosshairtexdata[i]);
 //     crosshairtex[1] = crosshairload(crosshairtex2);
 }
 
-void r_crosshairs_shutdown(void)
+static void r_crosshairs_shutdown(void)
 {
+       R_FreeTexturePool(&crosshairtexturepool);
 }
 
-void r_crosshairs_newmap(void)
+static void r_crosshairs_newmap(void)
 {
 }
 
index 6c45f70e5a89893918291c772312f9a70f898381..84b9d842e094822832ffcd58593324c6ffa9db95 100644 (file)
@@ -20,377 +20,175 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 #include "quakedef.h"
 
-#define MAX_DECALS 2048
-
-typedef struct decal_s
-{
-       vec3_t          org;
-       vec3_t          direction;
-       vec2_t          texcoord[4];
-       vec3_t          vert[4];
-       byte            color[4];
-       rtexture_t      *tex;
-       msurface_t      *surface;
-       byte            *lightmapaddress;
-       int                     lightmapstep;
-}
-decal_t;
-
-decal_t *decals;
-int currentdecal; // wraps around in decal array, replacing old ones when a new one is needed
-
 cvar_t r_drawdecals = {0, "r_drawdecals", "1"};
-cvar_t r_decals_lighting = {0, "r_decals_lighting", "1"};
 
-void r_decals_start(void)
+static void r_decals_start(void)
 {
-       decals = (decal_t *) qmalloc(MAX_DECALS * sizeof(decal_t));
-       memset(decals, 0, MAX_DECALS * sizeof(decal_t));
-       currentdecal = 0;
 }
 
-void r_decals_shutdown(void)
+static void r_decals_shutdown(void)
 {
-       qfree(decals);
 }
 
-void r_decals_newmap(void)
+static void r_decals_newmap(void)
 {
-       memset(decals, 0, MAX_DECALS * sizeof(decal_t));
-       currentdecal = 0;
 }
 
 void R_Decals_Init(void)
 {
        Cvar_RegisterVariable (&r_drawdecals);
-       Cvar_RegisterVariable (&r_decals_lighting);
 
        R_RegisterModule("R_Decals", r_decals_start, r_decals_shutdown, r_decals_newmap);
 }
 
-// these are static globals only to avoid putting unnecessary things on the stack
-static vec3_t decalorg;
-static float decalbestdist;
-static msurface_t *decalbestsurf;
-static int decalbestlightmapofs;
-void R_RecursiveDecalSurface (mnode_t *node)
+static int decalindexarray[2*3] =
 {
-       // these are static because only one occurance of them need exist at once, so avoid putting them on the stack
-       static float ndist, dist;
-       static msurface_t *surf, *endsurf;
-       static vec3_t impact;
-       static int ds, dt;
-
-loc0:
-       if (node->contents < 0)
-               return;
-
-       ndist = PlaneDiff(decalorg, node->plane);
-
-       if (ndist > 16)
-       {
-               node = node->children[0];
-               goto loc0;
-       }
-       if (ndist < -16)
-       {
-               node = node->children[1];
-               goto loc0;
-       }
+       0, 1, 2,
+       0, 2, 3,
+};
 
-// mark the polygons
-       surf = cl.worldmodel->surfaces + node->firstsurface;
-       endsurf = surf + node->numsurfaces;
-       for (;surf < endsurf;surf++)
-       {
-               if (surf->flags & SURF_DRAWTILED)
-                       continue;       // no lightmaps
-
-               dist = PlaneDiff(decalorg, surf->plane);
-               if (surf->flags & SURF_PLANEBACK)
-                       dist = -dist;
-               if (dist < 0)
-                       continue;
-               if (dist >= decalbestdist)
-                       continue;
+void R_DrawDecals (void)
+{
+       renderdecal_t *r;
+       int i, j, lightmapstep, ds, dt;
+       float fscale, fr, fg, fb, dist, f, ifog, impact[3], v[3], org[3], dir[3], right[3], up[3], tvertex[4][5];
+       particletexture_t *tex;
+       byte *lightmap;
+       msurface_t *surf;
+       rdlight_t *rd;
+       rmeshinfo_t m;
 
-               impact[0] = decalorg[0] - surf->plane->normal[0] * dist;
-               impact[1] = decalorg[1] - surf->plane->normal[1] * dist;
-               impact[2] = decalorg[2] - surf->plane->normal[2] * dist;
+       if (!r_drawdecals.integer)
+               return;
 
-               ds = (int) (DotProduct(impact, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]);
-               dt = (int) (DotProduct(impact, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3]);
+       ifog = 1;
 
-               if (ds < surf->texturemins[0] || dt < surf->texturemins[1])
-                       continue;
-               
-               ds -= surf->texturemins[0];
-               dt -= surf->texturemins[1];
-               
-               if (ds > surf->extents[0] || dt > surf->extents[1])
-                       continue;
+       Mod_CheckLoaded(cl.worldmodel);
 
-               decalbestsurf = surf;
-               decalbestdist = dist;
-               decalbestlightmapofs = (dt >> 4) * ((surf->extents[0] >> 4) + 1) + (ds >> 4);
-       }
+       memset(&m, 0, sizeof(m));
+       m.blendfunc1 = GL_SRC_ALPHA;
+       m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
+       m.numtriangles = 2;
+       m.numverts = 4;
+       m.index = decalindexarray;
+       m.vertex = &tvertex[0][0];
+       m.vertexstep = sizeof(float[5]);
+       m.tex[0] = R_GetTexture(particlefonttexture);
+       m.texcoords[0] = &tvertex[0][3];
+       m.texcoordstep[0] = sizeof(float[5]);
 
-       if (node->children[0]->contents >= 0)
+       for (i = 0, r = r_refdef.decals;i < r_refdef.numdecals;i++, r++)
        {
-               if (node->children[1]->contents >= 0)
-               {
-                       R_RecursiveDecalSurface (node->children[0]);
-                       node = node->children[1];
-                       goto loc0;
-               }
-               else
+               if (r->ent)
                {
-                       node = node->children[0];
-                       goto loc0;
-               }
-       }
-       else if (node->children[1]->contents >= 0)
-       {
-               node = node->children[1];
-               goto loc0;
-       }
-}
-
-void R_Decal(vec3_t org, rtexture_t *tex, float s1, float t1, float s2, float t2, float scale, int cred, int cgreen, int cblue, int alpha)
-{
-       vec3_t center, right, up;
-       decal_t *decal;
-
-       if (alpha < 1)
-               return;
-
-       // find the best surface to place the decal on
-       decalbestsurf = NULL;
-       decalbestdist = 16;
-       decalbestlightmapofs = 0;
-       VectorCopy(org, decalorg);
+                       if (r->ent->visframe != r_framecount)
+                               continue;
 
-       R_RecursiveDecalSurface (cl.worldmodel->nodes);
+                       Mod_CheckLoaded(r->ent->model);
 
-       // abort if no suitable surface was found
-       if (decalbestsurf == NULL)
-               return;
-
-       // grab a decal from the array and advance to the next decal to replace, wrapping to replace an old decal if necessary
-       decal = decals + currentdecal;
-       currentdecal++;
-       if (currentdecal >= MAX_DECALS)
-               currentdecal = 0;
-       decal->tex = tex;
-       VectorCopy(decalbestsurf->plane->normal, decal->direction);
-       // reverse direction
-       if (decalbestsurf->flags & SURF_PLANEBACK)
-               VectorNegate(decal->direction, decal->direction);
-       VectorNegate(decal->direction, decal->direction);
-       // 0.25 to push it off the surface a bit
-       decalbestdist -= 0.25f;
-       decal->org[0] = center[0] = org[0] + decal->direction[0] * decalbestdist;
-       decal->org[1] = center[1] = org[1] + decal->direction[1] * decalbestdist;
-       decal->org[2] = center[2] = org[2] + decal->direction[2] * decalbestdist;
-       // set up the 4 corners
-       scale *= 0.5f;
-       VectorVectors(decal->direction, right, up);
-       decal->texcoord[0][0] = s1;
-       decal->texcoord[0][1] = t1;
-       decal->vert[0][0] = center[0] - right[0] * scale - up[0] * scale;
-       decal->vert[0][1] = center[1] - right[1] * scale - up[1] * scale;
-       decal->vert[0][2] = center[2] - right[2] * scale - up[2] * scale;
-       decal->texcoord[1][0] = s1;
-       decal->texcoord[1][1] = t2;
-       decal->vert[1][0] = center[0] - right[0] * scale + up[0] * scale;
-       decal->vert[1][1] = center[1] - right[1] * scale + up[1] * scale;
-       decal->vert[1][2] = center[2] - right[2] * scale + up[2] * scale;
-       decal->texcoord[2][0] = s2;
-       decal->texcoord[2][1] = t2;
-       decal->vert[2][0] = center[0] + right[0] * scale + up[0] * scale;
-       decal->vert[2][1] = center[1] + right[1] * scale + up[1] * scale;
-       decal->vert[2][2] = center[2] + right[2] * scale + up[2] * scale;
-       decal->texcoord[3][0] = s2;
-       decal->texcoord[3][1] = t1;
-       decal->vert[3][0] = center[0] + right[0] * scale - up[0] * scale;
-       decal->vert[3][1] = center[1] + right[1] * scale - up[1] * scale;
-       decal->vert[3][2] = center[2] + right[2] * scale - up[2] * scale;
-       // store the color
-       decal->color[0] = (byte) bound(0, cred, 255);
-       decal->color[1] = (byte) bound(0, cgreen, 255);
-       decal->color[2] = (byte) bound(0, cblue, 255);
-       decal->color[3] = (byte) bound(0, alpha, 255);
-       // store the surface information for lighting
-       decal->surface = decalbestsurf;
-       decal->lightmapstep = ((decalbestsurf->extents[0]>>4)+1) * ((decalbestsurf->extents[1]>>4)+1)*3; // LordHavoc: *3 for colored lighting
-       if (decalbestsurf->samples)
-               decal->lightmapaddress = decalbestsurf->samples + decalbestlightmapofs * 3; // LordHavoc: *3 for colored lighitng
-       else
-               decal->lightmapaddress = NULL;
-}
+                       surf = r->ent->model->surfaces + r->surface;
 
-void GL_DrawDecals (void)
-{
-       decal_t *p;
-       int i, j, k, dynamiclight, bits, texnum, iscale, ir, ig, ib, lit, cr, cg, cb;
-       float /*fscale, */fr, fg, fb, dist, rad, mindist;
-       byte *lightmap;
-       vec3_t v;
-       msurface_t *surf;
-       dlight_t *dl;
+                       // skip decals on surfaces that aren't visible in this frame
+                       if (surf->visframe != r_framecount)
+                               continue;
 
-       if (!r_drawdecals.value)
-               return;
+                       softwaretransformforentity(r->ent);
+                       softwaretransform(r->org, org);
+                       softwaretransformdirection(r->dir, dir);
 
-       dynamiclight = (int) r_dynamic.value != 0 && (int) r_decals_lighting.value != 0;
+                       // do not render if the view origin is behind the decal
+                       VectorSubtract(org, r_origin, v);
+                       if (DotProduct(dir, v) < 0)
+                               continue;
+               }
+               else
+               {
+                       surf = cl.worldmodel->surfaces + r->surface;
 
-       mindist = DotProduct(r_origin, vpn) + 4.0f;
+                       // skip decals on surfaces that aren't visible in this frame
+                       if (surf->visframe != r_framecount)
+                               continue;
 
-       if (r_render.value)
-       {
-               glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-               glEnable(GL_BLEND);
-//             glShadeModel(GL_FLAT);
-               glDepthMask(0); // disable zbuffer updates
-               glDisable(GL_ALPHA_TEST);
-               glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-       }
-       texnum = -1;
+                       // do not render if the view origin is behind the decal
+                       VectorSubtract(r->org, r_origin, v);
+                       if (DotProduct(r->dir, v) < 0)
+                               continue;
 
-       for (i = 0, p = decals;i < MAX_DECALS;i++, p++)
-       {
-               if (p->tex == NULL)
-                       break;
-               // skip decals on surfaces that aren't visible in this frame
-               if (p->surface->visframe != r_framecount)
-                       continue;
+                       VectorCopy(r->org, org);
+                       VectorCopy(r->dir, dir);
+               }
 
-               // do not render if the decal is behind the view
-               if (DotProduct(p->org, vpn) < mindist)
-                       continue;
+               dist = -PlaneDiff(r->org, surf->plane);
+               VectorMA(r->org, dist, surf->plane->normal, impact);
 
-               // do not render if the view origin is behind the decal
-               VectorSubtract(p->org, r_origin, v);
-               if (DotProduct(p->direction, v) < 0)
-                       continue;
+               ds = (int) (DotProduct(impact, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]) - surf->texturemins[0];
+               dt = (int) (DotProduct(impact, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3]) - surf->texturemins[1];
 
-               // get the surface lighting
-               surf = p->surface;
-               lightmap = p->lightmapaddress;
-               // dynamic lighting
-               lit = false;
-               if (dynamiclight)
-               {
-                       fr = fg = fb = 0.0f;
-                       if (surf->dlightframe == r_framecount)
-                       {
-                               for (j = 0;j < 8;j++)
-                               {
-                                       bits = surf->dlightbits[j];
-                                       if (bits)
-                                       {
-                                               for (k = 0, dl = cl_dlights + j * 32;bits;k++, dl++)
-                                               {
-                                                       if (bits & (1 << k))
-                                                       {
-                                                               bits -= 1 << k;
-                                                               VectorSubtract(p->org, dl->origin, v);
-                                                               dist = DotProduct(v, v) + LIGHTOFFSET;
-                                                               rad = dl->radius * dl->radius;
-                                                               if (dist < rad)
-                                                               {
-                                                                       rad *= 128.0f / dist;
-                                                                       fr += rad * dl->color[0];
-                                                                       fg += rad * dl->color[1];
-                                                                       fb += rad * dl->color[2];
-                                                                       lit = true;
-                                                               }
-                                                       }
-                                               }
-                                       }
-                               }
-                       }
-               }
-               if (lit)
+               if (ds < 0 || dt < 0 || ds > surf->extents[0] || dt > surf->extents[1])
                {
-#if SLOWMATH
-                       ir = fr * 256.0f;
-                       ig = fg * 256.0f;
-                       ib = fb * 256.0f;
-#else
-                       fr += 8388608.0f;
-                       fg += 8388608.0f;
-                       fb += 8388608.0f;
-                       ir = (*((long *)&fr) & 0x7FFFFF) << 8;
-                       ig = (*((long *)&fg) & 0x7FFFFF) << 8;
-                       ib = (*((long *)&fb) & 0x7FFFFF) << 8;
-#endif
-               }
-               else
-                       ir = ig = ib = 0;
-#if 1
-               if (lightmap)
-               {
-                       if (surf->styles[0] != 255)
-                       {
-                               iscale = d_lightstylevalue[surf->styles[0]];
-                               ir += lightmap[0] * iscale;
-                               ig += lightmap[1] * iscale;
-                               ib += lightmap[2] * iscale;
-                               if (surf->styles[1] != 255)
-                               {
-                                       lightmap += p->lightmapstep;
-                                       iscale = d_lightstylevalue[surf->styles[1]];
-                                       ir += lightmap[0] * iscale;
-                                       ig += lightmap[1] * iscale;
-                                       ib += lightmap[2] * iscale;
-                                       if (surf->styles[2] != 255)
-                                       {
-                                               lightmap += p->lightmapstep;
-                                               iscale = d_lightstylevalue[surf->styles[2]];
-                                               ir += lightmap[0] * iscale;
-                                               ig += lightmap[1] * iscale;
-                                               ib += lightmap[2] * iscale;
-                                               if (surf->styles[3] != 255)
-                                               {
-                                                       lightmap += p->lightmapstep;
-                                                       iscale = d_lightstylevalue[surf->styles[3]];
-                                                       ir += lightmap[0] * iscale;
-                                                       ig += lightmap[1] * iscale;
-                                                       ib += lightmap[2] * iscale;
-                                               }
-                                       }
-                               }
-                       }
+                       // this should never happen
+                       continue;
                }
-#else
+
+               if (fogenabled)
+                       ifog = 1 - exp(fogdensity/DotProduct(v,v));
+
+               tex = &particletexture[r->tex][0];
+               VectorVectors(dir, right, up);
+               VectorScale(right, r->scale, right);
+               VectorScale(up, r->scale, up);
+               tvertex[0][0] = org[0] - right[0] - up[0];
+               tvertex[0][1] = org[1] - right[1] - up[1];
+               tvertex[0][2] = org[2] - right[2] - up[2];
+               tvertex[0][3] = tex->s1;
+               tvertex[0][4] = tex->t1;
+               tvertex[1][0] = org[0] - right[0] + up[0];
+               tvertex[1][1] = org[1] - right[1] + up[1];
+               tvertex[1][2] = org[2] - right[2] + up[2];
+               tvertex[1][3] = tex->s1;
+               tvertex[1][4] = tex->t2;
+               tvertex[2][0] = org[0] + right[0] + up[0];
+               tvertex[2][1] = org[1] + right[1] + up[1];
+               tvertex[2][2] = org[2] + right[2] + up[2];
+               tvertex[2][3] = tex->s2;
+               tvertex[2][4] = tex->t2;
+               tvertex[3][0] = org[0] + right[0] - up[0];
+               tvertex[3][1] = org[1] + right[1] - up[1];
+               tvertex[3][2] = org[2] + right[2] - up[2];
+               tvertex[3][3] = tex->s2;
+               tvertex[3][4] = tex->t1;
+
+               // lighting
                fr = fg = fb = 0.0f;
-               if (lightmap)
+
+               if ((lightmap = surf->samples))
                {
                        if (surf->styles[0] != 255)
                        {
-                               fscale = d_lightstylevalue[surf->styles[0]] * (1.0f / 256.0f);
+                               lightmap += ((dt >> 4) * ((surf->extents[0] >> 4) + 1) + (ds >> 4)) * 3;
+                               fscale = d_lightstylevalue[surf->styles[0]] * (1.0f / 32768.0f);
                                fr += lightmap[0] * fscale;
                                fg += lightmap[1] * fscale;
                                fb += lightmap[2] * fscale;
                                if (surf->styles[1] != 255)
                                {
-                                       lightmap += p->lightmapstep;
-                                       fscale = d_lightstylevalue[surf->styles[1]] * (1.0f / 256.0f);
+                                       lightmapstep = (((surf->extents[0] >> 4) + 1) * ((surf->extents[1] >> 4) + 1)) * 3;
+                                       lightmap += lightmapstep;
+                                       fscale = d_lightstylevalue[surf->styles[1]] * (1.0f / 32768.0f);
                                        fr += lightmap[0] * fscale;
                                        fg += lightmap[1] * fscale;
                                        fb += lightmap[2] * fscale;
                                        if (surf->styles[2] != 255)
                                        {
-                                               lightmap += p->lightmapstep;
-                                               fscale = d_lightstylevalue[surf->styles[2]] * (1.0f / 256.0f);
+                                               lightmap += lightmapstep;
+                                               fscale = d_lightstylevalue[surf->styles[2]] * (1.0f / 32768.0f);
                                                fr += lightmap[0] * fscale;
                                                fg += lightmap[1] * fscale;
                                                fb += lightmap[2] * fscale;
                                                if (surf->styles[3] != 255)
                                                {
-                                                       lightmap += p->lightmapstep;
-                                                       fscale = d_lightstylevalue[surf->styles[3]] * (1.0f / 256.0f);
+                                                       lightmap += lightmapstep;
+                                                       fscale = d_lightstylevalue[surf->styles[3]] * (1.0f / 32768.0f);
                                                        fr += lightmap[0] * fscale;
                                                        fg += lightmap[1] * fscale;
                                                        fb += lightmap[2] * fscale;
@@ -398,89 +196,140 @@ void GL_DrawDecals (void)
                                        }
                                }
                        }
-                       /*
-                       for (j = 0;j < MAXLIGHTMAPS && surf->styles[j] != 255;j++)
-                       {
-                               fscale = d_lightstylevalue[surf->styles[j]] * (1.0f / 256.0f);
-                               fr += lightmap[0] * fscale;
-                               fg += lightmap[1] * fscale;
-                               fb += lightmap[2] * fscale;
-                               lightmap += p->lightmapstep;
-                       }
-                       */
-               }
-#endif
-               /*
-               {
-                       int ir, ig, ib;
-                       byte br, bg, bb, ba;
-                       // apply color to lighting
-                       ir = (int) (fr * p->color[0] * (1.0f / 128.0f));
-                       ig = (int) (fg * p->color[1] * (1.0f / 128.0f));
-                       ib = (int) (fb * p->color[2] * (1.0f / 128.0f));
-                       // compute byte color
-                       br = (byte) min(ir, 255);
-                       bg = (byte) min(ig, 255);
-                       bb = (byte) min(ib, 255);
-                       ba = p->color[3];
-                       // put into transpoly system for sorted drawing later
-                       transpolybegin(R_GetTexture(p->tex), 0, R_GetTexture(p->tex), TPOLYTYPE_ALPHA);
-                       transpolyvertub(p->vert[0][0], p->vert[0][1], p->vert[0][2], 0,1,br,bg,bb,ba);
-                       transpolyvertub(p->vert[1][0], p->vert[1][1], p->vert[1][2], 0,0,br,bg,bb,ba);
-                       transpolyvertub(p->vert[2][0], p->vert[2][1], p->vert[2][2], 1,0,br,bg,bb,ba);
-                       transpolyvertub(p->vert[3][0], p->vert[3][1], p->vert[3][2], 1,1,br,bg,bb,ba);
-                       transpolyend();
                }
-               */
-               if (r_render.value)
+
+               if (surf->dlightframe == r_framecount)
                {
-                       j = R_GetTexture(p->tex);
-                       if (texnum != j)
-                       {
-                               glEnd();
-                               texnum = j;
-                               glBindTexture(GL_TEXTURE_2D, texnum);
-                               glBegin(GL_QUADS);
-                       }
-                       /*
-                       if (lighthalf)
-                               glColor4f(fr * p->color[0] * (1.0f / 255.0f / 256.0f), fg * p->color[1] * (1.0f / 255.0f / 256.0f), fb * p->color[2] * (1.0f / 255.0f / 256.0f), p->color[3] * (1.0f / 255.0f));
-                       else
-                               glColor4f(fr * p->color[0] * (1.0f / 255.0f / 128.0f), fg * p->color[1] * (1.0f / 255.0f / 128.0f), fb * p->color[2] * (1.0f / 255.0f / 128.0f), p->color[3] * (1.0f / 255.0f));
-                       */
-                       if (lighthalf)
-                       {
-                               cr = (ir * p->color[0]) >> 16;
-                               cg = (ig * p->color[1]) >> 16;
-                               cb = (ib * p->color[2]) >> 16;
-                       }
-                       else
+                       for (j = 0;j < r_numdlights;j++)
                        {
-                               cr = (ir * p->color[0]) >> 15;
-                               cg = (ig * p->color[1]) >> 15;
-                               cb = (ib * p->color[2]) >> 15;
+                               if (surf->dlightbits[j >> 5] & (1 << (j & 31)))
+                               {
+                                       rd = &r_dlight[j];
+                                       VectorSubtract(r->org, rd->origin, v);
+                                       dist = DotProduct(v, v) + LIGHTOFFSET;
+                                       if (dist < rd->cullradius2)
+                                       {
+                                               f = (1.0f / dist) - rd->lightsubtract;
+                                               if (f > 0)
+                                               {
+                                                       fr += f * rd->light[0];
+                                                       fg += f * rd->light[1];
+                                                       fb += f * rd->light[2];
+                                               }
+                                       }
+                               }
                        }
-                       cr = min(cr, 255);
-                       cg = min(cg, 255);
-                       cb = min(cb, 255);
-                       glColor4ub(cr, cg, cb, p->color[3]);
-
-                       glTexCoord2f(p->texcoord[0][0], p->texcoord[0][1]);
-                       glVertex3fv(p->vert[0]);
-                       glTexCoord2f(p->texcoord[1][0], p->texcoord[1][1]);
-                       glVertex3fv(p->vert[1]);
-                       glTexCoord2f(p->texcoord[2][0], p->texcoord[2][1]);
-                       glVertex3fv(p->vert[2]);
-                       glTexCoord2f(p->texcoord[3][0], p->texcoord[3][1]);
-                       glVertex3fv(p->vert[3]);
                }
+
+               // if the surface is transparent, render as transparent
+               m.transparent = !(surf->flags & SURF_CLIPSOLID);
+               m.cr = r->color[0] * fr;
+               m.cg = r->color[1] * fg;
+               m.cb = r->color[2] * fb;
+               m.ca = r->color[3];
+
+               if (fogenabled)
+               {
+                       m.cr *= ifog;
+                       m.cg *= ifog;
+                       m.cb *= ifog;
+               }
+
+               R_Mesh_Draw(&m);
        }
 
-       if (r_render.value)
+       if (!fogenabled)
+               return;
+
+       m.blendfunc2 = GL_ONE;
+       m.cr = fogcolor[0];
+       m.cg = fogcolor[1];
+       m.cb = fogcolor[2];
+
+       for (i = 0, r = r_refdef.decals;i < r_refdef.numdecals;i++, r++)
        {
-               glEnd();
+               if (r->ent)
+               {
+                       if (r->ent->visframe != r_framecount)
+                               continue;
+
+                       Mod_CheckLoaded(r->ent->model);
+
+                       surf = r->ent->model->surfaces + r->surface;
+
+                       // skip decals on surfaces that aren't visible in this frame
+                       if (surf->visframe != r_framecount)
+                               continue;
+
+                       softwaretransformforentity(r->ent);
+                       softwaretransform(r->org, org);
+                       softwaretransformdirection(r->dir, dir);
 
-               glDepthMask(1); // enable zbuffer updates
-               glDisable(GL_ALPHA_TEST);
+                       // do not render if the view origin is behind the decal
+                       VectorSubtract(org, r_origin, v);
+                       if (DotProduct(dir, v) < 0)
+                               continue;
+               }
+               else
+               {
+                       surf = cl.worldmodel->surfaces + r->surface;
+
+                       // skip decals on surfaces that aren't visible in this frame
+                       if (surf->visframe != r_framecount)
+                               continue;
+
+                       // do not render if the view origin is behind the decal
+                       VectorSubtract(r->org, r_origin, v);
+                       if (DotProduct(r->dir, v) < 0)
+                               continue;
+
+                       VectorCopy(r->org, org);
+                       VectorCopy(r->dir, dir);
+               }
+
+               dist = -PlaneDiff(r->org, surf->plane);
+               VectorMA(r->org, dist, surf->plane->normal, impact);
+
+               ds = (int) (DotProduct(impact, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]) - surf->texturemins[0];
+               dt = (int) (DotProduct(impact, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3]) - surf->texturemins[1];
+
+               if (ds < 0 || dt < 0 || ds > surf->extents[0] || dt > surf->extents[1])
+               {
+                       // this should never happen
+                       continue;
+               }
+
+               tex = &particletexture[r->tex][1];
+               VectorVectors(dir, right, up);
+               VectorScale(right, r->scale, right);
+               VectorScale(up, r->scale, up);
+               tvertex[0][0] = org[0] - right[0] - up[0];
+               tvertex[0][1] = org[1] - right[1] - up[1];
+               tvertex[0][2] = org[2] - right[2] - up[2];
+               tvertex[0][3] = tex->s1;
+               tvertex[0][4] = tex->t1;
+               tvertex[1][0] = org[0] - right[0] + up[0];
+               tvertex[1][1] = org[1] - right[1] + up[1];
+               tvertex[1][2] = org[2] - right[2] + up[2];
+               tvertex[1][3] = tex->s1;
+               tvertex[1][4] = tex->t2;
+               tvertex[2][0] = org[0] + right[0] + up[0];
+               tvertex[2][1] = org[1] + right[1] + up[1];
+               tvertex[2][2] = org[2] + right[2] + up[2];
+               tvertex[2][3] = tex->s2;
+               tvertex[2][4] = tex->t2;
+               tvertex[3][0] = org[0] + right[0] - up[0];
+               tvertex[3][1] = org[1] + right[1] - up[1];
+               tvertex[3][2] = org[2] + right[2] - up[2];
+               tvertex[3][3] = tex->s2;
+               tvertex[3][4] = tex->t1;
+
+               // if the surface is transparent, render as transparent
+               m.transparent = !(surf->flags & SURF_CLIPSOLID);
+               m.ca = r->color[3] * exp(fogdensity/DotProduct(v,v));
+
+               if (m.ca >= (1.0f / 255.0f))
+                       R_Mesh_Draw(&m);
        }
 }
+
index 8061b6062acd65b3fd929b014be899a695be6def..1a2470f6ebcfe1487f758cec1b8ef8899e17b600 100644 (file)
@@ -21,11 +21,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #include "quakedef.h"
 
 #define MAX_EXPLOSIONS 64
-#define EXPLOSIONGRID 16
+#define EXPLOSIONGRID 8
 #define EXPLOSIONVERTS ((EXPLOSIONGRID+1)*(EXPLOSIONGRID+1))
-#define EXPLOSIONTRIS (EXPLOSIONVERTS*2)
+#define EXPLOSIONTRIS (EXPLOSIONGRID*EXPLOSIONGRID*2)
 #define EXPLOSIONSTARTRADIUS (20.0f)
 #define EXPLOSIONSTARTVELOCITY (256.0f)
+#define EXPLOSIONRANDOMVELOCITY (64.0f)
 #define EXPLOSIONFADESTART (1.5f)
 #define EXPLOSIONFADERATE (4.5f)
 /*
@@ -68,30 +69,16 @@ explosion_t explosion[MAX_EXPLOSIONS];
 rtexture_t     *explosiontexture;
 rtexture_t     *explosiontexturefog;
 
+rtexturepool_t *explosiontexturepool;
+
 cvar_t r_explosionclip = {CVAR_SAVE, "r_explosionclip", "1"};
 cvar_t r_drawexplosions = {0, "r_drawexplosions", "1"};
 
-int R_ExplosionVert(int column, int row)
-{
-       int i;
-       float a, b, c;
-       i = row * (EXPLOSIONGRID + 1) + column;
-       a = row * M_PI * 2 / EXPLOSIONGRID;
-       b = column * M_PI * 2 / EXPLOSIONGRID;
-       c = cos(b);
-       explosionpoint[i][0] = cos(a) * c;
-       explosionpoint[i][1] = sin(a) * c;
-       explosionpoint[i][2] = -sin(b);
-       explosionnoiseindex[i] = (row & (EXPLOSIONGRID - 1)) * EXPLOSIONGRID + (column & (EXPLOSIONGRID - 1));
-       explosiontexcoords[i][0] = (float) column / (float) EXPLOSIONGRID;
-       explosiontexcoords[i][1] = (float) row / (float) EXPLOSIONGRID;
-       return i;
-}
-
 void r_explosion_start(void)
 {
        int x, y;
        byte noise1[128][128], noise2[128][128], noise3[128][128], data[128][128][4];
+       explosiontexturepool = R_AllocTexturePool();
        fractalnoise(&noise1[0][0], 128, 32);
        fractalnoise(&noise2[0][0], 128, 4);
        fractalnoise(&noise3[0][0], 128, 4);
@@ -111,15 +98,17 @@ void r_explosion_start(void)
                        data[y][x][3] = bound(0, a, 255);
                }
        }
-       explosiontexture = R_LoadTexture ("explosiontexture", 128, 128, &data[0][0][0], TEXF_MIPMAP | TEXF_ALPHA | TEXF_RGBA | TEXF_PRECACHE);
+       explosiontexture = R_LoadTexture (explosiontexturepool, "explosiontexture", 128, 128, &data[0][0][0], TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE);
        for (y = 0;y < 128;y++)
                for (x = 0;x < 128;x++)
                        data[y][x][0] = data[y][x][1] = data[y][x][2] = 255;
-       explosiontexturefog = R_LoadTexture ("explosiontexturefog", 128, 128, &data[0][0][0], TEXF_MIPMAP | TEXF_ALPHA | TEXF_RGBA | TEXF_PRECACHE);
+       explosiontexturefog = R_LoadTexture (explosiontexturepool, "explosiontexturefog", 128, 128, &data[0][0][0], TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE);
+       // note that explosions survive the restart
 }
 
 void r_explosion_shutdown(void)
 {
+       R_FreeTexturePool(&explosiontexturepool);
 }
 
 void r_explosion_newmap(void)
@@ -128,6 +117,23 @@ void r_explosion_newmap(void)
 //     memset(explosiongas, 0, sizeof(explosiongas));
 }
 
+int R_ExplosionVert(int column, int row)
+{
+       int i;
+       float a, b, c;
+       i = row * (EXPLOSIONGRID + 1) + column;
+       a = row * M_PI * 2 / EXPLOSIONGRID;
+       b = column * M_PI * 2 / EXPLOSIONGRID;
+       c = cos(b);
+       explosionpoint[i][0] = cos(a) * c;
+       explosionpoint[i][1] = sin(a) * c;
+       explosionpoint[i][2] = -sin(b);
+       explosionnoiseindex[i] = (row % EXPLOSIONGRID) * EXPLOSIONGRID + (column % EXPLOSIONGRID);
+       explosiontexcoords[i][0] = (float) column / (float) EXPLOSIONGRID;
+       explosiontexcoords[i][1] = (float) row / (float) EXPLOSIONGRID;
+       return i;
+}
+
 void R_Explosion_Init(void)
 {
        int i, x, y;
@@ -165,9 +171,12 @@ void R_Explosion_Init(void)
 void R_NewExplosion(vec3_t org)
 {
        int i, j;
-       float dist, v[3];
-       byte noise[EXPLOSIONGRID*EXPLOSIONGRID];
-       fractalnoise(noise, EXPLOSIONGRID, 4);
+       float dist, v[3], normal[3];
+       byte noise[4][EXPLOSIONGRID*EXPLOSIONGRID];
+       fractalnoise(noise[0], EXPLOSIONGRID, 4);
+       fractalnoise(noise[1], EXPLOSIONGRID, 2);
+       fractalnoise(noise[2], EXPLOSIONGRID, 2);
+       fractalnoise(noise[3], EXPLOSIONGRID, 2);
        for (i = 0;i < MAX_EXPLOSIONS;i++)
        {
                if (explosion[i].alpha <= 0.0f)
@@ -175,10 +184,13 @@ void R_NewExplosion(vec3_t org)
                        explosion[i].alpha = EXPLOSIONFADESTART;
                        for (j = 0;j < EXPLOSIONVERTS;j++)
                        {
-                               dist = noise[explosionnoiseindex[j]] * (1.0f / 256.0f) + 0.5;
+                               dist = noise[3][explosionnoiseindex[j]] * (1.0f / 256.0f) + 0.5;
                                VectorMA(org, dist, explosionspherevert[j], v);
-                               TraceLine(org, v, explosion[i].vert[j], NULL, 0);
-                               VectorScale(explosionspherevertvel[j], dist, explosion[i].vertvel[j]);
+                               TraceLine(org, v, explosion[i].vert[j], normal, 0);
+                               VectorAdd(explosion[i].vert[j], normal, explosion[i].vert[j]);
+                               explosion[i].vertvel[j][0] = explosionspherevertvel[j][0] * dist + (((float) noise[0][explosionnoiseindex[j]] - 128.0f) * (EXPLOSIONRANDOMVELOCITY / 128.0f));
+                               explosion[i].vertvel[j][1] = explosionspherevertvel[j][1] * dist + (((float) noise[1][explosionnoiseindex[j]] - 128.0f) * (EXPLOSIONRANDOMVELOCITY / 128.0f));
+                               explosion[i].vertvel[j][2] = explosionspherevertvel[j][2] * dist + (((float) noise[2][explosionnoiseindex[j]] - 128.0f) * (EXPLOSIONRANDOMVELOCITY / 128.0f));
                        }
                        break;
                }
@@ -208,44 +220,72 @@ void R_NewExplosion(vec3_t org)
 
 void R_DrawExplosion(explosion_t *e)
 {
-       int i, index, *indexlist = &explosiontris[0][0], alpha = bound(0, e->alpha * 128.0f, 128), texnum, fogtexnum;
-       float s, t;
-//     s = cl.time * 1;
-//     t = cl.time * 0.75;
-//     s -= (int) s;
-//     t -= (int) t;
-       s = 0;
-       t = 0;
-       /*
-       glColor4f(1,1,1,e->alpha);
-       glDisable(GL_TEXTURE_2D);
-//     glBindTexture(GL_TEXTURE_2D, explosiontexture);
-       glVertexPointer(3, GL_FLOAT, sizeof(float[3]), (float *) &e->vert[0][0]);
-//     glTexCoordPointer(2, GL_FLOAT, sizeof(float[2]), (float *) &explosiontexcoords[0][0]);
-       glEnableClientState(GL_VERTEX_ARRAY);
-//     glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-       glDrawElements(GL_TRIANGLES, EXPLOSIONTRIS, GL_UNSIGNED_INT, indexlist);
-//     glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-       glDisableClientState(GL_VERTEX_ARRAY);
-       glEnable(GL_TEXTURE_2D);
-       */
-       texnum = R_GetTexture(explosiontexture);
-       fogtexnum = R_GetTexture(explosiontexturefog);
-       for (i = 0;i < EXPLOSIONTRIS;i++)
+       int i;
+       float c[EXPLOSIONVERTS][4], diff[3], fog, ifog, alpha;
+       rmeshinfo_t m;
+       memset(&m, 0, sizeof(m));
+       m.transparent = true;
+       m.blendfunc1 = GL_SRC_ALPHA;
+       m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
+       m.numtriangles = EXPLOSIONTRIS;
+       m.index = &explosiontris[0][0];
+       m.numverts = EXPLOSIONVERTS;
+       m.vertex = &e->vert[0][0];
+       m.vertexstep = sizeof(float[3]);
+       alpha = e->alpha;
+       if (alpha > 1)
+               alpha = 1;
+       m.cr = 1;
+       m.cg = 1;
+       m.cb = 1;
+       m.ca = alpha;
+       if (fogenabled)
        {
-               transpolybegin(texnum, 0, fogtexnum, TPOLYTYPE_ALPHA);
-               index = *indexlist++;transpolyvert(e->vert[index][0], e->vert[index][1], e->vert[index][2], explosiontexcoords[index][0] + s, explosiontexcoords[index][1] + t, 255, 255, 255, alpha);
-               index = *indexlist++;transpolyvert(e->vert[index][0], e->vert[index][1], e->vert[index][2], explosiontexcoords[index][0] + s, explosiontexcoords[index][1] + t, 255, 255, 255, alpha);
-               index = *indexlist++;transpolyvert(e->vert[index][0], e->vert[index][1], e->vert[index][2], explosiontexcoords[index][0] + s, explosiontexcoords[index][1] + t, 255, 255, 255, alpha);
-               transpolyend();
+               m.color = &c[0][0];
+               m.colorstep = sizeof(float[4]);
+               for (i = 0;i < EXPLOSIONVERTS;i++)
+               {
+                       // use inverse fog alpha as color
+                       VectorSubtract(e->vert[i], r_origin, diff);
+                       ifog = 1 - exp(fogdensity/DotProduct(diff,diff));
+                       if (ifog < 0)
+                               ifog = 0;
+                       c[i][0] = ifog;
+                       c[i][1] = ifog;
+                       c[i][2] = ifog;
+                       c[i][3] = alpha;
+               }
+       }
+       m.tex[0] = R_GetTexture(explosiontexture);
+       m.texcoords[0] = &explosiontexcoords[0][0];
+       m.texcoordstep[0] = sizeof(float[2]);
+
+       R_Mesh_Draw(&m);
+
+       if (fogenabled)
+       {
+               m.blendfunc1 = GL_SRC_ALPHA;
+               m.blendfunc2 = GL_ONE;
+               for (i = 0;i < EXPLOSIONVERTS;i++)
+               {
+                       VectorSubtract(e->vert[i], r_origin, diff);
+                       fog = exp(fogdensity/DotProduct(diff,diff));
+                       c[i][0] = fogcolor[0];
+                       c[i][1] = fogcolor[1];
+                       c[i][2] = fogcolor[2];
+                       c[i][3] = alpha * fog;
+               }
+               //m.color = &c[0][0];
+               //m.colorstep = sizeof(float[4]);
+               m.tex[0] = R_GetTexture(explosiontexturefog);
+               R_Mesh_Draw(&m);
        }
 }
 
 void R_MoveExplosion(explosion_t *e, /*explosiongas_t **list, explosiongas_t **listend, */float frametime)
 {
        int i;
-       vec3_t end;
-       vec_t frictionscale;
+       float f, dot, frictionscale, end[3], impact[3], normal[3];
        /*
        vec3_t diff;
        vec_t dist;
@@ -261,19 +301,17 @@ void R_MoveExplosion(explosion_t *e, /*explosiongas_t **list, explosiongas_t **l
                        end[0] = e->vert[i][0] + frametime * e->vertvel[i][0];
                        end[1] = e->vert[i][1] + frametime * e->vertvel[i][1];
                        end[2] = e->vert[i][2] + frametime * e->vertvel[i][2];
-                       if (r_explosionclip.value)
+                       if (r_explosionclip.integer)
                        {
-                               float f, dot;
-                               vec3_t impact, normal;
                                f = TraceLine(e->vert[i], end, impact, normal, 0);
                                VectorCopy(impact, e->vert[i]);
                                if (f < 1)
                                {
                                        // clip velocity against the wall
-                                       dot = DotProduct(e->vertvel[i], normal) * -1.125f;
-                                       e->vertvel[i][0] += normal[0] * dot;
-                                       e->vertvel[i][1] += normal[1] * dot;
-                                       e->vertvel[i][2] += normal[2] * dot;
+                                       dot = DotProduct(e->vertvel[i], normal) * 1.125f;
+                                       e->vertvel[i][0] -= normal[0] * dot;
+                                       e->vertvel[i][1] -= normal[1] * dot;
+                                       e->vertvel[i][2] -= normal[2] * dot;
                                }
                        }
                        else
@@ -311,7 +349,7 @@ void R_MoveExplosionGas(explosiongas_t *e, explosiongas_t **list, explosiongas_t
                end[0] = e->origin[0] + frametime * e->velocity[0];
                end[1] = e->origin[1] + frametime * e->velocity[1];
                end[2] = e->origin[2] + frametime * e->velocity[2];
-               if (r_explosionclip.value)
+               if (r_explosionclip.integer)
                {
                        float f, dot;
                        vec3_t impact, normal;
@@ -388,7 +426,7 @@ void R_MoveExplosions(void)
 void R_DrawExplosions(void)
 {
        int i;
-       if (!r_drawexplosions.value)
+       if (!r_drawexplosions.integer)
                return;
        for (i = 0;i < MAX_EXPLOSIONS;i++)
        {
index 7e44e373f3e3bd7f1d082ef6b88608548e4b93e8..5fb248f78cfe0797209f40997e82374c0e324e24 100644 (file)
@@ -6,21 +6,21 @@
 // LordHavoc: later note: made FRAMEBLENDINSERT macro
 void R_LerpAnimation(entity_render_t *r)
 {
-       int sub1, sub2, numframes, f, i, data;
+       int sub1, sub2, numframes, f, i;
        double sublerp, lerp, d;
-       animscene_t *scene, *scenes;
+       animscene_t *scene;
        frameblend_t *blend;
        blend = r->frameblend;
 
        numframes = r->model->numframes;
 
-       if ((r->frame1 >= numframes))
+       if (r->frame1 >= numframes)
        {
                Con_Printf ("CL_LerpAnimation: no such frame %d\n", r->frame1);
                r->frame1 = 0;
        }
 
-       if ((r->frame2 >= numframes))
+       if (r->frame2 >= numframes)
        {
                Con_Printf ("CL_LerpAnimation: no such frame %d\n", r->frame2);
                r->frame2 = 0;
@@ -36,23 +36,13 @@ void R_LerpAnimation(entity_render_t *r)
        if (r->framelerp >= (65535.0f / 65536.0f))
                r->framelerp = 1;
 
-       blend[0].frame = blend[1].frame = blend[2].frame = blend[3].frame = -1;
+       blend[0].frame = blend[1].frame = blend[2].frame = blend[3].frame = 0;
        blend[0].lerp = blend[1].lerp = blend[2].lerp = blend[3].lerp = 0;
-       if (r->model->ofs_scenes)
+       if (r->model->animscenes)
        {
-               if (r->model->cachesize)
-               {
-                       data = (int) Mod_Extradata(r->model);
-                       if (!data)
-                               Host_Error("CL_LerpAnimation: model not loaded\n");
-                       scenes = (animscene_t *) (r->model->ofs_scenes + data);
-               }
-               else
-                       scenes = (animscene_t *) r->model->ofs_scenes;
-
                if (r->framelerp < 1 && r->frame1 >= 0)
                {
-                       scene = scenes + r->frame1;
+                       scene = r->model->animscenes + r->frame1;
                        lerp = 1 - r->framelerp;
 
                        if (scene->framecount > 1)
@@ -67,14 +57,16 @@ void R_LerpAnimation(entity_render_t *r)
                                        sublerp = 1;
                                if (scene->loop)
                                {
-                                       sub1 = (sub1 % scene->framecount) + scene->firstframe;
-                                       sub2 = (sub2 % scene->framecount) + scene->firstframe;
+                                       sub1 = (sub1 % scene->framecount);
+                                       sub2 = (sub2 % scene->framecount);
                                }
                                else
                                {
-                                       sub1 = bound(0, sub1, (scene->framecount - 1)) + scene->firstframe;
-                                       sub2 = bound(0, sub2, (scene->framecount - 1)) + scene->firstframe;
+                                       sub1 = bound(0, sub1, (scene->framecount - 1));
+                                       sub2 = bound(0, sub2, (scene->framecount - 1));
                                }
+                               sub1 += scene->firstframe;
+                               sub2 += scene->firstframe;
                                f = sub1;
                                d = (1 - sublerp) * lerp;
 #define FRAMEBLENDINSERT\
@@ -108,7 +100,7 @@ void R_LerpAnimation(entity_render_t *r)
                }
                if (r->framelerp > 0 && r->frame2 >= 0)
                {
-                       scene = scenes + r->frame2;
+                       scene = r->model->animscenes + r->frame2;
                        lerp = r->framelerp;
 
                        if (scene->framecount > 1)
@@ -123,14 +115,16 @@ void R_LerpAnimation(entity_render_t *r)
                                        sublerp = 1;
                                if (scene->loop)
                                {
-                                       sub1 = (sub1 % scene->framecount) + scene->firstframe;
-                                       sub2 = (sub2 % scene->framecount) + scene->firstframe;
+                                       sub1 = (sub1 % scene->framecount);
+                                       sub2 = (sub2 % scene->framecount);
                                }
                                else
                                {
-                                       sub1 = bound(0, sub1, (scene->framecount - 1)) + scene->firstframe;
-                                       sub2 = bound(0, sub2, (scene->framecount - 1)) + scene->firstframe;
+                                       sub1 = bound(0, sub1, (scene->framecount - 1));
+                                       sub2 = bound(0, sub2, (scene->framecount - 1));
                                }
+                               sub1 += scene->firstframe;
+                               sub2 += scene->firstframe;
                                f = sub1;
                                d = (1 - sublerp) * lerp;
                                FRAMEBLENDINSERT
@@ -161,5 +155,6 @@ void R_LerpAnimation(entity_render_t *r)
                        FRAMEBLENDINSERT
                }
        }
+       //Con_Printf("Lerp: %i:%f %i:%f %i:%f %i:%f\n", blend[0].frame, blend[0].lerp, blend[1].frame, blend[1].lerp, blend[2].frame, blend[2].lerp, blend[3].frame, blend[3].lerp);
 }
 
index db05fdea5b56a4a8909aff607ab5cde408b8bf79..340fa75b2729ad41ef0c342482d6c02568a4b8b4 100644 (file)
--- a/r_light.c
+++ b/r_light.c
@@ -21,7 +21,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 #include "quakedef.h"
 
-cvar_t r_lightmodels = {0, "r_lightmodels", "1"};
+rdlight_t r_dlight[MAX_DLIGHTS];
+int r_numdlights = 0;
+
+cvar_t r_lightmodels = {CVAR_SAVE, "r_lightmodels", "1"};
+cvar_t r_vismarklights = {0, "r_vismarklights", "1"};
+cvar_t r_lightmodelhardness = {CVAR_SAVE, "r_lightmodelhardness", "0.9"};
 
 void r_light_start(void)
 {
@@ -38,6 +43,8 @@ void r_light_newmap(void)
 void R_Light_Init(void)
 {
        Cvar_RegisterVariable(&r_lightmodels);
+       Cvar_RegisterVariable(&r_lightmodelhardness);
+       Cvar_RegisterVariable(&r_vismarklights);
        R_RegisterModule("R_Light", r_light_start, r_light_shutdown, r_light_newmap);
 }
 
@@ -48,13 +55,13 @@ R_AnimateLight
 */
 void R_AnimateLight (void)
 {
-       int                     i,j,k;
+       int i, j, k;
 
 //
 // light animations
 // 'm' is normal light, 'a' is no light, 'z' is double bright
-       i = (int)(cl.time*10);
-       for (j=0 ; j<MAX_LIGHTSTYLES ; j++)
+       i = (int)(cl.time * 10);
+       for (j = 0;j < MAX_LIGHTSTYLES;j++)
        {
                if (!cl_lightstyle[j].length)
                {
@@ -65,7 +72,40 @@ void R_AnimateLight (void)
                k = cl_lightstyle[j].map[k] - 'a';
                k = k*22;
                d_lightstylevalue[j] = k;
-       }       
+       }
+}
+
+
+void R_BuildLightList(void)
+{
+       int                     i;
+       dlight_t        *cd;
+       rdlight_t       *rd;
+
+       r_numdlights = 0;
+       c_dlights = 0;
+
+       if (!r_dynamic.integer)
+               return;
+
+       for (i = 0;i < MAX_DLIGHTS;i++)
+       {
+               cd = cl_dlights + i;
+               if (cd->radius <= 0)
+                       continue;
+               rd = &r_dlight[r_numdlights++];
+               VectorCopy(cd->origin, rd->origin);
+               VectorScale(cd->color, cd->radius * 256.0f, rd->light);
+               rd->cullradius = (1.0f / 256.0f) * sqrt(DotProduct(rd->light, rd->light));
+               // clamp radius to avoid overflowing division table in lightmap code
+               if (rd->cullradius > 2048.0f)
+                       rd->cullradius = 2048.0f;
+               rd->cullradius2 = rd->cullradius * rd->cullradius;
+               rd->lightsubtract = 1.0f / rd->cullradius2;
+               rd->ent = cd->ent;
+               r_numdlights++;
+               c_dlights++; // count every dlight in use
+       }
 }
 
 /*
@@ -81,22 +121,18 @@ DYNAMIC LIGHTS
 R_MarkLights
 =============
 */
-void R_OldMarkLights (vec3_t lightorigin, dlight_t *light, int bit, int bitindex, mnode_t *node)
+static void R_OldMarkLights (vec3_t lightorigin, rdlight_t *rd, int bit, int bitindex, mnode_t *node)
 {
        float           ndist, maxdist;
        msurface_t      *surf;
        mleaf_t         *leaf;
        int                     i;
 
-       if (!r_dynamic.value)
+       if (!r_dynamic.integer)
                return;
 
        // for comparisons to minimum acceptable light
-       maxdist = light->radius * light->radius;
-
-       // clamp radius to avoid exceeding 32768 entry division table
-       if (maxdist > 4194304)
-               maxdist = 4194304;
+       maxdist = rd->cullradius2;
 
 loc0:
        if (node->contents < 0)
@@ -115,13 +151,13 @@ loc0:
        }
 
        ndist = PlaneDiff(lightorigin, node->plane);
-       
-       if (ndist > light->radius)
+
+       if (ndist > rd->cullradius)
        {
                node = node->children[0];
                goto loc0;
        }
-       if (ndist < -light->radius)
+       if (ndist < -rd->cullradius)
        {
                node = node->children[1];
                goto loc0;
@@ -146,9 +182,9 @@ loc0:
                if (dist2 >= maxdist)
                        continue;
 
-               impact[0] = light->origin[0] - surf->plane->normal[0] * dist;
-               impact[1] = light->origin[1] - surf->plane->normal[1] * dist;
-               impact[2] = light->origin[2] - surf->plane->normal[2] * dist;
+               impact[0] = rd->origin[0] - surf->plane->normal[0] * dist;
+               impact[1] = rd->origin[1] - surf->plane->normal[1] * dist;
+               impact[2] = rd->origin[2] - surf->plane->normal[2] * dist;
 
                impacts = DotProduct (impact, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3] - surf->texturemins[0];
 
@@ -229,7 +265,7 @@ loc0:
        {
                if (node->children[1]->contents >= 0)
                {
-                       R_OldMarkLights (lightorigin, light, bit, bitindex, node->children[0]);
+                       R_OldMarkLights (lightorigin, rd, bit, bitindex, node->children[0]);
                        node = node->children[1];
                        goto loc0;
                }
@@ -246,207 +282,203 @@ loc0:
        }
 }
 
-void R_NoVisMarkLights (vec3_t lightorigin, dlight_t *light, int bit, int bitindex, model_t *model)
+/*
+static void R_NoVisMarkLights (rdlight_t *rd, int bit, int bitindex)
 {
-       R_OldMarkLights(lightorigin, light, bit, bitindex, model->nodes + model->hulls[0].firstclipnode);
+       vec3_t lightorigin;
+       softwareuntransform(rd->origin, lightorigin);
+
+       R_OldMarkLights(lightorigin, rd, bit, bitindex, currentrenderentity->model->nodes + currentrenderentity->model->hulls[0].firstclipnode);
 }
+*/
 
-void R_VisMarkLights (vec3_t lightorigin, dlight_t *light, int bit, int bitindex, model_t *model)
+static void R_VisMarkLights (rdlight_t *rd, int bit, int bitindex)
 {
        static int lightframe = 0;
-       mleaf_t *pvsleaf = Mod_PointInLeaf (lightorigin, model);
+       mleaf_t *pvsleaf;
+       vec3_t lightorigin;
+       model_t *model;
+       int             i, k, m, c, leafnum;
+       msurface_t *surf, **mark;
+       mleaf_t *leaf;
+       byte    *in;
+       int             row;
+       float   low[3], high[3], dist, maxdist;
 
-       if (!r_dynamic.value)
+       if (!r_dynamic.integer)
                return;
 
-       if (!pvsleaf->compressed_vis)
-       {       // no vis info, so make all visible
-               R_OldMarkLights(lightorigin, light, bit, bitindex, model->nodes + model->hulls[0].firstclipnode);
+       model = currentrenderentity->model;
+       softwareuntransform(rd->origin, lightorigin);
+
+       if (!r_vismarklights.integer)
+       {
+               R_OldMarkLights(lightorigin, rd, bit, bitindex, model->nodes + model->hulls[0].firstclipnode);
                return;
        }
-       else
+
+       pvsleaf = Mod_PointInLeaf (lightorigin, model);
+       if (pvsleaf == NULL)
        {
-               int             i, k, m, c, leafnum;
-               msurface_t *surf, **mark;
-               mleaf_t *leaf;
-               byte    *in = pvsleaf->compressed_vis;
-               int             row = (model->numleafs+7)>>3;
-               float   low[3], high[3], radius, dist, maxdist;
+               Con_Printf("R_VisMarkLights: NULL leaf??\n");
+               R_OldMarkLights(lightorigin, rd, bit, bitindex, model->nodes + model->hulls[0].firstclipnode);
+               return;
+       }
 
-               lightframe++;
+       in = pvsleaf->compressed_vis;
+       if (!in)
+       {
+               // no vis info, so make all visible
+               R_OldMarkLights(lightorigin, rd, bit, bitindex, model->nodes + model->hulls[0].firstclipnode);
+               return;
+       }
 
-               radius = light->radius * 3;
+       lightframe++;
 
-               // clamp radius to avoid exceeding 32768 entry division table
-               if (radius > 2048)
-                       radius = 2048;
+       low[0] = lightorigin[0] - rd->cullradius;low[1] = lightorigin[1] - rd->cullradius;low[2] = lightorigin[2] - rd->cullradius;
+       high[0] = lightorigin[0] + rd->cullradius;high[1] = lightorigin[1] + rd->cullradius;high[2] = lightorigin[2] + rd->cullradius;
 
-               low[0] = lightorigin[0] - radius;low[1] = lightorigin[1] - radius;low[2] = lightorigin[2] - radius;
-               high[0] = lightorigin[0] + radius;high[1] = lightorigin[1] + radius;high[2] = lightorigin[2] + radius;
+       // for comparisons to minimum acceptable light
+       maxdist = rd->cullradius2;
 
-               // for comparisons to minimum acceptable light
-               maxdist = radius*radius;
+       row = (model->numleafs+7)>>3;
 
-               k = 0;
-               while (k < row)
+       k = 0;
+       while (k < row)
+       {
+               c = *in++;
+               if (c)
                {
-                       c = *in++;
-                       if (c)
+                       for (i = 0;i < 8;i++)
                        {
-                               for (i = 0;i < 8;i++)
+                               if (c & (1<<i))
                                {
-                                       if (c & (1<<i))
+                                       // warning to the clumsy: numleafs is one less than it should be, it only counts leafs with vis bits (skips leaf 0)
+                                       leafnum = (k << 3)+i+1;
+                                       if (leafnum > model->numleafs)
+                                               return;
+                                       leaf = &model->leafs[leafnum];
+                                       if (leaf->visframe != r_framecount
+                                        || leaf->contents == CONTENTS_SOLID
+                                        || leaf->mins[0] > high[0] || leaf->maxs[0] < low[0]
+                                        || leaf->mins[1] > high[1] || leaf->maxs[1] < low[1]
+                                        || leaf->mins[2] > high[2] || leaf->maxs[2] < low[2])
+                                               continue;
+                                       if (leaf->dlightframe != r_framecount)
                                        {
-                                               // warning to the clumsy: numleafs is one less than it should be, it only counts leafs with vis bits (skips leaf 0)
-                                               leafnum = (k << 3)+i+1;
-                                               if (leafnum > model->numleafs)
-                                                       return;
-                                               leaf = &model->leafs[leafnum];
-//                                             if (leaf->visframe != r_framecount)
-//                                                     continue;
-//                                             if (leaf->contents == CONTENTS_SOLID)
-//                                                     continue;
-                                               // if out of the light radius, skip
-                                               if (leaf->mins[0] > high[0] || leaf->maxs[0] < low[0]
-                                                || leaf->mins[1] > high[1] || leaf->maxs[1] < low[1]
-                                                || leaf->mins[2] > high[2] || leaf->maxs[2] < low[2])
-                                                       continue;
-                                               if (leaf->dlightframe != r_framecount) // not dynamic until now
-                                               {
-                                                       leaf->dlightbits[0] = leaf->dlightbits[1] = leaf->dlightbits[2] = leaf->dlightbits[3] = leaf->dlightbits[4] = leaf->dlightbits[5] = leaf->dlightbits[6] = leaf->dlightbits[7] = 0;
-                                                       leaf->dlightframe = r_framecount;
-                                               }
-                                               leaf->dlightbits[bitindex] |= bit;
-                                               if ((m = leaf->nummarksurfaces))
+                                               // not dynamic until now
+                                               leaf->dlightbits[0] = leaf->dlightbits[1] = leaf->dlightbits[2] = leaf->dlightbits[3] = leaf->dlightbits[4] = leaf->dlightbits[5] = leaf->dlightbits[6] = leaf->dlightbits[7] = 0;
+                                               leaf->dlightframe = r_framecount;
+                                       }
+                                       leaf->dlightbits[bitindex] |= bit;
+                                       if ((m = leaf->nummarksurfaces))
+                                       {
+                                               mark = leaf->firstmarksurface;
+                                               do
                                                {
-                                                       mark = leaf->firstmarksurface;
-                                                       do
+                                                       surf = *mark++;
+                                                       // if not visible in current frame, or already marked because it was in another leaf we passed, skip
+                                                       if (surf->lightframe == lightframe)
+                                                               continue;
+                                                       surf->lightframe = lightframe;
+                                                       if (surf->visframe != r_framecount)
+                                                               continue;
+                                                       dist = PlaneDiff(lightorigin, surf->plane);
+                                                       if (surf->flags & SURF_PLANEBACK)
+                                                               dist = -dist;
+                                                       // LordHavoc: make sure it is infront of the surface and not too far away
+                                                       if (dist < rd->cullradius && (dist > -0.25f || ((surf->flags & SURF_LIGHTBOTHSIDES) && dist > -rd->cullradius)))
                                                        {
-                                                               surf = *mark++;
-                                                               // if not visible in current frame, or already marked because it was in another leaf we passed, skip
-                                                               if (surf->lightframe == lightframe)
-                                                                       continue;
-                                                               surf->lightframe = lightframe;
-                                                               if (surf->visframe != r_framecount)
-                                                                       continue;
-                                                               dist = PlaneDiff(lightorigin, surf->plane);
-                                                               if (surf->flags & SURF_PLANEBACK)
-                                                                       dist = -dist;
-                                                               // LordHavoc: make sure it is infront of the surface and not too far away
-                                                               if (dist < radius && (dist > -0.25f || ((surf->flags & SURF_LIGHTBOTHSIDES) && dist > -radius)))
-                                                               {
-                                                                       int d, impacts, impactt;
-                                                                       float dist2, impact[3];
-
-                                                                       dist2 = dist * dist;
+                                                               int d;
+                                                               int impacts, impactt;
+                                                               float dist2, impact[3];
 
-                                                                       impact[0] = light->origin[0] - surf->plane->normal[0] * dist;
-                                                                       impact[1] = light->origin[1] - surf->plane->normal[1] * dist;
-                                                                       impact[2] = light->origin[2] - surf->plane->normal[2] * dist;
+                                                               dist2 = dist * dist;
 
-                                                                       impacts = DotProduct (impact, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3] - surf->texturemins[0];
+                                                               impact[0] = rd->origin[0] - surf->plane->normal[0] * dist;
+                                                               impact[1] = rd->origin[1] - surf->plane->normal[1] * dist;
+                                                               impact[2] = rd->origin[2] - surf->plane->normal[2] * dist;
 
-                                                                       d = bound(0, impacts, surf->extents[0] + 16) - impacts;
-                                                                       dist2 += d * d;
-                                                                       if (dist2 > maxdist)
-                                                                               continue;
-
-                                                                       impactt = DotProduct (impact, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3] - surf->texturemins[1];
-
-                                                                       d = bound(0, impactt, surf->extents[1] + 16) - impactt;
+#if 0
+                                                               d = DotProduct (impact, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3] - surf->texturemins[0];
+                                                               if (d < 0)
+                                                               {
                                                                        dist2 += d * d;
                                                                        if (dist2 > maxdist)
                                                                                continue;
-
-                                                                       /*
-                                                                       d = DotProduct (impact, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3] - surf->texturemins[0];
-
+                                                               }
+                                                               else
+                                                               {
+                                                                       d -= surf->extents[0];
                                                                        if (d < 0)
                                                                        {
                                                                                dist2 += d * d;
-                                                                               if (dist2 >= maxdist)
+                                                                               if (dist2 > maxdist)
                                                                                        continue;
                                                                        }
-                                                                       else
-                                                                       {
-                                                                               d -= surf->extents[0] + 16;
-                                                                               if (d > 0)
-                                                                               {
-                                                                                       dist2 += d * d;
-                                                                                       if (dist2 >= maxdist)
-                                                                                               continue;
-                                                                               }
-                                                                       }
-
-                                                                       d = DotProduct (impact, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3] - surf->texturemins[1];
+                                                               }
 
+                                                               d = DotProduct (impact, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3] - surf->texturemins[1];
+                                                               if (d < 0)
+                                                               {
+                                                                       dist2 += d * d;
+                                                                       if (dist2 > maxdist)
+                                                                               continue;
+                                                               }
+                                                               else
+                                                               {
+                                                                       d -= surf->extents[1];
                                                                        if (d < 0)
                                                                        {
                                                                                dist2 += d * d;
-                                                                               if (dist2 >= maxdist)
+                                                                               if (dist2 > maxdist)
                                                                                        continue;
                                                                        }
-                                                                       else
-                                                                       {
-                                                                               d -= surf->extents[1] + 16;
-                                                                               if (d > 0)
-                                                                               {
-                                                                                       dist2 += d * d;
-                                                                                       if (dist2 >= maxdist)
-                                                                                               continue;
-                                                                               }
-                                                                       }
-                                                                       */
+                                                               }
 
-                                                                       if (surf->dlightframe != r_framecount) // not dynamic until now
-                                                                       {
-                                                                               surf->dlightbits[0] = surf->dlightbits[1] = surf->dlightbits[2] = surf->dlightbits[3] = surf->dlightbits[4] = surf->dlightbits[5] = surf->dlightbits[6] = surf->dlightbits[7] = 0;
-                                                                               surf->dlightframe = r_framecount;
-                                                                       }
-                                                                       surf->dlightbits[bitindex] |= bit;
+#else
+
+                                                               impacts = DotProduct (impact, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3] - surf->texturemins[0];
+                                                               d = bound(0, impacts, surf->extents[0] + 16) - impacts;
+                                                               dist2 += d * d;
+                                                               if (dist2 > maxdist)
+                                                                       continue;
+
+                                                               impactt = DotProduct (impact, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3] - surf->texturemins[1];
+                                                               d = bound(0, impactt, surf->extents[1] + 16) - impactt;
+                                                               dist2 += d * d;
+                                                               if (dist2 > maxdist)
+                                                                       continue;
+
+#endif
+
+                                                               if (surf->dlightframe != r_framecount) // not dynamic until now
+                                                               {
+                                                                       surf->dlightbits[0] = surf->dlightbits[1] = surf->dlightbits[2] = surf->dlightbits[3] = surf->dlightbits[4] = surf->dlightbits[5] = surf->dlightbits[6] = surf->dlightbits[7] = 0;
+                                                                       surf->dlightframe = r_framecount;
                                                                }
+                                                               surf->dlightbits[bitindex] |= bit;
                                                        }
-                                                       while (--m);
                                                }
+                                               while (--m);
                                        }
                                }
-                               k++;
-                               continue;
                        }
-
-                       k += *in++;
+                       k++;
+                       continue;
                }
+
+               k += *in++;
        }
 }
 
-
-/*
-=============
-R_PushDlights
-=============
-*/
-void R_PushDlights (void)
+void R_MarkLights(void)
 {
-       int             i;
-       dlight_t        *l;
-
-       if (!r_dynamic.value)
-               return;
-
-       l = cl_dlights;
-
-       for (i=0 ; i<MAX_DLIGHTS ; i++, l++)
-       {
-               if (!l->radius)
-                       continue;
-//             R_MarkLights (l->origin, l, 1<<(i&31), i >> 5, cl.worldmodel->nodes );
-               R_VisMarkLights (l->origin, l, 1<<(i&31), i >> 5, cl.worldmodel);
-       }
-
-
+       int i;
+       for (i = 0;i < r_numdlights;i++)
+               R_VisMarkLights (r_dlight + i, 1 << (i & 31), i >> 5);
 }
 
-
 /*
 =============================================================================
 
@@ -455,134 +487,7 @@ LIGHT SAMPLING
 =============================================================================
 */
 
-mplane_t               *lightplane;
-vec3_t                 lightspot;
-
-/*
-int RecursiveLightPoint (vec3_t color, mnode_t *node, vec3_t start, vec3_t end)
-{
-       float           front, back, frac;
-       vec3_t          mid;
-
-loc0:
-       if (node->contents < 0)
-               return false;           // didn't hit anything
-       
-// calculate mid point
-       front = PlaneDiff (start, node->plane);
-       back = PlaneDiff (end, node->plane);
-
-       // LordHavoc: optimized recursion
-       if ((back < 0) == (front < 0))
-//             return RecursiveLightPoint (color, node->children[front < 0], start, end);
-       {
-               node = node->children[front < 0];
-               goto loc0;
-       }
-       
-       frac = front / (front-back);
-       mid[0] = start[0] + (end[0] - start[0])*frac;
-       mid[1] = start[1] + (end[1] - start[1])*frac;
-       mid[2] = start[2] + (end[2] - start[2])*frac;
-       
-// go down front side
-       if (RecursiveLightPoint (color, node->children[front < 0], start, mid))
-               return true;    // hit something
-       else
-       {
-               int i, ds, dt;
-               msurface_t *surf;
-       // check for impact on this node
-               VectorCopy (mid, lightspot);
-               lightplane = node->plane;
-
-               surf = cl.worldmodel->surfaces + node->firstsurface;
-               for (i = 0;i < node->numsurfaces;i++, surf++)
-               {
-                       if (surf->flags & SURF_DRAWTILED)
-                               continue;       // no lightmaps
-
-                       ds = (int) ((float) DotProduct (mid, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]);
-                       dt = (int) ((float) DotProduct (mid, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3]);
-
-                       if (ds < surf->texturemins[0] || dt < surf->texturemins[1])
-                               continue;
-                       
-                       ds -= surf->texturemins[0];
-                       dt -= surf->texturemins[1];
-                       
-                       if (ds > surf->extents[0] || dt > surf->extents[1])
-                               continue;
-
-                       if (surf->samples)
-                       {
-                               byte *lightmap;
-                               int maps, line3, dsfrac = ds & 15, dtfrac = dt & 15, r00 = 0, g00 = 0, b00 = 0, r01 = 0, g01 = 0, b01 = 0, r10 = 0, g10 = 0, b10 = 0, r11 = 0, g11 = 0, b11 = 0;
-                               float scale;
-                               line3 = ((surf->extents[0]>>4)+1)*3;
-
-                               lightmap = surf->samples + ((dt>>4) * ((surf->extents[0]>>4)+1) + (ds>>4))*3; // LordHavoc: *3 for color
-
-                               for (maps = 0;maps < MAXLIGHTMAPS && surf->styles[maps] != 255;maps++)
-                               {
-                                       scale = (float) d_lightstylevalue[surf->styles[maps]] * 1.0 / 256.0;
-                                       r00 += (float) lightmap[      0] * scale;g00 += (float) lightmap[      1] * scale;b00 += (float) lightmap[2] * scale;
-                                       r01 += (float) lightmap[      3] * scale;g01 += (float) lightmap[      4] * scale;b01 += (float) lightmap[5] * scale;
-                                       r10 += (float) lightmap[line3+0] * scale;g10 += (float) lightmap[line3+1] * scale;b10 += (float) lightmap[line3+2] * scale;
-                                       r11 += (float) lightmap[line3+3] * scale;g11 += (float) lightmap[line3+4] * scale;b11 += (float) lightmap[line3+5] * scale;
-                                       lightmap += ((surf->extents[0]>>4)+1) * ((surf->extents[1]>>4)+1)*3; // LordHavoc: *3 for colored lighting
-                               }
-
-                               color[0] += (float) ((int) ((((((((r11-r10) * dsfrac) >> 4) + r10)-((((r01-r00) * dsfrac) >> 4) + r00)) * dtfrac) >> 4) + ((((r01-r00) * dsfrac) >> 4) + r00)));
-                               color[1] += (float) ((int) ((((((((g11-g10) * dsfrac) >> 4) + g10)-((((g01-g00) * dsfrac) >> 4) + g00)) * dtfrac) >> 4) + ((((g01-g00) * dsfrac) >> 4) + g00)));
-                               color[2] += (float) ((int) ((((((((b11-b10) * dsfrac) >> 4) + b10)-((((b01-b00) * dsfrac) >> 4) + b00)) * dtfrac) >> 4) + ((((b01-b00) * dsfrac) >> 4) + b00)));
-                       }
-                       return true; // success
-               }
-
-       // go down back side
-               return RecursiveLightPoint (color, node->children[front >= 0], mid, end);
-       }
-}
-
-void R_LightPoint (vec3_t color, vec3_t p)
-{
-       vec3_t          end;
-       
-       if (r_fullbright.value || !cl.worldmodel->lightdata)
-       {
-               color[0] = color[1] = color[2] = 255;
-               return;
-       }
-
-       end[0] = p[0];
-       end[1] = p[1];
-       end[2] = p[2] - 2048;
-
-       color[0] = color[1] = color[2] = r_ambient.value * 2.0f;
-       RecursiveLightPoint (color, cl.worldmodel->nodes, p, end);
-}
-
-void SV_LightPoint (vec3_t color, vec3_t p)
-{
-       vec3_t          end;
-       
-       if (!sv.worldmodel->lightdata)
-       {
-               color[0] = color[1] = color[2] = 255;
-               return;
-       }
-       
-       end[0] = p[0];
-       end[1] = p[1];
-       end[2] = p[2] - 2048;
-
-       color[0] = color[1] = color[2] = 0;
-       RecursiveLightPoint (color, sv.worldmodel->nodes, p, end);
-}
-*/
-
-int RecursiveLightPoint (vec3_t color, mnode_t *node, float x, float y, float startz, float endz)
+static int RecursiveLightPoint (vec3_t color, mnode_t *node, float x, float y, float startz, float endz)
 {
        int             side, distz = endz - startz;
        float   front, back;
@@ -631,7 +536,7 @@ loc0:
                mid = startz + distz * (front - node->plane->dist) / (front - back);
                break;
        }
-       
+
        // go down front side
        if (node->children[side]->contents >= 0 && RecursiveLightPoint (color, node->children[side], x, y, startz, mid))
                return true;    // hit something
@@ -642,15 +547,11 @@ loc0:
                {
                        int i, ds, dt;
                        msurface_t *surf;
-                       lightspot[0] = x;
-                       lightspot[1] = y;
-                       lightspot[2] = mid;
-                       lightplane = node->plane;
 
                        surf = cl.worldmodel->surfaces + node->firstsurface;
                        for (i = 0;i < node->numsurfaces;i++, surf++)
                        {
-                               if (surf->flags & SURF_DRAWTILED)
+                               if (!(surf->flags & SURF_LIGHTMAP))
                                        continue;       // no lightmaps
 
                                ds = (int) (x * surf->texinfo->vecs[0][0] + y * surf->texinfo->vecs[0][1] + mid * surf->texinfo->vecs[0][2] + surf->texinfo->vecs[0][3]);
@@ -712,9 +613,9 @@ loc0:
                                        b = (((b1-b0) * dtfrac) >> 4) + b0;
                                        */
 
-                                       color[0] += (float) ((((((((r11-r10) * dsfrac) >> 4) + r10)-((((r01-r00) * dsfrac) >> 4) + r00)) * dtfrac) >> 4) + ((((r01-r00) * dsfrac) >> 4) + r00)) * (1.0f / 256.0f);
-                                       color[1] += (float) ((((((((g11-g10) * dsfrac) >> 4) + g10)-((((g01-g00) * dsfrac) >> 4) + g00)) * dtfrac) >> 4) + ((((g01-g00) * dsfrac) >> 4) + g00)) * (1.0f / 256.0f);
-                                       color[2] += (float) ((((((((b11-b10) * dsfrac) >> 4) + b10)-((((b01-b00) * dsfrac) >> 4) + b00)) * dtfrac) >> 4) + ((((b01-b00) * dsfrac) >> 4) + b00)) * (1.0f / 256.0f);
+                                       color[0] += (float) ((((((((r11-r10) * dsfrac) >> 4) + r10)-((((r01-r00) * dsfrac) >> 4) + r00)) * dtfrac) >> 4) + ((((r01-r00) * dsfrac) >> 4) + r00)) * (1.0f / 32768.0f);
+                                       color[1] += (float) ((((((((g11-g10) * dsfrac) >> 4) + g10)-((((g01-g00) * dsfrac) >> 4) + g00)) * dtfrac) >> 4) + ((((g01-g00) * dsfrac) >> 4) + g00)) * (1.0f / 32768.0f);
+                                       color[2] += (float) ((((((((b11-b10) * dsfrac) >> 4) + b10)-((((b01-b00) * dsfrac) >> 4) + b00)) * dtfrac) >> 4) + ((((b01-b00) * dsfrac) >> 4) + b00)) * (1.0f / 32768.0f);
                                }
                                return true; // success
                        }
@@ -729,43 +630,12 @@ loc0:
        }
 }
 
-void R_DynamicLightPoint(vec3_t color, vec3_t org, int *dlightbits)
-{
-       int             i, j, k;
-       vec3_t  dist;
-       float   brightness, r, f;
-
-       if (!r_dynamic.value || (!dlightbits[0] && !dlightbits[1] && !dlightbits[2] && !dlightbits[3] && !dlightbits[4] && !dlightbits[5] && !dlightbits[6] && !dlightbits[7]))
-               return;
-
-       for (j = 0;j < (MAX_DLIGHTS >> 5);j++)
-       {
-               if (dlightbits[j])
-               {
-                       for (i=0 ; i<32 ; i++)
-                       {
-                               if (!((1 << i) & dlightbits[j]))
-                                       continue;
-                               k = (j<<5)+i;
-                               if (!cl_dlights[k].radius)
-                                       continue;
-                               VectorSubtract (org, cl_dlights[k].origin, dist);
-                               f = DotProduct(dist, dist) + LIGHTOFFSET;
-                               r = cl_dlights[k].radius*cl_dlights[k].radius;
-                               if (f < r)
-                               {
-                                       brightness = r * 128.0f / f;
-                                       color[0] += brightness * cl_dlights[k].color[0];
-                                       color[1] += brightness * cl_dlights[k].color[1];
-                                       color[2] += brightness * cl_dlights[k].color[2];
-                               }
-                       }
-               }
-       }
-}
-
 void R_CompleteLightPoint (vec3_t color, vec3_t p, int dynamic, mleaf_t *leaf)
 {
+       int      i, *dlightbits;
+       vec3_t dist;
+       float f;
+       rdlight_t *rd;
        if (leaf == NULL)
                leaf = Mod_PointInLeaf(p, cl.worldmodel);
 
@@ -775,17 +645,33 @@ void R_CompleteLightPoint (vec3_t color, vec3_t p, int dynamic, mleaf_t *leaf)
                return;
        }
 
-       if (r_fullbright.value || !cl.worldmodel->lightdata)
+       if (r_fullbright.integer || !cl.worldmodel->lightdata)
        {
-               color[0] = color[1] = color[2] = 255;
+               color[0] = color[1] = color[2] = 2;
                return;
        }
-       
-       color[0] = color[1] = color[2] = r_ambient.value * 2.0f;
+
+       color[0] = color[1] = color[2] = r_ambient.value * (2.0f / 128.0f);
        RecursiveLightPoint (color, cl.worldmodel->nodes, p[0], p[1], p[2], p[2] - 65536);
 
-       if (dynamic)
-               R_DynamicLightPoint(color, p, leaf->dlightbits);
+       if (dynamic && leaf->dlightframe == r_framecount)
+       {
+               dlightbits = leaf->dlightbits;
+               for (i = 0;i < r_numdlights;i++)
+               {
+                       if (!(dlightbits[i >> 5] & (1 << (i & 31))))
+                               continue;
+                       rd = r_dlight + i;
+                       VectorSubtract (p, rd->origin, dist);
+                       f = DotProduct(dist, dist) + LIGHTOFFSET;
+                       if (f < rd->cullradius2)
+                       {
+                               f = (1.0f / f) - rd->lightsubtract;
+                               if (f > 0)
+                                       VectorMA(color, f, rd->light, color);
+                       }
+               }
+       }
 }
 
 void R_ModelLightPoint (vec3_t color, vec3_t p, int *dlightbits)
@@ -799,14 +685,14 @@ void R_ModelLightPoint (vec3_t color, vec3_t p, int *dlightbits)
                return;
        }
 
-       if (r_fullbright.value || !cl.worldmodel->lightdata)
+       if (r_fullbright.integer || !cl.worldmodel->lightdata)
        {
-               color[0] = color[1] = color[2] = 255;
+               color[0] = color[1] = color[2] = 2;
                dlightbits[0] = dlightbits[1] = dlightbits[2] = dlightbits[3] = dlightbits[4] = dlightbits[5] = dlightbits[6] = dlightbits[7] = 0;
                return;
        }
 
-       color[0] = color[1] = color[2] = r_ambient.value * 2.0f;
+       color[0] = color[1] = color[2] = r_ambient.value * (2.0f / 128.0f);
        RecursiveLightPoint (color, cl.worldmodel->nodes, p[0], p[1], p[2], p[2] - 65536);
 
        if (leaf->dlightframe == r_framecount)
@@ -824,195 +710,99 @@ void R_ModelLightPoint (vec3_t color, vec3_t p, int *dlightbits)
                dlightbits[0] = dlightbits[1] = dlightbits[2] = dlightbits[3] = dlightbits[4] = dlightbits[5] = dlightbits[6] = dlightbits[7] = 0;
 }
 
-/* // not currently used
-void R_DynamicLightPointNoMask(vec3_t color, vec3_t org)
-{
-       int             i;
-       vec3_t  dist;
-       float   brightness, r, f;
-
-       if (!r_dynamic.value)
-               return;
-
-       for (i=0 ; i<MAX_DLIGHTS ; i++)
-       {
-               if (!cl_dlights[i].radius)
-                       continue;
-               VectorSubtract (org, cl_dlights[i].origin, dist);
-               f = DotProduct(dist, dist) + LIGHTOFFSET;
-               r = cl_dlights[i].radius*cl_dlights[i].radius;
-               if (f < r)
-               {
-                       brightness = r * 256.0f / f;
-                       if (cl_dlights[i].dark)
-                               brightness = -brightness;
-                       color[0] += brightness * cl_dlights[i].color[0];
-                       color[1] += brightness * cl_dlights[i].color[1];
-                       color[2] += brightness * cl_dlights[i].color[2];
-               }
-       }
-}
-*/
-
 void R_LightModel(int numverts)
 {
-       // LordHavoc: warning: reliance on int being 4 bytes here (of course the d_8to24table relies on that too...)
-       int i, j, nearlights = 0, color;
-       vec3_t dist, mod, basecolor, center;
-       float t, t1, t2, t3, *avn, number;
-       byte r,g,b,a, *avc;
+       int i, j, nearlights = 0;
+       float color[3], basecolor[3], v[3], t, *av, *avn, *avc, a, number, f, hardness, hardnessoffset, dist2;
        struct
        {
-               vec3_t color;
                vec3_t origin;
-       } nearlight[MAX_DLIGHTS];
-       int modeldlightbits[8];
-       avc = aliasvertcolor;
-       avn = aliasvertnorm;
-       VectorCopy(currentrenderentity->origin, center);
-       a = (byte) bound((int) 0, (int) (currentrenderentity->alpha * 255.0f), (int) 255);
-       if (lighthalf)
-       {
-               mod[0] = currentrenderentity->colormod[0] * 0.5f;
-               mod[1] = currentrenderentity->colormod[1] * 0.5f;
-               mod[2] = currentrenderentity->colormod[2] * 0.5f;
-       }
-       else
-       {
-               mod[0] = currentrenderentity->colormod[0];
-               mod[1] = currentrenderentity->colormod[1];
-               mod[2] = currentrenderentity->colormod[2];
+               vec_t cullradius2;
+               vec3_t light;
+               vec_t lightsubtract;
        }
+       nearlight[MAX_DLIGHTS], *nl;
+       int modeldlightbits[8];
+       a = currentrenderentity->alpha;
        if (currentrenderentity->effects & EF_FULLBRIGHT)
+               basecolor[0] = basecolor[1] = basecolor[2] = 1;
+       else
        {
-               if (a == 255)
-                       memset(avc, 0, 4 * numverts);
-               else
+               if (r_lightmodels.integer)
                {
-                       ((byte *)&color)[0] = (byte) (255.0f * mod[0]);
-                       ((byte *)&color)[1] = (byte) (255.0f * mod[1]);
-                       ((byte *)&color)[2] = (byte) (255.0f * mod[2]);
-                       ((byte *)&color)[3] = a;
-                       for (i = 0;i < numverts;i++)
-                       {
-                               *((int *)avc) = color;
-                               avc += 4;
-                       }
-               }
-               return;
-       }
-       R_ModelLightPoint(basecolor, center, modeldlightbits);
+                       R_ModelLightPoint(basecolor, currentrenderentity->origin, modeldlightbits);
 
-       basecolor[0] *= mod[0];
-       basecolor[1] *= mod[1];
-       basecolor[2] *= mod[2];
-       for (i = 0;i < MAX_DLIGHTS;i++)
-       {
-               if (!modeldlightbits[i >> 5])
-               {
-                       i |= 31;
-                       continue;
-               }
-               if (!(modeldlightbits[i >> 5] & (1 << (i & 31))))
-                       continue;
-               VectorSubtract (center, cl_dlights[i].origin, dist);
-               t2 = DotProduct(dist,dist) + LIGHTOFFSET;
-               t1 = cl_dlights[i].radius*cl_dlights[i].radius;
-               if (t2 < t1)
-               {
-                       if (TraceLine(center, cl_dlights[i].origin, NULL, NULL, 0))
+                       nl = &nearlight[0];
+                       for (i = 0;i < r_numdlights;i++)
                        {
-                               // transform the light into the model's coordinate system
-                               if (gl_transform.value)
-                                       softwareuntransform(cl_dlights[i].origin, nearlight[nearlights].origin);
-                               else
-                                       VectorCopy(cl_dlights[i].origin, nearlight[nearlights].origin);
-                               nearlight[nearlights].color[0] = cl_dlights[i].color[0] * t1 * mod[0];
-                               nearlight[nearlights].color[1] = cl_dlights[i].color[1] * t1 * mod[1];
-                               nearlight[nearlights].color[2] = cl_dlights[i].color[2] * t1 * mod[2];
-                               if (r_lightmodels.value && currentrenderentity != cl_dlights[i].ent)
+                               if (!(modeldlightbits[i >> 5] & (1 << (i & 31))))
+                                       continue;
+                               if (currentrenderentity == r_dlight[i].ent)
                                {
-                                       // boost color, to compensate for dark lighting calcs
-                                       VectorScale(nearlight[nearlights].color, cl_dlights[i].radius * 16.0f, nearlight[nearlights].color);
-                                       nearlights++;
+                                       f = (1.0f / LIGHTOFFSET) - nl->lightsubtract;
+                                       if (f > 0)
+                                               VectorMA(basecolor, f, r_dlight[i].light, basecolor);
                                }
                                else
                                {
-#if SLOWMATH
-                                       t1 = 1.0f / sqrt(t2);
-#else
-                                       number = t1;
-                                       *((long *)&t1) = 0x5f3759df - ((* (long *) &number) >> 1);
-                                       t1 = t1 * (1.5f - (number * 0.5f * t1 * t1));
-#endif
-                                       t1 = t1 * t1;
-                                       basecolor[0] += nearlight[nearlights].color[0] * t1;
-                                       basecolor[1] += nearlight[nearlights].color[1] * t1;
-                                       basecolor[2] += nearlight[nearlights].color[2] * t1;
+                                       // convert 0-255 radius coloring to 0-1, while also amplifying the brightness by 16
+                                       //if (TraceLine(currentrenderentity->origin, r_dlight[i].origin, NULL, NULL, 0) == 1)
+                                       {
+                                               // transform the light into the model's coordinate system
+                                               //if (gl_transform.integer)
+                                               //      softwareuntransform(r_dlight[i].origin, nl->origin);
+                                               //else
+                                                       VectorCopy(r_dlight[i].origin, nl->origin);
+                                               nl->cullradius2 = r_dlight[i].cullradius2;
+                                               VectorCopy(r_dlight[i].light, nl->light);
+                                               nl->lightsubtract = r_dlight[i].lightsubtract;
+                                               nl++;
+                                               nearlights++;
+                                       }
                                }
                        }
                }
+               else
+                       R_CompleteLightPoint (basecolor, currentrenderentity->origin, true, NULL);
        }
-       t1 = bound(0, basecolor[0], 255);r = (byte) t1;
-       t1 = bound(0, basecolor[1], 255);g = (byte) t1;
-       t1 = bound(0, basecolor[2], 255);b = (byte) t1;
-       ((byte *)&color)[0] = r;
-       ((byte *)&color)[1] = g;
-       ((byte *)&color)[2] = b;
-       ((byte *)&color)[3] = a;
+       avc = aliasvertcolor;
        if (nearlights)
        {
-               int i1, i2, i3;
-               vec3_t v;
-               float *av, number;
                av = aliasvert;
+               avn = aliasvertnorm;
+               hardness = r_lightmodelhardness.value;
+               hardnessoffset = (1.0f - hardness);
                for (i = 0;i < numverts;i++)
                {
-                       t1 = basecolor[0];
-                       t2 = basecolor[1];
-                       t3 = basecolor[2];
-                       for (j = 0;j < nearlights;j++)
+                       VectorCopy(basecolor, color);
+                       for (j = 0, nl = &nearlight[0];j < nearlights;j++, nl++)
                        {
-                               VectorSubtract(nearlight[j].origin, av, v);
-                               t = DotProduct(avn,v);
-                               if (t > 0)
+                               // distance attenuation
+                               VectorSubtract(nl->origin, av, v);
+                               dist2 = DotProduct(v,v);
+                               if (dist2 < nl->cullradius2)
                                {
-#if SLOWMATH
-                                       t = 1.0f / sqrt(DotProduct(v,v) + 1.0f);
-#else
-                                       number = DotProduct(v, v) + LIGHTOFFSET;
-                                       *((long *)&t) = 0x5f3759df - ((* (long *) &number) >> 1);
-                                       t = t * (1.5f - (number * 0.5f * t * t));
-#endif
-                                       t = t * t * t;
-                                       t1 += nearlight[j].color[0] * t;
-                                       t2 += nearlight[j].color[1] * t;
-                                       t3 += nearlight[j].color[2] * t;
+                                       f = (1.0f / (dist2 + LIGHTOFFSET)) - nl->lightsubtract;
+                                       if (f > 0)
+                                       {
+                                               // directional shading
+                                               #if SLOWMATH
+                                               t = 1.0f / sqrt(dist2);
+                                               #else
+                                               number = DotProduct(v, v);
+                                               *((long *)&t) = 0x5f3759df - ((* (long *) &number) >> 1);
+                                               t = t * (1.5f - (number * 0.5f * t * t));
+                                               #endif
+                                               // DotProduct(avn,v) * t is dotproduct with a normalized v,
+                                               // the hardness variables are for backlighting/shinyness
+                                               f *= DotProduct(avn,v) * t * hardness + hardnessoffset;
+                                               if (f > 0)
+                                                       VectorMA(color, f, nl->light, color);
+                                       }
                                }
                        }
 
-                       // FIXME: float to int conversions are very slow on x86 because of
-                       // mode switchs (switch from nearest rounding to down, then back,
-                       // each time), reimplement this part in assembly, SSE and 3DNow!
-                       // versions recommended as well
-#if SLOWMATH
-                       i1 = (int) t1;
-                       i2 = (int) t2;
-                       i3 = (int) t3;
-#else
-                       // later note: implemented bit hacking float to integer,
-                       // probably makes the issue irrelevant
-                       t1 += 8388608.0f;
-                       i1 = *((long *)&t1) & 0x007FFFFF;
-                       t2 += 8388608.0f;
-                       i2 = *((long *)&t2) & 0x007FFFFF;
-                       t3 += 8388608.0f;
-                       i3 = *((long *)&t3) & 0x007FFFFF;
-#endif
-
-                       avc[0] = bound(0, i1, 255);
-                       avc[1] = bound(0, i2, 255);
-                       avc[2] = bound(0, i3, 255);
+                       VectorCopy(color, avc);
                        avc[3] = a;
                        avc += 4;
                        av += 3;
@@ -1023,7 +813,8 @@ void R_LightModel(int numverts)
        {
                for (i = 0;i < numverts;i++)
                {
-                       *((int *)avc) = color;
+                       VectorCopy(basecolor, avc);
+                       avc[3] = a;
                        avc += 4;
                }
        }
index 0507c425eb9cb8859a538cdccb0fda334a97dc1f..e8fb4e8a6a49ae26d43ed2bd5e5ade0697e37f5c 100644 (file)
--- a/r_light.h
+++ b/r_light.h
@@ -1,7 +1,20 @@
 
-extern void R_CompleteLightPoint (vec3_t color, vec3_t p, int dynamic, mleaf_t *leaf);
-extern void R_DynamicLightPoint(vec3_t color, vec3_t org, int *dlightbits);
-extern void R_DynamicLightPointNoMask(vec3_t color, vec3_t org);
-extern void R_LightPoint (vec3_t color, vec3_t p);
-extern void R_AnimateLight (void);
-extern void R_LightModel (int numverts);
+typedef struct
+{
+       vec3_t origin;
+       vec_t cullradius2; // only for culling comparisons, squared version
+       vec3_t light; // the brightness of the light
+       vec_t cullradius; // only for culling comparisons
+       vec_t lightsubtract; // to avoid sudden brightness change at cullradius, subtract this
+       entity_render_t *ent; // owner of this light
+}
+rdlight_t;
+
+extern int r_numdlights;
+extern rdlight_t r_dlight[MAX_DLIGHTS];
+
+void R_BuildLightList(void);
+void R_AnimateLight (void);
+void R_MarkLights(void);
+void R_CompleteLightPoint (vec3_t color, vec3_t p, int dynamic, mleaf_t *leaf);
+void R_LightModel (int numverts);
index 969519a6f00c5cae30d6368f7ab0b093bff1c759..f9ce9508d018376c41d89b0c4a1d741e7252dcfc 100644 (file)
@@ -18,6 +18,7 @@ rendermodule_t rendermodule[MAXRENDERMODULES];
 void R_Modules_Init(void)
 {
        int i;
+       Cmd_AddCommand("r_restart", R_Modules_Restart);
        for (i = 0;i < MAXRENDERMODULES;i++)
                rendermodule[i].name = NULL;
 }
@@ -58,7 +59,8 @@ void R_Modules_Start(void)
 void R_Modules_Shutdown(void)
 {
        int i;
-       for (i = 0;i < MAXRENDERMODULES;i++)
+       // shutdown in reverse
+       for (i = MAXRENDERMODULES - 1;i >= 0;i--)
        {
                if (rendermodule[i].name == NULL)
                        continue;
@@ -71,6 +73,7 @@ void R_Modules_Shutdown(void)
 
 void R_Modules_Restart(void)
 {
+       Con_Printf("restarting renderer\n");
        R_Modules_Shutdown();
        R_Modules_Start();
 }
diff --git a/r_part.c b/r_part.c
deleted file mode 100644 (file)
index 6bb2dfb..0000000
--- a/r_part.c
+++ /dev/null
@@ -1,1478 +0,0 @@
-/*
-Copyright (C) 1996-1997 Id Software, Inc.
-
-This program is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License
-as published by the Free Software Foundation; either version 2
-of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
-See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-
-*/
-
-#include "quakedef.h"
-
-#define MAX_PARTICLES                  16384   // default max # of particles at one time
-#define ABSOLUTE_MIN_PARTICLES 512             // no fewer than this no matter what's on the command line
-
-typedef enum
-{
-       pt_static, pt_grav, pt_blob, pt_blob2, pt_bulletsmoke, pt_smoke, pt_snow, pt_rain, pt_spark, pt_bubble, pt_fade, pt_steam, pt_splash, pt_splashpuff, pt_flame, pt_blood, pt_oneframe, pt_lavasplash, pt_raindropsplash, pt_underwaterspark, pt_explosionsplash
-}
-ptype_t;
-
-typedef struct
-{
-       float s1, t1, s2, t2;
-}
-particletexture_t;
-
-typedef struct particle_s
-{
-       ptype_t         type;
-       vec3_t          org;
-       vec3_t          vel;
-       particletexture_t       *tex;
-       float           die;
-       float           scale;
-       float           alpha; // 0-255
-       float           time2; // used for various things (snow fluttering, for example)
-       float           bounce; // how much bounce-back from a surface the particle hits (0 = no physics, 1 = stop and slide, 2 = keep bouncing forever, 1.5 is typical)
-       vec3_t          oldorg;
-       vec3_t          vel2; // used for snow fluttering (base velocity, wind for instance)
-       float           friction; // how much air friction affects this object (objects with a low mass/size ratio tend to get more air friction)
-       float           pressure; // if non-zero, apply pressure to other particles
-       int                     dynlight; // if set the particle will be dynamically lit (if r_dynamicparticles is on), used for smoke and blood
-       int                     rendermode; // a TPOLYTYPE_ value
-       byte            color[4];
-}
-particle_t;
-
-static int particlepalette[256] =
-{
-       0x000000,0x0f0f0f,0x1f1f1f,0x2f2f2f,0x3f3f3f,0x4b4b4b,0x5b5b5b,0x6b6b6b,
-       0x7b7b7b,0x8b8b8b,0x9b9b9b,0xababab,0xbbbbbb,0xcbcbcb,0xdbdbdb,0xebebeb,
-       0x0f0b07,0x170f0b,0x1f170b,0x271b0f,0x2f2313,0x372b17,0x3f2f17,0x4b371b,
-       0x533b1b,0x5b431f,0x634b1f,0x6b531f,0x73571f,0x7b5f23,0x836723,0x8f6f23,
-       0x0b0b0f,0x13131b,0x1b1b27,0x272733,0x2f2f3f,0x37374b,0x3f3f57,0x474767,
-       0x4f4f73,0x5b5b7f,0x63638b,0x6b6b97,0x7373a3,0x7b7baf,0x8383bb,0x8b8bcb,
-       0x000000,0x070700,0x0b0b00,0x131300,0x1b1b00,0x232300,0x2b2b07,0x2f2f07,
-       0x373707,0x3f3f07,0x474707,0x4b4b0b,0x53530b,0x5b5b0b,0x63630b,0x6b6b0f,
-       0x070000,0x0f0000,0x170000,0x1f0000,0x270000,0x2f0000,0x370000,0x3f0000,
-       0x470000,0x4f0000,0x570000,0x5f0000,0x670000,0x6f0000,0x770000,0x7f0000,
-       0x131300,0x1b1b00,0x232300,0x2f2b00,0x372f00,0x433700,0x4b3b07,0x574307,
-       0x5f4707,0x6b4b0b,0x77530f,0x835713,0x8b5b13,0x975f1b,0xa3631f,0xaf6723,
-       0x231307,0x2f170b,0x3b1f0f,0x4b2313,0x572b17,0x632f1f,0x733723,0x7f3b2b,
-       0x8f4333,0x9f4f33,0xaf632f,0xbf772f,0xcf8f2b,0xdfab27,0xefcb1f,0xfff31b,
-       0x0b0700,0x1b1300,0x2b230f,0x372b13,0x47331b,0x533723,0x633f2b,0x6f4733,
-       0x7f533f,0x8b5f47,0x9b6b53,0xa77b5f,0xb7876b,0xc3937b,0xd3a38b,0xe3b397,
-       0xab8ba3,0x9f7f97,0x937387,0x8b677b,0x7f5b6f,0x775363,0x6b4b57,0x5f3f4b,
-       0x573743,0x4b2f37,0x43272f,0x371f23,0x2b171b,0x231313,0x170b0b,0x0f0707,
-       0xbb739f,0xaf6b8f,0xa35f83,0x975777,0x8b4f6b,0x7f4b5f,0x734353,0x6b3b4b,
-       0x5f333f,0x532b37,0x47232b,0x3b1f23,0x2f171b,0x231313,0x170b0b,0x0f0707,
-       0xdbc3bb,0xcbb3a7,0xbfa39b,0xaf978b,0xa3877b,0x977b6f,0x876f5f,0x7b6353,
-       0x6b5747,0x5f4b3b,0x533f33,0x433327,0x372b1f,0x271f17,0x1b130f,0x0f0b07,
-       0x6f837b,0x677b6f,0x5f7367,0x576b5f,0x4f6357,0x475b4f,0x3f5347,0x374b3f,
-       0x2f4337,0x2b3b2f,0x233327,0x1f2b1f,0x172317,0x0f1b13,0x0b130b,0x070b07,
-       0xfff31b,0xefdf17,0xdbcb13,0xcbb70f,0xbba70f,0xab970b,0x9b8307,0x8b7307,
-       0x7b6307,0x6b5300,0x5b4700,0x4b3700,0x3b2b00,0x2b1f00,0x1b0f00,0x0b0700,
-       0x0000ff,0x0b0bef,0x1313df,0x1b1bcf,0x2323bf,0x2b2baf,0x2f2f9f,0x2f2f8f,
-       0x2f2f7f,0x2f2f6f,0x2f2f5f,0x2b2b4f,0x23233f,0x1b1b2f,0x13131f,0x0b0b0f,
-       0x2b0000,0x3b0000,0x4b0700,0x5f0700,0x6f0f00,0x7f1707,0x931f07,0xa3270b,
-       0xb7330f,0xc34b1b,0xcf632b,0xdb7f3b,0xe3974f,0xe7ab5f,0xefbf77,0xf7d38b,
-       0xa77b3b,0xb79b37,0xc7c337,0xe7e357,0x7fbfff,0xabe7ff,0xd7ffff,0x670000,
-       0x8b0000,0xb30000,0xd70000,0xff0000,0xfff393,0xfff7c7,0xffffff,0x9f5b53
-};
-
-static int explosparkramp[8] = {0x4b0700, 0x6f0f00, 0x931f07, 0xb7330f, 0xcf632b, 0xe3974f, 0xffe7b5, 0xffffff};
-//static int explounderwatersparkramp[8] = {0x00074b, 0x000f6f, 0x071f93, 0x0f33b7, 0x2b63cf, 0x4f97e3, 0xb5e7ff, 0xffffff};
-
-static rtexture_t *particlefonttexture;
-
-static particletexture_t particletexture;
-static particletexture_t smokeparticletexture[8];
-static particletexture_t rainparticletexture;
-static particletexture_t bubbleparticletexture;
-static particletexture_t bulletholetexture[8];
-static particletexture_t rocketglowparticletexture;
-static particletexture_t raindropsplashparticletexture[16];
-
-static particle_t      *particles;
-static int                     r_numparticles;
-
-static int                     numparticles;
-static particle_t      **freeparticles; // list used only in compacting particles array
-
-static cvar_t r_particles = {CVAR_SAVE, "r_particles", "1"};
-static cvar_t r_drawparticles = {0, "r_drawparticles", "1"};
-static cvar_t r_particles_lighting = {CVAR_SAVE, "r_particles_lighting", "1"};
-static cvar_t r_particles_bloodshowers = {CVAR_SAVE, "r_particles_bloodshowers", "1"};
-static cvar_t r_particles_blood = {CVAR_SAVE, "r_particles_blood", "1"};
-static cvar_t r_particles_smoke = {CVAR_SAVE, "r_particles_smoke", "1"};
-static cvar_t r_particles_sparks = {CVAR_SAVE, "r_particles_sparks", "1"};
-static cvar_t r_particles_bubbles = {CVAR_SAVE, "r_particles_bubbles", "1"};
-static cvar_t r_particles_explosions = {CVAR_SAVE, "r_particles_explosions", "0"};
-
-static byte shadebubble(float dx, float dy, vec3_t light)
-{
-       float   dz, f, dot;
-       vec3_t  normal;
-       dz = 1 - (dx*dx+dy*dy);
-       if (dz > 0) // it does hit the sphere
-       {
-               f = 0;
-               // back side
-               normal[0] = dx;normal[1] = dy;normal[2] = dz;
-               VectorNormalize(normal);
-               dot = DotProduct(normal, light);
-               if (dot > 0.5) // interior reflection
-                       f += ((dot *  2) - 1);
-               else if (dot < -0.5) // exterior reflection
-                       f += ((dot * -2) - 1);
-               // front side
-               normal[0] = dx;normal[1] = dy;normal[2] = -dz;
-               VectorNormalize(normal);
-               dot = DotProduct(normal, light);
-               if (dot > 0.5) // interior reflection
-                       f += ((dot *  2) - 1);
-               else if (dot < -0.5) // exterior reflection
-                       f += ((dot * -2) - 1);
-               f *= 128;
-               f += 16; // just to give it a haze so you can see the outline
-               f = bound(0, f, 255);
-               return (byte) f;
-       }
-       else
-               return 0;
-}
-
-static void R_InitParticleTexture (void)
-{
-       int             x,y,d,i,m, texnum;
-       float   dx, dy, radius, f, f2;
-       byte    data[32][32][4], noise1[64][64], noise2[64][64];
-       vec3_t  light;
-       byte    particletexturedata[256][256][4];
-
-       memset(&particletexturedata[0][0][0], 255, sizeof(particletexturedata));
-       texnum = 0;
-       #define SETUPTEX(var)\
-       {\
-               int basex, basey, y;\
-               if (texnum >= 64)\
-               {\
-                       Sys_Error("R_InitParticleTexture: ran out of textures (64)\n");\
-                       return; /* only to hush compiler */ \
-               }\
-               basex = (texnum & 7) * 32;\
-               basey = ((texnum >> 3) & 7) * 32;\
-               var.s1 = (basex + 1) / 256.0f;\
-               var.t1 = (basey + 1) / 256.0f;\
-               var.s2 = (basex + 31) / 256.0f;\
-               var.t2 = (basey + 31) / 256.0f;\
-               for (y = 0;y < 32;y++)\
-                       memcpy(&particletexturedata[basey + y][basex][0], &data[y][0][0], 32*4);\
-               texnum++;\
-       }
-
-       for (y = 0;y < 32;y++)
-       {
-               dy = y - 16;
-               for (x = 0;x < 32;x++)
-               {
-                       data[y][x][0] = data[y][x][1] = data[y][x][2] = 255;
-                       dx = x - 16;
-                       d = (256 - (dx*dx+dy*dy));
-                       d = bound(0, d, 255);
-                       data[y][x][3] = (byte) d;
-               }
-       }
-       SETUPTEX(particletexture)
-//     particletexture = R_LoadTexture ("particletexture", 32, 32, &data[0][0][0], TEXF_MIPMAP | TEXF_ALPHA | TEXF_RGBA | TEXF_PRECACHE);
-
-       for (i = 0;i < 8;i++)
-       {
-               do
-               {
-                       fractalnoise(&noise1[0][0], 64, 4);
-                       fractalnoise(&noise2[0][0], 64, 8);
-                       m = 0;
-                       for (y = 0;y < 32;y++)
-                       {
-                               dy = y - 16;
-                               for (x = 0;x < 32;x++)
-                               {
-                                       d = (noise1[y][x] - 128) * 2 + 64; // was + 128
-                                       d = bound(0, d, 255);
-                                       data[y][x][0] = data[y][x][1] = data[y][x][2] = d;
-                                       dx = x - 16;
-                                       d = (noise2[y][x] - 128) * 3 + 192;
-                                       if (d > 0)
-                                               d = (d * (256 - (int) (dx*dx+dy*dy))) >> 8;
-                                       d = bound(0, d, 255);
-                                       data[y][x][3] = (byte) d;
-                                       if (m < d)
-                                               m = d;
-                               }
-                       }
-               }
-               while (m < 224);
-
-               SETUPTEX(smokeparticletexture[i])
-//             smokeparticletexture[i] = R_LoadTexture (va("smokeparticletexture%02d", i), 32, 32, &data[0][0][0], TEXF_MIPMAP | TEXF_ALPHA | TEXF_RGBA | TEXF_PRECACHE);
-       }
-
-       light[0] = 1;light[1] = 1;light[2] = 1;
-       VectorNormalize(light);
-       for (y = 0;y < 32;y++)
-       {
-               for (x = 0;x < 32;x++)
-               {
-                       data[y][x][0] = data[y][x][1] = data[y][x][2] = 255;
-                       data[y][x][3] = shadebubble((x - 16) * (1.0 / 8.0), y < 24 ? (y - 24) * (1.0 / 24.0) : (y - 24) * (1.0 / 8.0), light);
-               }
-       }
-       SETUPTEX(rainparticletexture)
-//     rainparticletexture = R_LoadTexture ("rainparticletexture", 32, 32, &data[0][0][0], TEXF_MIPMAP | TEXF_ALPHA | TEXF_RGBA | TEXF_PRECACHE);
-
-       light[0] = 1;light[1] = 1;light[2] = 1;
-       VectorNormalize(light);
-       for (y = 0;y < 32;y++)
-       {
-               for (x = 0;x < 32;x++)
-               {
-                       data[y][x][0] = data[y][x][1] = data[y][x][2] = 255;
-                       data[y][x][3] = shadebubble((x - 16) * (1.0 / 16.0), (y - 16) * (1.0 / 16.0), light);
-               }
-       }
-       SETUPTEX(bubbleparticletexture)
-//     bubbleparticletexture = R_LoadTexture ("bubbleparticletexture", 32, 32, &data[0][0][0], TEXF_MIPMAP | TEXF_ALPHA | TEXF_RGBA | TEXF_PRECACHE);
-
-       for (i = 0;i < 8;i++)
-       {
-               float p[32][32];
-               fractalnoise(&noise1[0][0], 64, 8);
-               for (y = 0;y < 32;y++)
-                       for (x = 0;x < 32;x++)
-                               p[y][x] = (noise1[y][x] / 8.0f) - 64.0f;
-               for (m = 0;m < 32;m++)
-               {
-                       int j;
-                       float fx, fy, f;
-                       fx = lhrandom(14, 18);
-                       fy = lhrandom(14, 18);
-                       do
-                       {
-                               dx = lhrandom(-1, 1);
-                               dy = lhrandom(-1, 1);
-                               f = (dx * dx + dy * dy);
-                       }
-                       while(f < 0.125f || f > 1.0f);
-                       f = (m + 1) / 40.0f; //lhrandom(0.0f, 1.0);
-                       dx *= 1.0f / 32.0f;
-                       dy *= 1.0f / 32.0f;
-                       for (j = 0;f > 0 && j < (32 * 14);j++)
-                       {
-                               y = fy;
-                               x = fx;
-                               fx += dx;
-                               fy += dy;
-                               p[y - 1][x - 1] += f * 0.125f;
-                               p[y - 1][x    ] += f * 0.25f;
-                               p[y - 1][x + 1] += f * 0.125f;
-                               p[y    ][x - 1] += f * 0.25f;
-                               p[y    ][x    ] += f;
-                               p[y    ][x + 1] += f * 0.25f;
-                               p[y + 1][x - 1] += f * 0.125f;
-                               p[y + 1][x    ] += f * 0.25f;
-                               p[y + 1][x + 1] += f * 0.125f;
-//                             f -= (0.5f / (32 * 16));
-                       }
-               }
-               for (y = 0;y < 32;y++)
-               {
-                       for (x = 0;x < 32;x++)
-                       {
-                               m = p[y][x];
-                               data[y][x][0] = data[y][x][1] = data[y][x][2] = 255;
-                               data[y][x][3] = (byte) bound(0, m, 255);
-                       }
-               }
-
-               SETUPTEX(bulletholetexture[i])
-//             bulletholetexture[i] = R_LoadTexture (va("bulletholetexture%02d", i), 32, 32, &data[0][0][0], TEXF_MIPMAP | TEXF_ALPHA | TEXF_RGBA | TEXF_PRECACHE);
-       }
-
-       for (y = 0;y < 32;y++)
-       {
-               dy = y - 16;
-               for (x = 0;x < 32;x++)
-               {
-                       dx = x - 16;
-                       d = (2048.0f / (dx*dx+dy*dy+1)) - 8.0f;
-                       data[y][x][0] = bound(0, d * 1.0f, 255);
-                       data[y][x][1] = bound(0, d * 0.8f, 255);
-                       data[y][x][2] = bound(0, d * 0.5f, 255);
-                       data[y][x][3] = bound(0, d * 1.0f, 255);
-               }
-       }
-       SETUPTEX(rocketglowparticletexture)
-//     rocketglowparticletexture = R_LoadTexture ("glowparticletexture", 32, 32, &data[0][0][0], TEXF_MIPMAP | TEXF_ALPHA | TEXF_RGBA | TEXF_PRECACHE);
-
-       for (i = 0;i < 16;i++)
-       {
-               radius = i * 3.0f / 16.0f;
-               f2 = 255.0f * ((15.0f - i) / 15.0f);
-               for (y = 0;y < 32;y++)
-               {
-                       dy = (y - 16) * 0.25f;
-                       for (x = 0;x < 32;x++)
-                       {
-                               dx = (x - 16) * 0.25f;
-                               data[y][x][0] = data[y][x][1] = data[y][x][2] = 255;
-                               f = (1.0 - fabs(radius - sqrt(dx*dx+dy*dy))) * f2;
-                               f = bound(0.0f, f, 255.0f);
-                               data[y][x][3] = (int) f;
-                       }
-               }
-               SETUPTEX(raindropsplashparticletexture[i])
-//             raindropsplashparticletexture[i] = R_LoadTexture (va("raindropslashparticletexture%02d", i), 32, 32, &data[0][0][0], TEXF_MIPMAP | TEXF_ALPHA | TEXF_RGBA | TEXF_PRECACHE);
-       }
-
-       particlefonttexture = R_LoadTexture ("particlefont", 256, 256, &particletexturedata[0][0][0], TEXF_ALPHA | TEXF_RGBA | TEXF_PRECACHE);
-}
-
-static void r_part_start(void)
-{
-       particles = (particle_t *) qmalloc(r_numparticles * sizeof(particle_t));
-       freeparticles = (void *) qmalloc(r_numparticles * sizeof(particle_t *));
-       numparticles = 0;
-       R_InitParticleTexture ();
-}
-
-static void r_part_shutdown(void)
-{
-       numparticles = 0;
-       qfree(particles);
-       qfree(freeparticles);
-}
-
-static void r_part_newmap(void)
-{
-       numparticles = 0;
-}
-
-/*
-===============
-R_InitParticles
-===============
-*/
-void R_ReadPointFile_f (void);
-void R_Particles_Init (void)
-{
-       int             i;
-
-       i = COM_CheckParm ("-particles");
-
-       if (i)
-       {
-               r_numparticles = (int)(atoi(com_argv[i+1]));
-               if (r_numparticles < ABSOLUTE_MIN_PARTICLES)
-                       r_numparticles = ABSOLUTE_MIN_PARTICLES;
-       }
-       else
-       {
-               r_numparticles = MAX_PARTICLES;
-       }
-
-       Cmd_AddCommand ("pointfile", R_ReadPointFile_f);
-
-       Cvar_RegisterVariable (&r_particles);
-       Cvar_RegisterVariable (&r_drawparticles);
-       Cvar_RegisterVariable (&r_particles_lighting);
-       Cvar_RegisterVariable (&r_particles_bloodshowers);
-       Cvar_RegisterVariable (&r_particles_blood);
-       Cvar_RegisterVariable (&r_particles_smoke);
-       Cvar_RegisterVariable (&r_particles_sparks);
-       Cvar_RegisterVariable (&r_particles_bubbles);
-       Cvar_RegisterVariable (&r_particles_explosions);
-
-       R_RegisterModule("R_Particles", r_part_start, r_part_shutdown, r_part_newmap);
-}
-
-//void particle(int ptype, int pcolor, int ptex, int prendermode, int plight, float pscale, float palpha, float ptime, float pbounce, float px, float py, float pz, float pvx, float pvy, float pvz)
-#define particle(ptype, pcolor, ptex, prendermode, plight, pscale, palpha, ptime, pbounce, px, py, pz, pvx, pvy, pvz, ptime2, pvx2, pvy2, pvz2, pfriction, ppressure)\
-{\
-       particle_t      *part;\
-       int tempcolor;\
-       if (numparticles >= r_numparticles)\
-               return;\
-       part = &particles[numparticles++];\
-       part->type = (ptype);\
-       tempcolor = (pcolor);\
-       part->color[0] = ((tempcolor) >> 16) & 0xFF;\
-       part->color[1] = ((tempcolor) >> 8) & 0xFF;\
-       part->color[2] = (tempcolor) & 0xFF;\
-       part->color[3] = 0xFF;\
-       part->tex = (&ptex);\
-       part->dynlight = (plight);\
-       part->rendermode = (prendermode);\
-       part->scale = (pscale);\
-       part->alpha = (palpha);\
-       part->die = cl.time + (ptime);\
-       part->bounce = (pbounce);\
-       part->org[0] = (px);\
-       part->org[1] = (py);\
-       part->org[2] = (pz);\
-       part->vel[0] = (pvx);\
-       part->vel[1] = (pvy);\
-       part->vel[2] = (pvz);\
-       part->time2 = (ptime2);\
-       part->vel2[0] = (pvx2);\
-       part->vel2[1] = (pvy2);\
-       part->vel2[2] = (pvz2);\
-       part->friction = (pfriction);\
-       part->pressure = (ppressure);\
-}
-
-/*
-===============
-R_EntityParticles
-===============
-*/
-void R_EntityParticles (entity_t *ent)
-{
-       int                     i;
-       float           angle;
-       float           sp, sy, cp, cy;
-       vec3_t          forward;
-       float           dist;
-       float           beamlength;
-       static vec3_t avelocities[NUMVERTEXNORMALS];
-       if (!r_particles.value) return; // LordHavoc: particles are optional
-
-       dist = 64;
-       beamlength = 16;
-
-       if (!avelocities[0][0])
-               for (i=0 ; i<NUMVERTEXNORMALS*3 ; i++)
-                       avelocities[0][i] = (rand()&255) * 0.01;
-
-       for (i=0 ; i<NUMVERTEXNORMALS ; i++)
-       {
-               angle = cl.time * avelocities[i][0];
-               sy = sin(angle);
-               cy = cos(angle);
-               angle = cl.time * avelocities[i][1];
-               sp = sin(angle);
-               cp = cos(angle);
-
-               forward[0] = cp*cy;
-               forward[1] = cp*sy;
-               forward[2] = -sp;
-
-               particle(pt_oneframe, particlepalette[0x6f], particletexture, TPOLYTYPE_ALPHA, false, 2, 255, 9999, 0, ent->render.origin[0] + m_bytenormals[i][0]*dist + forward[0]*beamlength, ent->render.origin[1] + m_bytenormals[i][1]*dist + forward[1]*beamlength, ent->render.origin[2] + m_bytenormals[i][2]*dist + forward[2]*beamlength, 0, 0, 0, 0, 0, 0, 0, 0, 0);
-       }
-}
-
-
-void R_ReadPointFile_f (void)
-{
-       QFile   *f;
-       vec3_t  org;
-       int             r;
-       int             c;
-       char    name[MAX_OSPATH];
-
-       sprintf (name,"maps/%s.pts", sv.name);
-
-       COM_FOpenFile (name, &f, false, true);
-       if (!f)
-       {
-               Con_Printf ("couldn't open %s\n", name);
-               return;
-       }
-
-       Con_Printf ("Reading %s...\n", name);
-       c = 0;
-       for (;;)
-       {
-               char *str = Qgetline (f);
-               r = sscanf (str,"%f %f %f\n", &org[0], &org[1], &org[2]);
-               if (r != 3)
-                       break;
-               c++;
-
-               if (numparticles >= r_numparticles)
-               {
-                       Con_Printf ("Not enough free particles\n");
-                       break;
-               }
-               particle(pt_static, particlepalette[(-c)&15], particletexture, TPOLYTYPE_ALPHA, false, 2, 255, 99999, 0, org[0], org[1], org[2], 0, 0, 0, 0, 0, 0, 0, 0, 0);
-       }
-
-       Qclose (f);
-       Con_Printf ("%i points read\n", c);
-}
-
-/*
-===============
-R_ParseParticleEffect
-
-Parse an effect out of the server message
-===============
-*/
-void R_ParseParticleEffect (void)
-{
-       vec3_t          org, dir;
-       int                     i, count, msgcount, color;
-
-       for (i=0 ; i<3 ; i++)
-               org[i] = MSG_ReadCoord ();
-       for (i=0 ; i<3 ; i++)
-               dir[i] = MSG_ReadChar () * (1.0/16);
-       msgcount = MSG_ReadByte ();
-       color = MSG_ReadByte ();
-
-       if (msgcount == 255)
-               count = 1024;
-       else
-               count = msgcount;
-
-       R_RunParticleEffect (org, dir, color, count);
-}
-
-/*
-===============
-R_ParticleExplosion
-
-===============
-*/
-void R_ParticleExplosion (vec3_t org, int smoke)
-{
-       int i, j;
-       float f;
-       vec3_t v, end, ang;
-       byte noise1[32*32], noise2[32*32];
-
-       if (r_particles.value && r_particles_explosions.value)
-       {
-               i = Mod_PointInLeaf(org, cl.worldmodel)->contents;
-               if (i == CONTENTS_SLIME || i == CONTENTS_WATER)
-               {
-                       for (i = 0;i < 128;i++)
-                               particle(pt_bubble, 0xFFFFFF, bubbleparticletexture, TPOLYTYPE_ALPHA, false, lhrandom(1, 2), 255, 9999, 1.5, org[0] + lhrandom(-16, 16), org[1] + lhrandom(-16, 16), org[2] + lhrandom(-16, 16), lhrandom(-96, 96), lhrandom(-96, 96), lhrandom(-96, 96), 0, 0, 0, 0, 0, 0);
-
-                       ang[2] = lhrandom(0, 360);
-                       fractalnoise(noise1, 32, 4);
-                       fractalnoise(noise2, 32, 8);
-                       for (i = 0;i < 32;i++)
-                       {
-                               for (j = 0;j < 32;j++)
-                               {
-                                       VectorRandom(v);
-                                       VectorMA(org, 16, v, v);
-                                       TraceLine(org, v, end, NULL, 0);
-                                       ang[0] = (j + 0.5f) * (360.0f / 32.0f);
-                                       ang[1] = (i + 0.5f) * (360.0f / 32.0f);
-                                       AngleVectors(ang, v, NULL, NULL);
-                                       f = noise1[j*32+i] * 1.5f;
-                                       VectorScale(v, f, v);
-                                       particle(pt_underwaterspark, noise2[j*32+i] * 0x010101, smokeparticletexture[rand()&7], TPOLYTYPE_ALPHA, false, 10, lhrandom(128, 255), 9999, 1.5, end[0], end[1], end[2], v[0], v[1], v[2], 512.0f, 0, 0, 0, 2, 0);
-                                       VectorScale(v, 0.75, v);
-                                       particle(pt_underwaterspark, explosparkramp[(noise2[j*32+i] >> 5)], particletexture, TPOLYTYPE_ALPHA, false, 10, lhrandom(128, 255), 9999, 1.5, end[0], end[1], end[2], v[0], v[1], v[2], 512.0f, 0, 0, 0, 2, 0);
-                               }
-                       }
-               }
-               else
-               {
-                       ang[2] = lhrandom(0, 360);
-                       fractalnoise(noise1, 32, 4);
-                       fractalnoise(noise2, 32, 8);
-                       for (i = 0;i < 32;i++)
-                       {
-                               for (j = 0;j < 32;j++)
-                               {
-                                       VectorRandom(v);
-                                       VectorMA(org, 16, v, v);
-                                       TraceLine(org, v, end, NULL, 0);
-                                       ang[0] = (j + 0.5f) * (360.0f / 32.0f);
-                                       ang[1] = (i + 0.5f) * (360.0f / 32.0f);
-                                       AngleVectors(ang, v, NULL, NULL);
-                                       f = noise1[j*32+i] * 1.5f;
-                                       VectorScale(v, f, v);
-                                       particle(pt_spark, noise2[j*32+i] * 0x010101, smokeparticletexture[rand()&7], TPOLYTYPE_ALPHA, false, 10, lhrandom(128, 255), 9999, 1.5, end[0], end[1], end[2], v[0], v[1], v[2] + 160.0f, 512.0f, 0, 0, 0, 2, 0);
-                                       VectorScale(v, 0.75, v);
-                                       particle(pt_spark, explosparkramp[(noise2[j*32+i] >> 5)], particletexture, TPOLYTYPE_ALPHA, false, 10, lhrandom(128, 255), 9999, 1.5, end[0], end[1], end[2], v[0], v[1], v[2] + 160.0f, 512.0f, 0, 0, 0, 2, 0);
-                               //      VectorRandom(v);
-                               //      VectorScale(v, 384, v);
-                               //      particle(pt_spark, explosparkramp[rand()&7], particletexture, TPOLYTYPE_ALPHA, false, 2, lhrandom(16, 255), 9999, 1.5, end[0], end[1], end[2], v[0], v[1], v[2] + 160.0f, 512.0f, 0, 0, 0, 2, 0);
-                               }
-                       }
-               }
-       }
-       else
-               R_NewExplosion(org);
-}
-
-/*
-===============
-R_ParticleExplosion2
-
-===============
-*/
-void R_ParticleExplosion2 (vec3_t org, int colorStart, int colorLength)
-{
-       int                     i;
-       if (!r_particles.value) return; // LordHavoc: particles are optional
-
-       for (i = 0;i < 512;i++)
-               particle(pt_fade, particlepalette[colorStart + (i % colorLength)], particletexture, TPOLYTYPE_ALPHA, false, 1.5, 255, 0.3, 0, org[0] + lhrandom(-8, 8), org[1] + lhrandom(-8, 8), org[2] + lhrandom(-8, 8), lhrandom(-192, 192), lhrandom(-192, 192), lhrandom(-192, 192), 0, 0, 0, 0, 0.1f, 0);
-}
-
-/*
-===============
-R_BlobExplosion
-
-===============
-*/
-void R_BlobExplosion (vec3_t org)
-{
-       int                     i;
-       if (!r_particles.value) return; // LordHavoc: particles are optional
-
-       for (i = 0;i < 256;i++)
-               particle(pt_blob , particlepalette[ 66+(rand()%6)], particletexture, TPOLYTYPE_ALPHA, false, 4, 255, 9999, 0, org[0] + lhrandom(-16, 16), org[1] + lhrandom(-16, 16), org[2] + lhrandom(-16, 16), lhrandom(-4, 4), lhrandom(-4, 4), lhrandom(-128, 128), 0, 0, 0, 0, 0, 0);
-       for (i = 0;i < 256;i++)
-               particle(pt_blob2, particlepalette[150+(rand()%6)], particletexture, TPOLYTYPE_ALPHA, false, 4, 255, 9999, 0, org[0] + lhrandom(-16, 16), org[1] + lhrandom(-16, 16), org[2] + lhrandom(-16, 16), lhrandom(-4, 4), lhrandom(-4, 4), lhrandom(-128, 128), 0, 0, 0, 0, 0, 0);
-}
-
-/*
-===============
-R_RunParticleEffect
-
-===============
-*/
-void R_RunParticleEffect (vec3_t org, vec3_t dir, int color, int count)
-{
-       if (!r_particles.value) return; // LordHavoc: particles are optional
-
-       if (count == 1024)
-       {
-               R_ParticleExplosion(org, false);
-               return;
-       }
-       while (count--)
-               particle(pt_fade, particlepalette[color + (rand()&7)], particletexture, TPOLYTYPE_ALPHA, false, 1, 128, 9999, 0, org[0] + lhrandom(-8, 8), org[1] + lhrandom(-8, 8), org[2] + lhrandom(-8, 8), lhrandom(-15, 15), lhrandom(-15, 15), lhrandom(-15, 15), 0, 0, 0, 0, 0, 0);
-}
-
-// LordHavoc: added this for spawning sparks/dust (which have strong gravity)
-/*
-===============
-R_SparkShower
-===============
-*/
-void R_SparkShower (vec3_t org, vec3_t dir, int count)
-{
-       particletexture_t *tex;
-       if (!r_particles.value) return; // LordHavoc: particles are optional
-
-       tex = &bulletholetexture[rand()&7];
-       R_Decal(org, particlefonttexture, tex->s1, tex->t1, tex->s2, tex->t2, 16, 0, 0, 0, 255);
-
-       // smoke puff
-       if (r_particles_smoke.value)
-               particle(pt_bulletsmoke, 0xA0A0A0, smokeparticletexture[rand()&7], TPOLYTYPE_ALPHA, true, 5, 255, 9999, 0, org[0], org[1], org[2], lhrandom(-8, 8), lhrandom(-8, 8), lhrandom(0, 16), 0, 0, 0, 0, 0, 0);
-
-       if (r_particles_sparks.value)
-       {
-               // sparks
-               while(count--)
-                       particle(pt_spark, particlepalette[0x68 + (rand() & 7)], particletexture, TPOLYTYPE_ALPHA, false, 1, lhrandom(0, 255), 9999, 1.5, org[0], org[1], org[2], lhrandom(-64, 64), lhrandom(-64, 64), lhrandom(0, 128), 512.0f, 0, 0, 0, 0.2f, 0);
-       }
-}
-
-void R_BloodPuff (vec3_t org, vec3_t vel, int count)
-{
-       // bloodcount is used to accumulate counts too small to cause a blood particle
-       static int bloodcount = 0;
-       if (!r_particles.value) return; // LordHavoc: particles are optional
-       if (!r_particles_blood.value) return;
-
-       if (count > 100)
-               count = 100;
-       bloodcount += count;
-       while(bloodcount >= 10)
-       {
-               particle(pt_blood, 0x300000, smokeparticletexture[rand()&7], TPOLYTYPE_ALPHA, true, 24, 255, 9999, -1, org[0], org[1], org[2], vel[0] + lhrandom(-64, 64), vel[1] + lhrandom(-64, 64), vel[2] + lhrandom(-64, 64), 0, 0, 0, 0, 1.0f, 0);
-               bloodcount -= 10;
-       }
-}
-
-void R_BloodShower (vec3_t mins, vec3_t maxs, float velspeed, int count)
-{
-       vec3_t          diff;
-       vec3_t          center;
-       vec3_t          velscale;
-       if (!r_particles.value) return; // LordHavoc: particles are optional
-       if (!r_particles_bloodshowers.value) return;
-       if (!r_particles_blood.value) return;
-
-       VectorSubtract(maxs, mins, diff);
-       center[0] = (mins[0] + maxs[0]) * 0.5;
-       center[1] = (mins[1] + maxs[1]) * 0.5;
-       center[2] = (mins[2] + maxs[2]) * 0.5;
-       // FIXME: change velspeed back to 2.0x after fixing mod
-       velscale[0] = velspeed * 2.0 / diff[0];
-       velscale[1] = velspeed * 2.0 / diff[1];
-       velscale[2] = velspeed * 2.0 / diff[2];
-
-       while (count--)
-       {
-               vec3_t org, vel;
-               org[0] = lhrandom(mins[0], maxs[0]);
-               org[1] = lhrandom(mins[1], maxs[1]);
-               org[2] = lhrandom(mins[2], maxs[2]);
-               vel[0] = (org[0] - center[0]) * velscale[0];
-               vel[1] = (org[1] - center[1]) * velscale[1];
-               vel[2] = (org[2] - center[2]) * velscale[2];
-               particle(pt_blood, 0x300000, smokeparticletexture[rand()&7], TPOLYTYPE_ALPHA, true, 24, 255, 9999, -1, org[0], org[1], org[2], vel[0], vel[1], vel[2], 0, 0, 0, 0, 1.0f, 0);
-       }
-}
-
-void R_ParticleCube (vec3_t mins, vec3_t maxs, vec3_t dir, int count, int colorbase, int gravity, int randomvel)
-{
-       float           t;
-       if (!r_particles.value) return; // LordHavoc: particles are optional
-       if (maxs[0] <= mins[0]) {t = mins[0];mins[0] = maxs[0];maxs[0] = t;}
-       if (maxs[1] <= mins[1]) {t = mins[1];mins[1] = maxs[1];maxs[1] = t;}
-       if (maxs[2] <= mins[2]) {t = mins[2];mins[2] = maxs[2];maxs[2] = t;}
-
-       while (count--)
-               particle(gravity ? pt_grav : pt_static, particlepalette[colorbase + (rand()&3)], particletexture, TPOLYTYPE_ALPHA, false, 2, 255, lhrandom(1, 2), 0, lhrandom(mins[0], maxs[0]), lhrandom(mins[1], maxs[1]), lhrandom(mins[2], maxs[2]), dir[0] + lhrandom(-randomvel, randomvel), dir[1] + lhrandom(-randomvel, randomvel), dir[2] + lhrandom(-randomvel, randomvel), 0, 0, 0, 0, 0, 0);
-}
-
-void R_ParticleRain (vec3_t mins, vec3_t maxs, vec3_t dir, int count, int colorbase, int type)
-{
-       vec3_t          vel;
-       float           t, z;
-       if (!r_particles.value) return; // LordHavoc: particles are optional
-       if (maxs[0] <= mins[0]) {t = mins[0];mins[0] = maxs[0];maxs[0] = t;}
-       if (maxs[1] <= mins[1]) {t = mins[1];mins[1] = maxs[1];maxs[1] = t;}
-       if (maxs[2] <= mins[2]) {t = mins[2];mins[2] = maxs[2];maxs[2] = t;}
-       if (dir[2] < 0) // falling
-       {
-               t = (maxs[2] - mins[2]) / -dir[2];
-               z = maxs[2];
-       }
-       else // rising??
-       {
-               t = (maxs[2] - mins[2]) / dir[2];
-               z = mins[2];
-       }
-       if (t < 0 || t > 2) // sanity check
-               t = 2;
-
-       switch(type)
-       {
-       case 0:
-               while(count--)
-               {
-                       vel[0] = dir[0] + lhrandom(-16, 16);
-                       vel[1] = dir[1] + lhrandom(-16, 16);
-                       vel[2] = dir[2] + lhrandom(-32, 32);
-                       particle(pt_rain, particlepalette[colorbase + (rand()&3)], rainparticletexture, TPOLYTYPE_ALPHA, true, 3, 255, t, 0, lhrandom(mins[0], maxs[0]), lhrandom(mins[1], maxs[1]), z, vel[0], vel[1], vel[2], 0, vel[0], vel[1], vel[2], 0, 0);
-               }
-               break;
-       case 1:
-               while(count--)
-               {
-                       vel[0] = dir[0] + lhrandom(-16, 16);
-                       vel[1] = dir[1] + lhrandom(-16, 16);
-                       vel[2] = dir[2] + lhrandom(-32, 32);
-                       particle(pt_snow, particlepalette[colorbase + (rand()&3)], particletexture, TPOLYTYPE_ALPHA, false, 2, 255, t, 0, lhrandom(mins[0], maxs[0]), lhrandom(mins[1], maxs[1]), z, vel[0], vel[1], vel[2], 0, vel[0], vel[1], vel[2], 0, 0);
-               }
-               break;
-       default:
-               Host_Error("R_ParticleRain: unknown type %i (0 = rain, 1 = snow)\n", type);
-       }
-}
-
-void R_FlameCube (vec3_t mins, vec3_t maxs, int count)
-{
-       float           t;
-       if (!r_particles.value) return; // LordHavoc: particles are optional
-       if (maxs[0] <= mins[0]) {t = mins[0];mins[0] = maxs[0];maxs[0] = t;}
-       if (maxs[1] <= mins[1]) {t = mins[1];mins[1] = maxs[1];maxs[1] = t;}
-       if (maxs[2] <= mins[2]) {t = mins[2];mins[2] = maxs[2];maxs[2] = t;}
-
-       while (count--)
-               particle(pt_flame, particlepalette[224 + (rand()&15)], smokeparticletexture[rand()&7], TPOLYTYPE_ALPHA, false, 8, 255, 9999, 1.1, lhrandom(mins[0], maxs[0]), lhrandom(mins[1], maxs[1]), lhrandom(mins[2], maxs[2]), lhrandom(-32, 32), lhrandom(-32, 32), lhrandom(-32, 64), 0, 0, 0, 0, 0.1f, 0);
-}
-
-void R_Flames (vec3_t org, vec3_t vel, int count)
-{
-       if (!r_particles.value) return; // LordHavoc: particles are optional
-
-       while (count--)
-               particle(pt_flame, particlepalette[224 + (rand()&15)], smokeparticletexture[rand()&7], TPOLYTYPE_ALPHA, false, 8, 255, 9999, 1.1, org[0], org[1], org[2], vel[0] + lhrandom(-128, 128), vel[1] + lhrandom(-128, 128), vel[2] + lhrandom(-128, 128), 0, 0, 0, 0, 0.1f, 0);
-}
-
-
-
-/*
-===============
-R_LavaSplash
-
-===============
-*/
-void R_LavaSplash (vec3_t origin)
-{
-       int                     i, j;
-       float           vel;
-       vec3_t          dir, org;
-       if (!r_particles.value) return; // LordHavoc: particles are optional
-
-       for (i=-128 ; i<128 ; i+=16)
-       {
-               for (j=-128 ; j<128 ; j+=16)
-               {
-                       dir[0] = j + lhrandom(0, 8);
-                       dir[1] = i + lhrandom(0, 8);
-                       dir[2] = 256;
-                       org[0] = origin[0] + dir[0];
-                       org[1] = origin[1] + dir[1];
-                       org[2] = origin[2] + lhrandom(0, 64);
-                       vel = lhrandom(50, 120) / VectorLength(dir); // normalize and scale
-                       particle(pt_lavasplash, particlepalette[224 + (rand()&7)], particletexture, TPOLYTYPE_ALPHA, false, 7, 255, 9999, 0, org[0], org[1], org[2], dir[0] * vel, dir[1] * vel, dir[2] * vel, 0, 0, 0, 0, 0, 0);
-               }
-       }
-}
-
-/*
-===============
-R_TeleportSplash
-
-===============
-*/
-void R_TeleportSplash (vec3_t org)
-{
-       int                     i, j, k;
-       if (!r_particles.value) return; // LordHavoc: particles are optional
-
-       for (i=-16 ; i<16 ; i+=8)
-               for (j=-16 ; j<16 ; j+=8)
-                       for (k=-24 ; k<32 ; k+=8)
-                               particle(pt_fade, 0xFFFFFF, particletexture, TPOLYTYPE_ALPHA, false, 1, lhrandom(64, 128), 9999, 0, org[0] + i + lhrandom(0, 8), org[1] + j + lhrandom(0, 8), org[2] + k + lhrandom(0, 8), i*2 + lhrandom(-12.5, 12.5), j*2 + lhrandom(-12.5, 12.5), k*2 + lhrandom(27.5, 52.5), 0, 0, 0, 0, 0.1f, -512.0f);
-}
-
-void R_RocketTrail (vec3_t start, vec3_t end, int type, entity_t *ent)
-{
-       vec3_t          vec, dir, vel;
-       float           len, dec = 0, speed;
-       int                     contents, bubbles, polytype;
-       double          t;
-       if (!r_particles.value) return; // LordHavoc: particles are optional
-
-       VectorSubtract(end, start, dir);
-       VectorNormalize(dir);
-
-       if (type == 0 && host_frametime != 0) // rocket glow
-               particle(pt_oneframe, 0xFFFFFF, rocketglowparticletexture, TPOLYTYPE_ALPHA, false, 24, 255, 9999, 0, end[0] - 12 * dir[0], end[1] - 12 * dir[1], end[2] - 12 * dir[2], 0, 0, 0, 0, 0, 0, 0, 0, 0);
-
-       t = ent->persistent.trail_time;
-       if (t >= cl.time)
-               return; // no particles to spawn this frame (sparse trail)
-
-       if (t < cl.oldtime)
-               t = cl.oldtime;
-
-       VectorSubtract (end, start, vec);
-       len = VectorNormalizeLength (vec);
-       if (len <= 0.01f)
-       {
-               // advance the trail time
-               ent->persistent.trail_time = cl.time;
-               return;
-       }
-       speed = len / (cl.time - cl.oldtime);
-       VectorScale(vec, speed, vel);
-
-       // advance into this frame to reach the first puff location
-       dec = t - cl.oldtime;
-       dec *= speed;
-       VectorMA(start, dec, vec, start);
-
-       contents = Mod_PointInLeaf(start, cl.worldmodel)->contents;
-       if (contents == CONTENTS_SKY || contents == CONTENTS_LAVA)
-       {
-               // advance the trail time
-               ent->persistent.trail_time = cl.time;
-               return;
-       }
-
-       bubbles = (contents == CONTENTS_WATER || contents == CONTENTS_SLIME);
-
-       polytype = TPOLYTYPE_ALPHA;
-       if (ent->render.effects & EF_ADDITIVE)
-               polytype = TPOLYTYPE_ADD;
-
-       while (t < cl.time)
-       {
-               switch (type)
-               {
-                       case 0: // rocket trail
-                               if (!r_particles_smoke.value)
-                                       dec = cl.time - t;
-                               else if (bubbles && r_particles_bubbles.value)
-                               {
-                                       dec = 0.005f;
-                                       particle(pt_bubble, 0xFFFFFF, bubbleparticletexture, polytype, false, lhrandom(1, 2), 255, 9999, 1.5, start[0], start[1], start[2], lhrandom(-16, 16), lhrandom(-16, 16), lhrandom(-16, 16), 0, 0, 0, 0, 0, 0);
-                                       particle(pt_bubble, 0xFFFFFF, bubbleparticletexture, polytype, false, lhrandom(1, 2), 255, 9999, 1.5, start[0], start[1], start[2], lhrandom(-16, 16), lhrandom(-16, 16), lhrandom(-16, 16), 0, 0, 0, 0, 0, 0);
-                                       particle(pt_smoke, 0xFFFFFF, smokeparticletexture[rand()&7], polytype, false, 2, 160, 9999, 0, start[0], start[1], start[2], 0, 0, 0, 0, 0, 0, 0, 0, 0);
-                               }
-                               else
-                               {
-                                       dec = 0.005f;
-                                       particle(pt_smoke, 0xC0C0C0, smokeparticletexture[rand()&7], polytype, true, 2, 160, 9999, 0, start[0], start[1], start[2], 0, 0, 0, 0, 0, 0, 0, 0, 0);
-                                       //particle(pt_spark, particlepalette[0x68 + (rand() & 7)], particletexture, TPOLYTYPE_ALPHA, false, 1, lhrandom(128, 255), 9999, 1.5, start[0], start[1], start[2], lhrandom(-64, 64) - vel[0] * 0.0625, lhrandom(-64, 64) - vel[1] * 0.0625, lhrandom(-64, 64) - vel[2] * 0.0625, 512.0f, 0, 0, 0, 0.1f, 0);
-                                       //particle(pt_spark, particlepalette[0x68 + (rand() & 7)], particletexture, TPOLYTYPE_ALPHA, false, 1, lhrandom(128, 255), 9999, 1.5, start[0], start[1], start[2], lhrandom(-64, 64) - vel[0] * 0.0625, lhrandom(-64, 64) - vel[1] * 0.0625, lhrandom(-64, 64) - vel[2] * 0.0625, 512.0f, 0, 0, 0, 0.1f, 0);
-                                       //particle(pt_spark, particlepalette[0x68 + (rand() & 7)], particletexture, TPOLYTYPE_ALPHA, false, 1, lhrandom(128, 255), 9999, 1.5, start[0], start[1], start[2], lhrandom(-64, 64) - vel[0] * 0.0625, lhrandom(-64, 64) - vel[1] * 0.0625, lhrandom(-64, 64) - vel[2] * 0.0625, 512.0f, 0, 0, 0, 0.1f, 0);
-                                       //particle(pt_spark, particlepalette[0x68 + (rand() & 7)], particletexture, TPOLYTYPE_ALPHA, false, 1, lhrandom(128, 255), 9999, 1.5, start[0], start[1], start[2], lhrandom(-64, 64) - vel[0] * 0.0625, lhrandom(-64, 64) - vel[1] * 0.0625, lhrandom(-64, 64) - vel[2] * 0.0625, 512.0f, 0, 0, 0, 0.1f, 0);
-                               }
-                               break;
-
-                       case 1: // grenade trail
-                               // FIXME: make it gradually stop smoking
-                               if (!r_particles_smoke.value)
-                                       dec = cl.time - t;
-                               else if (bubbles && r_particles_bubbles.value)
-                               {
-                                       dec = 0.02f;
-                                       particle(pt_bubble, 0xFFFFFF, bubbleparticletexture, polytype, false, lhrandom(1, 2), 255, 9999, 1.5, start[0], start[1], start[2], lhrandom(-16, 16), lhrandom(-16, 16), lhrandom(-16, 16), 0, 0, 0, 0, 0, 0);
-                                       particle(pt_bubble, 0xFFFFFF, bubbleparticletexture, polytype, false, lhrandom(1, 2), 255, 9999, 1.5, start[0], start[1], start[2], lhrandom(-16, 16), lhrandom(-16, 16), lhrandom(-16, 16), 0, 0, 0, 0, 0, 0);
-                                       particle(pt_smoke, 0xFFFFFF, smokeparticletexture[rand()&7], polytype, false, 2, 160, 9999, 0, start[0], start[1], start[2], 0, 0, 0, 0, 0, 0, 0, 0, 0);
-                               }
-                               else
-                               {
-                                       dec = 0.02f;
-                                       particle(pt_smoke, 0x808080, smokeparticletexture[rand()&7], polytype, true, 2, 160, 9999, 0, start[0], start[1], start[2], 0, 0, 0, 0, 0, 0, 0, 0, 0);
-                               }
-                               break;
-
-
-                       case 2: // blood
-                               if (!r_particles_blood.value)
-                                       dec = cl.time - t;
-                               else
-                               {
-                                       dec = 0.1f;
-                                       particle(pt_blood, 0x300000, smokeparticletexture[rand()&7], polytype, true, 24, 255, 9999, -1, start[0], start[1], start[2], vel[0] + lhrandom(-64, 64), vel[1] + lhrandom(-64, 64), vel[2] + lhrandom(-64, 64), 0, 0, 0, 0, 1.0f, 0);
-                               }
-                               break;
-
-                       case 4: // slight blood
-                               if (!r_particles_blood.value)
-                                       dec = cl.time - t;
-                               else
-                               {
-                                       dec = 0.15f;
-                                       particle(pt_blood, 0x300000, smokeparticletexture[rand()&7], polytype, true, 24, 255, 9999, -1, start[0], start[1], start[2], vel[0] + lhrandom(-64, 64), vel[1] + lhrandom(-64, 64), vel[2] + lhrandom(-64, 64), 0, 0, 0, 0, 1.0f, 0);
-                               }
-                               break;
-
-                       case 3: // green tracer
-                               dec = 0.02f;
-                               particle(pt_fade, 0x373707, smokeparticletexture[rand()&7], polytype, false, 4, 255, 9999, 0, start[0], start[1], start[2], 0, 0, 0, 0, 0, 0, 0, 0, 0);
-                               break;
-
-                       case 5: // flame tracer
-                               dec = 0.02f;
-                               particle(pt_fade, 0xCF632B, smokeparticletexture[rand()&7], polytype, false, 4, 255, 9999, 0, start[0], start[1], start[2], 0, 0, 0, 0, 0, 0, 0, 0, 0);
-                               break;
-
-                       case 6: // voor trail
-                               dec = 0.05f; // sparse trail
-                               particle(pt_fade, 0x47232B, smokeparticletexture[rand()&7], polytype, false, 4, 255, 9999, 0, start[0], start[1], start[2], 0, 0, 0, 0, 0, 0, 0, 0, 0);
-                               break;
-
-                       case 7: // Nehahra smoke tracer
-                               if (!r_particles_smoke.value)
-                                       dec = cl.time - t;
-                               else
-                               {
-                                       dec = 0.14f;
-                                       particle(pt_smoke, 0xC0C0C0, smokeparticletexture[rand()&7], polytype, true, 10, 64, 9999, 0, start[0], start[1], start[2], 0, 0, 0, 0, 0, 0, 0, 0, 0);
-                               }
-                               break;
-               }
-
-               // advance to next time and position
-               t += dec;
-               dec *= speed;
-               VectorMA (start, dec, vec, start);
-       }
-       ent->persistent.trail_time = t;
-}
-
-void R_RocketTrail2 (vec3_t start, vec3_t end, int color, entity_t *ent)
-{
-       vec3_t          vec;
-       int                     len;
-       if (!r_particles.value) return; // LordHavoc: particles are optional
-       if (!r_particles_smoke.value) return;
-
-       VectorSubtract (end, start, vec);
-       len = (int) (VectorNormalizeLength (vec) * (1.0f / 3.0f));
-       VectorScale(vec, 3, vec);
-       color = particlepalette[color];
-       while (len--)
-       {
-               particle(pt_smoke, color, particletexture, TPOLYTYPE_ALPHA, false, 8, 192, 9999, 0, start[0], start[1], start[2], 0, 0, 0, 0, 0, 0, 0, 0, 0);
-               VectorAdd (start, vec, start);
-       }
-}
-
-
-/*
-===============
-R_DrawParticles
-===============
-*/
-void R_MoveParticles (void)
-{
-       particle_t              *p;
-       int                             i, activeparticles, maxparticle, j, a, b, pressureused = false;
-       vec3_t                  v, org, o, normal;
-       float                   gravity, dvel, frametime, f;
-
-       // LordHavoc: early out condition
-       if (!numparticles)
-               return;
-
-       frametime = cl.time - cl.oldtime;
-       if (!frametime)
-               return; // if absolutely still, don't update particles
-       gravity = frametime * sv_gravity.value;
-       dvel = 1+4*frametime;
-
-       activeparticles = 0;
-       maxparticle = -1;
-       j = 0;
-       for (i = 0, p = particles;i < numparticles;i++, p++)
-       {
-               if (p->die < cl.time)
-               {
-                       freeparticles[j++] = p;
-                       continue;
-               }
-
-               VectorCopy(p->org, p->oldorg);
-               VectorMA(p->org, frametime, p->vel, p->org);
-               if (p->friction)
-               {
-                       f = 1.0f - (p->friction * frametime);
-                       VectorScale(p->vel, f, p->vel);
-               }
-               VectorCopy(p->org, org);
-               if (p->bounce)
-               {
-                       vec3_t normal;
-                       float dist;
-                       if (TraceLine(p->oldorg, p->org, v, normal, 0) < 1)
-                       {
-                               VectorCopy(v, p->org);
-                               if (p->bounce < 0)
-                               {
-                                       R_Decal(v, particlefonttexture, p->tex->s1, p->tex->t1, p->tex->s2, p->tex->t2, p->scale, p->color[0], p->color[1], p->color[2], p->alpha);
-                                       p->die = -1;
-                                       freeparticles[j++] = p;
-                                       continue;
-                               }
-                               else
-                               {
-                                       dist = DotProduct(p->vel, normal) * -p->bounce;
-                                       VectorMA(p->vel, dist, normal, p->vel);
-                                       if (DotProduct(p->vel, p->vel) < 0.03)
-                                               VectorClear(p->vel);
-                               }
-                       }
-               }
-
-               switch (p->type)
-               {
-               case pt_static:
-                       break;
-
-                       // LordHavoc: drop-through because of shared code
-               case pt_blob:
-                       p->vel[2] *= dvel;
-               case pt_blob2:
-                       p->vel[0] *= dvel;
-                       p->vel[1] *= dvel;
-                       p->alpha -= frametime * 256;
-                       if (p->alpha < 1)
-                               p->die = -1;
-                       break;
-
-               case pt_grav:
-                       p->vel[2] -= gravity;
-                       break;
-               case pt_lavasplash:
-                       p->vel[2] -= gravity * 0.05;
-                       p->alpha -= frametime * 192;
-                       if (p->alpha < 1)
-                               p->die = -1;
-                       break;
-               case pt_snow:
-                       if (cl.time > p->time2)
-                       {
-                               p->time2 = cl.time + (rand() & 3) * 0.1;
-                               p->vel[0] = (rand()&63)-32 + p->vel2[0];
-                               p->vel[1] = (rand()&63)-32 + p->vel2[1];
-                               p->vel[2] = (rand()&63)-32 + p->vel2[2];
-                       }
-                       a = Mod_PointInLeaf(p->org, cl.worldmodel)->contents;
-                       if (a != CONTENTS_EMPTY && a != CONTENTS_SKY)
-                       {
-                               vec3_t normal;
-                               if (a == CONTENTS_SOLID && Mod_PointInLeaf(p->oldorg, cl.worldmodel)->contents == CONTENTS_SOLID)
-                                       break; // still in solid
-                               p->die = cl.time + 1000;
-                               p->vel[0] = p->vel[1] = p->vel[2] = 0;
-                               switch (a)
-                               {
-                               case CONTENTS_LAVA:
-                               case CONTENTS_SLIME:
-                                       p->tex = &smokeparticletexture[rand()&7];
-                                       p->type = pt_steam;
-                                       p->alpha = 96;
-                                       p->scale = 5;
-                                       p->vel[2] = 96;
-                                       break;
-                               case CONTENTS_WATER:
-                                       p->tex = &smokeparticletexture[rand()&7];
-                                       p->type = pt_splash;
-                                       p->alpha = 96;
-                                       p->scale = 5;
-                                       p->vel[2] = 96;
-                                       break;
-                               default: // CONTENTS_SOLID and any others
-                                       TraceLine(p->oldorg, p->org, v, normal, 0);
-                                       VectorCopy(v, p->org);
-                                       p->tex = &smokeparticletexture[rand()&7];
-                                       p->type = pt_fade;
-                                       VectorClear(p->vel);
-                                       break;
-                               }
-                       }
-                       break;
-               case pt_blood:
-                       p->friction = 1;
-                       a = Mod_PointInLeaf(p->org, cl.worldmodel)->contents;
-                       if (a != CONTENTS_EMPTY)
-                       {
-                               if (a == CONTENTS_WATER || a == CONTENTS_SLIME)
-                               {
-                                       p->friction = 5;
-                                       p->scale += frametime * 32.0f;
-                                       p->alpha -= frametime * 128.0f;
-                                       p->vel[2] += gravity * 0.125f;
-                                       if (p->alpha < 1)
-                                               p->die = -1;
-                                       break;
-                               }
-                               else
-                               {
-                                       p->die = -1;
-                                       break;
-                               }
-                       }
-                       p->vel[2] -= gravity * 0.5;
-                       break;
-               case pt_spark:
-                       p->alpha -= frametime * p->time2;
-                       p->vel[2] -= gravity;
-                       if (p->alpha < 1)
-                               p->die = -1;
-                       else if (Mod_PointInLeaf(p->org, cl.worldmodel)->contents != CONTENTS_EMPTY)
-                               p->type = pt_underwaterspark;
-                       break;
-               case pt_underwaterspark:
-                       if (Mod_PointInLeaf(p->org, cl.worldmodel)->contents == CONTENTS_EMPTY)
-                       {
-                               p->tex = &smokeparticletexture[rand()&7];
-                               p->color[0] = p->color[1] = p->color[2] = 255;
-                               p->scale = 16;
-                               p->type = pt_explosionsplash;
-                       }
-                       else
-                               p->vel[2] += gravity * 0.5f;
-                       p->alpha -= frametime * p->time2;
-                       if (p->alpha < 1)
-                               p->die = -1;
-                       break;
-               case pt_explosionsplash:
-                       if (Mod_PointInLeaf(p->org, cl.worldmodel)->contents == CONTENTS_EMPTY)
-                               p->vel[2] -= gravity;
-                       else
-                               p->alpha = 0;
-                       p->scale += frametime * 64.0f;
-                       p->alpha -= frametime * 1024.0f;
-                       if (p->alpha < 1)
-                               p->die = -1;
-                       break;
-               case pt_fade:
-                       p->alpha -= frametime * 512;
-                       if (p->alpha < 1)
-                               p->die = -1;
-                       break;
-               case pt_bubble:
-                       a = Mod_PointInLeaf(p->org, cl.worldmodel)->contents;
-                       if (a != CONTENTS_WATER && a != CONTENTS_SLIME)
-                       {
-                               p->tex = &smokeparticletexture[rand()&7];
-                               p->type = pt_splashpuff;
-                               p->scale = 4;
-                               p->vel[0] = p->vel[1] = p->vel[2] = 0;
-                               break;
-                       }
-                       p->vel[2] += gravity * 0.25;
-                       p->vel[0] *= (1 - (frametime * 0.0625));
-                       p->vel[1] *= (1 - (frametime * 0.0625));
-                       p->vel[2] *= (1 - (frametime * 0.0625));
-                       if (cl.time > p->time2)
-                       {
-                               p->time2 = cl.time + lhrandom(0, 0.5);
-                               p->vel[0] += lhrandom(-32,32);
-                               p->vel[1] += lhrandom(-32,32);
-                               p->vel[2] += lhrandom(-32,32);
-                       }
-                       p->alpha -= frametime * 256;
-                       if (p->alpha < 1)
-                               p->die = -1;
-                       break;
-               case pt_bulletsmoke:
-                       p->scale += frametime * 16;
-                       p->alpha -= frametime * 1024;
-                       p->vel[2] += gravity * 0.1;
-                       if (p->alpha < 1)
-                               p->die = -1;
-                       break;
-               case pt_smoke:
-                       p->scale += frametime * 24;
-                       p->alpha -= frametime * 256;
-                       p->vel[2] += gravity * 0.1;
-                       if (p->alpha < 1)
-                               p->die = -1;
-                       break;
-               case pt_steam:
-                       p->scale += frametime * 48;
-                       p->alpha -= frametime * 512;
-                       p->vel[2] += gravity * 0.05;
-                       if (p->alpha < 1)
-                               p->die = -1;
-                       break;
-               case pt_splashpuff:
-                       p->alpha -= frametime * 1024;
-                       if (p->alpha < 1)
-                               p->die = -1;
-                       break;
-               case pt_rain:
-                       f = 0;
-                       b = Mod_PointInLeaf(p->oldorg, cl.worldmodel)->contents;
-                       VectorCopy(p->oldorg, o);
-                       while (f < 1)
-                       {
-                               a = b;
-                               f = TraceLine(o, p->org, v, normal, a);
-                               b = traceline_endcontents;
-                               if (f < 1 && b != CONTENTS_EMPTY && b != CONTENTS_SKY)
-                               {
-                                       p->die = cl.time + 1000;
-                                       p->vel[0] = p->vel[1] = p->vel[2] = 0;
-                                       VectorCopy(v, p->org);
-                                       switch (b)
-                                       {
-                                       case CONTENTS_LAVA:
-                                       case CONTENTS_SLIME:
-                                               p->tex = &smokeparticletexture[rand()&7];
-                                               p->type = pt_steam;
-                                               p->scale = 3;
-                                               p->vel[2] = 96;
-                                               break;
-                                       default: // water, solid, and anything else
-                                               p->tex = &raindropsplashparticletexture[0];
-                                               p->time2 = 0;
-                                               VectorCopy(normal, p->vel2);
-                                       //      VectorAdd(p->org, normal, p->org);
-                                               p->type = pt_raindropsplash;
-                                               p->scale = 8;
-                                               break;
-                                       }
-                               }
-                       }
-                       break;
-               case pt_raindropsplash:
-                       p->time2 += frametime * 64.0f;
-                       if (p->time2 >= 16.0f)
-                       {
-                               p->die = -1;
-                               break;
-                       }
-                       p->tex = &raindropsplashparticletexture[(int) p->time2];
-                       break;
-               case pt_flame:
-                       p->alpha -= frametime * 512;
-                       p->vel[2] += gravity;
-                       if (p->alpha < 16)
-                               p->die = -1;
-                       break;
-               case pt_oneframe:
-                       if (p->time2)
-                               p->die = -1;
-                       p->time2 = 1;
-                       break;
-               default:
-                       printf("unknown particle type %i\n", p->type);
-                       p->die = -1;
-                       break;
-               }
-
-               // LordHavoc: immediate removal of unnecessary particles (must be done to ensure compactor below operates properly in all cases)
-               if (p->die < cl.time)
-                       freeparticles[j++] = p;
-               else
-               {
-                       maxparticle = i;
-                       activeparticles++;
-                       if (p->pressure)
-                               pressureused = true;
-               }
-       }
-       // fill in gaps to compact the array
-       i = 0;
-       while (maxparticle >= activeparticles)
-       {
-               *freeparticles[i++] = particles[maxparticle--];
-               while (maxparticle >= activeparticles && particles[maxparticle].die < cl.time)
-                       maxparticle--;
-       }
-       numparticles = activeparticles;
-
-       if (pressureused)
-       {
-               activeparticles = 0;
-               for (i = 0, p = particles;i < numparticles;i++, p++)
-                       if (p->pressure)
-                               freeparticles[activeparticles++] = p;
-
-               if (activeparticles)
-               {
-                       for (i = 0, p = particles;i < numparticles;i++, p++)
-                       {
-                               for (j = 0;j < activeparticles;j++)
-                               {
-                                       if (freeparticles[j] != p)
-                                       {
-                                               float dist, diff[3];
-                                               VectorSubtract(p->org, freeparticles[j]->org, diff);
-                                               dist = DotProduct(diff, diff);
-                                               if (dist < 4096 && dist >= 1)
-                                               {
-                                                       dist = freeparticles[j]->scale * 4.0f * frametime / sqrt(dist);
-                                                       VectorMA(p->vel, dist, diff, p->vel);
-                                                       //dist = freeparticles[j]->scale * 4.0f * frametime / dist;
-                                                       //VectorMA(p->vel, dist, freeparticles[j]->vel, p->vel);
-                                               }
-                                       }
-                               }
-                       }
-               }
-       }
-}
-
-void R_DrawParticles (void)
-{
-       particle_t              *p;
-       int                             i, dynamiclight, staticlight, r, g, b, texnum;
-       float                   minparticledist;
-       vec3_t                  uprightangles, up2, right2, v, right, up;
-       mleaf_t                 *leaf;
-
-       // LordHavoc: early out condition
-       if ((!numparticles) || (!r_drawparticles.value))
-               return;
-
-       staticlight = dynamiclight = r_particles_lighting.value;
-       if (!r_dynamic.value)
-               dynamiclight = 0;
-       c_particles += numparticles;
-
-       uprightangles[0] = 0;
-       uprightangles[1] = r_refdef.viewangles[1];
-       uprightangles[2] = 0;
-       AngleVectors (uprightangles, NULL, right2, up2);
-
-       minparticledist = DotProduct(r_origin, vpn) + 16.0f;
-
-       texnum = R_GetTexture(particlefonttexture);
-       for (i = 0, p = particles;i < numparticles;i++, p++)
-       {
-               if (p->tex == NULL || p->alpha < 1 || p->scale < 0.1f)
-                       continue;
-
-               // LordHavoc: only render if not too close
-               if (DotProduct(p->org, vpn) < minparticledist)
-                       continue;
-
-               // LordHavoc: check if it's in a visible leaf
-               leaf = Mod_PointInLeaf(p->org, cl.worldmodel);
-               if (leaf->visframe != r_framecount)
-                       continue;
-
-               r = p->color[0];
-               g = p->color[1];
-               b = p->color[2];
-               if (staticlight && (p->dynlight || staticlight >= 2)) // LordHavoc: only light blood and smoke
-               {
-                       R_CompleteLightPoint(v, p->org, dynamiclight, leaf);
-#if SLOWMATH
-                       r = (r * (int) v[0]) >> 7;
-                       g = (g * (int) v[1]) >> 7;
-                       b = (b * (int) v[2]) >> 7;
-#else
-                       v[0] += 8388608.0f;
-                       v[1] += 8388608.0f;
-                       v[2] += 8388608.0f;
-                       r = (r * (*((long *) &v[0]) & 0x7FFFFF)) >> 7;
-                       g = (g * (*((long *) &v[1]) & 0x7FFFFF)) >> 7;
-                       b = (b * (*((long *) &v[2]) & 0x7FFFFF)) >> 7;
-#endif
-               }
-               if (p->type == pt_raindropsplash)
-               {
-                       // treat as double-sided
-                       if (DotProduct(p->vel2, r_origin) > DotProduct(p->vel2, p->org))
-                       {
-                               VectorNegate(p->vel2, v);
-                               VectorVectors(v, right, up);
-                       }
-                       else
-                               VectorVectors(p->vel2, right, up);
-                       transpolyparticle(p->org, right, up, p->scale, texnum, p->rendermode, r, g, b, p->alpha, p->tex->s1, p->tex->t1, p->tex->s2, p->tex->t2);
-               }
-               else if (p->tex == &rainparticletexture) // rain streak
-                       transpolyparticle(p->org, right2, up2, p->scale, texnum, p->rendermode, r, g, b, p->alpha, p->tex->s1, p->tex->t1, p->tex->s2, p->tex->t2);
-               else
-                       transpolyparticle(p->org, vright, vup, p->scale, texnum, p->rendermode, r, g, b, p->alpha, p->tex->s1, p->tex->t1, p->tex->s2, p->tex->t2);
-       }
-}
diff --git a/r_particles.c b/r_particles.c
new file mode 100644 (file)
index 0000000..88b8f01
--- /dev/null
@@ -0,0 +1,448 @@
+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+#include "quakedef.h"
+
+static rtexturepool_t *particletexturepool;
+
+// these are used by the decal system so they can't be static
+rtexture_t *particlefonttexture;
+// [0] is normal, [1] is fog, they may be the same
+particletexture_t particletexture[MAX_PARTICLETEXTURES][2];
+
+static cvar_t r_drawparticles = {0, "r_drawparticles", "1"};
+static cvar_t r_particles_lighting = {0, "r_particles_lighting", "1"};
+
+static byte shadebubble(float dx, float dy, vec3_t light)
+{
+       float   dz, f, dot;
+       vec3_t  normal;
+       dz = 1 - (dx*dx+dy*dy);
+       if (dz > 0) // it does hit the sphere
+       {
+               f = 0;
+               // back side
+               normal[0] = dx;normal[1] = dy;normal[2] = dz;
+               VectorNormalize(normal);
+               dot = DotProduct(normal, light);
+               if (dot > 0.5) // interior reflection
+                       f += ((dot *  2) - 1);
+               else if (dot < -0.5) // exterior reflection
+                       f += ((dot * -2) - 1);
+               // front side
+               normal[0] = dx;normal[1] = dy;normal[2] = -dz;
+               VectorNormalize(normal);
+               dot = DotProduct(normal, light);
+               if (dot > 0.5) // interior reflection
+                       f += ((dot *  2) - 1);
+               else if (dot < -0.5) // exterior reflection
+                       f += ((dot * -2) - 1);
+               f *= 128;
+               f += 16; // just to give it a haze so you can see the outline
+               f = bound(0, f, 255);
+               return (byte) f;
+       }
+       else
+               return 0;
+}
+
+static void setuptex(int cltexnum, int fog, int rtexnum, byte *data, byte *particletexturedata)
+{
+       int basex, basey, y;
+       basex = ((rtexnum >> 0) & 7) * 32;
+       basey = ((rtexnum >> 3) & 7) * 32;
+       particletexture[cltexnum][fog].s1 = (basex + 1) / 256.0f;
+       particletexture[cltexnum][fog].t1 = (basey + 1) / 256.0f;
+       particletexture[cltexnum][fog].s2 = (basex + 31) / 256.0f;
+       particletexture[cltexnum][fog].t2 = (basey + 31) / 256.0f;
+       for (y = 0;y < 32;y++)
+               memcpy(particletexturedata + ((basey + y) * 256 + basex) * 4, data + y * 32 * 4, 32 * 4);
+}
+
+static void R_InitParticleTexture (void)
+{
+       int             x,y,d,i,m;
+       float   dx, dy, radius, f, f2;
+       byte    data[32][32][4], noise1[64][64], noise2[64][64];
+       vec3_t  light;
+       byte    particletexturedata[256*256*4];
+
+       memset(particletexturedata, 255, sizeof(particletexturedata));
+
+       // the particletexture[][] array numbers must match the cl_part.c textures
+       for (i = 0;i < 8;i++)
+       {
+               do
+               {
+                       fractalnoise(&noise1[0][0], 64, 4);
+                       fractalnoise(&noise2[0][0], 64, 8);
+                       m = 0;
+                       for (y = 0;y < 32;y++)
+                       {
+                               dy = y - 16;
+                               for (x = 0;x < 32;x++)
+                               {
+                                       d = (noise1[y][x] - 128) * 2 + 64; // was + 128
+                                       d = bound(0, d, 255);
+                                       data[y][x][0] = data[y][x][1] = data[y][x][2] = d;
+                                       dx = x - 16;
+                                       d = (noise2[y][x] - 128) * 3 + 192;
+                                       if (d > 0)
+                                               d = (d * (256 - (int) (dx*dx+dy*dy))) >> 8;
+                                       d = bound(0, d, 255);
+                                       data[y][x][3] = (byte) d;
+                                       if (m < d)
+                                               m = d;
+                               }
+                       }
+               }
+               while (m < 224);
+
+               setuptex(i + 0, 0, i + 0, &data[0][0][0], particletexturedata);
+               for (y = 0;y < 32;y++)
+                       for (x = 0;x < 32;x++)
+                               data[y][x][0] = data[y][x][1] = data[y][x][2] = 255;
+               setuptex(i + 0, 1, i + 8, &data[0][0][0], particletexturedata);
+       }
+
+       for (i = 0;i < 8;i++)
+       {
+               float p[32][32];
+               fractalnoise(&noise1[0][0], 64, 8);
+               for (y = 0;y < 32;y++)
+                       for (x = 0;x < 32;x++)
+                               p[y][x] = (noise1[y][x] / 8.0f) - 64.0f;
+               for (m = 0;m < 32;m++)
+               {
+                       int j;
+                       float fx, fy, f;
+                       fx = lhrandom(14, 18);
+                       fy = lhrandom(14, 18);
+                       do
+                       {
+                               dx = lhrandom(-1, 1);
+                               dy = lhrandom(-1, 1);
+                               f = (dx * dx + dy * dy);
+                       }
+                       while(f < 0.125f || f > 1.0f);
+                       f = (m + 1) / 40.0f; //lhrandom(0.0f, 1.0);
+                       dx *= 1.0f / 32.0f;
+                       dy *= 1.0f / 32.0f;
+                       for (j = 0;f > 0 && j < (32 * 14);j++)
+                       {
+                               y = fy;
+                               x = fx;
+                               fx += dx;
+                               fy += dy;
+                               if (x < 1 || y < 1 || x >= 31 || y >= 31)
+                                       break;
+                               p[y - 1][x - 1] += f * 0.125f;
+                               p[y - 1][x    ] += f * 0.25f;
+                               p[y - 1][x + 1] += f * 0.125f;
+                               p[y    ][x - 1] += f * 0.25f;
+                               p[y    ][x    ] += f;
+                               p[y    ][x + 1] += f * 0.25f;
+                               p[y + 1][x - 1] += f * 0.125f;
+                               p[y + 1][x    ] += f * 0.25f;
+                               p[y + 1][x + 1] += f * 0.125f;
+//                             f -= (0.5f / (32 * 16));
+                       }
+               }
+               for (y = 0;y < 32;y++)
+               {
+                       for (x = 0;x < 32;x++)
+                       {
+                               m = p[y][x];
+                               data[y][x][0] = data[y][x][1] = data[y][x][2] = 255;
+                               data[y][x][3] = (byte) bound(0, m, 255);
+                       }
+               }
+
+               setuptex(i + 8, 0, i + 16, &data[0][0][0], particletexturedata);
+               setuptex(i + 8, 1, i + 16, &data[0][0][0], particletexturedata);
+       }
+
+       for (i = 0;i < 16;i++)
+       {
+               radius = i * 3.0f / 16.0f;
+               f2 = 255.0f * ((15.0f - i) / 15.0f);
+               for (y = 0;y < 32;y++)
+               {
+                       dy = (y - 16) * 0.25f;
+                       for (x = 0;x < 32;x++)
+                       {
+                               dx = (x - 16) * 0.25f;
+                               data[y][x][0] = data[y][x][1] = data[y][x][2] = 255;
+                               f = (1.0 - fabs(radius - sqrt(dx*dx+dy*dy))) * f2;
+                               f = bound(0.0f, f, 255.0f);
+                               data[y][x][3] = (int) f;
+                       }
+               }
+               setuptex(i + 16, 0, i + 24, &data[0][0][0], particletexturedata);
+               setuptex(i + 16, 1, i + 24, &data[0][0][0], particletexturedata);
+       }
+
+       for (y = 0;y < 32;y++)
+       {
+               dy = y - 16;
+               for (x = 0;x < 32;x++)
+               {
+                       data[y][x][0] = data[y][x][1] = data[y][x][2] = 255;
+                       dx = x - 16;
+                       d = (256 - (dx*dx+dy*dy));
+                       d = bound(0, d, 255);
+                       data[y][x][3] = (byte) d;
+               }
+       }
+       setuptex(32, 0, 40, &data[0][0][0], particletexturedata);
+       setuptex(32, 1, 40, &data[0][0][0], particletexturedata);
+
+       light[0] = 1;light[1] = 1;light[2] = 1;
+       VectorNormalize(light);
+       for (y = 0;y < 32;y++)
+       {
+               for (x = 0;x < 32;x++)
+               {
+                       data[y][x][0] = data[y][x][1] = data[y][x][2] = 255;
+                       data[y][x][3] = shadebubble((x - 16) * (1.0 / 8.0), y < 24 ? (y - 24) * (1.0 / 24.0) : (y - 24) * (1.0 / 8.0), light);
+               }
+       }
+       setuptex(33, 0, 41, &data[0][0][0], particletexturedata);
+       setuptex(33, 1, 41, &data[0][0][0], particletexturedata);
+
+       light[0] = 1;light[1] = 1;light[2] = 1;
+       VectorNormalize(light);
+       for (y = 0;y < 32;y++)
+       {
+               for (x = 0;x < 32;x++)
+               {
+                       data[y][x][0] = data[y][x][1] = data[y][x][2] = 255;
+                       data[y][x][3] = shadebubble((x - 16) * (1.0 / 16.0), (y - 16) * (1.0 / 16.0), light);
+               }
+       }
+       setuptex(34, 0, 42, &data[0][0][0], particletexturedata);
+       setuptex(34, 1, 42, &data[0][0][0], particletexturedata);
+
+       for (y = 0;y < 32;y++)
+       {
+               dy = y - 16;
+               for (x = 0;x < 32;x++)
+               {
+                       dx = x - 16;
+                       d = (2048.0f / (dx*dx+dy*dy+1)) - 8.0f;
+                       data[y][x][0] = bound(0, d * 1.0f, 255);
+                       data[y][x][1] = bound(0, d * 0.8f, 255);
+                       data[y][x][2] = bound(0, d * 0.5f, 255);
+                       data[y][x][3] = bound(0, d * 1.0f, 255);
+               }
+       }
+       setuptex(35, 0, 43, &data[0][0][0], particletexturedata);
+       for (y = 0;y < 32;y++)
+               for (x = 0;x < 32;x++)
+                       data[y][x][0] = data[y][x][1] = data[y][x][2] = 255;
+       setuptex(35, 1, 44, &data[0][0][0], particletexturedata);
+
+       particlefonttexture = R_LoadTexture (particletexturepool, "particlefont", 256, 256, particletexturedata, TEXTYPE_RGBA, TEXF_ALPHA | TEXF_PRECACHE);
+}
+
+static void r_part_start(void)
+{
+       particletexturepool = R_AllocTexturePool();
+       R_InitParticleTexture ();
+}
+
+static void r_part_shutdown(void)
+{
+       R_FreeTexturePool(&particletexturepool);
+}
+
+static void r_part_newmap(void)
+{
+}
+
+void R_Particles_Init (void)
+{
+       Cvar_RegisterVariable(&r_drawparticles);
+       Cvar_RegisterVariable(&r_particles_lighting);
+       R_RegisterModule("R_Particles", r_part_start, r_part_shutdown, r_part_newmap);
+}
+
+int partindexarray[6] = {0, 1, 2, 0, 2, 3};
+
+void R_DrawParticles (void)
+{
+       renderparticle_t *r;
+       int i, lighting;
+       float minparticledist, org[3], uprightangles[3], up2[3], right2[3], v[3], right[3], up[3], tv[4][5], fog, diff[3];
+       mleaf_t *leaf;
+       particletexture_t *tex, *texfog;
+       rmeshinfo_t m;
+
+       // LordHavoc: early out conditions
+       if ((!r_refdef.numparticles) || (!r_drawparticles.integer))
+               return;
+
+       lighting = r_particles_lighting.integer;
+       if (!r_dynamic.integer)
+               lighting = 0;
+
+       c_particles += r_refdef.numparticles;
+
+       uprightangles[0] = 0;
+       uprightangles[1] = r_refdef.viewangles[1];
+       uprightangles[2] = 0;
+       AngleVectors (uprightangles, NULL, right2, up2);
+
+       minparticledist = DotProduct(r_origin, vpn) + 16.0f;
+
+       memset(&m, 0, sizeof(m));
+       m.transparent = true;
+       m.blendfunc1 = GL_SRC_ALPHA;
+       m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
+       m.numtriangles = 2;
+       m.index = partindexarray;
+       m.numverts = 4;
+       m.vertex = &tv[0][0];
+       m.vertexstep = sizeof(float[5]);
+       m.tex[0] = R_GetTexture(particlefonttexture);
+       m.texcoords[0] = &tv[0][3];
+       m.texcoordstep[0] = sizeof(float[5]);
+
+       for (i = 0, r = r_refdef.particles;i < r_refdef.numparticles;i++, r++)
+       {
+               // LordHavoc: only render if not too close
+               if (DotProduct(r->org, vpn) < minparticledist)
+                       continue;
+
+               // LordHavoc: check if it's in a visible leaf
+               leaf = Mod_PointInLeaf(r->org, cl.worldmodel);
+               if (leaf->visframe != r_framecount)
+                       continue;
+
+               VectorCopy(r->org, org);
+               if (r->orientation == PARTICLE_BILLBOARD)
+               {
+                       VectorScale(vright, r->scale, right);
+                       VectorScale(vup, r->scale, up);
+               }
+               else if (r->orientation == PARTICLE_UPRIGHT_FACING)
+               {
+                       VectorScale(right2, r->scale, right);
+                       VectorScale(up2, r->scale, up);
+               }
+               else if (r->orientation == PARTICLE_ORIENTED_DOUBLESIDED)
+               {
+                       // double-sided
+                       if (DotProduct(r->dir, r_origin) > DotProduct(r->dir, org))
+                       {
+                               VectorNegate(r->dir, v);
+                               VectorVectors(v, right, up);
+                       }
+                       else
+                               VectorVectors(r->dir, right, up);
+                       VectorScale(right, r->scale, right);
+                       VectorScale(up, r->scale, up);
+               }
+               else
+                       Host_Error("R_DrawParticles: unknown particle orientation %i\n", r->orientation);
+
+               m.cr = r->color[0];
+               m.cg = r->color[1];
+               m.cb = r->color[2];
+               m.ca = r->color[3];
+               if (lighting >= 1 && (r->dynlight || lighting >= 2))
+               {
+                       R_CompleteLightPoint(v, org, true, leaf);
+                       m.cr *= v[0];
+                       m.cg *= v[1];
+                       m.cb *= v[2];
+               }
+
+               tex = &particletexture[r->tex][0];
+               texfog = &particletexture[r->tex][1];
+
+               fog = 0;
+               if (fogenabled)
+               {
+                       VectorSubtract(org, r_origin, diff);
+                       fog = exp(fogdensity/DotProduct(diff,diff));
+                       if (fog >= 0.01f)
+                       {
+                               if (fog > 1)
+                                       fog = 1;
+                               m.cr *= 1 - fog;
+                               m.cg *= 1 - fog;
+                               m.cb *= 1 - fog;
+                               if (tex->s1 == texfog->s1 && tex->t1 == texfog->t1)
+                               {
+                                       m.cr += fogcolor[0] * fog;
+                                       m.cg += fogcolor[1] * fog;
+                                       m.cb += fogcolor[2] * fog;
+                               }
+                       }
+                       else
+                               fog = 0;
+               }
+
+               tv[0][0] = org[0] - right[0] - up[0];
+               tv[0][1] = org[1] - right[1] - up[1];
+               tv[0][2] = org[2] - right[2] - up[2];
+               tv[0][3] = tex->s1;
+               tv[0][4] = tex->t1;
+               tv[1][0] = org[0] - right[0] + up[0];
+               tv[1][1] = org[1] - right[1] + up[1];
+               tv[1][2] = org[2] - right[2] + up[2];
+               tv[1][3] = tex->s1;
+               tv[1][4] = tex->t2;
+               tv[2][0] = org[0] + right[0] + up[0];
+               tv[2][1] = org[1] + right[1] + up[1];
+               tv[2][2] = org[2] + right[2] + up[2];
+               tv[2][3] = tex->s2;
+               tv[2][4] = tex->t2;
+               tv[3][0] = org[0] + right[0] - up[0];
+               tv[3][1] = org[1] + right[1] - up[1];
+               tv[3][2] = org[2] + right[2] - up[2];
+               tv[3][3] = tex->s2;
+               tv[3][4] = tex->t1;
+
+               R_Mesh_Draw(&m);
+
+               if (fog && (tex->s1 != texfog->s1 || tex->t1 != texfog->t1))
+               {
+                       m.blendfunc2 = GL_ONE;
+                       m.cr = fogcolor[0];
+                       m.cg = fogcolor[1];
+                       m.cb = fogcolor[2];
+                       m.ca = r->color[3] * fog;
+
+                       tv[0][3] = texfog->s1;
+                       tv[0][4] = texfog->t1;
+                       tv[1][3] = texfog->s1;
+                       tv[1][4] = texfog->t2;
+                       tv[2][3] = texfog->s2;
+                       tv[2][4] = texfog->t2;
+                       tv[3][3] = texfog->s2;
+                       tv[3][4] = texfog->t1;
+
+                       R_Mesh_Draw(&m);
+                       m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
+               }
+       }
+}
diff --git a/r_sky.c b/r_sky.c
new file mode 100644 (file)
index 0000000..fbf9e42
--- /dev/null
+++ b/r_sky.c
@@ -0,0 +1,520 @@
+#include "quakedef.h"
+
+void LoadSky_f(void);
+
+cvar_t r_skyquality = {CVAR_SAVE, "r_skyquality", "2"};
+cvar_t r_mergesky = {CVAR_SAVE, "r_mergesky", "0"};
+cvar_t r_skyflush = {0, "r_skyflush", "0"};
+
+static char skyworldname[1024];
+rtexture_t *mergeskytexture;
+rtexture_t *solidskytexture;
+rtexture_t *alphaskytexture;
+static qboolean skyavailable_quake;
+static qboolean skyavailable_box;
+static rtexturepool_t *skytexturepool;
+
+int skyrendernow;
+int skyrendermasked;
+int skyrenderglquake;
+
+static void R_BuildSky (int scrollupper, int scrolllower);
+
+static void r_sky_start(void)
+{
+       skytexturepool = R_AllocTexturePool();
+       mergeskytexture = NULL;
+       solidskytexture = NULL;
+       alphaskytexture = NULL;
+}
+
+static void r_sky_shutdown(void)
+{
+       R_FreeTexturePool(&skytexturepool);
+       mergeskytexture = NULL;
+       solidskytexture = NULL;
+       alphaskytexture = NULL;
+}
+
+int R_SetSkyBox(char *sky);
+
+static void r_sky_newmap(void)
+{
+       skyavailable_quake = false;
+       if (!strcmp(skyworldname, cl.worldmodel->name))
+               skyavailable_quake = true;
+}
+
+void R_Sky_Init(void)
+{
+       Cmd_AddCommand ("loadsky", &LoadSky_f);
+       Cvar_RegisterVariable (&r_skyquality);
+       Cvar_RegisterVariable (&r_mergesky);
+       Cvar_RegisterVariable (&r_skyflush);
+       R_RegisterModule("R_Sky", r_sky_start, r_sky_shutdown, r_sky_newmap);
+}
+
+static int skyrendersphere;
+static int skyrenderbox;
+
+void R_SkyStartFrame(void)
+{
+       skyrendernow = false;
+       skyrendersphere = false;
+       skyrenderbox = false;
+       skyrenderglquake = false;
+       skyrendermasked = false;
+       if (r_skyquality.integer >= 1 && !fogenabled)
+       {
+               if (skyavailable_box)
+                       skyrenderbox = true;
+               else if (skyavailable_quake)
+               {
+                       switch(r_skyquality.integer)
+                       {
+                       case 1:
+                               skyrenderglquake = true;
+                               break;
+                       default:
+                       case 2:
+                               skyrendersphere = true;
+                               break;
+                       }
+               }
+               if (r_mergesky.integer && (skyrenderglquake || skyrendersphere))
+               {
+       //              R_BuildSky((int) (cl.time * 8.0), (int) (cl.time * 16.0));
+       //              R_BuildSky((int) (cl.time * -8.0), 0);
+                       R_BuildSky(0, (int) (cl.time * 8.0));
+               }
+               if (skyrenderbox || skyrendersphere)
+               {
+                       // for depth-masked sky, render the sky on the first sky surface encountered
+                       skyrendernow = true;
+                       skyrendermasked = true;
+               }
+       }
+}
+
+static char skyname[256];
+
+/*
+==================
+R_SetSkyBox
+==================
+*/
+static char *suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"};
+static rtexture_t *skyboxside[6];
+int R_SetSkyBox(char *sky)
+{
+       int             i;
+       char    name[1024];
+       byte*   image_rgba;
+
+       if (strcmp(sky, skyname) == 0) // no change
+               return true;
+
+       skyboxside[0] = skyboxside[1] = skyboxside[2] = skyboxside[3] = skyboxside[4] = skyboxside[5] = NULL;
+       skyavailable_box = false;
+       skyname[0] = 0;
+
+       if (!sky[0])
+               return true;
+
+       if (strlen(sky) > 1000)
+       {
+               Con_Printf ("sky name too long (%i, max is 1000)\n", strlen(sky));
+               return false;
+       }
+
+       for (i = 0;i < 6;i++)
+       {
+               sprintf (name, "env/%s%s", sky, suf[i]);
+               if (!(image_rgba = loadimagepixels(name, false, 0, 0)))
+               {
+                       sprintf (name, "gfx/env/%s%s", sky, suf[i]);
+                       if (!(image_rgba = loadimagepixels(name, false, 0, 0)))
+                       {
+                               Con_Printf ("Couldn't load env/%s%s or gfx/env/%s%s\n", sky, suf[i], sky, suf[i]);
+                               continue;
+                       }
+               }
+               skyboxside[i] = R_LoadTexture(skytexturepool, va("skyboxside%d", i), image_width, image_height, image_rgba, TEXTYPE_RGBA, TEXF_PRECACHE);
+               Mem_Free(image_rgba);
+       }
+
+       if (skyboxside[0] || skyboxside[1] || skyboxside[2] || skyboxside[3] || skyboxside[4] || skyboxside[5])
+       {
+               skyavailable_box = true;
+               strcpy(skyname, sky);
+               return true;
+       }
+       return false;
+}
+
+// LordHavoc: added LoadSky console command
+void LoadSky_f (void)
+{
+       switch (Cmd_Argc())
+       {
+       case 1:
+               if (skyname[0])
+                       Con_Printf("current sky: %s\n", skyname);
+               else
+                       Con_Printf("no skybox has been set\n");
+               break;
+       case 2:
+               if (R_SetSkyBox(Cmd_Argv(1)))
+               {
+                       if (skyname[0])
+                               Con_Printf("skybox set to %s\n", skyname);
+                       else
+                               Con_Printf("skybox disabled\n");
+               }
+               else
+                       Con_Printf("failed to load skybox %s\n", Cmd_Argv(1));
+               break;
+       default:
+               Con_Printf("usage: loadsky skyname\n");
+               break;
+       }
+}
+
+#define R_SkyBoxPolyVec(i,s,t,x,y,z) \
+       vert[i][0] = (x) * 1024.0f + r_origin[0];\
+       vert[i][1] = (y) * 1024.0f + r_origin[1];\
+       vert[i][2] = (z) * 1024.0f + r_origin[2];\
+       vert[i][4] = (s) * (254.0f/256.0f) + (1.0f/256.0f);\
+       vert[i][5] = (t) * (254.0f/256.0f) + (1.0f/256.0f);
+
+int skyboxindex[6] = {0, 1, 2, 0, 2, 3};
+
+static void R_SkyBox(void)
+{
+       float vert[4][6];
+       rmeshinfo_t m;
+       memset(&m, 0, sizeof(m));
+       m.transparent = false;
+       m.blendfunc1 = GL_ONE;
+       m.blendfunc2 = GL_ZERO;
+       m.numtriangles = 2;
+       m.numverts = 4;
+       m.index = skyboxindex;
+       m.vertex = &vert[0][0];
+       m.vertexstep = sizeof(float[6]);
+       m.cr = 1;
+       m.cg = 1;
+       m.cb = 1;
+       m.ca = 1;
+       m.texcoords[0] = &vert[0][4];
+       m.texcoordstep[0] = sizeof(float[6]);
+       m.tex[0] = R_GetTexture(skyboxside[3]); // front
+       R_SkyBoxPolyVec(0, 1, 0,  1, -1,  1);
+       R_SkyBoxPolyVec(1, 1, 1,  1, -1, -1);
+       R_SkyBoxPolyVec(2, 0, 1,  1,  1, -1);
+       R_SkyBoxPolyVec(3, 0, 0,  1,  1,  1);
+       R_Mesh_Draw(&m);
+       m.tex[0] = R_GetTexture(skyboxside[1]); // back
+       R_SkyBoxPolyVec(0, 1, 0, -1,  1,  1);
+       R_SkyBoxPolyVec(1, 1, 1, -1,  1, -1);
+       R_SkyBoxPolyVec(2, 0, 1, -1, -1, -1);
+       R_SkyBoxPolyVec(3, 0, 0, -1, -1,  1);
+       R_Mesh_Draw(&m);
+       m.tex[0] = R_GetTexture(skyboxside[0]); // right
+       R_SkyBoxPolyVec(0, 1, 0,  1,  1,  1);
+       R_SkyBoxPolyVec(1, 1, 1,  1,  1, -1);
+       R_SkyBoxPolyVec(2, 0, 1, -1,  1, -1);
+       R_SkyBoxPolyVec(3, 0, 0, -1,  1,  1);
+       R_Mesh_Draw(&m);
+       m.tex[0] = R_GetTexture(skyboxside[2]); // left
+       R_SkyBoxPolyVec(0, 1, 0, -1, -1,  1);
+       R_SkyBoxPolyVec(1, 1, 1, -1, -1, -1);
+       R_SkyBoxPolyVec(2, 0, 1,  1, -1, -1);
+       R_SkyBoxPolyVec(3, 0, 0,  1, -1,  1);
+       R_Mesh_Draw(&m);
+       m.tex[0] = R_GetTexture(skyboxside[4]); // up
+       R_SkyBoxPolyVec(0, 1, 0,  1, -1,  1);
+       R_SkyBoxPolyVec(1, 1, 1,  1,  1,  1);
+       R_SkyBoxPolyVec(2, 0, 1, -1,  1,  1);
+       R_SkyBoxPolyVec(3, 0, 0, -1, -1,  1);
+       R_Mesh_Draw(&m);
+       m.tex[0] = R_GetTexture(skyboxside[5]); // down
+       R_SkyBoxPolyVec(0, 1, 0,  1,  1, -1);
+       R_SkyBoxPolyVec(1, 1, 1,  1, -1, -1);
+       R_SkyBoxPolyVec(2, 0, 1, -1, -1, -1);
+       R_SkyBoxPolyVec(3, 0, 0, -1,  1, -1);
+       R_Mesh_Draw(&m);
+       R_Mesh_Render();
+       if (r_skyflush.integer)
+               glFlush();
+       // clear the zbuffer that was used while rendering the sky
+       glClear(GL_DEPTH_BUFFER_BIT);
+       if (r_skyflush.integer)
+               glFlush();
+}
+
+static float skysphere[33*33*5];
+static int skysphereindices[32*32*6];
+static void skyspherecalc(float *sphere, float dx, float dy, float dz)
+{
+       float a, b, x, ax, ay, v[3], length;
+       int i, j, *index;
+       for (a = 0;a <= 1;a += (1.0 / 32.0))
+       {
+               ax = cos(a * M_PI * 2);
+               ay = -sin(a * M_PI * 2);
+               for (b = 0;b <= 1;b += (1.0 / 32.0))
+               {
+                       x = cos(b * M_PI * 2);
+                       v[0] = ax*x * dx;
+                       v[1] = ay*x * dy;
+                       v[2] = -sin(b * M_PI * 2) * dz;
+                       length = 3.0f / sqrt(v[0]*v[0]+v[1]*v[1]+(v[2]*v[2]*9));
+                       *sphere++ = v[0] * length;
+                       *sphere++ = v[1] * length;
+                       *sphere++ = v[0];
+                       *sphere++ = v[1];
+                       *sphere++ = v[2];
+               }
+       }
+       index = skysphereindices;
+       for (j = 0;j < 32;j++)
+       {
+               for (i = 0;i < 32;i++)
+               {
+                       *index++ =  j      * 33 + i;
+                       *index++ =  j      * 33 + i + 1;
+                       *index++ = (j + 1) * 33 + i;
+
+                       *index++ =  j      * 33 + i + 1;
+                       *index++ = (j + 1) * 33 + i + 1;
+                       *index++ = (j + 1) * 33 + i;
+               }
+               i++;
+       }
+}
+
+static void skyspherearrays(float *vert, float *tex, float *tex2, float *source, float s, float s2)
+{
+       float *v, *t, *t2, radius;
+       int i;
+       v = vert;
+       t = tex;
+       t2 = tex2;
+       radius = r_farclip - 8;
+       for (i = 0;i < (33*33);i++)
+       {
+               *t++ = source[0] + s;
+               *t++ = source[1] + s;
+               *t2++ = source[0] + s2;
+               *t2++ = source[1] + s2;
+               *v++ = source[2] + r_origin[0];
+               *v++ = source[3] + r_origin[1];
+               *v++ = source[4] + r_origin[2];
+               *v++ = 0;
+               source += 5;
+       }
+}
+
+static void R_SkySphere(void)
+{
+       float speedscale, speedscale2;
+       float vert[33*33*4], tex[33*33*2], tex2[33*33*2];
+       static qboolean skysphereinitialized = false;
+       rmeshinfo_t m;
+       if (!skysphereinitialized)
+       {
+               skysphereinitialized = true;
+               skyspherecalc(skysphere, 1024, 1024, 1024 / 3);
+       }
+       memset(&m, 0, sizeof(m));
+       m.transparent = false;
+       m.blendfunc1 = GL_ONE;
+       m.blendfunc2 = GL_ZERO;
+       m.numtriangles = 32*32*2;
+       m.numverts = 33*33;
+       m.index = skysphereindices;
+       m.vertex = vert;
+       m.vertexstep = sizeof(float[4]);
+       m.cr = 1;
+       m.cg = 1;
+       m.cb = 1;
+       m.ca = 1;
+       m.texcoords[0] = tex;
+       m.texcoordstep[0] = sizeof(float[2]);
+       speedscale = cl.time*8.0/128.0;
+       speedscale -= (int)speedscale;
+       speedscale2 = cl.time*16.0/128.0;
+       speedscale2 -= (int)speedscale2;
+       skyspherearrays(vert, tex, tex2, skysphere, speedscale, speedscale2);
+       // do not lock the texcoord array, because it will be switched
+       if (r_mergesky.integer)
+       {
+               m.tex[0] = R_GetTexture(mergeskytexture);
+               R_Mesh_Draw(&m);
+       }
+       else
+       {
+               m.tex[0] = R_GetTexture(solidskytexture);
+               R_Mesh_Draw(&m);
+
+               m.blendfunc1 = GL_SRC_ALPHA;
+               m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
+               m.tex[0] = R_GetTexture(alphaskytexture);
+               m.texcoords[0] = tex2;
+               R_Mesh_Draw(&m);
+       }
+       R_Mesh_Render();
+       if (r_skyflush.integer)
+               glFlush();
+       // clear the zbuffer that was used while rendering the sky
+       glClear(GL_DEPTH_BUFFER_BIT);
+       if (r_skyflush.integer)
+               glFlush();
+}
+
+void R_Sky(void)
+{
+       if (skyrendersphere)
+               R_SkySphere();
+       else if (skyrenderbox)
+               R_SkyBox();
+}
+
+//===============================================================
+
+static byte skyupperlayerpixels[128*128*4];
+static byte skylowerlayerpixels[128*128*4];
+static byte skymergedpixels[128*128*4];
+
+static void R_BuildSky (int scrollupper, int scrolllower)
+{
+       int x, y, ux, uy, lx, ly;
+       byte *m, *u, *l;
+       m = skymergedpixels;
+       for (y = 0;y < 128;y++)
+       {
+               uy = (y + scrollupper) & 127;
+               ly = (y + scrolllower) & 127;
+               for (x = 0;x < 128;x++)
+               {
+                       ux = (x + scrollupper) & 127;
+                       lx = (x + scrolllower) & 127;
+                       u = &skyupperlayerpixels[(uy * 128 + ux) * 4];
+                       l = &skylowerlayerpixels[(ly * 128 + lx) * 4];
+                       if (l[3])
+                       {
+                               if (l[3] == 255)
+                                       *((int *)m) = *((int *)l);
+                               else
+                               {
+                                       m[0] = ((((int) l[0] - (int) u[0]) * (int) l[3]) >> 8) + (int) u[0];
+                                       m[1] = ((((int) l[1] - (int) u[1]) * (int) l[3]) >> 8) + (int) u[1];
+                                       m[2] = ((((int) l[2] - (int) u[2]) * (int) l[3]) >> 8) + (int) u[2];
+                                       m[3] = 255;
+                               }
+                       }
+                       else
+                               *((int *)m) = *((int *)u);
+                       m += 4;
+               }
+       }
+       if (mergeskytexture)
+               R_UpdateTexture(mergeskytexture, skymergedpixels);
+       else
+               mergeskytexture = R_LoadTexture(skytexturepool, "mergedskytexture", 128, 128, skymergedpixels, TEXTYPE_RGBA, TEXF_ALWAYSPRECACHE);
+}
+
+/*
+=============
+R_InitSky
+
+A sky texture is 256*128, with the right side being a masked overlay
+==============
+*/
+void R_InitSky (byte *src, int bytesperpixel)
+{
+       int                     i, j, p;
+       unsigned        trans[128*128];
+       unsigned        transpix;
+       int                     r, g, b;
+       unsigned        *rgba;
+
+       strcpy(skyworldname, loadmodel->name);
+       if (bytesperpixel == 4)
+       {
+               for (i = 0;i < 128;i++)
+                       for (j = 0;j < 128;j++)
+                               trans[(i*128) + j] = src[i*256+j+128];
+       }
+       else
+       {
+               // make an average value for the back to avoid
+               // a fringe on the top level
+               r = g = b = 0;
+               for (i=0 ; i<128 ; i++)
+               {
+                       for (j=0 ; j<128 ; j++)
+                       {
+                               p = src[i*256 + j + 128];
+                               rgba = &d_8to24table[p];
+                               trans[(i*128) + j] = *rgba;
+                               r += ((byte *)rgba)[0];
+                               g += ((byte *)rgba)[1];
+                               b += ((byte *)rgba)[2];
+                       }
+               }
+
+               ((byte *)&transpix)[0] = r/(128*128);
+               ((byte *)&transpix)[1] = g/(128*128);
+               ((byte *)&transpix)[2] = b/(128*128);
+               ((byte *)&transpix)[3] = 0;
+       }
+
+       memcpy(skyupperlayerpixels, trans, 128*128*4);
+
+       solidskytexture = R_LoadTexture (skytexturepool, "sky_solidtexture", 128, 128, (byte *) trans, TEXTYPE_RGBA, TEXF_PRECACHE);
+       /*
+       for (i = 0;i < 128*128;i++)
+       {
+               ((byte *)&trans[i])[0] >>= 1;
+               ((byte *)&trans[i])[1] >>= 1;
+               ((byte *)&trans[i])[2] >>= 1;
+       }
+       solidskytexture_half = R_LoadTexture (skytexturepool, "sky_solidtexture_half", 128, 128, (byte *) trans, TEXTYPE_RGBA, TEXF_PRECACHE);
+       */
+
+       if (bytesperpixel == 4)
+       {
+               for (i = 0;i < 128;i++)
+                       for (j = 0;j < 128;j++)
+                               trans[(i*128) + j] = src[i*256+j];
+       }
+       else
+       {
+               for (i=0 ; i<128 ; i++)
+               {
+                       for (j=0 ; j<128 ; j++)
+                       {
+                               p = src[i*256 + j];
+                               if (p == 0)
+                                       trans[(i*128) + j] = transpix;
+                               else
+                                       trans[(i*128) + j] = d_8to24table[p];
+                       }
+               }
+       }
+
+       memcpy(skylowerlayerpixels, trans, 128*128*4);
+
+       alphaskytexture = R_LoadTexture (skytexturepool, "sky_alphatexture", 128, 128, (byte *) trans, TEXTYPE_RGBA, TEXF_ALPHA | TEXF_PRECACHE);
+       /*
+       for (i = 0;i < 128*128;i++)
+       {
+               ((byte *)&trans[i])[0] >>= 1;
+               ((byte *)&trans[i])[1] >>= 1;
+               ((byte *)&trans[i])[2] >>= 1;
+       }
+       alphaskytexture_half = R_LoadTexture (skytexturepool, "sky_alphatexture_half", 128, 128, (byte *) trans, TEXTYPE_RGBA, TEXF_ALPHA | TEXF_PRECACHE);
+       */
+}
index f9b43eadd4b6f32b9d0a6bca91b9eb18b7b36e2a..e72a1116576df014edc07be52c55a346c4784493 100644 (file)
@@ -1,19 +1,19 @@
 #include "quakedef.h"
 
-void R_ClipSpriteImage (msprite_t *psprite, vec3_t origin, vec3_t right, vec3_t up)
+void R_ClipSpriteImage (vec3_t origin, vec3_t right, vec3_t up)
 {
        int i;
        mspriteframe_t *frame;
        vec3_t points[4];
        float fleft, fright, fdown, fup;
-       frame = ((mspriteframe_t *)(psprite->ofs_frames + (int) psprite)) + currentrenderentity->frameblend[0].frame;
+       frame = currentrenderentity->model->sprdata_frames + currentrenderentity->frameblend[0].frame;
        fleft  = frame->left;
        fdown  = frame->down;
        fright = frame->right;
        fup    = frame->up;
        for (i = 1;i < 4 && currentrenderentity->frameblend[i].lerp;i++)
        {
-               frame = ((mspriteframe_t *)(psprite->ofs_frames + (int) psprite)) + currentrenderentity->frameblend[i].frame;
+               frame = currentrenderentity->model->sprdata_frames + currentrenderentity->frameblend[i].frame;
                fleft  = min(fleft , frame->left );
                fdown  = min(fdown , frame->down );
                fright = max(fright, frame->right);
@@ -96,29 +96,61 @@ int R_SpriteSetup (int type, float org[3], float right[3], float up[3])
 void R_ClipSprite (void)
 {
        vec3_t org, right, up;
-       msprite_t *psprite;
 
        if (currentrenderentity->frameblend[0].frame < 0)
                return;
 
-       psprite = Mod_Extradata(currentrenderentity->model);
-       if (R_SpriteSetup(psprite->type, org, right, up))
+       if (R_SpriteSetup(currentrenderentity->model->sprnum_type, org, right, up))
                return;
 
        // LordHavoc: interpolated sprite rendering
-       R_ClipSpriteImage(psprite, org, right, up);
+       R_ClipSpriteImage(org, right, up);
 }
 
-void GL_DrawSpriteImage (mspriteframe_t *frame, vec3_t origin, vec3_t up, vec3_t right, byte red, byte green, byte blue, int alpha)
+void GL_DrawSpriteImage (int fog, mspriteframe_t *frame, int texture, vec3_t origin, vec3_t up, vec3_t right, float red, float green, float blue, float alpha)
 {
-       byte alphaub;
-       alphaub = bound(0, alpha, 255);
-       transpolybegin(R_GetTexture(frame->texture), 0, R_GetTexture(frame->fogtexture), ((currentrenderentity->effects & EF_ADDITIVE) || (currentrenderentity->model->flags & EF_ADDITIVE)) ? TPOLYTYPE_ADD : TPOLYTYPE_ALPHA);
-       transpolyvertub(origin[0] + frame->down * up[0] + frame->left  * right[0], origin[1] + frame->down * up[1] + frame->left  * right[1], origin[2] + frame->down * up[2] + frame->left  * right[2], 0, 1, red, green, blue, alphaub);
-       transpolyvertub(origin[0] + frame->up   * up[0] + frame->left  * right[0], origin[1] + frame->up   * up[1] + frame->left  * right[1], origin[2] + frame->up   * up[2] + frame->left  * right[2], 0, 0, red, green, blue, alphaub);
-       transpolyvertub(origin[0] + frame->up   * up[0] + frame->right * right[0], origin[1] + frame->up   * up[1] + frame->right * right[1], origin[2] + frame->up   * up[2] + frame->right * right[2], 1, 0, red, green, blue, alphaub);
-       transpolyvertub(origin[0] + frame->down * up[0] + frame->right * right[0], origin[1] + frame->down * up[1] + frame->right * right[1], origin[2] + frame->down * up[2] + frame->right * right[2], 1, 1, red, green, blue, alphaub);
-       transpolyend();
+       rmeshinfo_t m;
+       float v[4][5];
+       memset(&m, 0, sizeof(m));
+       m.transparent = true;
+       m.blendfunc1 = GL_SRC_ALPHA;
+       m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
+       if ((currentrenderentity->effects & EF_ADDITIVE)
+        || (currentrenderentity->model->flags & EF_ADDITIVE)
+        || fog)
+               m.blendfunc2 = GL_ONE;
+       m.vertex = &v[0][0];
+       m.vertexstep = sizeof(float[5]);
+       m.cr = red;
+       m.cg = green;
+       m.cb = blue;
+       m.ca = alpha;
+       m.tex[0] = texture;
+       m.texcoords[0] = &v[0][3];
+       m.texcoordstep[0] = sizeof(float[5]);
+
+       v[0][0] = origin[0] + frame->down * up[0] + frame->left  * right[0];
+       v[0][1] = origin[1] + frame->down * up[1] + frame->left  * right[1];
+       v[0][2] = origin[2] + frame->down * up[2] + frame->left  * right[2];
+       v[0][3] = 0;
+       v[0][4] = 1;
+       v[1][0] = origin[0] + frame->up   * up[0] + frame->left  * right[0];
+       v[1][1] = origin[1] + frame->up   * up[1] + frame->left  * right[1];
+       v[1][2] = origin[2] + frame->up   * up[2] + frame->left  * right[2];
+       v[1][3] = 0;
+       v[1][4] = 0;
+       v[2][0] = origin[0] + frame->up   * up[0] + frame->right * right[0];
+       v[2][1] = origin[1] + frame->up   * up[1] + frame->right * right[1];
+       v[2][2] = origin[2] + frame->up   * up[2] + frame->right * right[2];
+       v[2][3] = 1;
+       v[2][4] = 0;
+       v[3][0] = origin[0] + frame->down * up[0] + frame->right * right[0];
+       v[3][1] = origin[1] + frame->down * up[1] + frame->right * right[1];
+       v[3][2] = origin[2] + frame->down * up[2] + frame->right * right[2];
+       v[3][3] = 1;
+       v[3][4] = 1;
+
+       R_Mesh_DrawPolygon(&m, 4);
 }
 
 /*
@@ -130,34 +162,43 @@ void R_DrawSpriteModel ()
 {
        int                     i;
        vec3_t          right, up, org, color;
-       byte            colorub[4];
-       msprite_t       *psprite;
+       mspriteframe_t *frame;
+       vec3_t diff;
+       float           fog, ifog;
 
        if (currentrenderentity->frameblend[0].frame < 0)
                return;
 
-       psprite = Mod_Extradata(currentrenderentity->model);
-       if (R_SpriteSetup(psprite->type, org, right, up))
+       if (R_SpriteSetup(currentrenderentity->model->sprnum_type, org, right, up))
                return;
 
        c_sprites++;
 
        if ((currentrenderentity->model->flags & EF_FULLBRIGHT) || (currentrenderentity->effects & EF_FULLBRIGHT))
-       {
-               color[0] = currentrenderentity->colormod[0] * 255;
-               color[1] = currentrenderentity->colormod[1] * 255;
-               color[2] = currentrenderentity->colormod[2] * 255;
-       }
+               color[0] = color[1] = color[2] = 1;
        else
                R_CompleteLightPoint(color, currentrenderentity->origin, true, NULL);
 
-       colorub[0] = bound(0, color[0], 255);
-       colorub[1] = bound(0, color[1], 255);
-       colorub[2] = bound(0, color[2], 255);
+       if (fogenabled)
+       {
+               VectorSubtract(currentrenderentity->origin, r_origin, diff);
+               fog = exp(fogdensity/DotProduct(diff,diff));
+               if (fog > 1)
+                       fog = 1;
+       }
+       else
+               fog = 0;
+       ifog = 1 - fog;
 
        // LordHavoc: interpolated sprite rendering
        for (i = 0;i < 4;i++)
-               if (currentrenderentity->frameblend[i].lerp)
-                       GL_DrawSpriteImage(((mspriteframe_t *)(psprite->ofs_frames + (int) psprite)) + currentrenderentity->frameblend[i].frame, org, up, right, colorub[0],colorub[1],colorub[2], currentrenderentity->alpha*255*currentrenderentity->frameblend[i].lerp);
+       {
+               if (currentrenderentity->frameblend[i].lerp >= 0.01f)
+               {
+                       frame = currentrenderentity->model->sprdata_frames + currentrenderentity->frameblend[i].frame;
+                       GL_DrawSpriteImage(false, frame, R_GetTexture(frame->texture), org, up, right, color[0] * ifog, color[1] * ifog, color[2] * ifog, currentrenderentity->alpha * currentrenderentity->frameblend[i].lerp);
+                       if (fog * currentrenderentity->frameblend[i].lerp >= 0.01f)
+                               GL_DrawSpriteImage(true, frame, R_GetTexture(frame->fogtexture), org, up, right, fogcolor[0],fogcolor[1],fogcolor[2], fog * currentrenderentity->alpha * currentrenderentity->frameblend[i].lerp);
+               }
+       }
 }
-
index fb4b844d2acf043acc8644df5639a262ea99e60b..3bf15de7d04ebe8caf8881b27f0e7b5246f55f55 100644 (file)
@@ -1,21 +1,70 @@
 
-#define TEXF_ALPHA 1 // transparent
-#define TEXF_MIPMAP 2 // mipmapped
-#define TEXF_RGBA 4 // 32bit RGBA, as opposed to 8bit paletted
-#define TEXF_PRECACHE 8 // upload immediately, otherwise defer loading until it is used (r_textureprecache can override this)
-#define TEXF_ALWAYSPRECACHE 16 // upload immediately, never defer (ignore r_textureprecache)
+// transparent
+#define TEXF_ALPHA 0x00000001
+// mipmapped
+#define TEXF_MIPMAP 0x00000002
+// upload if r_textureprecache >= 1, otherwise defer loading until it is used
+#define TEXF_PRECACHE 0x00000004
+// upload immediately, never defer (ignore r_textureprecache)
+#define TEXF_ALWAYSPRECACHE 0x00000008
+// allocated as a fragment in a larger texture, mipmap is not allowed with
+// this, mostly used for lightmaps (which are procedural textures)
+#define TEXF_FRAGMENT 0x00000010
+// used for checking if textures mismatch
+#define TEXF_IMPORTANTBITS (TEXF_ALPHA | TEXF_MIPMAP | TEXF_FRAGMENT)
+
+// 8bit quake paletted
+#define TEXTYPE_QPALETTE 1
+// 24bit RGB
+#define TEXTYPE_RGB 2
+// 32bit RGBA
+#define TEXTYPE_RGBA 3
 
 // contents of this structure are private to gl_textures.c
-typedef struct rtexture_s
+typedef struct
 {
        int useless;
 }
 rtexture_t;
 
-// uploads a texture
-extern rtexture_t *R_LoadTexture (char *identifier, int width, int height, byte *data, int flags);
-// returns the renderer dependent texture slot number (call this before each use, as a texture might not have been precached)
-extern int R_GetTexture (rtexture_t *rt);
-// returns a GL texture slot (only used for lightmaps)
-extern int R_GetTextureSlots(int count);
-extern int R_TextureHasAlpha(rtexture_t *rt);
+// contents of this structure are private to gl_textures.c
+typedef struct
+{
+       int useless;
+}
+rtexturepool_t;
+
+// allocate a texture pool, to be used with R_LoadTexture/R_ProceduralTexture
+rtexturepool_t *R_AllocTexturePool(void);
+// free a texture pool (textures can not be freed individually)
+void R_FreeTexturePool(rtexturepool_t **rtexturepool);
+
+// important technical note:
+// fragment textures must have a width that is compatible with the fragment
+// update system, to get a compliant size, use R_CompatibleFragmentWidth
+int R_CompatibleFragmentWidth(int width, int textype, int flags);
+
+// these two functions add a texture to a pool, and may precache (upload) it
+// a normal static texture
+rtexture_t *R_LoadTexture (rtexturepool_t *rtexturepool, char *identifier, int width, int height, byte *data, int textype, int flags);
+// a procedurally generated texture, often animated over time, note: generate can be NULL (for odd uses)
+rtexture_t *R_ProceduralTexture (rtexturepool_t *rtexturepool, char *identifier, int width, int height, int textype, int flags, int (*generate)(byte *buffer, int width, int height, void *parameterdata, int parameterdatasize), void *parameterdata, int parameterdatasize);
+
+// update the image data of a texture, used by lightmap updates and procedural
+// textures.
+void R_UpdateTexture(rtexture_t *rt, byte *data);
+
+// location of the fragment in the texture (note: any parameter except rt can be NULL)
+void R_GetFragmentLocation(rtexture_t *rt, int *x, int *y, float *fx1, float *fy1, float *fx2, float *fy2);
+
+// returns the renderer dependent texture slot number (call this before each use, as a texture might not have been precached, or it might change over time if it is procedural)
+int R_GetTexture (rtexture_t *rt);
+
+// returns true if the texture is transparent (useful for rendering code)
+int R_TextureHasAlpha(rtexture_t *rt);
+
+// returns width of texture, as was specified when it was uploaded
+int R_TextureWidth(rtexture_t *rt);
+
+// returns height of texture, as was specified when it was uploaded
+int R_TextureHeight(rtexture_t *rt);
index 7950e9f6e35a4e6954771c724868c79fe7991fb8..0053ca0b280eb52efdf545cc2af983e57a22fae6 100644 (file)
--- a/render.h
+++ b/render.h
@@ -20,13 +20,28 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 // refresh.h -- public interface to refresh functions
 
+// 1.0f / N table
+extern float ixtable[4096];
+
 // far clip distance for scene
-extern cvar_t r_farclip;
+extern float r_farclip, r_newfarclip;
 
 // fog stuff
 extern void FOG_clear(void);
 extern float fog_density, fog_red, fog_green, fog_blue;
 
+// sky stuff
+extern int R_SetSkyBox(char* sky);
+extern cvar_t r_skyquality;
+// these are exposed because surface rendering uses them
+extern rtexture_t *solidskytexture;
+extern rtexture_t *alphaskytexture;
+extern rtexture_t *mergeskytexture;
+extern int skyrendernow, skyrendermasked, skyrenderglquake;
+extern cvar_t r_mergesky;
+extern void R_SkyStartFrame(void);
+extern void R_Sky(void);
+
 // SHOWLMP stuff (Nehahra)
 extern void SHOWLMP_decodehide(void);
 extern void SHOWLMP_decodeshow(void);
@@ -47,87 +62,19 @@ extern float lightscale;
 // model rendering stuff
 extern float *aliasvert;
 extern float *aliasvertnorm;
-extern byte *aliasvertcolor;
+extern float *aliasvertcolor;
 
 // vis stuff
 extern cvar_t r_novis;
 
 // model transform stuff
-extern cvar_t gl_transform;
-
-// LordHavoc: 1.0f / N table
-extern float ixtable[4096];
+//extern cvar_t gl_transform;
 
 #define        TOP_RANGE               16                      // soldier uniform colors
 #define        BOTTOM_RANGE    96
 
 //=============================================================================
 
-typedef struct frameblend_s
-{
-       int frame;
-       float lerp;
-}
-frameblend_t;
-
-// LordHavoc: nothing in this structure is persistant, it may be overwritten by the client every frame, for persistant data use entity_lerp_t.
-typedef struct entity_render_s
-{
-       vec3_t  origin;                 // location
-       vec3_t  angles;                 // orientation
-       float   colormod[3];    // color tint for model
-       float   alpha;                  // opacity (alpha) of the model
-       float   scale;                  // size the model is shown
-
-       model_t *model;                 // NULL = no model
-       int             frame;                  // current uninterpolated animation frame (for things which do not use interpolation)
-       int             colormap;               // entity shirt and pants colors
-       int             effects;                // light, particles, etc
-       int             skinnum;                // for Alias models
-       int             flags;                  // render flags
-
-       // these are copied from the persistent data
-       int             frame1;                 // frame that the model is interpolating from
-       int             frame2;                 // frame that the model is interpolating to
-       double  framelerp;              // interpolation factor, usually computed from frame2time
-       double  frame1time;             // time frame1 began playing (for framegroup animations)
-       double  frame2time;             // time frame2 began playing (for framegroup animations)
-
-       // calculated by the renderer (but not persistent)
-       int             visframe;               // if visframe == r_framecount, it is visible
-       vec3_t  mins, maxs;             // calculated during R_AddModelEntities
-       frameblend_t    frameblend[4]; // 4 frame numbers (-1 if not used) and their blending scalers (0-1), if interpolation is not desired, use frame instead
-}
-entity_render_t;
-
-typedef struct entity_persistent_s
-{
-       // particles
-       vec3_t  trail_origin;   // trail rendering
-       float   trail_time;             // trail rendering
-
-       // interpolated animation
-       int             modelindex;             // lerp resets when model changes
-       int             frame1;                 // frame that the model is interpolating from
-       int             frame2;                 // frame that the model is interpolating to
-       double  framelerp;              // interpolation factor, usually computed from frame2time
-       double  frame1time;             // time frame1 began playing (for framegroup animations)
-       double  frame2time;             // time frame2 began playing (for framegroup animations)
-}
-entity_persistent_t;
-
-typedef struct entity_s
-{
-       entity_state_t state_baseline;  // baseline state (default values)
-       entity_state_t state_previous;  // previous state (interpolating from this)
-       entity_state_t state_current;   // current state (interpolating to this)
-
-       entity_persistent_t persistent; // used for regenerating parts of render
-
-       entity_render_t render; // the only data the renderer should know about
-}
-entity_t;
-
 typedef struct
 {
        // area to render in
@@ -137,12 +84,20 @@ typedef struct
        // view point
        vec3_t  vieworg;
        vec3_t  viewangles;
+
+       int numdecals;
+       renderdecal_t *decals;
+
+       // LordHavoc: this will be enabled at some point, taking the place of cl_visedicts
+       int numentities;
+       entity_render_t *entities;
+
+       int numparticles;
+       struct renderparticle_s *particles;
 }
 refdef_t;
 
-extern qboolean hlbsp;
 //extern       qboolean        r_cache_thrash;         // compatability
-extern vec3_t          modelorg;
 extern entity_render_t *currentrenderentity;
 extern int                     r_framecount;
 extern mplane_t        frustum[4];
@@ -161,6 +116,8 @@ extern      vec3_t  r_origin;
 // screen size info
 //
 extern refdef_t        r_refdef;
+
+
 extern mleaf_t         *r_viewleaf, *r_oldviewleaf;
 extern unsigned short  d_lightstylevalue[256]; // 8.8 fraction of base light value
 
@@ -179,49 +136,30 @@ extern    cvar_t  r_waterripple;
 void R_Init (void);
 void R_RenderView (void); // must set r_refdef first
 
-// LordHavoc: changed this for sake of GLQuake
+
 void R_InitSky (byte *src, int bytesperpixel); // called at level load
 
 //int R_VisibleCullBox (vec3_t mins, vec3_t maxs);
 
 void R_NewMap (void);
 
-#include "r_decals.h"
-
-void R_ParseParticleEffect (void);
-void R_RunParticleEffect (vec3_t org, vec3_t dir, int color, int count);
-void R_RocketTrail (vec3_t start, vec3_t end, int type, entity_t *ent);
-void R_RocketTrail2 (vec3_t start, vec3_t end, int type, entity_t *ent);
-void R_SparkShower (vec3_t org, vec3_t dir, int count);
-void R_BloodPuff (vec3_t org, vec3_t vel, int count);
-void R_FlameCube (vec3_t mins, vec3_t maxs, int count);
-void R_Flames (vec3_t org, vec3_t vel, int count);
-
-void R_EntityParticles (entity_t *ent);
-void R_BlobExplosion (vec3_t org);
-void R_ParticleExplosion (vec3_t org, int smoke);
-void R_ParticleExplosion2 (vec3_t org, int colorStart, int colorLength);
-void R_LavaSplash (vec3_t org);
-void R_TeleportSplash (vec3_t org);
-
-void R_NewExplosion(vec3_t org);
-
-void R_PushDlights (void);
-void R_DrawWorld (void);
-//void R_RenderDlights (void);
-void R_DrawParticles (void);
-void R_MoveParticles (void);
-void R_DrawExplosions (void);
-void R_MoveExplosions (void);
+void R_Decals_Init(void);
+void R_DrawDecals(void);
+
+void R_DrawWorld(void);
+void R_SetupForWorldRendering(void);
+void R_MarkWorldLights(void);
+void R_PrepareSurfaces(void);
+void R_DrawSurfacesAll(void);
+void R_DrawPortals(void);
+void R_DrawParticles(void);
+void R_DrawExplosions(void);
 
 #include "r_clip.h"
 
 // LordHavoc: vertex transform
 #include "transform.h"
 
-// LordHavoc: transparent polygon system
-#include "gl_poly.h"
-
 #define gl_solid_format 3
 #define gl_alpha_format 4
 
@@ -244,10 +182,8 @@ extern qboolean lighthalf;
 
 #include "r_lerpanim.h"
 
-void GL_LockArray(int first, int count);
-void GL_UnlockArray(void);
-
-void R_DrawBrushModel (void);
+void R_DrawBrushModelSky (void);
+void R_DrawBrushModelNormal (void);
 void R_DrawAliasModel (void);
 void R_DrawSpriteModel (void);
 
@@ -255,11 +191,29 @@ void R_ClipSprite (void);
 void R_Entity_Callback(void *data, void *junk);
 
 extern cvar_t r_render;
-extern cvar_t r_upload;
 extern cvar_t r_ser;
 #include "image.h"
 
-// if contents is not zero, it will impact on content changes
-// (leafs matching contents are considered empty, others are solid)
-extern int traceline_endcontents; // set by TraceLine
-float TraceLine (vec3_t start, vec3_t end, vec3_t impact, vec3_t normal, int contents);
+extern cvar_t r_multitexture;
+extern cvar_t gl_dither;
+
+// FIXME: this should live in the backend only
+void GL_LockArray(int first, int count);
+void GL_UnlockArray(void);
+
+#include "gl_backend.h"
+
+#include "r_light.h"
+
+extern rtexture_t *particlefonttexture;
+
+// particletexture_t is a rectangle in the particlefonttexture
+typedef struct
+{
+       float s1, t1, s2, t2;
+}
+particletexture_t;
+
+#define MAX_PARTICLETEXTURES 64
+// [0] is normal, [1] is fog, they may be the same
+extern particletexture_t particletexture[MAX_PARTICLETEXTURES][2];
diff --git a/sbar.c b/sbar.c
index 018cbf9eb3863054860fc3d3aefd2a0dc329cd29..683fcd3d22d6af0da1846c5dbe3b90d8dc89ef2d 100644 (file)
--- a/sbar.c
+++ b/sbar.c
@@ -8,7 +8,7 @@ of the License, or (at your option) any later version.
 
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 See the GNU General Public License for more details.
 
@@ -21,47 +21,80 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 #include "quakedef.h"
 
+typedef struct
+{
+       char name[16];
+       qpic_t *qpic;
+}
+sbarpic_t;
+
+static sbarpic_t sbarpics[256];
+static int numsbarpics;
+
+static sbarpic_t *Sbar_NewPic(char *name)
+{
+       strcpy(sbarpics[numsbarpics].name, name);
+       sbarpics[numsbarpics].qpic = NULL;
+       return sbarpics + (numsbarpics++);
+}
+
+static qpic_t *Sbar_GetQPic(sbarpic_t *p)
+{
+       if (!p->qpic)
+               p->qpic = Draw_CachePic(p->name);
+       return p->qpic;
+}
+
+static void Sbar_ClearPics(void)
+{
+       int i;
+       for (i = 0;i < numsbarpics;i++)
+               sbarpics[i].qpic = NULL;
+}
+
+sbarpic_t *sb_disc;
+
+#define STAT_MINUS 10 // num frame for '-' stats digit
+sbarpic_t *sb_nums[2][11];
+sbarpic_t *sb_colon, *sb_slash;
+sbarpic_t *sb_ibar;
+sbarpic_t *sb_sbar;
+sbarpic_t *sb_scorebar;
 
-#define STAT_MINUS             10      // num frame for '-' stats digit
-qpic_t         *sb_nums[2][11];
-qpic_t         *sb_colon, *sb_slash;
-qpic_t         *sb_ibar;
-qpic_t         *sb_sbar;
-qpic_t         *sb_scorebar;
+sbarpic_t *sb_weapons[7][8]; // 0 is active, 1 is owned, 2-5 are flashes
+sbarpic_t *sb_ammo[4];
+sbarpic_t *sb_sigil[4];
+sbarpic_t *sb_armor[3];
+sbarpic_t *sb_items[32];
 
-qpic_t      *sb_weapons[7][8];   // 0 is active, 1 is owned, 2-5 are flashes
-qpic_t      *sb_ammo[4];
-qpic_t         *sb_sigil[4];
-qpic_t         *sb_armor[3];
-qpic_t         *sb_items[32];
+// 0 is gibbed, 1 is dead, 2-6 are alive
+// 0 is static, 1 is temporary animation
+sbarpic_t *sb_faces[7][2];
 
-qpic_t *sb_faces[7][2];                // 0 is gibbed, 1 is dead, 2-6 are alive
-                                                       // 0 is static, 1 is temporary animation
-qpic_t *sb_face_invis;
-qpic_t *sb_face_quad;
-qpic_t *sb_face_invuln;
-qpic_t *sb_face_invis_invuln;
+sbarpic_t *sb_face_invis;
+sbarpic_t *sb_face_quad;
+sbarpic_t *sb_face_invuln;
+sbarpic_t *sb_face_invis_invuln;
 
-qboolean       sb_showscores;
+qboolean sb_showscores;
 
-int                    sb_lines;                       // scan lines to draw
+int sb_lines;                  // scan lines to draw
 
-qpic_t      *rsb_invbar[2];
-qpic_t      *rsb_weapons[5];
-qpic_t      *rsb_items[2];
-qpic_t      *rsb_ammo[3];
-qpic_t      *rsb_teambord;             // PGM 01/19/97 - team color border
+sbarpic_t *rsb_invbar[2];
+sbarpic_t *rsb_weapons[5];
+sbarpic_t *rsb_items[2];
+sbarpic_t *rsb_ammo[3];
+sbarpic_t *rsb_teambord;               // PGM 01/19/97 - team color border
 
 //MED 01/04/97 added two more weapons + 3 alternates for grenade launcher
-qpic_t      *hsb_weapons[7][5];   // 0 is active, 1 is owned, 2-5 are flashes
+sbarpic_t *hsb_weapons[7][5];   // 0 is active, 1 is owned, 2-5 are flashes
 //MED 01/04/97 added array to simplify weapon parsing
-int         hipweapons[4] = {HIT_LASER_CANNON_BIT,HIT_MJOLNIR_BIT,4,HIT_PROXIMITY_GUN_BIT};
+int hipweapons[4] = {HIT_LASER_CANNON_BIT,HIT_MJOLNIR_BIT,4,HIT_PROXIMITY_GUN_BIT};
 //MED 01/04/97 added hipnotic items array
-qpic_t      *hsb_items[2];
+sbarpic_t *hsb_items[2];
 
 void Sbar_MiniDeathmatchOverlay (void);
 void Sbar_DeathmatchOverlay (void);
-void M_DrawPic (int x, int y, qpic_t *pic);
 
 /*
 ===============
@@ -89,6 +122,20 @@ void Sbar_DontShowScores (void)
        sb_showscores = false;
 }
 
+void sbar_start(void)
+{
+       Sbar_ClearPics();
+}
+
+void sbar_shutdown(void)
+{
+       Sbar_ClearPics();
+}
+
+void sbar_newmap(void)
+{
+}
+
 /*
 ===============
 Sbar_Init
@@ -96,141 +143,146 @@ Sbar_Init
 */
 void Sbar_Init (void)
 {
-       int             i;
+       int i;
+
+       Cmd_AddCommand ("+showscores", Sbar_ShowScores);
+       Cmd_AddCommand ("-showscores", Sbar_DontShowScores);
+
+       numsbarpics = 0;
+
+       sb_disc = Sbar_NewPic("disc");
 
        for (i=0 ; i<10 ; i++)
        {
-               sb_nums[0][i] = Draw_PicFromWad (va("num_%i",i));
-               sb_nums[1][i] = Draw_PicFromWad (va("anum_%i",i));
+               sb_nums[0][i] = Sbar_NewPic (va("num_%i",i));
+               sb_nums[1][i] = Sbar_NewPic (va("anum_%i",i));
        }
 
-       sb_nums[0][10] = Draw_PicFromWad ("num_minus");
-       sb_nums[1][10] = Draw_PicFromWad ("anum_minus");
+       sb_nums[0][10] = Sbar_NewPic ("num_minus");
+       sb_nums[1][10] = Sbar_NewPic ("anum_minus");
 
-       sb_colon = Draw_PicFromWad ("num_colon");
-       sb_slash = Draw_PicFromWad ("num_slash");
+       sb_colon = Sbar_NewPic ("num_colon");
+       sb_slash = Sbar_NewPic ("num_slash");
 
-       sb_weapons[0][0] = Draw_PicFromWad ("inv_shotgun");
-       sb_weapons[0][1] = Draw_PicFromWad ("inv_sshotgun");
-       sb_weapons[0][2] = Draw_PicFromWad ("inv_nailgun");
-       sb_weapons[0][3] = Draw_PicFromWad ("inv_snailgun");
-       sb_weapons[0][4] = Draw_PicFromWad ("inv_rlaunch");
-       sb_weapons[0][5] = Draw_PicFromWad ("inv_srlaunch");
-       sb_weapons[0][6] = Draw_PicFromWad ("inv_lightng");
+       sb_weapons[0][0] = Sbar_NewPic ("inv_shotgun");
+       sb_weapons[0][1] = Sbar_NewPic ("inv_sshotgun");
+       sb_weapons[0][2] = Sbar_NewPic ("inv_nailgun");
+       sb_weapons[0][3] = Sbar_NewPic ("inv_snailgun");
+       sb_weapons[0][4] = Sbar_NewPic ("inv_rlaunch");
+       sb_weapons[0][5] = Sbar_NewPic ("inv_srlaunch");
+       sb_weapons[0][6] = Sbar_NewPic ("inv_lightng");
 
-       sb_weapons[1][0] = Draw_PicFromWad ("inv2_shotgun");
-       sb_weapons[1][1] = Draw_PicFromWad ("inv2_sshotgun");
-       sb_weapons[1][2] = Draw_PicFromWad ("inv2_nailgun");
-       sb_weapons[1][3] = Draw_PicFromWad ("inv2_snailgun");
-       sb_weapons[1][4] = Draw_PicFromWad ("inv2_rlaunch");
-       sb_weapons[1][5] = Draw_PicFromWad ("inv2_srlaunch");
-       sb_weapons[1][6] = Draw_PicFromWad ("inv2_lightng");
+       sb_weapons[1][0] = Sbar_NewPic ("inv2_shotgun");
+       sb_weapons[1][1] = Sbar_NewPic ("inv2_sshotgun");
+       sb_weapons[1][2] = Sbar_NewPic ("inv2_nailgun");
+       sb_weapons[1][3] = Sbar_NewPic ("inv2_snailgun");
+       sb_weapons[1][4] = Sbar_NewPic ("inv2_rlaunch");
+       sb_weapons[1][5] = Sbar_NewPic ("inv2_srlaunch");
+       sb_weapons[1][6] = Sbar_NewPic ("inv2_lightng");
 
        for (i=0 ; i<5 ; i++)
        {
-               sb_weapons[2+i][0] = Draw_PicFromWad (va("inva%i_shotgun",i+1));
-               sb_weapons[2+i][1] = Draw_PicFromWad (va("inva%i_sshotgun",i+1));
-               sb_weapons[2+i][2] = Draw_PicFromWad (va("inva%i_nailgun",i+1));
-               sb_weapons[2+i][3] = Draw_PicFromWad (va("inva%i_snailgun",i+1));
-               sb_weapons[2+i][4] = Draw_PicFromWad (va("inva%i_rlaunch",i+1));
-               sb_weapons[2+i][5] = Draw_PicFromWad (va("inva%i_srlaunch",i+1));
-               sb_weapons[2+i][6] = Draw_PicFromWad (va("inva%i_lightng",i+1));
+               sb_weapons[2+i][0] = Sbar_NewPic (va("inva%i_shotgun",i+1));
+               sb_weapons[2+i][1] = Sbar_NewPic (va("inva%i_sshotgun",i+1));
+               sb_weapons[2+i][2] = Sbar_NewPic (va("inva%i_nailgun",i+1));
+               sb_weapons[2+i][3] = Sbar_NewPic (va("inva%i_snailgun",i+1));
+               sb_weapons[2+i][4] = Sbar_NewPic (va("inva%i_rlaunch",i+1));
+               sb_weapons[2+i][5] = Sbar_NewPic (va("inva%i_srlaunch",i+1));
+               sb_weapons[2+i][6] = Sbar_NewPic (va("inva%i_lightng",i+1));
        }
 
-       sb_ammo[0] = Draw_PicFromWad ("sb_shells");
-       sb_ammo[1] = Draw_PicFromWad ("sb_nails");
-       sb_ammo[2] = Draw_PicFromWad ("sb_rocket");
-       sb_ammo[3] = Draw_PicFromWad ("sb_cells");
-
-       sb_armor[0] = Draw_PicFromWad ("sb_armor1");
-       sb_armor[1] = Draw_PicFromWad ("sb_armor2");
-       sb_armor[2] = Draw_PicFromWad ("sb_armor3");
-
-       sb_items[0] = Draw_PicFromWad ("sb_key1");
-       sb_items[1] = Draw_PicFromWad ("sb_key2");
-       sb_items[2] = Draw_PicFromWad ("sb_invis");
-       sb_items[3] = Draw_PicFromWad ("sb_invuln");
-       sb_items[4] = Draw_PicFromWad ("sb_suit");
-       sb_items[5] = Draw_PicFromWad ("sb_quad");
-
-       sb_sigil[0] = Draw_PicFromWad ("sb_sigil1");
-       sb_sigil[1] = Draw_PicFromWad ("sb_sigil2");
-       sb_sigil[2] = Draw_PicFromWad ("sb_sigil3");
-       sb_sigil[3] = Draw_PicFromWad ("sb_sigil4");
-
-       sb_faces[4][0] = Draw_PicFromWad ("face1");
-       sb_faces[4][1] = Draw_PicFromWad ("face_p1");
-       sb_faces[3][0] = Draw_PicFromWad ("face2");
-       sb_faces[3][1] = Draw_PicFromWad ("face_p2");
-       sb_faces[2][0] = Draw_PicFromWad ("face3");
-       sb_faces[2][1] = Draw_PicFromWad ("face_p3");
-       sb_faces[1][0] = Draw_PicFromWad ("face4");
-       sb_faces[1][1] = Draw_PicFromWad ("face_p4");
-       sb_faces[0][0] = Draw_PicFromWad ("face5");
-       sb_faces[0][1] = Draw_PicFromWad ("face_p5");
-
-       sb_face_invis = Draw_PicFromWad ("face_invis");
-       sb_face_invuln = Draw_PicFromWad ("face_invul2");
-       sb_face_invis_invuln = Draw_PicFromWad ("face_inv2");
-       sb_face_quad = Draw_PicFromWad ("face_quad");
-
-       Cmd_AddCommand ("+showscores", Sbar_ShowScores);
-       Cmd_AddCommand ("-showscores", Sbar_DontShowScores);
-
-       sb_sbar = Draw_PicFromWad ("sbar");
-       sb_ibar = Draw_PicFromWad ("ibar");
-       sb_scorebar = Draw_PicFromWad ("scorebar");
+       sb_ammo[0] = Sbar_NewPic ("sb_shells");
+       sb_ammo[1] = Sbar_NewPic ("sb_nails");
+       sb_ammo[2] = Sbar_NewPic ("sb_rocket");
+       sb_ammo[3] = Sbar_NewPic ("sb_cells");
+
+       sb_armor[0] = Sbar_NewPic ("sb_armor1");
+       sb_armor[1] = Sbar_NewPic ("sb_armor2");
+       sb_armor[2] = Sbar_NewPic ("sb_armor3");
+
+       sb_items[0] = Sbar_NewPic ("sb_key1");
+       sb_items[1] = Sbar_NewPic ("sb_key2");
+       sb_items[2] = Sbar_NewPic ("sb_invis");
+       sb_items[3] = Sbar_NewPic ("sb_invuln");
+       sb_items[4] = Sbar_NewPic ("sb_suit");
+       sb_items[5] = Sbar_NewPic ("sb_quad");
+
+       sb_sigil[0] = Sbar_NewPic ("sb_sigil1");
+       sb_sigil[1] = Sbar_NewPic ("sb_sigil2");
+       sb_sigil[2] = Sbar_NewPic ("sb_sigil3");
+       sb_sigil[3] = Sbar_NewPic ("sb_sigil4");
+
+       sb_faces[4][0] = Sbar_NewPic ("face1");
+       sb_faces[4][1] = Sbar_NewPic ("face_p1");
+       sb_faces[3][0] = Sbar_NewPic ("face2");
+       sb_faces[3][1] = Sbar_NewPic ("face_p2");
+       sb_faces[2][0] = Sbar_NewPic ("face3");
+       sb_faces[2][1] = Sbar_NewPic ("face_p3");
+       sb_faces[1][0] = Sbar_NewPic ("face4");
+       sb_faces[1][1] = Sbar_NewPic ("face_p4");
+       sb_faces[0][0] = Sbar_NewPic ("face5");
+       sb_faces[0][1] = Sbar_NewPic ("face_p5");
+
+       sb_face_invis = Sbar_NewPic ("face_invis");
+       sb_face_invuln = Sbar_NewPic ("face_invul2");
+       sb_face_invis_invuln = Sbar_NewPic ("face_inv2");
+       sb_face_quad = Sbar_NewPic ("face_quad");
+
+       sb_sbar = Sbar_NewPic ("sbar");
+       sb_ibar = Sbar_NewPic ("ibar");
+       sb_scorebar = Sbar_NewPic ("scorebar");
 
 //MED 01/04/97 added new hipnotic weapons
        if (gamemode == GAME_HIPNOTIC)
        {
-               hsb_weapons[0][0] = Draw_PicFromWad ("inv_laser");
-               hsb_weapons[0][1] = Draw_PicFromWad ("inv_mjolnir");
-               hsb_weapons[0][2] = Draw_PicFromWad ("inv_gren_prox");
-               hsb_weapons[0][3] = Draw_PicFromWad ("inv_prox_gren");
-               hsb_weapons[0][4] = Draw_PicFromWad ("inv_prox");
-
-               hsb_weapons[1][0] = Draw_PicFromWad ("inv2_laser");
-               hsb_weapons[1][1] = Draw_PicFromWad ("inv2_mjolnir");
-               hsb_weapons[1][2] = Draw_PicFromWad ("inv2_gren_prox");
-               hsb_weapons[1][3] = Draw_PicFromWad ("inv2_prox_gren");
-               hsb_weapons[1][4] = Draw_PicFromWad ("inv2_prox");
+               hsb_weapons[0][0] = Sbar_NewPic ("inv_laser");
+               hsb_weapons[0][1] = Sbar_NewPic ("inv_mjolnir");
+               hsb_weapons[0][2] = Sbar_NewPic ("inv_gren_prox");
+               hsb_weapons[0][3] = Sbar_NewPic ("inv_prox_gren");
+               hsb_weapons[0][4] = Sbar_NewPic ("inv_prox");
+
+               hsb_weapons[1][0] = Sbar_NewPic ("inv2_laser");
+               hsb_weapons[1][1] = Sbar_NewPic ("inv2_mjolnir");
+               hsb_weapons[1][2] = Sbar_NewPic ("inv2_gren_prox");
+               hsb_weapons[1][3] = Sbar_NewPic ("inv2_prox_gren");
+               hsb_weapons[1][4] = Sbar_NewPic ("inv2_prox");
 
                for (i=0 ; i<5 ; i++)
                {
-                       hsb_weapons[2+i][0] = Draw_PicFromWad (va("inva%i_laser",i+1));
-                       hsb_weapons[2+i][1] = Draw_PicFromWad (va("inva%i_mjolnir",i+1));
-                       hsb_weapons[2+i][2] = Draw_PicFromWad (va("inva%i_gren_prox",i+1));
-                       hsb_weapons[2+i][3] = Draw_PicFromWad (va("inva%i_prox_gren",i+1));
-                       hsb_weapons[2+i][4] = Draw_PicFromWad (va("inva%i_prox",i+1));
+                       hsb_weapons[2+i][0] = Sbar_NewPic (va("inva%i_laser",i+1));
+                       hsb_weapons[2+i][1] = Sbar_NewPic (va("inva%i_mjolnir",i+1));
+                       hsb_weapons[2+i][2] = Sbar_NewPic (va("inva%i_gren_prox",i+1));
+                       hsb_weapons[2+i][3] = Sbar_NewPic (va("inva%i_prox_gren",i+1));
+                       hsb_weapons[2+i][4] = Sbar_NewPic (va("inva%i_prox",i+1));
                }
 
-               hsb_items[0] = Draw_PicFromWad ("sb_wsuit");
-               hsb_items[1] = Draw_PicFromWad ("sb_eshld");
+               hsb_items[0] = Sbar_NewPic ("sb_wsuit");
+               hsb_items[1] = Sbar_NewPic ("sb_eshld");
        }
-
        else if (gamemode == GAME_ROGUE)
        {
-               rsb_invbar[0] = Draw_PicFromWad ("r_invbar1");
-               rsb_invbar[1] = Draw_PicFromWad ("r_invbar2");
+               rsb_invbar[0] = Sbar_NewPic ("r_invbar1");
+               rsb_invbar[1] = Sbar_NewPic ("r_invbar2");
 
-               rsb_weapons[0] = Draw_PicFromWad ("r_lava");
-               rsb_weapons[1] = Draw_PicFromWad ("r_superlava");
-               rsb_weapons[2] = Draw_PicFromWad ("r_gren");
-               rsb_weapons[3] = Draw_PicFromWad ("r_multirock");
-               rsb_weapons[4] = Draw_PicFromWad ("r_plasma");
+               rsb_weapons[0] = Sbar_NewPic ("r_lava");
+               rsb_weapons[1] = Sbar_NewPic ("r_superlava");
+               rsb_weapons[2] = Sbar_NewPic ("r_gren");
+               rsb_weapons[3] = Sbar_NewPic ("r_multirock");
+               rsb_weapons[4] = Sbar_NewPic ("r_plasma");
 
-               rsb_items[0] = Draw_PicFromWad ("r_shield1");
-               rsb_items[1] = Draw_PicFromWad ("r_agrav1");
+               rsb_items[0] = Sbar_NewPic ("r_shield1");
+               rsb_items[1] = Sbar_NewPic ("r_agrav1");
 
 // PGM 01/19/97 - team color border
-               rsb_teambord = Draw_PicFromWad ("r_teambord");
+               rsb_teambord = Sbar_NewPic ("r_teambord");
 // PGM 01/19/97 - team color border
 
-               rsb_ammo[0] = Draw_PicFromWad ("r_ammolava");
-               rsb_ammo[1] = Draw_PicFromWad ("r_ammomulti");
-               rsb_ammo[2] = Draw_PicFromWad ("r_ammoplasma");
+               rsb_ammo[0] = Sbar_NewPic ("r_ammolava");
+               rsb_ammo[1] = Sbar_NewPic ("r_ammomulti");
+               rsb_ammo[2] = Sbar_NewPic ("r_ammoplasma");
        }
+
+       R_RegisterModule("sbar", sbar_start, sbar_shutdown, sbar_newmap);
 }
 
 
@@ -238,26 +290,22 @@ void Sbar_Init (void)
 
 // drawing routines are relative to the status bar location
 
+int sbar_x, sbar_y;
+
 /*
 =============
 Sbar_DrawPic
 =============
 */
-void Sbar_DrawPic (int x, int y, qpic_t *pic)
+void Sbar_DrawPic (int x, int y, sbarpic_t *sbarpic)
 {
-       if (cl.gametype == GAME_DEATHMATCH)
-               Draw_Pic (x, y + (vid.conheight-SBAR_HEIGHT), pic);
-       else
-               Draw_Pic (x + ((vid.conwidth - 320)>>1), y + (vid.conheight-SBAR_HEIGHT), pic);
+       Draw_Pic (sbar_x + x, sbar_y + y, Sbar_GetQPic(sbarpic));
 }
 
 void Draw_AlphaPic (int x, int y, qpic_t *pic, float alpha);
-void Sbar_DrawAlphaPic (int x, int y, qpic_t *pic, float alpha)
+void Sbar_DrawAlphaPic (int x, int y, sbarpic_t *sbarpic, float alpha)
 {
-       if (cl.gametype == GAME_DEATHMATCH)
-               Draw_AlphaPic (x, y + (vid.conheight-SBAR_HEIGHT), pic, alpha);
-       else
-               Draw_AlphaPic (x + ((vid.conwidth - 320)>>1), y + (vid.conheight-SBAR_HEIGHT), pic, alpha);
+       Draw_AlphaPic (sbar_x + x, sbar_y + y, Sbar_GetQPic(sbarpic), alpha);
 }
 
 /*
@@ -269,10 +317,7 @@ Draws one solid graphics character
 */
 void Sbar_DrawCharacter (int x, int y, int num)
 {
-       if (cl.gametype == GAME_DEATHMATCH)
-               Draw_Character ( x + 4 , y + vid.conheight-SBAR_HEIGHT, num);
-       else
-               Draw_Character ( x + ((vid.conwidth - 320)>>1) + 4 , y + vid.conheight-SBAR_HEIGHT, num);
+       Draw_Character (sbar_x + x + 4 , sbar_y + y, num);
 }
 
 /*
@@ -282,12 +327,23 @@ Sbar_DrawString
 */
 void Sbar_DrawString (int x, int y, char *str)
 {
-       if (cl.gametype == GAME_DEATHMATCH)
-               Draw_String (x, y+ vid.conheight-SBAR_HEIGHT, str, 0);
-       else
-               Draw_String (x + ((vid.conwidth - 320)>>1), y+ vid.conheight-SBAR_HEIGHT, str, 0);
+       Draw_String (sbar_x + x, sbar_y + y, str, 0);
 }
 
+int pow10table[10] =
+{
+       1,
+       10,
+       100,
+       1000,
+       10000,
+       100000,
+       1000000,
+       10000000,
+       100000000,
+       1000000000,
+};
+
 /*
 =============
 Sbar_itoa
@@ -295,9 +351,8 @@ Sbar_itoa
 */
 int Sbar_itoa (int num, char *buf)
 {
-       char    *str;
-       int             pow10;
-       int             dig;
+       int i;
+       char *str;
 
        str = buf;
 
@@ -307,20 +362,22 @@ int Sbar_itoa (int num, char *buf)
                num = -num;
        }
 
-       for (pow10 = 10 ; num >= pow10 ; pow10 *= 10)
-       ;
+       for (i = 9;i > 0 && num < pow10table[i];i--);
 
-       do
+       for (;i >= 0;i--)
        {
-               pow10 /= 10;
-               dig = num/pow10;
-               *str++ = '0'+dig;
-               num -= dig*pow10;
-       } while (pow10 != 1);
+               *str = '0';
+               while (num >= pow10table[i])
+               {
+                       num -= pow10table[i];
+                       (*str)++;
+               }
+               str++;
+       }
 
        *str = 0;
 
-       return str-buf;
+       return str - buf;
 }
 
 
@@ -331,7 +388,7 @@ Sbar_DrawNum
 */
 void Sbar_DrawNum (int x, int y, int num, int digits, int color)
 {
-       char                    str[12];
+       char                    str[16];
        char                    *ptr;
        int                             l, frame;
 
@@ -349,7 +406,7 @@ void Sbar_DrawNum (int x, int y, int num, int digits, int color)
                else
                        frame = *ptr -'0';
 
-               Sbar_DrawPic (x,y,sb_nums[color][frame]);
+               Sbar_DrawPic (x, y, sb_nums[color][frame]);
                x += 24;
                ptr++;
        }
@@ -628,8 +685,7 @@ void Sbar_DrawFrags (void)
 {
        int                             i, k, l;
        int                             top, bottom;
-       int                             x, y, f;
-       int                             xofs;
+       int                             x, f;
        char                    num[12];
        scoreboard_t    *s;
 
@@ -638,14 +694,9 @@ void Sbar_DrawFrags (void)
 // draw the text
        l = scoreboardlines <= 4 ? scoreboardlines : 4;
 
-       x = 23;
-       if (cl.gametype == GAME_DEATHMATCH)
-               xofs = 0;
-       else
-               xofs = (vid.conwidth - 320)>>1;
-       y = vid.conheight - SBAR_HEIGHT - 23;
+       x = 23 * 8;
 
-       for (i=0 ; i<l ; i++)
+       for (i = 0;i < l;i++)
        {
                k = fragsort[i];
                s = &cl.scores[k];
@@ -656,23 +707,23 @@ void Sbar_DrawFrags (void)
                top = (s->colors & 0xf0) + 8;
                bottom = ((s->colors & 15)<<4) + 8;
 
-               Draw_Fill (xofs + x*8 + 10, y, 28, 4, top);
-               Draw_Fill (xofs + x*8 + 10, y+4, 28, 3, bottom);
+               Draw_Fill (sbar_x + x + 10, sbar_y     - 23, 28, 4, top);
+               Draw_Fill (sbar_x + x + 10, sbar_y + 4 - 23, 28, 3, bottom);
 
        // draw number
                f = s->frags;
                sprintf (num, "%3i",f);
 
-               Sbar_DrawCharacter ( (x+1)*8 , -24, num[0]);
-               Sbar_DrawCharacter ( (x+2)*8 , -24, num[1]);
-               Sbar_DrawCharacter ( (x+3)*8 , -24, num[2]);
+               Sbar_DrawCharacter (x +  8, -24, num[0]);
+               Sbar_DrawCharacter (x + 16, -24, num[1]);
+               Sbar_DrawCharacter (x + 24, -24, num[2]);
 
                if (k == cl.viewentity - 1)
                {
-                       Sbar_DrawCharacter (x*8+2, -24, 16);
-                       Sbar_DrawCharacter ( (x+4)*8-4, -24, 17);
+                       Sbar_DrawCharacter ( x      + 2, -24, 16);
+                       Sbar_DrawCharacter ( x + 32 - 4, -24, 17);
                }
-               x+=4;
+               x += 32;
        }
 }
 
@@ -690,10 +741,9 @@ void Sbar_DrawFace (void)
 
 // PGM 01/19/97 - team color drawing
 // PGM 03/02/97 - fixed so color swatch only appears in CTF modes
-       if (gamemode == GAME_ROGUE && (cl.maxclients != 1) && (teamplay.value > 3) && (teamplay.value < 7))
+       if (gamemode == GAME_ROGUE && (cl.maxclients != 1) && (teamplay.integer > 3) && (teamplay.integer < 7))
        {
                int                             top, bottom;
-               int                             xofs;
                char                    num[12];
                scoreboard_t    *s;
 
@@ -702,14 +752,9 @@ void Sbar_DrawFace (void)
                top = (s->colors & 0xf0) + 8;
                bottom = ((s->colors & 15)<<4) + 8;
 
-               if (cl.gametype == GAME_DEATHMATCH)
-                       xofs = 113;
-               else
-                       xofs = ((vid.conwidth - 320)>>1) + 113;
-
                Sbar_DrawPic (112, 0, rsb_teambord);
-               Draw_Fill (xofs, vid.conheight-SBAR_HEIGHT+3, 22, 9, top);
-               Draw_Fill (xofs, vid.conheight-SBAR_HEIGHT+12, 22, 9, bottom);
+               Draw_Fill (sbar_x + 113, vid.conheight-SBAR_HEIGHT+3, 22, 9, top);
+               Draw_Fill (sbar_x + 113, vid.conheight-SBAR_HEIGHT+12, 22, 9, bottom);
 
                // draw number
                f = s->frags;
@@ -761,6 +806,12 @@ void Sbar_Draw (void)
        if (scr_con_current == vid.conheight)
                return;         // console is full screen
 
+       sbar_y = vid.conheight - SBAR_HEIGHT;
+       if (cl.gametype == GAME_DEATHMATCH)
+               sbar_x = 0;
+       else
+               sbar_x = (vid.conwidth - 320)/2;
+
        if (sb_lines > 24)
        {
                Sbar_DrawInventory ();
@@ -790,7 +841,7 @@ void Sbar_Draw (void)
                if (cl.items & IT_INVULNERABILITY)
                {
                        Sbar_DrawNum (24, 0, 666, 3, 1);
-                       Sbar_DrawPic (0, 0, draw_disc);
+                       Sbar_DrawPic (0, 0, sb_disc);
                }
                else
                {
@@ -861,38 +912,6 @@ void Sbar_Draw (void)
 
 //=============================================================================
 
-/*
-==================
-Sbar_IntermissionNumber
-
-==================
-*/
-void Sbar_IntermissionNumber (int x, int y, int num, int digits, int color)
-{
-       char                    str[12];
-       char                    *ptr;
-       int                             l, frame;
-
-       l = Sbar_itoa (num, str);
-       ptr = str;
-       if (l > digits)
-               ptr += (l-digits);
-       if (l < digits)
-               x += (digits-l)*24;
-
-       while (*ptr)
-       {
-               if (*ptr == '-')
-                       frame = STAT_MINUS;
-               else
-                       frame = *ptr -'0';
-
-               Draw_Pic (x,y,sb_nums[color][frame]);
-               x += 24;
-               ptr++;
-       }
-}
-
 /*
 ==================
 Sbar_DeathmatchOverlay
@@ -907,7 +926,7 @@ void Sbar_DeathmatchOverlay (void)
        scoreboard_t    *s;
 
        pic = Draw_CachePic ("gfx/ranking.lmp");
-       M_DrawPic ((320-pic->width)/2, 8, pic);
+       Draw_Pic ((vid.conwidth - pic->width)/2, 8, pic);
 
 // scores
        Sbar_SortFrags ();
@@ -934,15 +953,15 @@ void Sbar_DeathmatchOverlay (void)
                total = cl.time - s->entertime;
                minutes = (int)total/60;
                n = total - minutes*60;
-               tens = n/10;
-               units = n%10;
+               tens = '0' + n/10;
+               units = '0' + n%10;
 
                fph = total ? (int) ((float) s->frags * 3600.0 / total) : 0;
                if (fph < -999) fph = -999;
                if (fph > 9999) fph = 9999;
 
                // put it together
-               sprintf (num, "%c %4i:%4i  %3i:%i%i %s", k == cl.viewentity - 1 ? 12 : ' ', (int) s->frags, fph, minutes, tens, units, s->name);
+               sprintf (num, "%c %4i:%4i %4i:%c%c %s", k == cl.viewentity - 1 ? 12 : ' ', (int) s->frags, fph, minutes, tens, units, s->name);
                Draw_String(x - 8, y, num, 0);
 
                y += 8;
@@ -1007,7 +1026,7 @@ void Sbar_MiniDeathmatchOverlay (void)
                fph = (cl.time - s->entertime) ? (int) ((float) s->frags * 3600.0 / (cl.time - s->entertime)) : 0;
                if (fph < -999) fph = -999;
                if (fph > 9999) fph = 9999;
-               
+
                // put it together
                sprintf (num, "%c%4i:%4i%c %s", k == cl.viewentity - 1 ? 16 : ' ', (int) s->frags, fph, k == cl.viewentity - 1 ? 17 : ' ', s->name);
                Draw_String(x - 8, y, num, 0);
@@ -1024,7 +1043,6 @@ Sbar_IntermissionOverlay
 */
 void Sbar_IntermissionOverlay (void)
 {
-       qpic_t  *pic;
        int             dig;
        int             num;
 
@@ -1034,27 +1052,27 @@ void Sbar_IntermissionOverlay (void)
                return;
        }
 
-       pic = Draw_CachePic ("gfx/complete.lmp");
-       Draw_Pic (64, 24, pic);
+       sbar_x = 0;
+       sbar_y = 0;
 
-       pic = Draw_CachePic ("gfx/inter.lmp");
-       Draw_Pic (0, 56, pic);
+       Draw_Pic (64, 24, Draw_CachePic ("gfx/complete.lmp"));
+       Draw_Pic (0, 56, Draw_CachePic ("gfx/inter.lmp"));
 
 // time
        dig = cl.completed_time/60;
-       Sbar_IntermissionNumber (160, 64, dig, 3, 0);
+       Sbar_DrawNum (160, 64, dig, 3, 0);
        num = cl.completed_time - dig*60;
-       Draw_Pic (234,64,sb_colon);
-       Draw_Pic (246,64,sb_nums[0][num/10]);
-       Draw_Pic (266,64,sb_nums[0][num%10]);
+       Sbar_DrawPic (234,64,sb_colon);
+       Sbar_DrawPic (246,64,sb_nums[0][num/10]);
+       Sbar_DrawPic (266,64,sb_nums[0][num%10]);
 
-       Sbar_IntermissionNumber (160, 104, cl.stats[STAT_SECRETS], 3, 0);
-       Draw_Pic (232,104,sb_slash);
-       Sbar_IntermissionNumber (240, 104, cl.stats[STAT_TOTALSECRETS], 3, 0);
+       Sbar_DrawNum (160, 104, cl.stats[STAT_SECRETS], 3, 0);
+       Sbar_DrawPic (232, 104, sb_slash);
+       Sbar_DrawNum (240, 104, cl.stats[STAT_TOTALSECRETS], 3, 0);
 
-       Sbar_IntermissionNumber (160, 144, cl.stats[STAT_MONSTERS], 3, 0);
-       Draw_Pic (232,144,sb_slash);
-       Sbar_IntermissionNumber (240, 144, cl.stats[STAT_TOTALMONSTERS], 3, 0);
+       Sbar_DrawNum (160, 144, cl.stats[STAT_MONSTERS], 3, 0);
+       Sbar_DrawPic (232, 144, sb_slash);
+       Sbar_DrawNum (240, 144, cl.stats[STAT_TOTALMONSTERS], 3, 0);
 
 }
 
@@ -1070,5 +1088,5 @@ void Sbar_FinaleOverlay (void)
        qpic_t  *pic;
 
        pic = Draw_CachePic ("gfx/finale.lmp");
-       Draw_Pic ( (vid.conwidth-pic->width)/2, 16, pic);
+       Draw_Pic((vid.conwidth - pic->width)/2, 16, pic);
 }
index 862287355bcf30a71292bb2ee99164277b333f53..aa51cbfd9c69c745f5ad9bff174620f837dcc471 100644 (file)
--- a/snd_dma.c
+++ b/snd_dma.c
@@ -64,7 +64,7 @@ int                   num_sfx;
 
 sfx_t          *ambient_sfx[NUM_AMBIENTS];
 
-int sound_started=0;
+int sound_started = 0;
 
 // FIXME: make bgmvolume/volume always be registered for sake of config saving, and add check for whether sound is enabled to menu
 cvar_t bgmvolume = {CVAR_SAVE, "bgmvolume", "1"};
@@ -147,9 +147,7 @@ void S_Startup (void)
 
                if (!rc)
                {
-#ifndef        _WIN32
                        Con_Printf("S_Startup: SNDDMA_Init failed.\n");
-#endif
                        sound_started = 0;
                        return;
                }
@@ -161,6 +159,8 @@ void S_Startup (void)
 
 void S_Play2(void);
 
+mempool_t *snd_mempool;
+
 /*
 ================
 S_Init
@@ -168,12 +168,13 @@ S_Init
 */
 void S_Init (void)
 {
-
        Con_Printf("\nSound Initialization\n");
 
        if (COM_CheckParm("-nosound"))
                return;
 
+       snd_mempool = Mem_AllocPool("sound");
+
        if (COM_CheckParm("-simsound"))
                fakedma = true;
 
@@ -209,18 +210,18 @@ void S_Init (void)
 
        snd_initialized = true;
 
+       known_sfx = Mem_Alloc(snd_mempool, MAX_SFX*sizeof(sfx_t));
+       num_sfx = 0;
+
        S_Startup ();
 
        SND_InitScaletable ();
 
-       known_sfx = Hunk_AllocName (MAX_SFX*sizeof(sfx_t), "sfx_t");
-       num_sfx = 0;
-
 // create a piece of DMA memory
 
        if (fakedma)
        {
-               shm = (void *) Hunk_AllocName(sizeof(*shm), "shm");
+               shm = (void *) Mem_Alloc(snd_mempool, sizeof(*shm));
                shm->splitbuffer = 0;
                shm->samplebits = 16;
                shm->speed = 22050;
@@ -230,7 +231,7 @@ void S_Init (void)
                shm->soundalive = true;
                shm->gamealive = true;
                shm->submission_chunk = 1;
-               shm->buffer = Hunk_AllocName(1<<16, "shmbuf");
+               shm->buffer = Mem_Alloc(snd_mempool, shm->channels * shm->samples * (shm->samplebits / 8));
        }
 
        if (!sound_started)
@@ -256,7 +257,6 @@ void S_Init (void)
 
 void S_Shutdown(void)
 {
-
        if (!sound_started)
                return;
 
@@ -267,9 +267,7 @@ void S_Shutdown(void)
        sound_started = 0;
 
        if (!fakedma)
-       {
                SNDDMA_Shutdown();
-       }
 }
 
 
@@ -327,7 +325,6 @@ void S_TouchSound (char *name)
                return;
 
        sfx = S_FindName (name);
-       Cache_Check (&sfx->cache);
 }
 
 /*
@@ -340,15 +337,15 @@ sfx_t *S_PrecacheSound (char *name)
 {
        sfx_t   *sfx;
 
-       if (!sound_started || nosound.value)
+       if (!sound_started || nosound.integer)
                return NULL;
 
        sfx = S_FindName (name);
-       
+
 // cache it in
-       if (precache.value)
+       if (precache.integer)
                S_LoadSound (sfx);
-       
+
        return sfx;
 }
 
@@ -396,8 +393,8 @@ channel_t *SND_PickChannel(int entnum, int entchannel)
        if (channels[first_to_die].sfx)
                channels[first_to_die].sfx = NULL;
 
-    return &channels[first_to_die];    
-}       
+    return &channels[first_to_die];
+}
 
 /*
 =================
@@ -425,9 +422,9 @@ void SND_Spatialize(channel_t *ch)
 
        snd = ch->sfx;
        VectorSubtract(ch->origin, listener_origin, source_vec);
-       
+
        dist = VectorNormalizeLength(source_vec) * ch->dist_mult;
-       
+
        dot = DotProduct(listener_right, source_vec);
 
        if (shm->channels == 1)
@@ -451,7 +448,7 @@ void SND_Spatialize(channel_t *ch)
        ch->leftvol = (int) (ch->master_vol * scale);
        if (ch->leftvol < 0)
                ch->leftvol = 0;
-}           
+}
 
 
 // =======================================================================
@@ -472,7 +469,7 @@ void S_StartSound(int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float f
        if (!sfx)
                return;
 
-       if (nosound.value)
+       if (nosound.integer)
                return;
 
        vol = fvol*255;
@@ -481,7 +478,7 @@ void S_StartSound(int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float f
        target_chan = SND_PickChannel(entnum, entchannel);
        if (!target_chan)
                return;
-               
+
 // spatialize
        memset (target_chan, 0, sizeof(*target_chan));
        VectorCopy(origin, target_chan->origin);
@@ -504,7 +501,7 @@ void S_StartSound(int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float f
 
        target_chan->sfx = sfx;
        target_chan->pos = 0.0;
-    target_chan->end = paintedtime + sc->length;       
+    target_chan->end = paintedtime + sc->length;
 
 // if an identical sound has also been started this frame, offset the pos
 // a bit to keep it from just making the first one louder
@@ -525,7 +522,7 @@ void S_StartSound(int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float f
                        target_chan->end -= skip;
                        break;
                }
-               
+
        }
 }
 
@@ -572,7 +569,7 @@ void S_StopAllSoundsC (void)
 void S_ClearBuffer (void)
 {
        int             clear;
-               
+
 #ifdef _WIN32
        if (!sound_started || !shm || (!shm->buffer && !pDSBuf))
 #else
@@ -615,7 +612,7 @@ void S_ClearBuffer (void)
                memset(pData, clear, shm->samples * shm->samplebits/8);
 
                pDSBuf->lpVtbl->Unlock(pDSBuf, pData, dwSize, NULL, 0);
-       
+
        }
        else
 #endif
@@ -656,13 +653,13 @@ void S_StaticSound (sfx_t *sfx, vec3_t origin, float vol, float attenuation)
                Con_Printf ("Sound %s not looped\n", sfx->name);
                return;
        }
-       
+
        ss->sfx = sfx;
        VectorCopy (origin, ss->origin);
        ss->master_vol = vol;
        ss->dist_mult = (attenuation/64) / sound_nominal_clip_dist;
-    ss->end = paintedtime + sc->length;        
-       
+    ss->end = paintedtime + sc->length;
+
        SND_Spatialize (ss);
 }
 
@@ -695,7 +692,7 @@ void S_UpdateAmbientSounds (void)
 // calc ambient sound levels
        for (ambient_channel = 0 ; ambient_channel< NUM_AMBIENTS ; ambient_channel++)
        {
-               chan = &channels[ambient_channel];      
+               chan = &channels[ambient_channel];
                chan->sfx = ambient_sfx[ambient_channel];
 
                vol = ambient_level.value * l->ambient_sound_level[ambient_channel];
@@ -715,7 +712,7 @@ void S_UpdateAmbientSounds (void)
                        if (chan->master_vol < vol)
                                chan->master_vol = vol;
                }
-               
+
                chan->leftvol = chan->rightvol = chan->master_vol;
        }
 }
@@ -742,13 +739,13 @@ void S_Update(vec3_t origin, vec3_t forward, vec3_t right, vec3_t up)
        VectorCopy(forward, listener_forward);
        VectorCopy(right, listener_right);
        VectorCopy(up, listener_up);
-       
+
 // update general area ambient sound sources
        S_UpdateAmbientSounds ();
 
        combine = NULL;
 
-// update spatialization for static and dynamic sounds 
+// update spatialization for static and dynamic sounds
        ch = channels+NUM_AMBIENTS;
        for (i=NUM_AMBIENTS ; i<total_channels; i++, ch++)
        {
@@ -760,7 +757,7 @@ void S_Update(vec3_t origin, vec3_t forward, vec3_t right, vec3_t up)
 
        // try to combine static sounds with a previous channel of the same
        // sound effect so we don't mix five torches every frame
-       
+
                if (i > MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS)
                {
                // see if it can just use the last one
@@ -776,7 +773,7 @@ void S_Update(vec3_t origin, vec3_t forward, vec3_t right, vec3_t up)
                        for (j=MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS ; j<i; j++, combine++)
                                if (combine->sfx == ch->sfx)
                                        break;
-                                       
+
                        if (j == total_channels)
                        {
                                combine = NULL;
@@ -792,14 +789,14 @@ void S_Update(vec3_t origin, vec3_t forward, vec3_t right, vec3_t up)
                                continue;
                        }
                }
-               
-               
+
+
        }
 
 //
 // debugging output
 //
-       if (snd_show.value)
+       if (snd_show.integer)
        {
                total = 0;
                ch = channels;
@@ -809,7 +806,7 @@ void S_Update(vec3_t origin, vec3_t forward, vec3_t right, vec3_t up)
                                //Con_Printf ("%3i %3i %s\n", ch->leftvol, ch->rightvol, ch->sfx->name);
                                total++;
                        }
-               
+
                Con_Printf ("----(%i)----\n", total);
        }
 
@@ -823,7 +820,7 @@ void GetSoundtime(void)
        static  int             buffers;
        static  int             oldsamplepos;
        int             fullsamples;
-       
+
        fullsamples = shm->samples / shm->channels;
 
 // it is possible to miscount buffers if it has wrapped twice between
@@ -837,7 +834,7 @@ void GetSoundtime(void)
        if (samplepos < oldsamplepos)
        {
                buffers++;                                      // buffer wrapped
-               
+
                if (paintedtime > 0x40000000)
                {       // time to chop things off to avoid 32 bit limits
                        buffers = 0;
@@ -860,7 +857,7 @@ void S_ExtraUpdate (void)
        IN_Accumulate ();
 #endif
 
-       if (snd_noextraupdate.value)
+       if (snd_noextraupdate.integer)
                return;         // don't pollute timings
        S_Update_();
 }
@@ -869,7 +866,7 @@ void S_Update_(void)
 {
        unsigned        endtime;
        int                             samps;
-       
+
        if (!sound_started || (snd_blocked > 0))
                return;
 
@@ -898,10 +895,10 @@ void S_Update_(void)
                {
                        if (pDSBuf->lpVtbl->GetStatus (pDSBuf, &dwStatus) != DD_OK)
                                Con_Printf ("Couldn't get sound buffer status\n");
-                       
+
                        if (dwStatus & DSBSTATUS_BUFFERLOST)
                                pDSBuf->lpVtbl->Restore (pDSBuf);
-                       
+
                        if (!(dwStatus & DSBSTATUS_PLAYING))
                                pDSBuf->lpVtbl->Play(pDSBuf, 0, 0, DSBPLAY_LOOPING);
                }
@@ -927,7 +924,7 @@ void S_Play(void)
        int     i;
        char name[256];
        sfx_t   *sfx;
-       
+
        i = 1;
        while (i<Cmd_Argc())
        {
@@ -950,7 +947,7 @@ void S_Play2(void)
        int     i;
        char name[256];
        sfx_t   *sfx;
-       
+
        i = 1;
        while (i<Cmd_Argc())
        {
@@ -974,7 +971,7 @@ void S_PlayVol(void)
        float vol;
        char name[256];
        sfx_t   *sfx;
-       
+
        i = 1;
        while (i<Cmd_Argc())
        {
@@ -1002,7 +999,7 @@ void S_SoundList(void)
        total = 0;
        for (sfx=known_sfx, i=0 ; i<num_sfx ; i++, sfx++)
        {
-               sc = Cache_Check (&sfx->cache);
+               sc = sfx->sfxcache;
                if (!sc)
                        continue;
                size = sc->length*sc->width*(sc->stereo+1);
@@ -1021,15 +1018,15 @@ void S_LocalSound (char *sound)
 {
        sfx_t   *sfx;
 
-       if (nosound.value)
+       if (nosound.integer)
                return;
        if (!sound_started)
                return;
-               
+
        sfx = S_PrecacheSound (sound);
        if (!sfx)
        {
-               Con_Printf ("S_LocalSound: can't cache %s\n", sound);
+               Con_Printf ("S_LocalSound: can't precache %s\n", sound);
                return;
        }
        S_StartSound (cl.viewentity, -1, sfx, vec3_origin, 1, 1);
index 09758a63057b1887860157b2b2315218433e95d1..af98487d1f830feac5de23bde3668d64c0ea7ea2 100644 (file)
--- a/snd_mem.c
+++ b/snd_mem.c
@@ -21,8 +21,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 #include "quakedef.h"
 
-int                    cache_full_cycle;
-
 byte *S_Alloc (int size);
 
 /*
@@ -39,7 +37,7 @@ void ResampleSfx (sfx_t *sfx, int inrate, byte *data, char *name)
        int             samplefrac, fracstep;
        sfxcache_t      *sc;
        
-       sc = Cache_Check (&sfx->cache);
+       sc = sfx->sfxcache;
        if (!sc)
                return;
 
@@ -260,9 +258,8 @@ sfxcache_t *S_LoadSound (sfx_t *s)
        sfxcache_t      *sc;
 
 // see if still in memory
-       sc = Cache_Check (&s->cache);
-       if (sc)
-               return sc;
+       if (s->sfxcache)
+               return s->sfxcache;
 
 //Con_Printf ("S_LoadSound: %x\n", (int)stackbuf);
 // load it in
@@ -271,7 +268,7 @@ sfxcache_t *S_LoadSound (sfx_t *s)
 
 //     Con_Printf ("loading %s\n",namebuffer);
 
-       data = COM_LoadMallocFile(namebuffer, false);
+       data = COM_LoadFile(namebuffer, false);
 
        if (!data)
        {
@@ -284,7 +281,7 @@ sfxcache_t *S_LoadSound (sfx_t *s)
        if (info.channels < 1 || info.channels > 2)
        {
                Con_Printf ("%s has an unsupported number of channels (%i)\n",s->name, info.channels);
-               qfree(data);
+               Mem_Free(data);
                return NULL;
        }
        /*
@@ -295,18 +292,21 @@ sfxcache_t *S_LoadSound (sfx_t *s)
        }
        */
 
-       stepscale = (float)info.rate / shm->speed;      
+       stepscale = (float)info.rate / shm->speed;
        len = info.samples / stepscale;
 
        len = len * info.width * info.channels;
 
-       sc = Cache_Alloc ( &s->cache, len + sizeof(sfxcache_t), s->name);
+       // FIXME: add S_UnloadSounds or something?
+       Mem_FreePool(&s->mempool);
+       s->mempool = Mem_AllocPool(s->name);
+       sc = s->sfxcache = Mem_Alloc(s->mempool, len + sizeof(sfxcache_t));
        if (!sc)
        {
-               qfree(data);
+               Mem_Free(data);
                return NULL;
        }
-       
+
        sc->length = info.samples;
        sc->loopstart = info.loopstart;
        sc->speed = info.rate;
@@ -315,7 +315,7 @@ sfxcache_t *S_LoadSound (sfx_t *s)
 
        ResampleSfx (s, sc->speed, data + info.dataofs, s->name);
 
-       qfree(data);
+       Mem_Free(data);
        return sc;
 }
 
diff --git a/sound.h b/sound.h
index 4e8cafcab16bd2d11a1d03ffef834f70160a6dfa..bf2afa71786a701de5098a54e43869228df305d1 100644 (file)
--- a/sound.h
+++ b/sound.h
@@ -8,7 +8,7 @@ of the License, or (at your option) any later version.
 
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 See the GNU General Public License for more details.
 
@@ -31,12 +31,6 @@ typedef struct
        int right;
 } portable_samplepair_t;
 
-typedef struct sfx_s
-{
-       char    name[MAX_QPATH];
-       cache_user_t    cache;
-} sfx_t;
-
 typedef struct
 {
        int     length;
@@ -47,6 +41,13 @@ typedef struct
        byte    data[1];                // variable sized
 } sfxcache_t;
 
+typedef struct sfx_s
+{
+       char    name[MAX_QPATH];
+       mempool_t       *mempool;
+       sfxcache_t      *sfxcache;
+} sfx_t;
+
 typedef struct
 {
        qboolean                gamealive;
index 1bde4d72764812699578e0101693c53ff5f37851..79c18d0ead72084718336478676eb099c803112e 100644 (file)
@@ -104,7 +104,3 @@ typedef enum { SPR_SINGLE=0, SPR_GROUP } spriteframetype_t;
 typedef struct {
        spriteframetype_t       type;
 } dspriteframetype_t;
-
-#define IDSPRITEHEADER (('P'<<24)+('S'<<16)+('D'<<8)+'I')
-                                                                                                               // little-endian "IDSP"
-
index 87d15fa61870fd5dcc37e99d7b4f327b71b8e6bc..7e4c5e96fb252609ae8b2c2661811cd9afec664f 100644 (file)
@@ -8,7 +8,7 @@ of the License, or (at your option) any later version.
 
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 See the GNU General Public License for more details.
 
@@ -85,8 +85,8 @@ loc0:
                        surf = sv.worldmodel->surfaces + node->firstsurface;
                        for (i = 0;i < node->numsurfaces;i++, surf++)
                        {
-                               if (surf->flags & SURF_DRAWTILED)
-                                       continue;       // no lightmaps
+                               if (!(surf->flags & SURF_LIGHTMAP))
+                                       continue;
 
                                ds = (int) (x * surf->texinfo->vecs[0][0] + y * surf->texinfo->vecs[0][1] + mid * surf->texinfo->vecs[0][2] + surf->texinfo->vecs[0][3]);
                                dt = (int) (x * surf->texinfo->vecs[1][0] + y * surf->texinfo->vecs[1][1] + mid * surf->texinfo->vecs[1][2] + surf->texinfo->vecs[1][3]);
@@ -139,12 +139,13 @@ loc0:
 // LordHavoc: added light checking to the server
 void SV_LightPoint (vec3_t color, vec3_t p)
 {
+       Mod_CheckLoaded(sv.worldmodel);
        if (!sv.worldmodel->lightdata)
        {
                color[0] = color[1] = color[2] = 255;
                return;
        }
-       
+
        color[0] = color[1] = color[2] = 0;
        SV_RecursiveLightPoint (color, sv.worldmodel->nodes, p[0], p[1], p[2], p[2] - 65536);
 }
index 9aa91f8dfd64b9ab5aa44d143e96785738c48c6e..429f46e716c4013c05051de2ac5df7f5df95472a 100644 (file)
--- a/sv_main.c
+++ b/sv_main.c
@@ -21,15 +21,17 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 #include "quakedef.h"
 
-cvar_t sv_pvscheckentities = {0, "sv_pvscheckentities", "1"};
-cvar_t sv_vischeckentities = {0, "sv_vischeckentities", "0"}; // extremely accurate visibility checking, but too slow
-cvar_t sv_reportvischeckentities = {0, "sv_reportvischeckentities", "0"};
-int sv_vischeckentitycullcount = 0;
+static cvar_t sv_pvscheckentities = {0, "sv_pvscheckentities", "1"};
+static cvar_t sv_vischeckentities = {0, "sv_vischeckentities", "0"}; // extremely accurate visibility checking, but too slow
+static cvar_t sv_reportvischeckentities = {0, "sv_reportvischeckentities", "0"};
+static int sv_vischeckentitycullcount = 0;
 
 server_t               sv;
 server_static_t        svs;
 
-char   localmodels[MAX_MODELS][5];                     // inline model names for precache
+static char localmodels[MAX_MODELS][5];                        // inline model names for precache
+
+static mempool_t *sv_edicts_mempool = NULL;
 
 //============================================================================
 
@@ -60,6 +62,8 @@ void SV_Init (void)
 
        for (i = 0;i < MAX_MODELS;i++)
                sprintf (localmodels[i], "*%i", i);
+
+       sv_edicts_mempool = Mem_AllocPool("edicts");
 }
 
 /*
@@ -175,13 +179,13 @@ void SV_StartSound (edict_t *entity, int channel, char *sample, int volume,
         && sv.sound_precache[sound_num] ; sound_num++)
         if (!strcmp(sample, sv.sound_precache[sound_num]))
             break;
-    
+
     if ( sound_num == MAX_SOUNDS || !sv.sound_precache[sound_num] )
     {
         Con_Printf ("SV_StartSound: %s not precached\n", sample);
         return;
     }
-    
+
        ent = NUM_FOR_EDICT(entity);
 
        channel = (ent<<3) | channel;
@@ -209,7 +213,7 @@ void SV_StartSound (edict_t *entity, int channel, char *sample, int volume,
                MSG_WriteByte (&sv.datagram, sound_num);
        for (i=0 ; i<3 ; i++)
                MSG_WriteFloatCoord (&sv.datagram, entity->v.origin[i]+0.5*(entity->v.mins[i]+entity->v.maxs[i]));
-}           
+}
 
 /*
 ==============================================================================
@@ -240,7 +244,7 @@ void SV_SendServerinfo (client_t *client)
        MSG_WriteLong (&client->message, DPPROTOCOL_VERSION);
        MSG_WriteByte (&client->message, svs.maxclients);
 
-       if (!coop.value && deathmatch.value)
+       if (!coop.integer && deathmatch.integer)
                MSG_WriteByte (&client->message, GAME_DEATHMATCH);
        else
                MSG_WriteByte (&client->message, GAME_COOP);
@@ -297,7 +301,7 @@ void SV_ConnectClient (int clientnum)
        edictnum = clientnum+1;
 
        ent = EDICT_NUM(edictnum);
-       
+
 // set up the client_t
        netconnection = client->netconnection;
 
@@ -338,7 +342,7 @@ void SV_CheckForNewClients (void)
 {
        struct qsocket_s        *ret;
        int                             i;
-               
+
 //
 // check for new connections
 //
@@ -348,7 +352,7 @@ void SV_CheckForNewClients (void)
                if (!ret)
                        break;
 
-       // 
+       //
        // init a new client structure
        //
                for (i=0 ; i<svs.maxclients ; i++)
@@ -356,10 +360,10 @@ void SV_CheckForNewClients (void)
                                break;
                if (i == svs.maxclients)
                        Sys_Error ("Host_CheckForNewClients: no free clients");
-               
+
                svs.clients[i].netconnection = ret;
-               SV_ConnectClient (i);   
-       
+               SV_ConnectClient (i);
+
                net_activeconnections++;
        }
 }
@@ -495,16 +499,18 @@ SV_WriteEntitiesToClient
 */
 void SV_WriteEntitiesToClient (client_t *client, edict_t *clent, sizebuf_t *msg)
 {
-       int             e, i, clentnum, bits, alpha, glowcolor, glowsize, scale, colormod, effects;
+       int             e, clentnum, bits, alpha, glowcolor, glowsize, scale, effects;
        byte    *pvs;
        vec3_t  org, origin, angles, entmins, entmaxs;
-       float   movelerp, moveilerp, nextfullupdate;
+       float   nextfullupdate;
        edict_t *ent;
        eval_t  *val;
        entity_state_t  *baseline; // LordHavoc: delta or startup baseline
        trace_t trace;
        model_t *model;
 
+       Mod_CheckLoaded(sv.worldmodel);
+
 // find the client's PVS
        VectorAdd (clent->v.origin, clent->v.view_ofs, org);
        pvs = SV_FatPVS (org);
@@ -561,7 +567,10 @@ void SV_WriteEntitiesToClient (client_t *client, edict_t *clent, sizebuf_t *msg)
                        bits |= U_GLOWTRAIL;
 
                if (ent->v.modelindex >= 0 && ent->v.modelindex < MAX_MODELS && pr_strings[ent->v.model])
+               {
                        model = sv.models[(int)ent->v.modelindex];
+                       Mod_CheckLoaded(model);
+               }
                else
                {
                        model = NULL;
@@ -570,67 +579,17 @@ void SV_WriteEntitiesToClient (client_t *client, edict_t *clent, sizebuf_t *msg)
                                        continue;
                }
 
-               if (ent->v.movetype == MOVETYPE_STEP && ((int) ent->v.flags & (FL_ONGROUND | FL_FLY | FL_SWIM))) // monsters have smoothed walking/flying/swimming movement
+               VectorCopy(ent->v.angles, angles);
+               if (DotProduct(ent->v.velocity, ent->v.velocity) >= 1.0f)
                {
-                       if (!ent->steplerptime || ent->steplerptime > sv.time) // when the level just started...
-                       {
-                               ent->steplerptime = sv.time;
-                               VectorCopy(ent->v.origin, ent->stepoldorigin);
-                               VectorCopy(ent->v.angles, ent->stepoldangles);
-                               VectorCopy(ent->v.origin, ent->steporigin);
-                               VectorCopy(ent->v.angles, ent->stepangles);
-                       }
-                       VectorSubtract(ent->v.origin, ent->steporigin, origin);
-                       VectorSubtract(ent->v.angles, ent->stepangles, angles);
-                       if (DotProduct(origin, origin) >= 0.125 || DotProduct(angles, angles) >= 1.4)
-                       {
-                               // update lerp positions
-                               ent->steplerptime = sv.time;
-                               VectorCopy(ent->steporigin, ent->stepoldorigin);
-                               VectorCopy(ent->stepangles, ent->stepoldangles);
-                               VectorCopy(ent->v.origin, ent->steporigin);
-                               VectorCopy(ent->v.angles, ent->stepangles);
-                       }
-                       movelerp = (sv.time - ent->steplerptime) * 10.0;
-                       if (movelerp > 1) movelerp = 1;
-                       moveilerp = 1 - movelerp;
-                       origin[0] = ent->stepoldorigin[0] * moveilerp + ent->steporigin[0] * movelerp;
-                       origin[1] = ent->stepoldorigin[1] * moveilerp + ent->steporigin[1] * movelerp;
-                       origin[2] = ent->stepoldorigin[2] * moveilerp + ent->steporigin[2] * movelerp;
-                       // choose shortest rotate (to avoid 'spin around' situations)
-                       VectorSubtract(ent->stepangles, ent->stepoldangles, angles);
-                       if (angles[0] < -180) angles[0] += 360;if (angles[0] >= 180) angles[0] -= 360;
-                       if (angles[1] < -180) angles[1] += 360;if (angles[1] >= 180) angles[1] -= 360;
-                       if (angles[2] < -180) angles[2] += 360;if (angles[2] >= 180) angles[2] -= 360;
-                       angles[0] = angles[0] * movelerp + ent->stepoldangles[0];
-                       angles[1] = angles[1] * movelerp + ent->stepoldangles[1];
-                       angles[2] = angles[2] * movelerp + ent->stepoldangles[2];
-                       //VectorMA(origin, host_client->latency, ent->v.velocity, origin);
+                       VectorMA(ent->v.origin, host_client->latency, ent->v.velocity, origin);
+                       // LordHavoc: trace predicted movement to avoid putting things in walls
+                       trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, origin, MOVE_NORMAL, ent);
+                       VectorCopy(trace.endpos, origin);
                }
-               else // copy as they are
+               else
                {
-                       if (ent->v.movetype == MOVETYPE_STEP) // monster, but airborn, update lerp info
-                       {
-                               // update lerp positions
-                               ent->steplerptime = sv.time;
-                               VectorCopy(ent->v.origin, ent->stepoldorigin);
-                               VectorCopy(ent->v.angles, ent->stepoldangles);
-                               VectorCopy(ent->v.origin, ent->steporigin);
-                               VectorCopy(ent->v.angles, ent->stepangles);
-                       }
-
-                       VectorCopy(ent->v.angles, angles);
-                       if (DotProduct(ent->v.velocity, ent->v.velocity) >= 1.0f)
-                       {
-                               VectorMA(ent->v.origin, host_client->latency, ent->v.velocity, origin);
-                               // LordHavoc: trace predicted movement to avoid putting things in walls
-                               trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, origin, MOVE_NORMAL, ent);
-                               VectorCopy(trace.endpos, origin);
-                       }
-                       else
-                       {
-                               VectorCopy(ent->v.origin, origin);
-                       }
+                       VectorCopy(ent->v.origin, origin);
                }
 
                // ent has survived every check so far, check if it is visible
@@ -664,11 +623,11 @@ void SV_WriteEntitiesToClient (client_t *client, edict_t *clent, sizebuf_t *msg)
                        }
 
                        // if not touching a visible leaf
-                       if (sv_pvscheckentities.value && !SV_BoxTouchingPVS(pvs, entmins, entmaxs, sv.worldmodel->nodes))
+                       if (sv_pvscheckentities.integer && !SV_BoxTouchingPVS(pvs, entmins, entmaxs, sv.worldmodel->nodes))
                                continue;
 
                        // or not visible through the portals
-                       if (sv_vischeckentities.value && !Portal_CheckBox(sv.worldmodel, org, entmins, entmaxs))
+                       if (sv_vischeckentities.integer && !Portal_CheckBox(sv.worldmodel, org, entmins, entmaxs))
                        {
                                sv_vischeckentitycullcount++;
                                continue;
@@ -678,7 +637,6 @@ void SV_WriteEntitiesToClient (client_t *client, edict_t *clent, sizebuf_t *msg)
                alpha = 255;
                scale = 16;
                glowcolor = 254;
-               colormod = 255;
                effects = ent->v.effects;
 
                if ((val = GETEDICTFIELDVALUE(ent, eval_alpha)))
@@ -707,10 +665,6 @@ void SV_WriteEntitiesToClient (client_t *client, edict_t *clent, sizebuf_t *msg)
                if (val->_float != 0)
                        effects |= EF_FULLBRIGHT;
 
-               if ((val = GETEDICTFIELDVALUE(ent, eval_colormod)))
-               if (val->vector[0] != 0 || val->vector[1] != 0 || val->vector[2] != 0)
-                       colormod = (bound(0, (int) (val->vector[0] * 8.0), 7) << 5) | (bound(0, (int) (val->vector[1] * 8.0), 7) << 2) | bound(0, (int) (val->vector[2] * 4.0), 3);
-
                if (ent != clent)
                {
                        if (glowsize == 0 && (bits & U_GLOWTRAIL) == 0) // no effects
@@ -741,7 +695,7 @@ void SV_WriteEntitiesToClient (client_t *client, edict_t *clent, sizebuf_t *msg)
 // send an update
                baseline = &ent->baseline;
 
-               if (((int)ent->v.effects & EF_DELTA) && sv_deltacompress.value)
+               if (((int)ent->v.effects & EF_DELTA) && sv_deltacompress.integer)
                {
                        // every half second a full update is forced
                        if (realtime < client->nextfullupdate[e])
@@ -771,9 +725,9 @@ void SV_WriteEntitiesToClient (client_t *client, edict_t *clent, sizebuf_t *msg)
                if (origin[0] != baseline->origin[0])                                                                                   bits |= U_ORIGIN1;
                if (origin[1] != baseline->origin[1])                                                                                   bits |= U_ORIGIN2;
                if (origin[2] != baseline->origin[2])                                                                                   bits |= U_ORIGIN3;
-               if ((int)(angles[0]*(256.0/360.0)) != (int)(baseline->angles[0]*(256.0/360.0))) bits |= U_ANGLE1;
-               if ((int)(angles[1]*(256.0/360.0)) != (int)(baseline->angles[1]*(256.0/360.0))) bits |= U_ANGLE2;
-               if ((int)(angles[2]*(256.0/360.0)) != (int)(baseline->angles[2]*(256.0/360.0))) bits |= U_ANGLE3;
+               if (((int)(angles[0]*(256.0/360.0)) & 255) != ((int)(baseline->angles[0]*(256.0/360.0)) & 255)) bits |= U_ANGLE1;
+               if (((int)(angles[1]*(256.0/360.0)) & 255) != ((int)(baseline->angles[1]*(256.0/360.0)) & 255)) bits |= U_ANGLE2;
+               if (((int)(angles[2]*(256.0/360.0)) & 255) != ((int)(baseline->angles[2]*(256.0/360.0)) & 255)) bits |= U_ANGLE3;
                if (baseline->colormap != (byte) ent->v.colormap)                                                               bits |= U_COLORMAP;
                if (baseline->skin != (byte) ent->v.skin)                                                                               bits |= U_SKIN;
                if ((baseline->frame & 0x00FF) != ((int) ent->v.frame & 0x00FF))                                bits |= U_FRAME;
@@ -786,7 +740,6 @@ void SV_WriteEntitiesToClient (client_t *client, edict_t *clent, sizebuf_t *msg)
                if (((int) baseline->effects & 0xFF00) != ((int) ent->v.effects & 0xFF00))              bits |= U_EFFECTS2;
                if (baseline->glowsize != glowsize)                                                                                             bits |= U_GLOWSIZE;
                if (baseline->glowcolor != glowcolor)                                                                                   bits |= U_GLOWCOLOR;
-               if (baseline->colormod != colormod)                                                                                             bits |= U_COLORMOD;
                if (((int) baseline->frame & 0xFF00) != ((int) ent->v.frame & 0xFF00))                  bits |= U_FRAME2;
                if (((int) baseline->frame & 0xFF00) != ((int) ent->v.modelindex & 0xFF00))             bits |= U_MODEL2;
 
@@ -802,10 +755,6 @@ void SV_WriteEntitiesToClient (client_t *client, edict_t *clent, sizebuf_t *msg)
                ent->deltabaseline.scale = scale;
                ent->deltabaseline.glowsize = glowsize;
                ent->deltabaseline.glowcolor = glowcolor;
-               ent->deltabaseline.colormod = colormod;
-
-               if (bits & (U_ALPHA | U_SCALE | U_EFFECTS2 | U_GLOWSIZE | U_GLOWCOLOR | U_COLORMOD | U_FRAME2 | U_MODEL2))
-                       i = -1;
 
                // write the message
                if (bits >= 16777216)
@@ -848,12 +797,11 @@ void SV_WriteEntitiesToClient (client_t *client, edict_t *clent, sizebuf_t *msg)
                if (bits & U_EFFECTS2)  MSG_WriteByte(msg, (int)ent->v.effects >> 8);
                if (bits & U_GLOWSIZE)  MSG_WriteByte(msg, glowsize);
                if (bits & U_GLOWCOLOR) MSG_WriteByte(msg, glowcolor);
-               if (bits & U_COLORMOD)  MSG_WriteByte(msg, colormod);
                if (bits & U_FRAME2)    MSG_WriteByte(msg, (int)ent->v.frame >> 8);
                if (bits & U_MODEL2)    MSG_WriteByte(msg, (int)ent->v.modelindex >> 8);
        }
 
-       if (sv_reportvischeckentities.value)
+       if (sv_reportvischeckentities.integer)
                Con_Printf("sv_vischeck culled entities: %d\n", sv_vischeckentitycullcount);
        sv_vischeckentitycullcount = 0;
 }
@@ -871,10 +819,7 @@ void SV_CleanupEnts (void)
 
        ent = NEXT_EDICT(sv.edicts);
        for (e=1 ; e<sv.num_edicts ; e++, ent = NEXT_EDICT(ent))
-       {
                ent->v.effects = (int)ent->v.effects & ~EF_MUZZLEFLASH;
-       }
-
 }
 
 /*
@@ -940,13 +885,13 @@ void SV_WriteClientdataToMessage (edict_t *ent, sizebuf_t *msg)
                items = (int)ent->v.items | ((int)pr_global_struct->serverflags << 28);
 
        bits |= SU_ITEMS;
-       
+
        if ( (int)ent->v.flags & FL_ONGROUND)
                bits |= SU_ONGROUND;
-       
+
        if ( ent->v.waterlevel >= 2)
                bits |= SU_INWATER;
-       
+
        // dpprotocol
        VectorClear(punchvector);
        if ((val = GETEDICTFIELDVALUE(ent, eval_punchvector)))
@@ -1010,7 +955,7 @@ void SV_WriteClientdataToMessage (edict_t *ent, sizebuf_t *msg)
                MSG_WriteByte (msg, ent->v.armorvalue);
        if (bits & SU_WEAPON)
                MSG_WriteByte (msg, SV_ModelIndex(pr_strings+ent->v.weaponmodel));
-       
+
        MSG_WriteShort (msg, ent->v.health);
        MSG_WriteByte (msg, ent->v.currentammo);
        MSG_WriteByte (msg, ent->v.ammo_shells);
@@ -1044,7 +989,7 @@ qboolean SV_SendClientDatagram (client_t *client)
 {
        byte            buf[MAX_DATAGRAM];
        sizebuf_t       msg;
-       
+
        msg.data = buf;
        msg.maxsize = sizeof(buf);
        msg.cursize = 0;
@@ -1098,7 +1043,7 @@ void SV_UpdateToReliableMessages (void)
                        host_client->old_frags = host_client->edict->v.frags;
                }
        }
-       
+
        for (j=0, client = svs.clients ; j<svs.maxclients ; j++, client++)
        {
                if (!client->active)
@@ -1122,7 +1067,7 @@ void SV_SendNop (client_t *client)
 {
        sizebuf_t       msg;
        byte            buf[4];
-       
+
        msg.data = buf;
        msg.maxsize = sizeof(buf);
        msg.cursize = 0;
@@ -1142,7 +1087,7 @@ SV_SendClientMessages
 void SV_SendClientMessages (void)
 {
        int                     i;
-       
+
 // update frags, names, etc
        SV_UpdateToReliableMessages ();
 
@@ -1162,7 +1107,7 @@ void SV_SendClientMessages (void)
                // the player isn't totally in the game yet
                // send small keepalive messages if too much time has passed
                // send a full message when the next signon stage has been requested
-               // some other message data (name changes, etc) may accumulate 
+               // some other message data (name changes, etc) may accumulate
                // between signon stages
                        if (!host_client->sendsignon)
                        {
@@ -1181,7 +1126,7 @@ void SV_SendClientMessages (void)
                        host_client->message.overflowed = false;
                        continue;
                }
-                       
+
                if (host_client->message.cursize || host_client->dropasap)
                {
                        if (!NET_CanSendMessage (host_client->netconnection))
@@ -1202,8 +1147,8 @@ void SV_SendClientMessages (void)
                        }
                }
        }
-       
-       
+
+
 // clear muzzle flashes
        SV_CleanupEnts ();
 }
@@ -1226,7 +1171,7 @@ SV_ModelIndex
 int SV_ModelIndex (char *name)
 {
        int             i;
-       
+
        if (!name || !name[0])
                return 0;
 
@@ -1263,9 +1208,7 @@ void SV_CreateBaseline (void)
                if (entnum > svs.maxclients && !svent->v.modelindex)
                        continue;
 
-       //
                // create entity baseline
-       //
                VectorCopy (svent->v.origin, svent->baseline.origin);
                VectorCopy (svent->v.angles, svent->baseline.angles);
                svent->baseline.frame = svent->v.frame;
@@ -1284,9 +1227,8 @@ void SV_CreateBaseline (void)
                large = false;
                if (svent->baseline.modelindex & 0xFF00 || svent->baseline.frame & 0xFF00)
                        large = true;
-       //
+
                // add to the message
-       //
                if (large)
                        MSG_WriteByte (&sv.signon, svc_spawnbaseline2);
                else
@@ -1366,8 +1308,6 @@ void SV_SaveSpawnparms (void)
        }
 }
 
-qboolean isworldmodel;
-
 /*
 ================
 SV_SpawnServer
@@ -1394,23 +1334,17 @@ void SV_SpawnServer (char *server)
 // tell all connected clients that we are going to a new level
 //
        if (sv.active)
-       {
                SV_SendReconnect ();
-       }
 
 //
 // make cvars consistant
 //
-       if (coop.value)
+       if (coop.integer)
                Cvar_SetValue ("deathmatch", 0);
-       current_skill = (int)(skill.value + 0.5);
-       if (current_skill < 0)
-               current_skill = 0;
-       if (current_skill > 3)
-               current_skill = 3;
+       current_skill = bound(0, (int)(skill.value + 0.5), 3);
 
        Cvar_SetValue ("skill", (float)current_skill);
-       
+
 //
 // set up the new server
 //
@@ -1425,17 +1359,19 @@ void SV_SpawnServer (char *server)
 
 // allocate server memory
        sv.max_edicts = MAX_EDICTS;
-       
-       sv.edicts = Hunk_AllocName (sv.max_edicts*pr_edict_size, "edicts");
+
+       // clear the edict memory pool
+       Mem_EmptyPool(sv_edicts_mempool);
+       sv.edicts = Mem_Alloc(sv_edicts_mempool, sv.max_edicts * pr_edict_size);
 
        sv.datagram.maxsize = sizeof(sv.datagram_buf);
        sv.datagram.cursize = 0;
        sv.datagram.data = sv.datagram_buf;
-       
+
        sv.reliable_datagram.maxsize = sizeof(sv.reliable_datagram_buf);
        sv.reliable_datagram.cursize = 0;
        sv.reliable_datagram.data = sv.reliable_datagram_buf;
-       
+
        sv.signon.maxsize = sizeof(sv.signon_buf);
        sv.signon.cursize = 0;
        sv.signon.data = sv.signon_buf;
@@ -1447,17 +1383,15 @@ void SV_SpawnServer (char *server)
                ent = EDICT_NUM(i+1);
                svs.clients[i].edict = ent;
        }
-       
+
        sv.state = ss_loading;
        sv.paused = false;
 
        sv.time = 1.0;
-       
+
        strcpy (sv.name, server);
        sprintf (sv.modelname,"maps/%s.bsp", server);
-       isworldmodel = true; // LordHavoc: only load submodels on the world model
-       sv.worldmodel = Mod_ForName (sv.modelname, false);
-       isworldmodel = false;
+       sv.worldmodel = Mod_ForName(sv.modelname, false, true, true);
        if (!sv.worldmodel)
        {
                Con_Printf ("Couldn't spawn server %s\n", sv.modelname);
@@ -1470,20 +1404,20 @@ void SV_SpawnServer (char *server)
 // clear world interaction links
 //
        SV_ClearWorld ();
-       
+
        sv.sound_precache[0] = pr_strings;
 
        sv.model_precache[0] = pr_strings;
        sv.model_precache[1] = sv.modelname;
-       for (i=1 ; i<sv.worldmodel->numsubmodels ; i++)
+       for (i = 1;i < sv.worldmodel->numsubmodels;i++)
        {
-               sv.model_precache[1+i] = localmodels[i];
-               sv.models[i+1] = Mod_ForName (localmodels[i], false);
+               sv.model_precache[i+1] = localmodels[i];
+               sv.models[i+1] = Mod_ForName (localmodels[i], false, true, false);
        }
 
 //
 // load the rest of the entities
-//     
+//
        ent = EDICT_NUM(0);
        memset (&ent->v, 0, progs->entityfields * 4);
        ent->free = false;
@@ -1492,10 +1426,10 @@ void SV_SpawnServer (char *server)
        ent->v.solid = SOLID_BSP;
        ent->v.movetype = MOVETYPE_PUSH;
 
-       if (coop.value)
-               pr_global_struct->coop = coop.value;
+       if (coop.integer)
+               pr_global_struct->coop = coop.integer;
        else
-               pr_global_struct->deathmatch = deathmatch.value;
+               pr_global_struct->deathmatch = deathmatch.integer;
 
        pr_global_struct->mapname = sv.name - pr_strings;
 
index 3cf4fd1a11f7d24dd5ddded80dc0da1b9376f54b..91f35921d2a3aabd3510b8ad635d1dbda7589936 100644 (file)
--- a/sv_phys.c
+++ b/sv_phys.c
@@ -1006,7 +1006,7 @@ void SV_WalkMove (edict_t *ent)
        if (ent->v.movetype != MOVETYPE_WALK)
                return;         // gibbed by a trigger
        
-       if (sv_nostep.value)
+       if (sv_nostep.integer)
                return;
        
        if ( (int)sv_player->v.flags & FL_WATERJUMP )
index 27a6e108b5e8f7299ed347d213db24b46b96e41b..3f306413eb6326bfc7b1e76844b420866803c38a 100644 (file)
--- a/sv_user.c
+++ b/sv_user.c
@@ -471,7 +471,7 @@ void SV_ReadClientMove (usercmd_t *move)
                total += host_client->ping_times[i];
        host_client->ping = total / NUM_PING_TIMES; // can be used for prediction
        host_client->latency = 0;
-       if (sv_predict.value && (svs.maxclients > 1) && (!sv.paused)) // if paused or a local game, don't predict
+       if (sv_predict.integer && (svs.maxclients > 1) && (!sv.paused)) // if paused or a local game, don't predict
                host_client->latency = host_client->ping;
        if ((val = GETEDICTFIELDVALUE(host_client->edict, eval_ping)))
                val->_float = host_client->ping * 1000.0;
index 405dc31496c80fa66349e8b7d81c36d4cf2dedf6..7c3033a612d15b352e567f4592349a1ba2f14bde 100644 (file)
@@ -48,7 +48,7 @@ void Sys_Quit (void)
        Host_Shutdown();
     fcntl (0, F_SETFL, fcntl (0, F_GETFL, 0) & ~FNDELAY);
 #if 0
-       if (registered.value)
+       if (registered.integer)
                printf("%s", end2);
        else
                printf("%s", end1);
@@ -268,8 +268,6 @@ int main (int c, char **v)
        host_parms.argc = com_argc;
        host_parms.argv = com_argv;
 
-       host_parms.memsize = DEFAULTMEM * 1024*1024;
-
        host_parms.basedir = basedir;
 
        fcntl(0, F_SETFL, fcntl (0, F_GETFL, 0) | FNDELAY);
index 01fd0fbabee12a34fb4509fc4dcafcd9c171688b..c4c539d96f3b1f783130fc60eb7f3332713ad533 100644 (file)
@@ -79,7 +79,7 @@ void Sys_Printf (char *fmt, ...)
        if (sys_nostdout)
                return;
 
-       if (timestamps.value)
+       if (timestamps.integer)
        {
                mytime = time (NULL);
                local = localtime (&mytime);
index 82b5179be4510168be8ca50a0a9650105b4fc7c0..bbf95e6be3c2fa68fa7a9ef736271eda635829e7 100644 (file)
--- a/sys_win.c
+++ b/sys_win.c
@@ -46,37 +46,6 @@ static HANDLE        hFile;
 static HANDLE  heventParent;
 static HANDLE  heventChild;
 
-volatile int                                   sys_checksum;
-
-
-/*
-================
-Sys_PageIn
-================
-*/
-/*
-void Sys_PageIn (void *ptr, int size)
-{
-       byte    *x;
-       int             m, n;
-
-// touch all the memory to make sure it's there. The 16-page skip is to
-// keep Win 95 from thinking we're trying to page ourselves in (we are
-// doing that, of course, but there's no reason we shouldn't)
-       x = (byte *)ptr;
-
-       for (n=0 ; n<4 ; n++)
-       {
-               for (m=0 ; m<(size - 16 * 0x1000) ; m += 4)
-               {
-                       sys_checksum += *(int *)&x[m];
-                       sys_checksum += *(int *)&x[m + 16 * 0x1000];
-               }
-       }
-}
-*/
-
-
 /*
 ===============================================================================
 
@@ -592,24 +561,6 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin
 
        Sys_Shared_EarlyInit();
 
-// take the greater of all the available memory or half the total memory,
-// but at least 8 Mb and no more than 16 Mb, unless they explicitly
-// request otherwise
-       /*
-       host_parms.memsize = lpBuffer.dwAvailPhys;
-
-       if (host_parms.memsize < MINIMUM_WIN_MEMORY)
-               host_parms.memsize = MINIMUM_WIN_MEMORY;
-
-       if (host_parms.memsize < (lpBuffer.dwTotalPhys >> 1))
-               host_parms.memsize = lpBuffer.dwTotalPhys >> 1;
-
-       if (host_parms.memsize > MAXIMUM_WIN_MEMORY)
-               host_parms.memsize = MAXIMUM_WIN_MEMORY;
-       */
-
-//     Sys_PageIn (parms.membase, parms.memsize);
-
        tevent = CreateEvent(NULL, false, false, NULL);
 
        if (!tevent)
index 363d04c921bceb25d5daa08f70a09d6ffb647b3a..91bdd1a7d1b27d0f7f2bd9d700fab67aef8c4695 100644 (file)
-// LordHavoc: transform code for purposes of transpoly, wallpoly, etc
 
 #include "quakedef.h"
 
-vec3_t softwaretransform_x;
-vec3_t softwaretransform_y;
-vec3_t softwaretransform_z;
-vec_t softwaretransform_scale;
-vec3_t softwaretransform_offset;
+vec_t softwaretransform_rotatematrix[3][4];
+vec_t softwaretransform_matrix[3][4];
+vec_t softwaretransform_invmatrix[3][4];
+int softwaretransform_complexity;
 
-// set to different transform code depending on complexity of transform
-void (*softwaretransform) (vec3_t in, vec3_t out);
-
-// the real deal
-void softwaretransform_dorotatescaletranslate (vec3_t in, vec3_t out)
-{
-       out[0] = (in[0] * softwaretransform_x[0] + in[1] * softwaretransform_y[0] + in[2] * softwaretransform_z[0]) * softwaretransform_scale + softwaretransform_offset[0];
-       out[1] = (in[0] * softwaretransform_x[1] + in[1] * softwaretransform_y[1] + in[2] * softwaretransform_z[1]) * softwaretransform_scale + softwaretransform_offset[1];
-       out[2] = (in[0] * softwaretransform_x[2] + in[1] * softwaretransform_y[2] + in[2] * softwaretransform_z[2]) * softwaretransform_scale + softwaretransform_offset[2];
-}
-
-void softwaretransform_doscaletranslate (vec3_t in, vec3_t out)
+vec_t softwaretransform_identitymatrix[3][4] =
 {
-       out[0] = in[0] * softwaretransform_scale + softwaretransform_offset[0];
-       out[1] = in[1] * softwaretransform_scale + softwaretransform_offset[1];
-       out[2] = in[2] * softwaretransform_scale + softwaretransform_offset[2];
-}
-
-void softwaretransform_dorotatetranslate (vec3_t in, vec3_t out)
-{
-       out[0] = (in[0] * softwaretransform_x[0] + in[1] * softwaretransform_y[0] + in[2] * softwaretransform_z[0]) + softwaretransform_offset[0];
-       out[1] = (in[0] * softwaretransform_x[1] + in[1] * softwaretransform_y[1] + in[2] * softwaretransform_z[1]) + softwaretransform_offset[1];
-       out[2] = (in[0] * softwaretransform_x[2] + in[1] * softwaretransform_y[2] + in[2] * softwaretransform_z[2]) + softwaretransform_offset[2];
-}
-
-void softwaretransform_dotranslate (vec3_t in, vec3_t out)
-{
-       out[0] = in[0] + softwaretransform_offset[0];
-       out[1] = in[1] + softwaretransform_offset[1];
-       out[2] = in[2] + softwaretransform_offset[2];
-}
+       {1, 0, 0, 0},
+       {0, 1, 0, 0},
+       {0, 0, 1, 0}
+};
 
-void softwaretransform_dorotatescale (vec3_t in, vec3_t out)
-{
-       out[0] = (in[0] * softwaretransform_x[0] + in[1] * softwaretransform_y[0] + in[2] * softwaretransform_z[0]) * softwaretransform_scale;
-       out[1] = (in[0] * softwaretransform_x[1] + in[1] * softwaretransform_y[1] + in[2] * softwaretransform_z[1]) * softwaretransform_scale;
-       out[2] = (in[0] * softwaretransform_x[2] + in[1] * softwaretransform_y[2] + in[2] * softwaretransform_z[2]) * softwaretransform_scale;
-}
-
-void softwaretransform_doscale (vec3_t in, vec3_t out)
-{
-       out[0] = in[0] * softwaretransform_scale + softwaretransform_offset[0];
-       out[1] = in[1] * softwaretransform_scale + softwaretransform_offset[1];
-       out[2] = in[2] * softwaretransform_scale + softwaretransform_offset[2];
-}
-
-void softwaretransform_dorotate (vec3_t in, vec3_t out)
-{
-       out[0] = (in[0] * softwaretransform_x[0] + in[1] * softwaretransform_y[0] + in[2] * softwaretransform_z[0]);
-       out[1] = (in[0] * softwaretransform_x[1] + in[1] * softwaretransform_y[1] + in[2] * softwaretransform_z[1]);
-       out[2] = (in[0] * softwaretransform_x[2] + in[1] * softwaretransform_y[2] + in[2] * softwaretransform_z[2]);
-}
-
-void softwaretransform_docopy (vec3_t in, vec3_t out)
+void softwaretransformidentity(void)
 {
-       out[0] = in[0];
-       out[1] = in[1];
-       out[2] = in[2];
+       memcpy(softwaretransform_rotatematrix, softwaretransform_identitymatrix, sizeof(vec_t[3][4]));
+       memcpy(softwaretransform_matrix      , softwaretransform_identitymatrix, sizeof(vec_t[3][4]));
+       memcpy(softwaretransform_invmatrix   , softwaretransform_identitymatrix, sizeof(vec_t[3][4]));
+       softwaretransform_complexity = 0;
 }
 
-void softwareuntransform (vec3_t in, vec3_t out)
+void softwaretransformset (vec3_t origin, vec3_t angles, vec_t scale)
 {
-       vec3_t v;
-       float s = 1.0f / softwaretransform_scale;
-       v[0] = in[0] - softwaretransform_offset[0];
-       v[1] = in[1] - softwaretransform_offset[1];
-       v[2] = in[2] - softwaretransform_offset[2];
-       out[0] = (v[0] * softwaretransform_x[0] + v[1] * softwaretransform_x[1] + v[2] * softwaretransform_x[2]) * s;
-       out[1] = (v[0] * softwaretransform_y[0] + v[1] * softwaretransform_y[1] + v[2] * softwaretransform_y[2]) * s;
-       out[2] = (v[0] * softwaretransform_z[0] + v[1] * softwaretransform_z[1] + v[2] * softwaretransform_z[2]) * s;
+       float invscale;
+       invscale = 1.0f / scale;
+       if (scale == 0)
+               Host_Error("softwaretransformset: 0 scale\n");
+
+       AngleMatrix(angles, origin, softwaretransform_rotatematrix);
+
+       softwaretransform_matrix[0][0] = softwaretransform_rotatematrix[0][0] * scale;
+       softwaretransform_matrix[0][1] = softwaretransform_rotatematrix[0][1] * scale;
+       softwaretransform_matrix[0][2] = softwaretransform_rotatematrix[0][2] * scale;
+       softwaretransform_matrix[1][0] = softwaretransform_rotatematrix[1][0] * scale;
+       softwaretransform_matrix[1][1] = softwaretransform_rotatematrix[1][1] * scale;
+       softwaretransform_matrix[1][2] = softwaretransform_rotatematrix[1][2] * scale;
+       softwaretransform_matrix[2][0] = softwaretransform_rotatematrix[2][0] * scale;
+       softwaretransform_matrix[2][1] = softwaretransform_rotatematrix[2][1] * scale;
+       softwaretransform_matrix[2][2] = softwaretransform_rotatematrix[2][2] * scale;
+       softwaretransform_matrix[0][3] = softwaretransform_rotatematrix[0][3];
+       softwaretransform_matrix[1][3] = softwaretransform_rotatematrix[1][3];
+       softwaretransform_matrix[2][3] = softwaretransform_rotatematrix[2][3];
+
+       softwaretransform_invmatrix[0][0] = softwaretransform_rotatematrix[0][0] * invscale;
+       softwaretransform_invmatrix[0][1] = softwaretransform_rotatematrix[1][0] * invscale;
+       softwaretransform_invmatrix[0][2] = softwaretransform_rotatematrix[2][0] * invscale;
+       softwaretransform_invmatrix[1][0] = softwaretransform_rotatematrix[0][1] * invscale;
+       softwaretransform_invmatrix[1][1] = softwaretransform_rotatematrix[1][1] * invscale;
+       softwaretransform_invmatrix[1][2] = softwaretransform_rotatematrix[2][1] * invscale;
+       softwaretransform_invmatrix[2][0] = softwaretransform_rotatematrix[0][2] * invscale;
+       softwaretransform_invmatrix[2][1] = softwaretransform_rotatematrix[1][2] * invscale;
+       softwaretransform_invmatrix[2][2] = softwaretransform_rotatematrix[2][2] * invscale;
+       softwaretransform_invmatrix[0][3] = softwaretransform_rotatematrix[0][3];
+       softwaretransform_invmatrix[1][3] = softwaretransform_rotatematrix[1][3];
+       softwaretransform_invmatrix[2][3] = softwaretransform_rotatematrix[2][3];
+
+       // choose transform mode
+       if (softwaretransform_matrix[0][0] != 1 || softwaretransform_matrix[0][1] != 0 || softwaretransform_matrix[0][2] != 0
+        || softwaretransform_matrix[1][0] != 0 || softwaretransform_matrix[1][1] != 1 || softwaretransform_matrix[1][2] != 0
+        || softwaretransform_matrix[2][0] != 0 || softwaretransform_matrix[2][1] != 0 || softwaretransform_matrix[2][2] != 1)
+               softwaretransform_complexity = 2;
+       else if (softwaretransform_matrix[0][3] != 0 || softwaretransform_matrix[1][3] != 0 || softwaretransform_matrix[2][3] != 0)
+               softwaretransform_complexity = 1;
+       else
+               softwaretransform_complexity = 0;
 }
 
-// to save time on transforms, choose the appropriate function
-void softwaretransform_classify(void)
+void softwaretransformforentity (entity_render_t *r)
 {
-       if (softwaretransform_offset[0] != 0 || softwaretransform_offset[1] != 0 || softwaretransform_offset[2] != 0)
+       vec3_t angles;
+       if (r->model->type == mod_brush)
        {
-               if (softwaretransform_scale != 1)
-               {
-                       if (softwaretransform_x[0] != 1 || softwaretransform_x[1] != 0 || softwaretransform_x[2] != 0 ||
-                               softwaretransform_y[0] != 0 || softwaretransform_y[1] != 1 || softwaretransform_y[2] != 0 ||
-                               softwaretransform_z[0] != 0 || softwaretransform_z[1] != 0 || softwaretransform_z[2] != 1)
-                               softwaretransform = &softwaretransform_dorotatescaletranslate;
-                       else
-                               softwaretransform = &softwaretransform_doscaletranslate;
-               }
-               else
-               {
-                       if (softwaretransform_x[0] != 1 || softwaretransform_x[1] != 0 || softwaretransform_x[2] != 0 ||
-                               softwaretransform_y[0] != 0 || softwaretransform_y[1] != 1 || softwaretransform_y[2] != 0 ||
-                               softwaretransform_z[0] != 0 || softwaretransform_z[1] != 0 || softwaretransform_z[2] != 1)
-                               softwaretransform = &softwaretransform_dorotatetranslate;
-                       else
-                               softwaretransform = &softwaretransform_dotranslate;
-               }
+               angles[0] = r->angles[0];
+               angles[1] = r->angles[1];
+               angles[2] = r->angles[2];
+               softwaretransformset(r->origin, angles, r->scale);
        }
        else
        {
-               if (softwaretransform_scale != 1)
-               {
-                       if (softwaretransform_x[0] != 1 || softwaretransform_x[1] != 0 || softwaretransform_x[2] != 0 ||
-                               softwaretransform_y[0] != 0 || softwaretransform_y[1] != 1 || softwaretransform_y[2] != 0 ||
-                               softwaretransform_z[0] != 0 || softwaretransform_z[1] != 0 || softwaretransform_z[2] != 1)
-                               softwaretransform = &softwaretransform_dorotatescale;
-                       else
-                               softwaretransform = &softwaretransform_doscale;
-               }
-               else
-               {
-                       if (softwaretransform_x[0] != 1 || softwaretransform_x[1] != 0 || softwaretransform_x[2] != 0 ||
-                               softwaretransform_y[0] != 0 || softwaretransform_y[1] != 1 || softwaretransform_y[2] != 0 ||
-                               softwaretransform_z[0] != 0 || softwaretransform_z[1] != 0 || softwaretransform_z[2] != 1)
-                               softwaretransform = &softwaretransform_dorotate;
-                       else
-                               softwaretransform = &softwaretransform_docopy;
-               }
+               angles[0] = -r->angles[0];
+               angles[1] = r->angles[1];
+               angles[2] = r->angles[2];
+               softwaretransformset(r->origin, angles, r->scale);
        }
 }
-
-void softwaretransformidentity(void)
-{
-       softwaretransform_offset[0] = softwaretransform_offset[1] = softwaretransform_offset[2] = softwaretransform_x[1] = softwaretransform_x[2] = softwaretransform_y[0] = softwaretransform_y[2] = softwaretransform_z[0] = softwaretransform_z[1] = 0;
-       softwaretransform_x[0] = softwaretransform_y[1] = softwaretransform_z[2] = 1;
-       softwaretransform_scale = 1;
-       // we know what it is
-       softwaretransform = &softwaretransform_docopy;
-}
-
-void softwaretransformset (vec3_t origin, vec3_t angles, vec_t scale)
-{
-       VectorCopy(origin, softwaretransform_offset);
-       AngleVectors(angles, softwaretransform_x, softwaretransform_y, softwaretransform_z);
-       softwaretransform_y[0] = -softwaretransform_y[0];
-       softwaretransform_y[1] = -softwaretransform_y[1];
-       softwaretransform_y[2] = -softwaretransform_y[2];
-       softwaretransform_scale = scale;
-       // choose best transform code
-       softwaretransform_classify();
-}
-
-void softwaretransformforentity (entity_render_t *r)
-{
-       vec3_t angles;
-       angles[0] = -r->angles[0];
-       angles[1] = r->angles[1];
-       angles[2] = r->angles[2];
-       softwaretransformset(r->origin, angles, r->scale);
-}
-
-// brush entities are not backwards like models and sprites are
-void softwaretransformforbrushentity (entity_render_t *r)
-{
-       softwaretransformset(r->origin, r->angles, r->scale);
-}
index e2d82e58e1f0618c19b8b870b72d0b223999f095..2cfe37ba27160f9ae194ff8f3668893310ecdb10 100644 (file)
@@ -1,18 +1,66 @@
-// LordHavoc: software transform support, intended for transpoly and wallpoly systems
 
-#define tft_translate 1
-#define tft_rotate 2
+extern vec_t softwaretransform_rotatematrix[3][4];
+extern vec_t softwaretransform_matrix[3][4];
+extern vec_t softwaretransform_invmatrix[3][4];
+extern int softwaretransform_complexity;
 
-extern vec_t softwaretransform_scale;
-extern vec3_t softwaretransform_offset;
-extern vec3_t softwaretransform_x;
-extern vec3_t softwaretransform_y;
-extern vec3_t softwaretransform_z;
-extern int softwaretransform_type;
+void softwaretransformidentity (void);
+void softwaretransformset (vec3_t origin, vec3_t angles, vec_t scale);
+void softwaretransformforentity (entity_render_t *r);
 
-extern void softwaretransformforentity (entity_render_t *r);
-extern void softwaretransformforbrushentity (entity_render_t *r);
-extern void softwaretransformidentity (void);
-extern void softwaretransformset (vec3_t origin, vec3_t angles, vec_t scale);
-extern void (*softwaretransform) (vec3_t in, vec3_t out);
-extern void softwareuntransform (vec3_t in, vec3_t out);
+// #defines for speed reasons
+#define softwaretransform(in, out)\
+{\
+       if (softwaretransform_complexity == 0)\
+       {\
+               VectorCopy(in, out);\
+       }\
+       else if (softwaretransform_complexity == 1)\
+       {\
+               out[0] = in[0] + softwaretransform_matrix[0][3];\
+               out[1] = in[1] + softwaretransform_matrix[1][3];\
+               out[2] = in[2] + softwaretransform_matrix[2][3];\
+       }\
+       else\
+       {\
+               out[0] = DotProduct(in, softwaretransform_matrix[0]) + softwaretransform_matrix[0][3];\
+               out[1] = DotProduct(in, softwaretransform_matrix[1]) + softwaretransform_matrix[1][3];\
+               out[2] = DotProduct(in, softwaretransform_matrix[2]) + softwaretransform_matrix[2][3];\
+       }\
+}
+
+#define softwaretransformdirection(in, out)\
+{\
+       if (softwaretransform_complexity == 2)\
+       {\
+               out[0] = DotProduct(in, softwaretransform_rotatematrix[0]);\
+               out[1] = DotProduct(in, softwaretransform_rotatematrix[1]);\
+               out[2] = DotProduct(in, softwaretransform_rotatematrix[2]);\
+       }\
+       else\
+               VectorCopy(in, out);\
+}
+
+#define softwareuntransform(in, out)\
+{\
+       if (softwaretransform_complexity == 0)\
+       {\
+               VectorCopy(in, out);\
+       }\
+       else if (softwaretransform_complexity == 1)\
+       {\
+               out[0] = in[0] - softwaretransform_invmatrix[0][3];\
+               out[1] = in[1] - softwaretransform_invmatrix[1][3];\
+               out[2] = in[2] - softwaretransform_invmatrix[2][3];\
+       }\
+       else\
+       {\
+               vec3_t soft_v;\
+               soft_v[0] = in[0] - softwaretransform_invmatrix[0][3];\
+               soft_v[1] = in[1] - softwaretransform_invmatrix[1][3];\
+               soft_v[2] = in[2] - softwaretransform_invmatrix[2][3];\
+               out[0] = DotProduct(soft_v, softwaretransform_invmatrix[0]);\
+               out[1] = DotProduct(soft_v, softwaretransform_invmatrix[1]);\
+               out[2] = DotProduct(soft_v, softwaretransform_invmatrix[2]);\
+       }\
+}
diff --git a/ui.c b/ui.c
index 88e1c2e51f61cc999466dcbab356bc73d996ca05..9097aaf5b2c772eb55c1d9b9670a198ace63e384 100644 (file)
--- a/ui.c
+++ b/ui.c
@@ -27,46 +27,73 @@ static rtexture_t *ui_mousepointertexture;
 
 static byte pointerimage[256] =
 {
-       0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
-       0x02, 0x06, 0x07, 0x07, 0x07, 0x07, 0x06, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
-       0x02, 0x06, 0x05, 0x05, 0x05, 0x04, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
-       0x02, 0x06, 0x05, 0x05, 0x04, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
-       0x02, 0x06, 0x05, 0x04, 0x05, 0x06, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
-       0x02, 0x06, 0x04, 0x01, 0x04, 0x05, 0x06, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
-       0x02, 0x05, 0x01, 0xFF, 0x01, 0x04, 0x05, 0x06, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
-       0x02, 0x01, 0xFF, 0xFF, 0xFF, 0x01, 0x04, 0x05, 0x06, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
-       0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x04, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
-       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
-       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
-       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
-       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
-       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
-       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+       "333333332......."
+       "26777761........"
+       "2655541........."
+       "265541.........."
+       "2654561........."
+       "26414561........"
+       "251.14561......."
+       "21...14561......"
+       "1.....141......."
+       ".......1........"
+       "................"
+       "................"
+       "................"
+       "................"
+       "................"
+       "................"
 };
 
-void ui_start(void)
+static rtexturepool_t *uitexturepool;
+
+static void ui_start(void)
 {
+       int i;
+       byte buffer[256][4];
+       uitexturepool = R_AllocTexturePool();
 //     ui_mousepointer = Draw_CachePic("ui/mousepointer.lmp");
-       ui_mousepointertexture = R_LoadTexture("mousepointer", 16, 16, pointerimage, TEXF_ALPHA | TEXF_PRECACHE);
+       for (i = 0;i < 256;i++)
+       {
+               if (pointerimage[i] == '.')
+               {
+                       buffer[i][0] = 0;
+                       buffer[i][1] = 0;
+                       buffer[i][2] = 0;
+                       buffer[i][3] = 0;
+               }
+               else
+               {
+                       buffer[i][0] = (pointerimage[i] - '0') * 16;
+                       buffer[i][1] = (pointerimage[i] - '0') * 16;
+                       buffer[i][2] = (pointerimage[i] - '0') * 16;
+                       buffer[i][3] = 255;
+               }
+       }
+       ui_mousepointertexture = R_LoadTexture(uitexturepool, "mousepointer", 16, 16, &buffer[0][0], TEXTYPE_RGBA, TEXF_ALPHA | TEXF_PRECACHE);
        ui_mouse_x = vid.conwidth * 0.5;
        ui_mouse_y = vid.conheight * 0.5;
        ui_alive = true;
 }
 
-void ui_shutdown(void)
+static void ui_shutdown(void)
 {
 //     ui_mousepointer = NULL;
        ui_mousepointertexture = NULL;
        ui_alive = false;
+       R_FreeTexturePool(&uitexturepool);
 }
 
-void ui_newmap(void)
+static void ui_newmap(void)
 {
 }
 
+static mempool_t *uimempool;
+
 void ui_init(void)
 {
+       uimempool = Mem_AllocPool("UI");
+
        Cvar_RegisterVariable(&ui_showname);
        R_RegisterModule("UI", ui_start, ui_shutdown, ui_newmap);
 }
@@ -94,7 +121,7 @@ void ui_mouseupdaterelative(float x, float y)
 ui_t *ui_create(void)
 {
        ui_t *ui;
-       ui = qmalloc(sizeof(*ui));
+       ui = Mem_Alloc(uimempool, sizeof(*ui));
        if (ui == NULL)
                Sys_Error("ui_create: unable to allocate memory for new ui\n");
        memset(ui, 0, sizeof(*ui));
@@ -104,7 +131,7 @@ ui_t *ui_create(void)
 void ui_free(ui_t *ui)
 {
        if (ui)
-               qfree(ui);
+               Mem_Free(ui);
 }
 
 void ui_clear(ui_t *ui)
@@ -417,7 +444,7 @@ void ui_draw(void)
                                Draw_AdditivePic(it->draw_x, it->draw_y, it->draw_pic);
                        if (it->draw_string)
                                Draw_AdditiveString(it->draw_x, it->draw_y, it->draw_string, 9999);
-                       if (ui_showname.value)
+                       if (ui_showname.integer)
                                Draw_String(ui_mouse_x, ui_mouse_y + 16, it->name, 9999);
        }
 
index cc1f9cca5d9bfd436d9309531821153021f97903..97124a1ced1c7515d2325dec0adbe42517472954 100644 (file)
@@ -158,7 +158,7 @@ void GL_BeginRendering (int *x, int *y, int *width, int *height)
 
 void GL_EndRendering (void)
 {
-       if (!r_render.value)
+       if (!r_render.integer)
                return;
        glFlush();
        fxMesaSwapBuffers();
index 868d74d07e85e14f766a3563243fda4b28c45f22..3735592e734189133b9620dec6aa3838c879fb67 100644 (file)
--- a/vid_glx.c
+++ b/vid_glx.c
@@ -227,7 +227,7 @@ static void install_grabs(void)
 
        XGrabPointer(vidx11_display, win,  True, 0, GrabModeAsync, GrabModeAsync, win, None, CurrentTime);
 
-       if (vid_dga.value)
+       if (vid_dga.integer)
        {
                int MajorVersion, MinorVersion;
 
@@ -235,11 +235,11 @@ static void install_grabs(void)
                {
                        // unable to query, probalby not supported
                        Con_Printf( "Failed to detect XF86DGA Mouse\n" );
-                       vid_dga.value = 0;
+                       vid_dga.integer = 0;
                }
                else
                {
-                       vid_dga.value = 1;
+                       vid_dga.integer = 1;
                        XF86DGADirectVideo(vidx11_display, DefaultScreen(vidx11_display), XF86DGADirectMouse);
                        XWarpPointer(vidx11_display, None, win, 0, 0, 0, 0, 0, 0);
                }
@@ -260,7 +260,7 @@ static void uninstall_grabs(void)
        if (!vidx11_display || !win)
                return;
 
-       if (vid_dga.value == 1)
+       if (vid_dga.integer == 1)
                XF86DGADirectVideo(vidx11_display, DefaultScreen(vidx11_display), 0);
 
        XUngrabPointer(vidx11_display, CurrentTime);
@@ -295,7 +295,7 @@ static void HandleEvents(void)
                case MotionNotify:
                        if (usingmouse)
                        {
-                               if (vid_dga.value == 1)
+                               if (vid_dga.integer == 1)
                                {
                                        mouse_x += event.xmotion.x_root * vid_dga_mouseaccel.value;
                                        mouse_y += event.xmotion.y_root * vid_dga_mouseaccel.value;
@@ -495,14 +495,14 @@ void GL_BeginRendering (int *x, int *y, int *width, int *height)
 void GL_EndRendering (void)
 {
        int usemouse;
-       if (!r_render.value)
+       if (!r_render.integer)
                return;
        glFlush();
        glXSwapBuffers(vidx11_display, win);
 
 // handle the mouse state when windowed if that's changed
        usemouse = false;
-       if (vid_mouse.value && key_dest == key_game)
+       if (vid_mouse.integer && key_dest == key_game)
                usemouse = true;
        if (vidmode_active)
                usemouse = true;
@@ -844,7 +844,7 @@ void IN_MouseMove (usercmd_t *cmd)
        if (!mouse_avail)
                return;
 
-       if (m_filter.value)
+       if (m_filter.integer)
        {
                mouse_x = (mouse_x + old_mouse_x) * 0.5;
                mouse_y = (mouse_y + old_mouse_y) * 0.5;
index cda7de6361ca64b66df8f2fdd99cf94c1a78cca9..f5ec2f6eb9387740cc6bca23439587796103fd88 100644 (file)
@@ -6,8 +6,8 @@ qboolean isG200 = false; // LordHavoc: the Matrox G200 can't do per pixel alpha,
 qboolean isRagePro = false; // LordHavoc: the ATI Rage Pro has limitations with per pixel alpha (the color scaler does not apply to per pixel alpha images...), although not as bad as a G200.
 
 // LordHavoc: GL_ARB_multitexture support
-int gl_mtexable = false;
-// LordHavoc: GL_ARB_texture_env_combine support
+int gl_textureunits;
+// LordHavoc: GL_ARB_texture_env_combine or GL_EXT_texture_env_combine support
 int gl_combine_extension = false;
 // LordHavoc: GL_EXT_compiled_vertex_array support
 int gl_supportslockarrays = false;
@@ -57,69 +57,104 @@ static gl_extensionfunctionlist_t compiledvertexarrayfuncs[] =
        {NULL, NULL}
 };
 
-static gl_extensioninfo_t gl_extensioninfo[] =
-{
-       {"GL_ARB_multitexture", multitexturefuncs, &gl_mtexable, "-nomtex"},
-       {"GL_ARB_texture_env_combine", NULL, &gl_combine_extension, "-nocombine"},
-       {"GL_EXT_compiled_vertex_array", compiledvertexarrayfuncs, &gl_supportslockarrays, "-nocva"},
-       {NULL, NULL, NULL, NULL}
-};
-
 #ifndef WIN32
 #include <dlfcn.h>
 #endif
 
-void VID_CheckExtensions(void)
+static void *prjobj = NULL;
+
+static void gl_getfuncs_begin(void)
 {
 #ifndef WIN32
-       void *prjobj;
-#endif
-       gl_extensioninfo_t *info;
-       gl_extensionfunctionlist_t *func;
-//     multitexturefuncs[0].funcvariable = (void **)&qglMultiTexCoord2f;
-       Con_Printf("Checking OpenGL extensions...\n");
-#ifndef WIN32
-       if ((prjobj = dlopen(NULL, RTLD_LAZY)) == NULL)
+       if (prjobj)
+               dlclose(prjobj);
+
+       prjobj = dlopen(NULL, RTLD_LAZY);
+       if (prjobj == NULL)
        {
                Con_Printf("Unable to open symbol list for main program.\n");
                return;
        }
 #endif
-       for (info = gl_extensioninfo;info && info->name;info++)
+}
+
+static void gl_getfuncs_end(void)
+{
+#ifndef WIN32
+       if (prjobj)
        {
-               *info->enablevariable = false;
-               for (func = info->funcs;func && func->name;func++)
-                       *func->funcvariable = NULL;
-               Con_Printf("checking for %s...  ", info->name);
-               if (info->disableparm && COM_CheckParm(info->disableparm))
-               {
-                       Con_Printf("disabled by commandline\n");
-                       continue;
-               }
-               if (strstr(gl_extensions, info->name))
-               {
-                       for (func = info->funcs;func && func->name != NULL;func++)
-                       {
+               dlclose(prjobj);
+               prjobj = NULL;
+       }
+#endif
+}
+
+static void *gl_getfuncaddress(char *name)
+{
 #ifdef WIN32
-                               if (!(*func->funcvariable = (void *) wglGetProcAddress(func->name)))
+       return (void *) wglGetProcAddress(func->name);
 #else
-                               if (!(*func->funcvariable = (void *) dlsym(prjobj, func->name)))
+       return (void *) dlsym(prjobj, name);
 #endif
-                               {
-                                       Con_Printf("missing function \"%s\"!\n", func->name);
-                                       goto missingfunc;
-                               }
+}
+
+static int gl_checkextension(char *name, gl_extensionfunctionlist_t *funcs, char *disableparm)
+{
+       gl_extensionfunctionlist_t *func;
+
+       Con_Printf("checking for %s...  ", name);
+
+       for (func = funcs;func && func->name;func++)
+               *func->funcvariable = NULL;
+
+       if (disableparm && COM_CheckParm(disableparm))
+       {
+               Con_Printf("disabled by commandline\n");
+               return false;
+       }
+
+       if (strstr(gl_extensions, name))
+       {
+               for (func = funcs;func && func->name != NULL;func++)
+               {
+                       if (!(*func->funcvariable = (void *) gl_getfuncaddress(func->name)))
+                       {
+                               Con_Printf("missing function \"%s\"!\n", func->name);
+                               return false;
                        }
-                       Con_Printf("enabled\n");
-                       *info->enablevariable = true;
-                       missingfunc:;
                }
+               Con_Printf("enabled\n");
+               return true;
+       }
+       else
+       {
+               Con_Printf("not detected\n");
+               return false;
+       }
+}
+
+void VID_CheckExtensions(void)
+{
+       Con_Printf("Checking OpenGL extensions...\n");
+
+       gl_getfuncs_begin();
+
+       gl_combine_extension = false;
+       gl_supportslockarrays = false;
+       gl_textureunits = 1;
+
+       if (gl_checkextension("GL_ARB_multitexture", multitexturefuncs, "-nomtex"))
+       {
+               glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &gl_textureunits);
+               if (gl_textureunits > 1)
+                       gl_combine_extension = gl_checkextension("GL_ARB_texture_env_combine", NULL, "-nocombine") || gl_checkextension("GL_EXT_texture_env_combine", NULL, "-nocombine");
                else
-                       Con_Printf("not detected\n");
+                       gl_textureunits = 1; // for sanity sake, make sure it's not 0
        }
-#ifndef WIN32
-       dlclose(prjobj);
-#endif
+
+       gl_supportslockarrays = gl_checkextension("GL_EXT_compiled_vertex_array", compiledvertexarrayfuncs, "-nocva");
+
+       gl_getfuncs_end();
 }
 
 void Force_CenterView_f (void)
index 7f4cc5f6438194b515d3491cf3bc0e84fa586de2..5da80a2cae5672018f788f61793ab437b7ca476e 100644 (file)
--- a/vid_wgl.c
+++ b/vid_wgl.c
@@ -93,8 +93,6 @@ unsigned char vid_curpal[256*3];
 HGLRC  baseRC;
 HDC            maindc;
 
-glvert_t glv;
-
 HWND WINAPI InitializeWindow (HINSTANCE hInstance, int nCmdShow);
 
 viddef_t       vid;                            // global video state
@@ -274,7 +272,7 @@ int VID_SetMode (int modenum)
        // Set either the fullscreen or windowed mode
        if (modelist[modenum].type == MS_WINDOWED)
        {
-//             if (vid_mouse.value && key_dest == key_game)
+//             if (vid_mouse.integer && key_dest == key_game)
 //             {
 //                     stat = VID_SetWindowedMode(modenum);
 //                     usingmouse = true;
@@ -387,12 +385,12 @@ void GL_BeginRendering (int *x, int *y, int *width, int *height)
 void GL_EndRendering (void)
 {
        int usemouse;
-       if (r_render.value && !scr_skipupdate)
+       if (r_render.integer && !scr_skipupdate)
                SwapBuffers(maindc);
 
 // handle the mouse state when windowed if that's changed
        usemouse = false;
-       if (vid_mouse.value && key_dest == key_game)
+       if (vid_mouse.integer && key_dest == key_game)
                usemouse = true;
        if (modestate == MS_FULLDIB)
                usemouse = true;
@@ -583,7 +581,7 @@ void ClearAllStates (void)
 }
 
 void VID_RestoreGameGamma(void);
-extern qboolean hostloopactive;
+extern qboolean host_loopactive;
 
 void AppActivate(BOOL fActive, BOOL minimize)
 /****************************************************************************
@@ -631,13 +629,13 @@ void AppActivate(BOOL fActive, BOOL minimize)
                        // LordHavoc: from dabb, fix for alt-tab bug in NVidia drivers
                        MoveWindow(mainwindow,0,0,gdevmode.dmPelsWidth,gdevmode.dmPelsHeight,false);
                }
-//             else if ((modestate == MS_WINDOWED) && vid_mouse.value && key_dest == key_game)
+//             else if ((modestate == MS_WINDOWED) && vid_mouse.integer && key_dest == key_game)
 //             {
 //                     usingmouse = true;
 //                     IN_ActivateMouse ();
 //                     IN_HideMouse ();
 //             }
-               if (hostloopactive)
+               if (host_loopactive)
                        VID_RestoreGameGamma();
        }
 
@@ -657,7 +655,7 @@ void AppActivate(BOOL fActive, BOOL minimize)
                                vid_wassuspended = true;
                        }
                }
-//             else if ((modestate == MS_WINDOWED) && vid_mouse.value)
+//             else if ((modestate == MS_WINDOWED) && vid_mouse.integer)
 //             {
 //                     usingmouse = false;
 //                     IN_DeactivateMouse ();
diff --git a/view.c b/view.c
index 65ba402a6bf6b4bf75881df2bc20d7b6659f2e61..5a8e7af55913760ca2c637bc2d48c3b9a6e11027 100644 (file)
--- a/view.c
+++ b/view.c
@@ -563,53 +563,6 @@ CalcGunAngle
 */
 void CalcGunAngle (void)
 {
-       /*
-       float   yaw, pitch, move;
-       static float oldyaw = 0;
-       static float oldpitch = 0;
-       
-       yaw = r_refdef.viewangles[YAW];
-       pitch = -r_refdef.viewangles[PITCH];
-
-       yaw = angledelta(yaw - r_refdef.viewangles[YAW]) * 0.4;
-       if (yaw > 10)
-               yaw = 10;
-       if (yaw < -10)
-               yaw = -10;
-       pitch = angledelta(-pitch - r_refdef.viewangles[PITCH]) * 0.4;
-       if (pitch > 10)
-               pitch = 10;
-       if (pitch < -10)
-               pitch = -10;
-       move = cl.frametime*20;
-       if (yaw > oldyaw)
-       {
-               if (oldyaw + move < yaw)
-                       yaw = oldyaw + move;
-       }
-       else
-       {
-               if (oldyaw - move > yaw)
-                       yaw = oldyaw - move;
-       }
-
-       if (pitch > oldpitch)
-       {
-               if (oldpitch + move < pitch)
-                       pitch = oldpitch + move;
-       }
-       else
-       {
-               if (oldpitch - move > pitch)
-                       pitch = oldpitch - move;
-       }
-       
-       oldyaw = yaw;
-       oldpitch = pitch;
-
-       cl.viewent.angles[YAW] = r_refdef.viewangles[YAW] + yaw;
-       cl.viewent.angles[PITCH] = - (r_refdef.viewangles[PITCH] + pitch);
-       */
        cl.viewent.render.angles[YAW] = r_refdef.viewangles[YAW];
        cl.viewent.render.angles[PITCH] = -r_refdef.viewangles[PITCH];
 
@@ -718,8 +671,6 @@ void V_CalcIntermissionRefdef (void)
        v_idlescale.value = old;
 }
 
-extern void CL_LerpUpdate(entity_t *e, int frame, int modelindex);
-
 /*
 ==================
 V_CalcRefdef
@@ -811,7 +762,6 @@ void V_CalcRefdef (void)
                view->render.alpha = ent->render.alpha; // LordHavoc: if the player is transparent, so is the gun
                view->render.effects = ent->render.effects;
                view->render.scale = 1;
-               VectorCopy(ent->render.colormod, view->render.colormod);
 
        // set up the refresh position
 
@@ -858,7 +808,7 @@ the entity origin, so any view position inside that will be valid
 */
 void V_RenderView (void)
 {
-       if (con_forcedup)
+       if (scr_con_current >= vid.conheight)
                return;
 
        if (cl.intermission)
diff --git a/wad.c b/wad.c
index 241c065ebd77dfc6dffe96912363b6a1a31b7662..bba4c97a69572b833fc5c1c13d5bfd0100124302 100644 (file)
--- a/wad.c
+++ b/wad.c
@@ -8,7 +8,7 @@ of the License, or (at your option) any later version.
 
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 See the GNU General Public License for more details.
 
@@ -21,9 +21,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 #include "quakedef.h"
 
-int                    wad_numlumps;
-lumpinfo_t     *wad_lumps;
-byte           *wad_base;
+static int                     wad_numlumps;
+static lumpinfo_t      *wad_lumps;
+static byte                    *wad_base = NULL;
+static mempool_t       *wad_mempool = NULL;
 
 void SwapPic (qpic_t *pic);
 
@@ -38,22 +39,22 @@ Space padding is so names can be printed nicely in tables.
 Can safely be performed in place.
 ==================
 */
-void W_CleanupName (char *in, char *out)
+static void W_CleanupName (char *in, char *out)
 {
        int             i;
        int             c;
-       
+
        for (i=0 ; i<16 ; i++ )
        {
                c = in[i];
                if (!c)
                        break;
-                       
+
                if (c >= 'A' && c <= 'Z')
                        c += ('a' - 'A');
                out[i] = c;
        }
-       
+
        for ( ; i< 16 ; i++ )
                out[i] = 0;
 }
@@ -71,23 +72,29 @@ void W_LoadWadFile (char *filename)
        wadinfo_t               *header;
        unsigned                i;
        int                             infotableofs;
-       
-       wad_base = COM_LoadHunkFile (filename, false);
-       if (!wad_base)
+       void                    *temp;
+
+       temp = COM_LoadFile (filename, false);
+       if (!temp)
                Sys_Error ("W_LoadWadFile: couldn't load %s", filename);
 
+       if (wad_mempool)
+               Mem_FreePool(&wad_mempool);
+       wad_mempool = Mem_AllocPool(filename);
+       wad_base = Mem_Alloc(wad_mempool, loadsize);
+
+       memcpy(wad_base, temp, loadsize);
+       Mem_Free(temp);
+
        header = (wadinfo_t *)wad_base;
-       
-       if (header->identification[0] != 'W'
-       || header->identification[1] != 'A'
-       || header->identification[2] != 'D'
-       || header->identification[3] != '2')
+
+       if (memcmp(header->identification, "WAD2", 4))
                Sys_Error ("Wad file %s doesn't have WAD2 id\n",filename);
-               
+
        wad_numlumps = LittleLong(header->numlumps);
        infotableofs = LittleLong(header->infotableofs);
        wad_lumps = (lumpinfo_t *)(wad_base + infotableofs);
-       
+
        for (i=0, lump_p = wad_lumps ; i<wad_numlumps ; i++,lump_p++)
        {
                lump_p->filepos = LittleLong(lump_p->filepos);
@@ -98,49 +105,20 @@ void W_LoadWadFile (char *filename)
        }
 }
 
-
-/*
-=============
-W_GetLumpinfo
-=============
-*/
-lumpinfo_t     *W_GetLumpinfo (char *name)
+void *W_GetLumpName (char *name)
 {
        int             i;
-       lumpinfo_t      *lump_p;
+       lumpinfo_t      *lump;
        char    clean[16];
-       
+
        W_CleanupName (name, clean);
-       
-       for (lump_p=wad_lumps, i=0 ; i<wad_numlumps ; i++,lump_p++)
-       {
-               if (!strcmp(clean, lump_p->name))
-                       return lump_p;
-       }
-       
-       Sys_Error ("W_GetLumpinfo: %s not found", name);
-       return NULL;
-}
 
-void *W_GetLumpName (char *name)
-{
-       lumpinfo_t      *lump;
-       
-       lump = W_GetLumpinfo (name);
-       
-       return (void *)(wad_base + lump->filepos);
-}
+       for (lump = wad_lumps, i = 0;i < wad_numlumps;i++, lump++)
+               if (!strcmp(clean, lump->name))
+                       return (void *)(wad_base + lump->filepos);
 
-void *W_GetLumpNum (int num)
-{
-       lumpinfo_t      *lump;
-       
-       if (num < 0 || num > wad_numlumps)
-               Sys_Error ("W_GetLumpNum: bad number: %i", num);
-               
-       lump = wad_lumps + num;
-       
-       return (void *)(wad_base + lump->filepos);
+       Sys_Error ("W_GetLumpinfo: %s not found", name);
+       return NULL;
 }
 
 /*
@@ -154,7 +132,7 @@ automatic byte swapping
 void SwapPic (qpic_t *pic)
 {
        pic->width = LittleLong(pic->width);
-       pic->height = LittleLong(pic->height);  
+       pic->height = LittleLong(pic->height);
 }
 
 // LordHavoc: added alternate WAD2/WAD3 system for HalfLife texture wads
@@ -167,7 +145,7 @@ typedef struct
        int size;
 } texwadlump_t;
 
-texwadlump_t   texwadlump[TEXWAD_MAXIMAGES];
+static texwadlump_t texwadlump[TEXWAD_MAXIMAGES];
 
 /*
 ====================
@@ -182,7 +160,7 @@ void W_LoadTextureWadFile (char *filename, int complain)
        int                             infotableofs;
        QFile                   *file;
        int                             numlumps;
-       
+
        COM_FOpenFile (filename, &file, false, false);
        if (!file)
        {
@@ -193,11 +171,8 @@ void W_LoadTextureWadFile (char *filename, int complain)
 
        if (Qread(file, &header, sizeof(wadinfo_t)) != sizeof(wadinfo_t))
        {Con_Printf ("W_LoadTextureWadFile: unable to read wad header");return;}
-       
-       if(header.identification[0] != 'W'
-       || header.identification[1] != 'A'
-       || header.identification[2] != 'D'
-       || header.identification[3] != '3')
+
+       if(memcmp(header.identification, "WAD3", 4))
        {Con_Printf ("W_LoadTextureWadFile: Wad file %s doesn't have WAD3 id\n",filename);return;}
 
        numlumps = LittleLong(header.numlumps);
@@ -206,7 +181,7 @@ void W_LoadTextureWadFile (char *filename, int complain)
        infotableofs = LittleLong(header.infotableofs);
        if (Qseek(file, infotableofs, SEEK_SET))
        {Con_Printf ("W_LoadTextureWadFile: unable to seek to lump table");return;}
-       if (!(lumps = qmalloc(sizeof(lumpinfo_t)*numlumps)))
+       if (!(lumps = Mem_Alloc(tempmempool, sizeof(lumpinfo_t)*numlumps)))
        {Con_Printf ("W_LoadTextureWadFile: unable to allocate temporary memory for lump table");return;}
 
        if (Qread(file, lumps, sizeof(lumpinfo_t) * numlumps) != sizeof(lumpinfo_t) * numlumps)
@@ -232,7 +207,7 @@ void W_LoadTextureWadFile (char *filename, int complain)
                texwadlump[j].position = LittleLong(lump_p->filepos);
                texwadlump[j].size = LittleLong(lump_p->disksize);
        }
-       qfree(lumps);
+       Mem_Free(lumps);
        // leaves the file open
 }
 
@@ -296,7 +271,7 @@ byte *W_ConvertWAD3Texture(miptex_t *tex)
 //     int palsize;
        int d, p;
        in = (byte *)((int) tex + tex->offsets[0]);
-       data = out = qmalloc(tex->width * tex->height * 4);
+       data = out = Mem_Alloc(tempmempool, tex->width * tex->height * 4);
        if (!data)
                return NULL;
        image_width = tex->width;
@@ -346,7 +321,7 @@ byte *W_GetTexture(char *name)
                                if (Qseek(file, texwadlump[i].position, SEEK_SET))
                                {Con_Printf("W_GetTexture: corrupt WAD3 file");return NULL;}
 
-                               tex = qmalloc(texwadlump[i].size);
+                               tex = Mem_Alloc(tempmempool, texwadlump[i].size);
                                if (!tex)
                                        return NULL;
                                if (Qread(file, tex, texwadlump[i].size) < texwadlump[i].size)
@@ -357,7 +332,7 @@ byte *W_GetTexture(char *name)
                                for (j = 0;j < MIPLEVELS;j++)
                                        tex->offsets[j] = LittleLong(tex->offsets[j]);
                                data = W_ConvertWAD3Texture(tex);
-                               qfree(tex);
+                               Mem_Free(tex);
                                return data;
                                /*
                                image_width = LittleLong(t.width);
@@ -370,7 +345,7 @@ byte *W_GetTexture(char *name)
                                {Con_Printf("W_GetTexture: corrupt WAD3 file");return NULL;}
                                // allocate space for expanded image,
                                // and load incoming image into upper area (overwritten as it expands)
-                               if (!(data = outdata = qmalloc(image_width*image_height*4)))
+                               if (!(data = outdata = Mem_Alloc(tempmempool, image_width*image_height*4)))
                                {Con_Printf("W_GetTexture: out of memory");return NULL;}
                                indata = outdata + image_width*image_height*3;
                                datasize = image_width*image_height*85/64;
diff --git a/wad.h b/wad.h
index 9c16b566c7f208244f900f897e420e401d35e8cd..6a20203e659f43a8e53a612d8893351cae866c37 100644 (file)
--- a/wad.h
+++ b/wad.h
@@ -67,15 +67,12 @@ extern      lumpinfo_t      *wad_lumps;
 extern byte            *wad_base;
 
 void   W_LoadWadFile (char *filename);
-void   W_CleanupName (char *in, char *out);
-lumpinfo_t     *W_GetLumpinfo (char *name);
 void   *W_GetLumpName (char *name);
-void   *W_GetLumpNum (int num);
 
 void SwapPic (qpic_t *pic);
 
 // LordHavoc: added alternate texture WAD2/WAD3 system for easier loading of HalfLife texture wads
 extern int image_width, image_height;
 void   W_LoadTextureWadFile (char *filename, int complain);
-byte   *W_GetTexture (char *name); // returns malloc'd image data, width and height are in image_width and image_height
-byte   *W_ConvertWAD3Texture(miptex_t *tex); // returns malloc'd image data, width and height are in image_width and image_height
+byte   *W_GetTexture (char *name); // returns tempmempool allocated image data, width and height are in image_width and image_height
+byte   *W_ConvertWAD3Texture(miptex_t *tex); // returns tempmempool allocated image data, width and height are in image_width and image_height
diff --git a/world.c b/world.c
index c0edd62e5acc5da7e56f04b8ded32e06a2de5c77..cf3acfcb4748019766e25a09808541ea3b420904 100644 (file)
--- a/world.c
+++ b/world.c
@@ -187,6 +187,7 @@ hull_t *SV_HullForEntity (edict_t *ent, vec3_t mins, vec3_t maxs, vec3_t offset)
                        Host_Error ("SOLID_BSP without MOVETYPE_PUSH");
 
                model = sv.models[ (int)ent->v.modelindex ];
+               Mod_CheckLoaded(model);
 
                // LordHavoc: fixed SOLID_BSP error message
                if (!model || model->type != mod_brush)
@@ -198,7 +199,7 @@ hull_t *SV_HullForEntity (edict_t *ent, vec3_t mins, vec3_t maxs, vec3_t offset)
 
                VectorSubtract (maxs, mins, size);
                // LordHavoc: FIXME!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-               if (hlbsp)
+               if (sv.worldmodel->ishlbsp)
                {
                        if (size[0] < 3)
                                hull = &model->hulls[0]; // 0x0x0
@@ -320,6 +321,7 @@ void SV_ClearWorld (void)
 
        memset (sv_areanodes, 0, sizeof(sv_areanodes));
        sv_numareanodes = 0;
+       Mod_CheckLoaded(sv.worldmodel);
        SV_CreateAreaNode (0, sv.worldmodel->normalmins, sv.worldmodel->normalmaxs);
 }
 
@@ -878,6 +880,8 @@ loc0:
 }
 */
 
+/*
+// FIXME: this is broken and I'm not interested in figuring out what is broken about it right now
 qboolean SV_TestLine (hull_t *hull, int num, vec3_t p1, vec3_t p2)
 {
        dclipnode_t     *node;
@@ -991,6 +995,7 @@ loc0:
                }
        }
 }
+*/
 
 
 /*
diff --git a/world.h b/world.h
index 7de90a32ba973694ae44bebc811bcd41e0390cf2..55838dca58f57943901937f6837f84ae78c52da0 100644 (file)
--- a/world.h
+++ b/world.h
@@ -96,3 +96,7 @@ RecursiveHullCheckTraceInfo_t;
 // LordHavoc: FIXME: this is not thread safe, if threading matters here, pass
 // this as a struct to RecursiveHullCheck, RecursiveHullCheck_Impact, etc...
 extern RecursiveHullCheckTraceInfo_t RecursiveHullCheckInfo;
+
+// optimized variant of RecursiveHullCheck that only returns success/failure
+// FIXME: broken, fix it
+//extern qboolean SV_TestLine (hull_t *hull, int num, vec3_t p1, vec3_t p2);
diff --git a/zone.c b/zone.c
index 556c709496ec24813ad2bad6045fb78988186821..a6b7cf2bc09ba8defb975355b01a3df2e2807da3 100644 (file)
--- a/zone.c
+++ b/zone.c
@@ -8,7 +8,7 @@ of the License, or (at your option) any later version.
 
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 See the GNU General Public License for more details.
 
@@ -21,879 +21,313 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 #include "quakedef.h"
 
-// LordHavoc: everyone used a -zone 512, but 128k is sufficient usually, I think...
-#define        DYNAMIC_SIZE    0x20000
-//#define      DYNAMIC_SIZE    0xc000
+mempool_t *poolchain = NULL;
 
-#define        ZONEID  0x1d4a11
-#define MINFRAGMENT    64
-
-typedef struct memblock_s
-{
-       int             size;           // including the header and possibly tiny fragments
-       int     tag;            // a tag of 0 is a free block
-       int     id;                     // should be ZONEID
-       struct memblock_s       *next, *prev;
-       int             pad;                    // pad to 64 bit boundary
-} memblock_t;
-
-typedef struct
-{
-       int             size;           // total bytes malloced, including header
-       memblock_t      blocklist;              // start / end cap for linked list
-       memblock_t      *rover;
-} memzone_t;
-
-void Cache_FreeLow (int new_low_hunk);
-void Cache_FreeHigh (int new_high_hunk);
-
-
-/*
-==============================================================================
-
-                                               ZONE MEMORY ALLOCATION
-
-There is never any space between memblocks, and there will never be two
-contiguous free memblocks.
-
-The rover can be left pointing at a non-empty block
-
-The zone calls are pretty much only used for small strings and structures,
-all big things are allocated on the hunk.
-==============================================================================
-*/
-
-memzone_t      *mainzone;
-
-void Z_ClearZone (memzone_t *zone, int size);
-
-
-/*
-========================
-Z_ClearZone
-========================
-*/
-void Z_ClearZone (memzone_t *zone, int size)
-{
-       memblock_t      *block;
-       
-// set the entire zone to one free block
-
-       zone->blocklist.next = zone->blocklist.prev = block =
-               (memblock_t *)( (byte *)zone + sizeof(memzone_t) );
-       zone->blocklist.tag = 1;        // in use block
-       zone->blocklist.id = 0;
-       zone->blocklist.size = 0;
-       zone->rover = block;
-       
-       block->prev = block->next = &zone->blocklist;
-       block->tag = 0;                 // free block
-       block->id = ZONEID;
-       block->size = size - sizeof(memzone_t);
-}
-
-
-/*
-========================
-Z_Free
-========================
-*/
-void Z_Free (void *ptr)
-{
-       memblock_t      *block, *other;
-       
-       if (!ptr)
-               Sys_Error ("Z_Free: NULL pointer");
-
-       block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t));
-       if (block->id != ZONEID)
-               Sys_Error ("Z_Free: freed a pointer without ZONEID");
-       if (block->tag == 0)
-               Sys_Error ("Z_Free: freed a freed pointer");
-
-       block->tag = 0;         // mark as free
-       
-       other = block->prev;
-       if (!other->tag)
-       {       // merge with previous free block
-               other->size += block->size;
-               other->next = block->next;
-               other->next->prev = other;
-               if (block == mainzone->rover)
-                       mainzone->rover = other;
-               block = other;
-       }
-       
-       other = block->next;
-       if (!other->tag)
-       {       // merge the next free block onto the end
-               block->size += other->size;
-               block->next = other->next;
-               block->next->prev = block;
-               if (other == mainzone->rover)
-                       mainzone->rover = block;
-       }
-}
-
-
-/*
-========================
-Z_Malloc
-========================
-*/
-void *Z_Malloc (int size)
-{
-       void    *buf;
-       
-Z_CheckHeap ();        // DEBUG
-       buf = Z_TagMalloc (size, 1);
-       if (!buf)
-               Sys_Error ("Z_Malloc: failed on allocation of %i bytes",size);
-       memset (buf, 0, size);
-
-       return buf;
-}
-
-void *Z_TagMalloc (int size, int tag)
-{
-       int             extra;
-       memblock_t      *start, *rover, *new, *base;
-
-       if (!tag)
-               Sys_Error ("Z_TagMalloc: tried to use a 0 tag");
-
-//
-// scan through the block list looking for the first free block
-// of sufficient size
-//
-       size += sizeof(memblock_t);     // account for size of block header
-       size += 4;                                      // space for memory trash tester
-       size = (size + 7) & ~7;         // align to 8-byte boundary
-       
-       base = rover = mainzone->rover;
-       start = base->prev;
-       
-       do
-       {
-               if (rover == start)     // scaned all the way around the list
-                       return NULL;
-               if (rover->tag)
-                       base = rover = rover->next;
-               else
-                       rover = rover->next;
-       } while (base->tag || base->size < size);
-       
-//
-// found a block big enough
-//
-       extra = base->size - size;
-       if (extra >  MINFRAGMENT)
-       {       // there will be a free fragment after the allocated block
-               new = (memblock_t *) ((byte *)base + size );
-               new->size = extra;
-               new->tag = 0;                   // free block
-               new->prev = base;
-               new->id = ZONEID;
-               new->next = base->next;
-               new->next->prev = new;
-               base->next = new;
-               base->size = size;
-       }
-       
-       base->tag = tag;                                // no longer a free block
-       
-       mainzone->rover = base->next;   // next allocation will start looking here
-       
-       base->id = ZONEID;
-
-// marker for memory trash testing
-       *(int *)((byte *)base + base->size - 4) = ZONEID;
-
-       return (void *) ((byte *)base + sizeof(memblock_t));
-}
-
-
-/*
-========================
-Z_Print
-========================
-*/
-void Z_Print (memzone_t *zone)
-{
-       memblock_t      *block;
-       
-       Con_Printf ("zone size: %i  location: %p\n",mainzone->size,mainzone);
-       
-       for (block = zone->blocklist.next ; ; block = block->next)
-       {
-               Con_Printf ("block:%p    size:%7i    tag:%3i\n",
-                       block, block->size, block->tag);
-               
-               if (block->next == &zone->blocklist)
-                       break;                  // all blocks have been hit     
-               if ( (byte *)block + block->size != (byte *)block->next)
-                       Con_Printf ("ERROR: block size does not touch the next block\n");
-               if ( block->next->prev != block)
-                       Con_Printf ("ERROR: next block doesn't have proper back link\n");
-               if (!block->tag && !block->next->tag)
-                       Con_Printf ("ERROR: two consecutive free blocks\n");
-       }
-}
-
-
-/*
-========================
-Z_CheckHeap
-========================
-*/
-void Z_CheckHeap (void)
+void *_Mem_Alloc(mempool_t *pool, int size, char *filename, int fileline)
 {
-       memblock_t      *block;
-       
-       for (block = mainzone->blocklist.next ; ; block = block->next)
+       int i, j, k, needed, endbit, largest;
+       memclump_t *clump, **clumpchainpointer;
+       memheader_t *mem;
+       if (size <= 0)
+               return NULL;
+       if (pool == NULL)
+               Host_Error("Mem_Alloc: pool == NULL");
+       pool->totalsize += size;
+       if (size < 4096)
        {
-               if (block->next == &mainzone->blocklist)
-                       break;                  // all blocks have been hit     
-               if ( (byte *)block + block->size != (byte *)block->next)
-                       Sys_Error ("Z_CheckHeap: block size does not touch the next block\n");
-               if ( block->next->prev != block)
-                       Sys_Error ("Z_CheckHeap: next block doesn't have proper back link\n");
-               if (!block->tag && !block->next->tag)
-                       Sys_Error ("Z_CheckHeap: two consecutive free blocks\n");
+               // clumping
+               needed = (sizeof(memheader_t) + size + sizeof(int) + (MEMUNIT - 1)) / MEMUNIT;
+               endbit = MEMBITS - needed;
+               for (clumpchainpointer = &pool->clumpchain;*clumpchainpointer;clumpchainpointer = &(*clumpchainpointer)->chain)
+               {
+                       clump = *clumpchainpointer;
+                       if (clump->sentinel1 != MEMCLUMP_SENTINEL)
+                               Sys_Error("Mem_Alloc: trashed clump sentinel 1\n");
+                       if (clump->sentinel2 != MEMCLUMP_SENTINEL)
+                               Sys_Error("Mem_Alloc: trashed clump sentinel 2\n");
+                       if (clump->largestavailable >= needed)
+                       {
+                               largest = 0;
+                               for (i = 0;i < endbit;i++)
+                               {
+                                       if (clump->bits[i >> 5] & (1 << (i & 31)))
+                                               continue;
+                                       k = i + needed;
+                                       for (j = i;i < k;i++)
+                                               if (clump->bits[i >> 5] & (1 << (i & 31)))
+                                                       goto loopcontinue;
+                                       goto choseclump;
+       loopcontinue:;
+                                       if (largest < j - i)
+                                               largest = j - i;
+                               }
+                               // since clump falsely advertised enough space (nothing wrong
+                               // with that), update largest count to avoid wasting time in
+                               // later allocations
+                               clump->largestavailable = largest;
+                       }
+               }
+               pool->realsize += sizeof(memclump_t);
+               clump = malloc(sizeof(memclump_t));
+               if (clump == NULL)
+                       Host_Error("Mem_Alloc: out of memory");
+               memset(clump, 0, sizeof(memclump_t));
+               *clumpchainpointer = clump;
+               clump->sentinel1 = MEMCLUMP_SENTINEL;
+               clump->sentinel2 = MEMCLUMP_SENTINEL;
+               clump->chain = NULL;
+               clump->blocksinuse = 0;
+               clump->largestavailable = MEMBITS - needed;
+               j = 0;
+choseclump:
+               mem = (memheader_t *)((long) clump->block + j * MEMUNIT);
+               mem->clump = clump;
+               clump->blocksinuse += needed;
+               for (i = j + needed;j < i;j++)
+                       clump->bits[j >> 5] |= (1 << (j & 31));
        }
-}
-
-//============================================================================
-
-#define        HUNK_SENTINAL   0x1df001ed
-
-typedef struct
-{
-       int             sentinal;
-       int             size;           // including sizeof(hunk_t), -1 = not allocated
-       char    name[56];
-} hunk_t;
-
-byte   *hunk_base;
-int            hunk_size;
-
-int            hunk_low_used;
-int            hunk_high_used;
-
-void R_FreeTextures (void);
-
-/*
-==============
-Hunk_Check
-
-Run consistancy and sentinal trashing checks
-==============
-*/
-void Hunk_Check (void)
-{
-       hunk_t  *h;
-       
-       for (h = (hunk_t *)hunk_base ; (byte *)h != hunk_base + hunk_low_used ; )
+       else
        {
-               if (h->sentinal != HUNK_SENTINAL)
-                       Sys_Error ("Hunk_Check: trashed sentinal");
-               if (h->size < sizeof(hunk_t) || h->size + (byte *)h - hunk_base > hunk_size)
-                       Sys_Error ("Hunk_Check: bad size");
-               h = (hunk_t *)((byte *)h+h->size);
+               // big allocations are not clumped
+               pool->realsize += sizeof(memheader_t) + size + sizeof(int);
+               mem = malloc(sizeof(memheader_t) + size + sizeof(int));
+               if (mem == NULL)
+                       Host_Error("Mem_Alloc: out of memory");
+               mem->clump = NULL;
        }
+       mem->filename = filename;
+       mem->fileline = fileline;
+       mem->size = size;
+       mem->pool = pool;
+       mem->sentinel1 = MEMHEADER_SENTINEL;
+       *((int *)((long) mem + sizeof(memheader_t) + mem->size)) = MEMHEADER_SENTINEL;
+       // append to head of list
+       mem->chain = pool->chain;
+       pool->chain = mem;
+       memset((void *)((long) mem + sizeof(memheader_t)), 0, mem->size);
+       return (void *)((long) mem + sizeof(memheader_t));
 }
 
-/*
-==============
-Hunk_Print
-
-If "all" is specified, every single allocation is printed.
-Otherwise, allocations with the same name will be totaled up before printing.
-==============
-*/
-void Hunk_Print (qboolean all)
+void Mem_Free(void *data)
 {
-       hunk_t  *h, *next, *endlow, *starthigh, *endhigh;
-       int             count, sum, i;
-       int             totalblocks;
-       char    name[51];
-
-       name[50] = 0;
-       count = 0;
-       sum = 0;
-       totalblocks = 0;
-       
-       h = (hunk_t *)hunk_base;
-       endlow = (hunk_t *)(hunk_base + hunk_low_used);
-       starthigh = (hunk_t *)(hunk_base + hunk_size - hunk_high_used);
-       endhigh = (hunk_t *)(hunk_base + hunk_size);
+       int i, firstblock, endblock;
+       memclump_t *clump, **clumpchainpointer;
+       memheader_t *mem, **memchainpointer;
+       mempool_t *pool;
+       if (data == NULL)
+               Host_Error("Mem_Free: data == NULL");
 
-       Con_Printf ("          :%8i total hunk                 size\n", hunk_size);
-       Con_Printf ("-------------------------\n");
 
-       while (1)
+       mem = (memheader_t *)((long) data - sizeof(memheader_t));
+       if (mem->sentinel1 != MEMHEADER_SENTINEL)
+               Sys_Error("Mem_Free: trashed header sentinel 1 (block allocated in %s:%i)\n", mem->filename, mem->fileline);
+       if (*((int *)((long) mem + sizeof(memheader_t) + mem->size)) != MEMHEADER_SENTINEL)
+               Sys_Error("Mem_Free: trashed header sentinel 2 (block allocated in %s:%i)\n", mem->filename, mem->fileline);
+       pool = mem->pool;
+       for (memchainpointer = &pool->chain;*memchainpointer;memchainpointer = &(*memchainpointer)->chain)
        {
-       //
-       // skip to the high hunk if done with low hunk
-       //
-               if ( h == endlow )
+               if (*memchainpointer == mem)
                {
-                       Con_Printf ("-------------------------\n");
-                       Con_Printf ("          :%8i REMAINING\n", hunk_size - hunk_low_used - hunk_high_used);
-                       Con_Printf ("-------------------------\n");
-                       h = starthigh;
-               }
-               
-       //
-       // if totally done, break
-       //
-               if ( h == endhigh )
-                       break;
-
-       //
-       // run consistancy checks
-       //
-               if (h->sentinal != HUNK_SENTINAL)
-                       Sys_Error ("Hunk_Check: trashed sentinal");
-               if (h->size < sizeof(hunk_t) || h->size + (byte *)h - hunk_base > hunk_size)
-                       Sys_Error ("Hunk_Check: bad size");
-                       
-               next = (hunk_t *)((byte *)h+h->size);
-               count++;
-               totalblocks++;
-               sum += h->size;
-
-       //
-       // print the single block
-       //
-               // LordHavoc: pad name to full length
-               for (i = 0;i < 50;i++)
-               {
-                       if (!h->name[i])
-                               break;
-                       name[i] = h->name[i];
-               }
-               for (;i < 50;i++)
-                       name[i] = ' ';
-               //memcpy (name, h->name, 51);
-               if (all)
-                       Con_Printf ("%8p :%8i %s\n",h, h->size, name);
-                       
-       //
-       // print the total
-       //
-               if (next == endlow || next == endhigh || strncmp(h->name, next->name, 50))
-               {
-                       if (!all)
-                               Con_Printf ("         :%8i %s (TOTAL)\n",sum, name);
-                       count = 0;
-                       sum = 0;
+                       *memchainpointer = mem->chain;
+                       pool->totalsize -= mem->size;
+                       if ((clump = mem->clump))
+                       {
+                               if (clump->sentinel1 != MEMCLUMP_SENTINEL)
+                                       Sys_Error("Mem_Alloc: trashed clump sentinel 1\n");
+                               if (clump->sentinel2 != MEMCLUMP_SENTINEL)
+                                       Sys_Error("Mem_Alloc: trashed clump sentinel 2\n");
+                               firstblock = ((long) mem - (long) clump->block);
+                               if (firstblock & (MEMUNIT - 1))
+                                       Host_Error("Mem_Free: address not valid in clump\n");
+                               firstblock /= MEMUNIT;
+                               endblock = firstblock + ((sizeof(memheader_t) + mem->size + sizeof(int) + (MEMUNIT - 1)) / MEMUNIT);
+                               clump->blocksinuse -= endblock - firstblock;
+                               // could use &, but we know the bit is set
+                               for (i = firstblock;i < endblock;i++)
+                                       clump->bits[i >> 5] -= (1 << (i & 31));
+                               if (clump->blocksinuse <= 0)
+                               {
+                                       // unlink from chain
+                                       for (clumpchainpointer = &pool->clumpchain;*clumpchainpointer;clumpchainpointer = &(*clumpchainpointer)->chain)
+                                       {
+                                               if (*clumpchainpointer == clump)
+                                               {
+                                                       *clumpchainpointer = clump->chain;
+                                                       break;
+                                               }
+                                       }
+                                       pool->realsize -= sizeof(memclump_t);
+                                       memset(clump, 0xBF, sizeof(memclump_t));
+                                       free(clump);
+                               }
+                               else
+                               {
+                                       // clump still has some allocations
+                                       // force re-check of largest available space on next alloc
+                                       clump->largestavailable = MEMBITS - clump->blocksinuse;
+                               }
+                       }
+                       else
+                       {
+                               pool->realsize -= sizeof(memheader_t) + mem->size + sizeof(int);
+                               memset(mem, 0xBF, sizeof(memheader_t) + mem->size + sizeof(int));
+                               free(mem);
+                       }
+                       return;
                }
-
-               h = next;
        }
-
-//     Con_Printf ("-------------------------\n");
-       Con_Printf ("%8i total blocks\n", totalblocks);
-       
-}
-
-/*
-===================
-Hunk_AllocName
-===================
-*/
-void *Hunk_AllocName (int size, char *name)
-{
-       hunk_t  *h;
-       
-#ifdef PARANOID
-       Hunk_Check ();
-#endif
-
-       if (size < 0)
-               Sys_Error ("Hunk_Alloc: bad size: %i", size);
-               
-       size = sizeof(hunk_t) + ((size+15)&~15);
-       
-       if (hunk_size - hunk_low_used - hunk_high_used < size)
-               Sys_Error ("Hunk_Alloc: failed on %i bytes (name = %s)",size, name);
-       
-       h = (hunk_t *)(hunk_base + hunk_low_used);
-       hunk_low_used += size;
-
-       Cache_FreeLow (hunk_low_used);
-
-       memset (h, 0, size);
-       
-       h->size = size;
-       h->sentinal = HUNK_SENTINAL;
-       strncpy (h->name, name, 50);
-       h->name[50] = 0;
-       
-       return (void *)(h+1);
-}
-
-int    Hunk_LowMark (void)
-{
-       return hunk_low_used;
-}
-
-void Hunk_FreeToLowMark (int mark)
-{
-       if (mark < 0 || mark > hunk_low_used)
-               Sys_Error ("Hunk_FreeToLowMark: bad mark %i", mark);
-       memset (hunk_base + mark, 0, hunk_low_used - mark);
-       hunk_low_used = mark;
-}
-
-int    Hunk_HighMark (void)
-{
-       return hunk_high_used;
+       Host_Error("Mem_Free: not allocated\n");
 }
 
-void Hunk_FreeToHighMark (int mark)
-{
-       if (mark < 0 || mark > hunk_high_used)
-               Sys_Error ("Hunk_FreeToHighMark: bad mark %i", mark);
-       memset (hunk_base + hunk_size - hunk_high_used, 0, hunk_high_used - mark);
-       hunk_high_used = mark;
+mempool_t *Mem_AllocPool(char *name)
+{
+//     int i;
+       mempool_t *pool;
+       pool = malloc(sizeof(mempool_t));
+       if (pool == NULL)
+               Host_Error("Mem_AllocPool: out of memory");
+       memset(pool, 0, sizeof(mempool_t));
+       pool->chain = NULL;
+       pool->totalsize = 0;
+       pool->realsize = sizeof(mempool_t);
+       strcpy(pool->name, name);
+//     for (i = 0;i < (POOLNAMESIZE - 1) && name[i];i++)
+//             pool->name[i] = name[i];
+//     for (i = 0;i < POOLNAMESIZE;i++)
+//             pool->name[i] = 0;
+       pool->next = poolchain;
+       poolchain = pool;
+       return pool;
 }
 
-
-/*
-===================
-Hunk_HighAllocName
-===================
-*/
-void *Hunk_HighAllocName (int size, char *name)
+void Mem_FreePool(mempool_t **pool)
 {
-       hunk_t  *h;
-
-       if (size < 0)
-               Sys_Error ("Hunk_HighAllocName: bad size: %i", size);
-
-#ifdef PARANOID
-       Hunk_Check ();
-#endif
-
-       size = sizeof(hunk_t) + ((size+15)&~15);
-
-       if (hunk_size - hunk_low_used - hunk_high_used < size)
+       mempool_t **chainaddress;
+       if (*pool)
        {
-               Con_Printf ("Hunk_HighAlloc: failed on %i bytes\n",size);
-               return NULL;
+               // unlink pool from chain
+               for (chainaddress = &poolchain;*chainaddress && *chainaddress != *pool;chainaddress = &((*chainaddress)->next));
+               if (*chainaddress != *pool)
+                       Host_Error("Mem_FreePool: pool already free");
+               *chainaddress = (*pool)->next;
+
+               // free memory owned by the pool
+               while ((*pool)->chain)
+                       Mem_Free((void *)((long) (*pool)->chain + sizeof(memheader_t)));
+
+               // free the pool itself
+               memset(*pool, 0xBF, sizeof(mempool_t));
+               free(*pool);
+               *pool = NULL;
        }
-
-       hunk_high_used += size;
-       Cache_FreeHigh (hunk_high_used);
-
-       h = (hunk_t *)(hunk_base + hunk_size - hunk_high_used);
-
-       memset (h, 0, size);
-       h->size = size;
-       h->sentinal = HUNK_SENTINAL;
-       strncpy (h->name, name, 8);
-
-       return (void *)(h+1);
 }
 
-/*
-===============================================================================
-
-CACHE MEMORY
-
-===============================================================================
-*/
-
-typedef struct cache_system_s
+void Mem_EmptyPool(mempool_t *pool)
 {
-       int                                             size;           // including this header
-       cache_user_t                    *user;
-       char                                    name[16];
-       struct cache_system_s   *prev, *next;
-       struct cache_system_s   *lru_prev, *lru_next;   // for LRU flushing     
-} cache_system_t;
-
-cache_system_t *Cache_TryAlloc (int size, qboolean nobottom);
+       if (pool == NULL)
+               Con_Printf("Mem_EmptyPool: pool == NULL\n");
 
-cache_system_t cache_head;
+       // free memory owned by the pool
+       while (pool->chain)
+               Mem_Free((void *)((long) pool->chain + sizeof(memheader_t)));
+}
 
-/*
-===========
-Cache_Move
-===========
-*/
-void Cache_Move ( cache_system_t *c)
+void _Mem_CheckSentinels(void *data, char *filename, int fileline)
 {
-       cache_system_t          *new;
+       memheader_t *mem;
 
-// we are clearing up space at the bottom, so only allocate it late
-       new = Cache_TryAlloc (c->size, true);
-       if (new)
-       {
-//             Con_Printf ("cache_move ok\n");
+       if (data == NULL)
+               Host_Error("Mem_CheckSentinels: data == NULL\n");
 
-               memcpy ( new+1, c+1, c->size - sizeof(cache_system_t) );
-               new->user = c->user;
-               memcpy (new->name, c->name, sizeof(new->name));
-               Cache_Free (c->user);
-               new->user->data = (void *)(new+1);
-       }
-       else
-       {
-//             Con_Printf ("cache_move failed\n");
-
-               Cache_Free (c->user);           // tough luck...
-       }
+       mem = (memheader_t *)((long) data - sizeof(memheader_t));
+       if (mem->sentinel1 != MEMHEADER_SENTINEL)
+               Host_Error("Mem_CheckSentinels: trashed header sentinel 1 (block allocated at %s:%i, sentinel check at %s:%i)\n", mem->filename, mem->fileline, filename, fileline);
+       if (*((int *)((long) mem + sizeof(memheader_t) + mem->size)) != MEMHEADER_SENTINEL)
+               Host_Error("Mem_CheckSentinels: trashed header sentinel 2 (block allocated at %s:%i, sentinel check at %s:%i)\n", mem->filename, mem->fileline, filename, fileline);
 }
 
-/*
-============
-Cache_FreeLow
-
-Throw things out until the hunk can be expanded to the given point
-============
-*/
-void Cache_FreeLow (int new_low_hunk)
+static void _Mem_CheckClumpSentinels(memclump_t *clump, char *filename, int fileline)
 {
-       cache_system_t  *c;
-       
-       while (1)
-       {
-               c = cache_head.next;
-               if (c == &cache_head)
-                       return;         // nothing in cache at all
-               if ((byte *)c >= hunk_base + new_low_hunk)
-                       return;         // there is space to grow the hunk
-               Cache_Move ( c );       // reclaim the space
-       }
+       // this isn't really very useful
+       if (clump->sentinel1 != MEMCLUMP_SENTINEL)
+               Host_Error("Mem_CheckClumpSentinels: trashed sentinel 1 (sentinel check at %s:%i)\n", filename, fileline);
+       if (clump->sentinel2 != MEMCLUMP_SENTINEL)
+               Host_Error("Mem_CheckClumpSentinels: trashed sentinel 2 (sentinel check at %s:%i)\n", filename, fileline);
 }
 
-/*
-============
-Cache_FreeHigh
-
-Throw things out until the hunk can be expanded to the given point
-============
-*/
-void Cache_FreeHigh (int new_high_hunk)
+void _Mem_CheckSentinelsGlobal(char *filename, int fileline)
 {
-       cache_system_t  *c, *prev;
-       
-       prev = NULL;
-       while (1)
+       memheader_t *mem;
+       memclump_t *clump;
+       mempool_t *pool;
+       for (pool = poolchain;pool;pool = pool->next)
        {
-               c = cache_head.prev;
-               if (c == &cache_head)
-                       return;         // nothing in cache at all
-               if ( (byte *)c + c->size <= hunk_base + hunk_size - new_high_hunk)
-                       return;         // there is space to grow the hunk
-               if (c == prev)
-                       Cache_Free (c->user);   // didn't move out of the way
-               else
-               {
-                       Cache_Move (c); // try to move it
-                       prev = c;
-               }
+               for (mem = pool->chain;mem;mem = mem->chain)
+                       _Mem_CheckSentinels((void *)((long) mem + sizeof(memheader_t)), filename, fileline);
+               for (clump = pool->clumpchain;clump;clump = clump->chain)
+                       _Mem_CheckClumpSentinels(clump, filename, fileline);
        }
 }
 
-void Cache_UnlinkLRU (cache_system_t *cs)
-{
-       if (!cs->lru_next || !cs->lru_prev)
-               Sys_Error ("Cache_UnlinkLRU: NULL link");
+// used for temporary memory allocations around the engine, not for longterm storage
+mempool_t *tempmempool;
+// only for zone
+mempool_t *zonemempool;
 
-       cs->lru_next->lru_prev = cs->lru_prev;
-       cs->lru_prev->lru_next = cs->lru_next;
-       
-       cs->lru_prev = cs->lru_next = NULL;
-}
-
-void Cache_MakeLRU (cache_system_t *cs)
-{
-       if (cs->lru_next || cs->lru_prev)
-               Sys_Error ("Cache_MakeLRU: active link");
-
-       cache_head.lru_next->lru_prev = cs;
-       cs->lru_next = cache_head.lru_next;
-       cs->lru_prev = &cache_head;
-       cache_head.lru_next = cs;
-}
-
-/*
-============
-Cache_TryAlloc
-
-Looks for a free block of memory between the high and low hunk marks
-Size should already include the header and padding
-============
-*/
-cache_system_t *Cache_TryAlloc (int size, qboolean nobottom)
+void Mem_PrintStats(void)
 {
-       cache_system_t  *cs, *new;
-       
-// is the cache completely empty?
-
-       if (!nobottom && cache_head.prev == &cache_head)
-       {
-               if (hunk_size - hunk_high_used - hunk_low_used < size)
-                       Sys_Error ("Cache_TryAlloc: %i is greater then free hunk", size);
-
-               new = (cache_system_t *) (hunk_base + hunk_low_used);
-               memset (new, 0, sizeof(*new));
-               new->size = size;
-
-               cache_head.prev = cache_head.next = new;
-               new->prev = new->next = &cache_head;
-               
-               Cache_MakeLRU (new);
-               return new;
-       }
-       
-// search from the bottom up for space
-
-       new = (cache_system_t *) (hunk_base + hunk_low_used);
-       cs = cache_head.next;
-       
-       do
-       {
-               if (!nobottom || cs != cache_head.next)
-               {
-                       if ( (byte *)cs - (byte *)new >= size)
-                       {       // found space
-                               memset (new, 0, sizeof(*new));
-                               new->size = size;
-                               
-                               new->next = cs;
-                               new->prev = cs->prev;
-                               cs->prev->next = new;
-                               cs->prev = new;
-                               
-                               Cache_MakeLRU (new);
-       
-                               return new;
-                       }
-               }
-
-       // continue looking             
-               new = (cache_system_t *)((byte *)cs + cs->size);
-               cs = cs->next;
-
-       } while (cs != &cache_head);
-       
-// try to allocate one at the very end
-       if ( hunk_base + hunk_size - hunk_high_used - (byte *)new >= size)
+       int count = 0, size = 0;
+       mempool_t *pool;
+       for (pool = poolchain;pool;pool = pool->next)
        {
-               memset (new, 0, sizeof(*new));
-               new->size = size;
-               
-               new->next = &cache_head;
-               new->prev = cache_head.prev;
-               cache_head.prev->next = new;
-               cache_head.prev = new;
-               
-               Cache_MakeLRU (new);
-
-               return new;
+               count++;
+               size += pool->totalsize;
        }
-       
-       return NULL;            // couldn't allocate
-}
-
-/*
-============
-Cache_Flush
-
-Throw everything out, so new data will be demand cached
-============
-*/
-void Cache_Flush (void)
-{
-       while (cache_head.next != &cache_head)
-               Cache_Free ( cache_head.next->user );   // reclaim the space
+       Con_Printf("%i memory pools, totalling %i bytes (%.3fMB)\n", count, size, size / 1048576.0);
+       if (tempmempool == NULL)
+               Con_Printf("Error: no tempmempool allocated\n");
+       else if (tempmempool->chain)
+               Con_Printf("%i bytes (%.3fMB) of temporary memory still allocated (Leak!)\n", tempmempool->totalsize, tempmempool->totalsize / 1048576.0);
 }
 
-
-/*
-============
-Cache_Print
-
-============
-*/
-void Cache_Print (void)
+void Mem_PrintList_f(void)
 {
-       cache_system_t  *cd;
-
-       for (cd = cache_head.next ; cd != &cache_head ; cd = cd->next)
+       mempool_t *pool;
+       Con_Printf("memory pool list:\n"
+                  "size    name\n");
+       for (pool = poolchain;pool;pool = pool->next)
        {
-               Con_Printf ("%8i : %s\n", cd->size, cd->name);
+               if (pool->lastchecksize != 0 && pool->totalsize != pool->lastchecksize)
+                       Con_Printf("%6ik (%6ik actual) %s (%i byte change)\n", (pool->totalsize + 1023) / 1024, (pool->realsize + 1023) / 1024, pool->name, pool->totalsize - pool->lastchecksize);
+               else
+                       Con_Printf("%6ik (%6ik actual) %s\n", (pool->totalsize + 1023) / 1024, (pool->realsize + 1023) / 1024, pool->name);
+               pool->lastchecksize = pool->totalsize;
        }
+       Mem_PrintStats();
 }
 
-/*
-============
-Cache_Report
-
-============
-*/
-void Cache_Report (void)
-{
-       Con_DPrintf ("%4.1f megabyte data cache\n", (hunk_size - hunk_high_used - hunk_low_used) / (float)(1024*1024) );
-}
-
-/*
-============
-Cache_Compact
-
-============
-*/
-void Cache_Compact (void)
-{
-}
-
-/*
-============
-Cache_Init
-
-============
-*/
-void Cache_Init (void)
-{
-       cache_head.next = cache_head.prev = &cache_head;
-       cache_head.lru_next = cache_head.lru_prev = &cache_head;
-
-       Cmd_AddCommand ("flush", Cache_Flush);
-}
-
-/*
-==============
-Cache_Free
-
-Frees the memory and removes it from the LRU list
-==============
-*/
-void Cache_Free (cache_user_t *c)
-{
-       cache_system_t  *cs;
-
-       if (!c->data)
-               Sys_Error ("Cache_Free: not allocated");
-
-       cs = ((cache_system_t *)c->data) - 1;
-
-       cs->prev->next = cs->next;
-       cs->next->prev = cs->prev;
-       cs->next = cs->prev = NULL;
-
-       c->data = NULL;
-
-       Cache_UnlinkLRU (cs);
-}
-
-
-
-/*
-==============
-Cache_Check
-==============
-*/
-void *Cache_Check (cache_user_t *c)
-{
-       cache_system_t  *cs;
-
-       if (!c->data)
-               return NULL;
-
-       cs = ((cache_system_t *)c->data) - 1;
-
-// move to head of LRU
-       Cache_UnlinkLRU (cs);
-       Cache_MakeLRU (cs);
-       
-       return c->data;
-}
-
-
-/*
-==============
-Cache_Alloc
-==============
-*/
-void *Cache_Alloc (cache_user_t *c, int size, char *name)
+extern void R_TextureStats_PrintTotal(void);
+void Memstats_f(void)
 {
-       cache_system_t  *cs;
-
-       if (c->data)
-               Sys_Error ("Cache_Alloc: already allocated");
-       
-       if (size <= 0)
-               Sys_Error ("Cache_Alloc: size %i", size);
-
-       size = (size + sizeof(cache_system_t) + 15) & ~15;
-
-// find memory for it  
-       while (1)
-       {
-               cs = Cache_TryAlloc (size, false);
-               if (cs)
-               {
-                       strncpy (cs->name, name, sizeof(cs->name)-1);
-                       c->data = (void *)(cs+1);
-                       cs->user = c;
-                       break;
-               }
-       
-       // free the least recently used cahedat
-               if (cache_head.lru_prev == &cache_head)
-                       Sys_Error ("Cache_Alloc: out of memory");
-                                                                                                       // not enough memory at all
-               Cache_Free ( cache_head.lru_prev->user );
-       } 
-       
-       return Cache_Check (c);
+       R_TextureStats_PrintTotal();
+       Mem_PrintStats();
 }
 
-//============================================================================
-
-
-void HunkList_f(void)
-{
-       if (Cmd_Argc() == 2)
-               if (strcmp(Cmd_Argv(1), "all"))
-                       Con_Printf("usage: hunklist [all]\n");
-               else
-                       Hunk_Print(true);
-       else
-               Hunk_Print(false);
-}
 
 /*
 ========================
 Memory_Init
 ========================
 */
-void Memory_Init (void *buf, int size)
+void Memory_Init (void)
 {
-       int p;
-       int zonesize = DYNAMIC_SIZE;
+       tempmempool = Mem_AllocPool("Temporary Memory");
+       zonemempool = Mem_AllocPool("Zone");
+}
 
-       hunk_base = buf;
-       hunk_size = size;
-       hunk_low_used = 0;
-       hunk_high_used = 0;
-       
-       Cache_Init ();
-       p = COM_CheckParm ("-zone");
-       if (p)
-       {
-               if (p < com_argc-1)
-                       zonesize = atoi (com_argv[p+1]) * 1024;
-               else
-                       Sys_Error ("Memory_Init: you must specify a size in KB after -zone");
-       }
-       mainzone = Hunk_AllocName (zonesize, "zone" );
-       Z_ClearZone (mainzone, zonesize);
-       Cmd_AddCommand ("hunklist", HunkList_f);
+void Memory_Init_Commands (void)
+{
+       Cmd_AddCommand ("memstats", Memstats_f);
+       Cmd_AddCommand ("memlist", Mem_PrintList_f);
 }
 
diff --git a/zone.h b/zone.h
index 6ec7efca18ab9abf80a5d16ae78f7e0e48b6a5c6..d487969644fb413c8e179e26b15d6c407af6b541 100644 (file)
--- a/zone.h
+++ b/zone.h
@@ -8,7 +8,7 @@ of the License, or (at your option) any later version.
 
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 See the GNU General Public License for more details.
 
@@ -17,112 +17,97 @@ along with this program; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 */
-/*
- memory allocation
-
-
-H_??? The hunk manages the entire memory block given to quake.  It must be
-contiguous.  Memory can be allocated from either the low or high end in a
-stack fashion.  The only way memory is released is by resetting one of the
-pointers.
-
-Hunk allocations should be given a name, so the Hunk_Print () function
-can display usage.
-
-Hunk allocations are guaranteed to be 16 byte aligned.
-
-The video buffers are allocated high to avoid leaving a hole underneath
-server allocations when changing to a higher video mode.
-
-
-Z_??? Zone memory functions used for small, dynamic allocations like text
-strings from command input.  There is only about 48K for it, allocated at
-the very bottom of the hunk.
-
-Cache_??? Cache memory is for objects that can be dynamically loaded and
-can usefully stay persistant between levels.  The size of the cache
-fluctuates from level to level.
-
-To allocate a cachable object
-
-
-Temp_??? Temp memory is used for file loading and surface caching.  The size
-of the cache memory is adjusted so that there is a minimum of 512k remaining
-for temp memory.
-
-
------- Top of Memory -------
-
-high hunk allocations
-
-<--- high hunk reset point held by vid
-
-video buffer
-
-z buffer
-
-surface cache
-
-<--- high hunk used
-
-cachable memory
-
-<--- low hunk used
-
-client and server low hunk allocations
-
-<-- low hunk reset point held by host
 
-startup hunk allocations
+#define POOLNAMESIZE 128
+// give malloc padding so we can't waste most of a page at the end
+#define MEMCLUMPSIZE (65536 - 1536)
+// smallest unit we care about is this many bytes
+#define MEMUNIT 8
+#define MEMBITS (MEMCLUMPSIZE / MEMUNIT)
+#define MEMBITINTS (MEMBITS / 32)
 
-Zone block
+#define MEMHEADER_SENTINEL 0xABADCAFE
+#define MEMCLUMP_SENTINEL 0xDEADF00D
 
------ Bottom of Memory -----
-
-
-
-*/
-
-void Memory_Init (void *buf, int size);
-
-void Z_Free (void *ptr);
-void *Z_Malloc (int size);                     // returns 0 filled memory
-void *Z_TagMalloc (int size, int tag);
-
-void Z_DumpHeap (void);
-void Z_CheckHeap (void);
-int Z_FreeMemory (void);
-
-void *Hunk_AllocName (int size, char *name);
-
-void *Hunk_HighAllocName (int size, char *name);
-
-int    Hunk_LowMark (void);
-void Hunk_FreeToLowMark (int mark);
-
-int    Hunk_HighMark (void);
-void Hunk_FreeToHighMark (int mark);
-
-void Hunk_Check (void);
-
-typedef struct cache_user_s
+typedef struct memheader_s
 {
-       void    *data;
-} cache_user_t;
-
-void Cache_Flush (void);
-
-void *Cache_Check (cache_user_t *c);
-// returns the cached data, and moves to the head of the LRU list
-// if present, otherwise returns NULL
-
-void Cache_Free (cache_user_t *c);
-
-void *Cache_Alloc (cache_user_t *c, int size, char *name);
-// Returns NULL if all purgable data was tossed and there still
-// wasn't enough room.
-
-void Cache_Report (void);
-
-
-
+       // next memheader in chain belonging to pool
+       struct memheader_s *chain;
+       // pool this memheader belongs to
+       struct mempool_s *pool;
+       // clump this memheader lives in, NULL if not in a clump
+       struct memclump_s *clump;
+       // size of the memory after the header (excluding header and sentinel2)
+       int size;
+       // file name and line where Mem_Alloc was called
+       char *filename;
+       int fileline;
+       // should always be MEMHEADER_SENTINEL
+       int sentinel1;
+       // immediately followed by data, which is followed by another MEMHEADER_SENTINEL
+}
+memheader_t;
+
+typedef struct memclump_s
+{
+       // contents of the clump
+       byte block[MEMCLUMPSIZE];
+       // should always be MEMCLUMP_SENTINEL
+       int sentinel1;
+       // if a bit is on, it means that the MEMUNIT bytes it represents are
+       // allocated, otherwise free
+       int bits[MEMBITINTS];
+       // should always be MEMCLUMP_SENTINEL
+       int sentinel2;
+       // if this drops to 0, the clump is freed
+       int blocksinuse;
+       // largest block of memory available (this is reset to an optimistic
+       // number when anything is freed, and updated when alloc fails the clump)
+       int largestavailable;
+       // next clump in the chain
+       struct memclump_s *chain;
+}
+memclump_t;
+
+typedef struct mempool_s
+{
+       // chain of individual memory allocations
+       struct memheader_s *chain;
+       // chain of clumps (if any)
+       struct memclump_s *clumpchain;
+       // total memory allocated in this pool (inside memheaders)
+       int totalsize;
+       // total memory allocated in this pool (actual malloc total)
+       int realsize;
+       // updated each time the pool is displayed by memlist, shows change from previous time (unless pool was freed)
+       int lastchecksize;
+       // name of the pool
+       char name[POOLNAMESIZE];
+       // linked into global mempool list
+       struct mempool_s *next;
+}
+mempool_t;
+
+#define Mem_Alloc(pool,size) _Mem_Alloc(pool, size, __FILE__, __LINE__)
+#define Mem_CheckSentinels(data) _Mem_CheckSentinels(data, __FILE__, __LINE__)
+#define Mem_CheckSentinelsGlobal() _Mem_CheckSentinelsGlobal(__FILE__, __LINE__)
+
+void *_Mem_Alloc(mempool_t *pool, int size, char *filename, int fileline);
+void Mem_Free(void *data);
+mempool_t *Mem_AllocPool(char *name);
+void Mem_FreePool(mempool_t **pool);
+void Mem_EmptyPool(mempool_t *pool);
+void _Mem_CheckSentinels(void *data, char *filename, int fileline);
+void _Mem_CheckSentinelsGlobal(char *filename, int fileline);
+void Mem_PrintStats(void);
+void Mem_PrintList(void);
+
+// used for temporary allocations
+mempool_t *tempmempool;
+
+void Memory_Init (void);
+void Memory_Init_Commands (void);
+
+extern mempool_t *zonemempool;
+#define Z_Malloc(size) Mem_Alloc(zonemempool,size)
+#define Z_Free(data) Mem_Free(data)