-#define BUILDNUMBER 256
+#define BUILDNUMBER 604
int buildnumber = BUILDNUMBER;
{
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;
--- /dev/null
+/*
+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;
+}
+
==============================================================================
*/
+/*
+=====================
+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
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)
Qclose (cls.demofile);
cls.demoplayback = false;
cls.demofile = NULL;
- cls.state = ca_disconnected;
if (cls.timedemo)
CL_FinishTimeDemo ();
r = Qread (cls.demofile, net_message.data, net_message.cursize);
if (r != net_message.cursize)
{
- CL_StopPlayback ();
+ CL_Disconnect ();
return 0;
}
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
time = cl.time - cl.oldtime;
- c_dlights = 0;
dl = cl_dlights;
for (i=0 ; i<MAX_DLIGHTS ; i++, dl++)
{
continue;
}
- c_dlights++; // count every dlight in use
-
dl->radius -= time*dl->decay;
if (dl->radius < 0)
dl->radius = 0;
#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);
-
// 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?
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
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++)
{
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)
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;
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)
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;
}
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];
+ }
}
/*
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();
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);
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
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);
if (effects)
{
if (effects & EF_BRIGHTFIELD)
- R_EntityParticles (ent);
+ CL_EntityParticles (ent);
if (effects & EF_MUZZLEFLASH)
{
vec3_t v, v2;
}
// 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;
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;
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
}
// 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])
{
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;
}
}
-void CL_LerpPlayerVelocity (void)
+static void CL_LerpPlayerVelocity (void)
{
int i;
float frac, d;
}
}
+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();
}
cl.oldtime = cl.time;
cl.time += cl.frametime;
-
+
netshown = false;
do
{
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
// allow mice or other external controllers to add to the move
IN_Move (&cmd);
-
+
// send the unreliable message
CL_SendMove (&cmd);
}
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");
}
// LordHavoc: pausedemo command
-void CL_PauseDemo_f (void)
+static void CL_PauseDemo_f (void)
{
cls.demopaused = !cls.demopaused;
if (cls.demopaused)
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;
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)
CL_Fog_f
======================
*/
-void CL_Fog_f (void)
+static void CL_Fog_f (void)
{
if (Cmd_Argc () == 1)
{
=================
*/
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);
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);
// 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();
}
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.
{
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;
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))
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))
staticlights++;
}
}
- if (hlbsp)
+ if (cl.worldmodel->ishlbsp)
n = LIGHTFADE_LDIVX2;
else if (tyrlite)
n = LIGHTFADE_LMINUSX;
}
}
+/*
+=====================
+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
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;
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 ();
// needlessly purge it
//
- Hunk_Check ();
+ Mem_CheckSentinelsGlobal();
+
+ Mod_ClearUsed();
+
+ Mem_CheckSentinelsGlobal();
// precache models
memset (cl.model_precache, 0, sizeof(cl.model_precache));
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
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)
{
CL_KeepaliveMessage ();
}
- Hunk_Check ();
+ Mem_CheckSentinelsGlobal();
S_BeginPrecaching ();
for (i=1 ; i<numsounds ; i++)
}
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
}
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;
}
}
{
int i, num, deltadie;
entity_t *ent;
+ entity_state_t new;
if (cls.signon == SIGNONS - 1)
{ // first update is the final signon stage
bits |= MSG_ReadByte() << 24;
}
- if (bits & U_LONGENTITY)
+ if (bits & U_LONGENTITY)
num = (unsigned) MSG_ReadShort ();
else
num = (unsigned) MSG_ReadByte ();
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))
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;
}
}
"U_EFFECTS2",
"U_GLOWSIZE",
"U_GLOWCOLOR",
- "U_COLORMOD",
+ "obsolete U_COLORMOD",
"U_EXTEND2",
"U_GLOWTRAIL",
"U_VIEWMODEL",
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);
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);
}
-#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);
/*
=====================
//
// 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
cl.mtime[1] = cl.mtime[0];
cl.mtime[0] = MSG_ReadFloat ();
break;
-
+
case svc_clientdata:
i = MSG_ReadShort ();
CL_ParseClientdata (i);
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;
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
i = MSG_ReadShort();
S_StopSound(i>>3, i&7);
break;
-
+
case svc_updatename:
i = MSG_ReadByte ();
if (i >= cl.maxclients)
break;
case svc_particle:
- R_ParseParticleEffect ();
+ CL_ParseParticleEffect ();
break;
case svc_effect:
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:
--- /dev/null
+/*
+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);
+ }
+ }
+ }
+ }
+ }
+ }
+}
#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;
/*
=================
*/
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");
vec3_t start, end;
beam_t *b;
int i;
-
+
ent = MSG_ReadShort ();
MSG_ReadVector(start);
MSG_ReadVector(end);
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;
-}
/*
=================
{
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
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 )
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
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);
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);
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
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
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
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
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;
/*
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;
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);
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);
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);
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);
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;
}
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;
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.
*/
// 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;
#define SIGNONS 4 // signon messages to receive before connected
-#include "r_light.h"
-
#define MAX_BEAMS 24
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
{
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
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]
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
}
client_state_t;
+extern mempool_t *cl_scores_mempool;
//
// cvars
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;
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);
+
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.
#include "quakedef.h"
-void Cmd_ForwardToServer (void);
-
#define MAX_ALIAS_NAME 32
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;
//=============================================================================
bind g "impulse 5 ; +attack ; wait ; -attack ; impulse 2"
============
*/
-void Cmd_Wait_f (void)
+static void Cmd_Wait_f (void)
{
cmd_wait = true;
}
=============================================================================
*/
-sizebuf_t cmd_text;
+static sizebuf_t cmd_text;
/*
============
*/
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
}
void Cbuf_AddText (char *text)
{
int l;
-
+
l = strlen (text);
if (cmd_text.cursize + l >= cmd_text.maxsize)
}
else
temp = NULL; // shut up compiler
-
+
// add the entire text of the file
Cbuf_AddText (text);
-
+
// add the copied off data
if (templen)
{
char *text;
char line[1024];
int quotes;
-
+
while (cmd_text.cursize)
{
// find a \n or ; line break
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
// 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
int i, j;
int s;
char *text, *build, c;
-
+
if (Cmd_Argc () != 1)
{
Con_Printf ("stuffcmds : execute command line parameters\n");
}
if (!s)
return;
-
+
text = Z_Malloc (s+1);
text[0] = 0;
for (i=1 ; i<com_argc ; i++)
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] == '+')
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);
}
Cmd_Exec_f
===============
*/
-void Cmd_Exec_f (void)
+static void Cmd_Exec_f (void)
{
char *f;
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);
}
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");
===============
*/
-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];
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
strcat (cmd, " ");
}
strcat (cmd, "\n");
-
+
a->value = CopyString (cmd);
}
#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
/*
========
========
*/
-void Cmd_List_f (void)
+static void Cmd_List_f (void)
{
cmd_function_t *cmd;
char *partial;
*/
void Cmd_Init (void)
{
+ cmd_mempool = Mem_AllocPool("commands");
+
//
// register our commands
//
{
if (arg >= cmd_argc )
return cmd_null_string;
- return cmd_argv[arg];
+ return cmd_argv[arg];
}
/*
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
{
text++;
}
-
+
if (*text == '\n')
{ // a newline seperates commands in the buffer
text++;
if (!*text)
return;
-
+
if (cmd_argc == 1)
cmd_args = text;
-
+
text = COM_Parse (text);
if (!text)
return;
cmd_argc++;
}
}
-
+
}
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)
{
}
}
- 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;
cmd_function_t *cmd;
for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
- {
if (!strcmp (cmd_name,cmd->name))
return true;
- }
return false;
}
{
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))
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))
Thanks to taniwha
*/
-char **
-Cmd_CompleteBuildList (char *partial)
+char **Cmd_CompleteBuildList (char *partial)
{
cmd_function_t *cmd;
int len = 0;
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))
Thanks to taniwha
*/
-char
-*Cmd_CompleteAlias (char * partial)
+char *Cmd_CompleteAlias (char * partial)
{
cmdalias_t *alias;
int len;
Thanks to taniwha
*/
-int
-Cmd_CompleteAliasCountPossible (char *partial)
+int Cmd_CompleteAliasCountPossible (char *partial)
{
cmdalias_t *alias;
int len;
Thanks to taniwha
*/
-char **
-Cmd_CompleteAliasBuildList (char *partial)
+char **Cmd_CompleteAliasBuildList (char *partial)
{
cmdalias_t *alias;
int len = 0;
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))
============
*/
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
return;
}
}
-
+
// check cvars
if (!Cvar_Command ())
Con_Printf ("Unknown command \"%s\"\n", Cmd_Argv(0));
-
}
Con_Printf ("Can't \"%s\", not connected\n", Cmd_Argv(0));
return;
}
-
+
if (cls.demoplayback)
return; // not really connected
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;
}
// 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.
#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;
s1++;
s2++;
}
-
+
return -1;
}
s1++;
s2++;
}
-
+
return -1;
}
*/
if (!n--)
return 0; // strings are equal until end point
-
+
if (c1 != c2)
{
if (c1 >= 'a' && c1 <= 'z')
// s1++;
// s2++;
}
-
+
return -1;
}
return (b1<<8) + b2;
}
+#if !defined(ENDIAN_LITTLE) && !defined(ENDIAN_BIG)
short ShortNoSwap (short l)
{
return l;
}
+#endif
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)
{
float f;
byte b[4];
} dat1, dat2;
-
-
+
+
dat1.f = f;
dat2.b[0] = dat1.b[3];
dat2.b[1] = dat1.b[2];
return dat2.f;
}
+#if !defined(ENDIAN_LITTLE) && !defined(ENDIAN_BIG)
float FloatNoSwap (float f)
{
return f;
}
+#endif
/*
==============================================================================
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");
void MSG_WriteLong (sizebuf_t *sb, int c)
{
byte *buf;
-
+
buf = SZ_GetSpace (sb, 4);
buf[0] = c&0xff;
buf[1] = (c>>8)&0xff;
float f;
int l;
} dat;
-
-
+
+
dat.f = f;
dat.l = LittleLong (dat.l);
-
+
SZ_Write (sb, &dat.l, 4);
}
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);
}
//
c = (signed char)net_message.data[msg_readcount];
msg_readcount++;
-
+
return c;
}
msg_badread = true;
return -1;
}
-
+
c = (unsigned char)net_message.data[msg_readcount];
msg_readcount++;
int MSG_ReadShort (void)
{
int c;
-
+
if (msg_readcount+2 > net_message.cursize)
{
msg_badread = true;
//===========================================================================
-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;
}
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;
}
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;
char *COM_SkipPath (char *pathname)
{
char *last;
-
+
last = pathname;
while (*pathname)
{
// 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;
}
-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);
/*
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;
}
#endif
+ pak_mempool = Mem_AllocPool("paks");
+
Cvar_RegisterVariable (®istered);
Cvar_RegisterVariable (&cmdline);
Cmd_AddCommand ("path", COM_Path_f);
- Cmd_AddCommand ("memstats", COM_Memstats_f);
Mathlib_Init();
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;
//
//
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];
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;
void COM_Path_f (void)
{
searchpath_t *s;
-
+
Con_Printf ("Current search path:\n");
for (s=com_searchpaths ; s ; s=s->next)
{
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);
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;
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
{
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;
}
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)
//
// 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;
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;
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]);
*/
// 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
//============================================================================
-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__)
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);
//============================================================================
extern int com_filesize;
-struct cache_user_s;
extern char com_gamedir[MAX_OSPATH];
// 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);
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.
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);
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 ();
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);
}
for (i = 0; i < 3; i++)
if (list[i])
- qfree (list[i]);
+ Mem_Free(list[i]);
}
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))
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)
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;
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;
// 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);
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)
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
}
--- /dev/null
+
+#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 *)¢er) & 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);
+}
--- /dev/null
+
+#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
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.
*/
-// 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
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;
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;
+ }
}
/*
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);
}
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);
glTexCoord2f (fcol, frow + size);
glVertex2f (x, y+8);
glEnd ();
+ CHECKGLERROR
// LordHavoc: revert to LINEAR mode
// if (vid.realwidth <= (int) vid.conwidth)
{
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;
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
{
x += 8;
}
glEnd ();
+ CHECKGLERROR
// LordHavoc: revert to LINEAR mode
// if (vid.realwidth < (int) vid.conwidth)
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
}
/*
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
}
}
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);
}
*/
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];
}
else
glColor4ubv ((byte *)&d_8to24table[c]);
+ CHECKGLERROR
glBegin (GL_QUADS);
glVertex2f (x, y+h);
glEnd ();
+ CHECKGLERROR
glColor3f(1,1,1);
+ CHECKGLERROR
glEnable (GL_TEXTURE_2D);
+ CHECKGLERROR
}
//=============================================================================
*/
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
#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
// 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;
}
}
+/*
void GL_SetupModelTransform (vec3_t origin, vec3_t angles, vec_t scale)
{
glTranslatef (origin[0], origin[1], origin[2]);
if (angles[2])
glRotatef (angles[2], 1, 0, 0);
}
+*/
+
+rtexturepool_t *chrometexturepool;
// currently unused reflection effect texture
void makechrometexture(void)