Make our q2/q3 bsp code more modular, with q2/q3 gamecode treating it more generically.
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@6097 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
parent
23196df675
commit
2b81527a69
28 changed files with 1180 additions and 1959 deletions
|
@ -27,7 +27,7 @@ extern int mod_numknown;
|
||||||
#define VM_FROMSHANDLE(a) ((a&&(unsigned int)a<=r_numshaders)?r_shaders[a-1]:NULL)
|
#define VM_FROMSHANDLE(a) ((a&&(unsigned int)a<=r_numshaders)?r_shaders[a-1]:NULL)
|
||||||
#define VM_TOSHANDLE(a) (a?a->id+1:0)
|
#define VM_TOSHANDLE(a) (a?a->id+1:0)
|
||||||
|
|
||||||
extern model_t box_model;
|
static model_t *box_model;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
CG_PRINT,
|
CG_PRINT,
|
||||||
|
@ -696,7 +696,7 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con
|
||||||
// if (modhandle == MAX_PRECACHE_MODELS+1)
|
// if (modhandle == MAX_PRECACHE_MODELS+1)
|
||||||
// mod = &capsule_model;
|
// mod = &capsule_model;
|
||||||
// else
|
// else
|
||||||
mod = &box_model;
|
mod = box_model;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
mod = cl.model_precache[modhandle+1];
|
mod = cl.model_precache[modhandle+1];
|
||||||
|
@ -721,7 +721,7 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con
|
||||||
// if (modhandle == MAX_PRECACHE_MODELS+1)
|
// if (modhandle == MAX_PRECACHE_MODELS+1)
|
||||||
// mod = &capsule_model;
|
// mod = &capsule_model;
|
||||||
// else
|
// else
|
||||||
mod = &box_model;
|
mod = box_model;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
mod = cl.model_precache[modhandle+1];
|
mod = cl.model_precache[modhandle+1];
|
||||||
|
@ -773,7 +773,7 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con
|
||||||
// if (modhandle == MAX_PRECACHE_MODELS+1)
|
// if (modhandle == MAX_PRECACHE_MODELS+1)
|
||||||
// mod = &capsule_model;
|
// mod = &capsule_model;
|
||||||
// else
|
// else
|
||||||
mod = &box_model;
|
mod = box_model;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
mod = cl.model_precache[modhandle+1];
|
mod = cl.model_precache[modhandle+1];
|
||||||
|
@ -836,7 +836,7 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con
|
||||||
// if (modhandle == MAX_PRECACHE_MODELS+1)
|
// if (modhandle == MAX_PRECACHE_MODELS+1)
|
||||||
// mod = &capsule_model;
|
// mod = &capsule_model;
|
||||||
// else
|
// else
|
||||||
mod = &box_model;
|
mod = box_model;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
mod = cl.model_precache[modhandle+1];
|
mod = cl.model_precache[modhandle+1];
|
||||||
|
@ -848,7 +848,7 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con
|
||||||
if (mod->loadstate == MLS_LOADING)
|
if (mod->loadstate == MLS_LOADING)
|
||||||
COM_WorkerPartialSync(mod, &mod->loadstate, MLS_LOADING);
|
COM_WorkerPartialSync(mod, &mod->loadstate, MLS_LOADING);
|
||||||
if (mod->loadstate != MLS_LOADED)
|
if (mod->loadstate != MLS_LOADED)
|
||||||
mod = &box_model; //stop crashes, even if this is wrong.
|
mod = box_model; //stop crashes, even if this is wrong.
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mins)
|
if (!mins)
|
||||||
|
@ -901,11 +901,11 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CG_CM_TEMPBOXMODEL:
|
case CG_CM_TEMPBOXMODEL:
|
||||||
CM_TempBoxModel(VM_POINTER(arg[0]), VM_POINTER(arg[1]));
|
box_model = CM_TempBoxModel(VM_POINTER(arg[0]), VM_POINTER(arg[1]));
|
||||||
VM_LONG(ret) = MAX_PRECACHE_MODELS;
|
VM_LONG(ret) = MAX_PRECACHE_MODELS;
|
||||||
break;
|
break;
|
||||||
case CG_CM_TEMPCAPSULEMODEL:
|
case CG_CM_TEMPCAPSULEMODEL:
|
||||||
CM_TempBoxModel(VM_POINTER(arg[0]), VM_POINTER(arg[1]));
|
box_model = CM_TempBoxModel(VM_POINTER(arg[0]), VM_POINTER(arg[1]));
|
||||||
VM_LONG(ret) = MAX_PRECACHE_MODELS+1;
|
VM_LONG(ret) = MAX_PRECACHE_MODELS+1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1359,6 +1359,8 @@ void CG_Start (void)
|
||||||
Z_FreeTags(CGTAGNUM);
|
Z_FreeTags(CGTAGNUM);
|
||||||
SCR_BeginLoadingPlaque();
|
SCR_BeginLoadingPlaque();
|
||||||
|
|
||||||
|
box_model = CM_TempBoxModel(vec3_origin, vec3_origin);
|
||||||
|
|
||||||
cgvm = VM_Create("cgame", com_nogamedirnativecode.ival?NULL:CG_SystemCallsNative, "vm/cgame", CG_SystemCallsVM);
|
cgvm = VM_Create("cgame", com_nogamedirnativecode.ival?NULL:CG_SystemCallsNative, "vm/cgame", CG_SystemCallsVM);
|
||||||
if (cgvm)
|
if (cgvm)
|
||||||
{ //hu... cgame doesn't appear to have a query version call!
|
{ //hu... cgame doesn't appear to have a query version call!
|
||||||
|
|
|
@ -6902,57 +6902,56 @@ void CL_DumpPacket(void)
|
||||||
static void CL_ParsePortalState(void)
|
static void CL_ParsePortalState(void)
|
||||||
{
|
{
|
||||||
int mode = MSG_ReadByte();
|
int mode = MSG_ReadByte();
|
||||||
int a1, a2;
|
int p = -1, a1 = -1, a2 = -1, state = -1;
|
||||||
|
#define PS_NEW (1<<7)
|
||||||
|
#define PS_AREANUMS (1<<6) //q3 style
|
||||||
|
#define PS_PORTALNUM (1<<5) //q2 style
|
||||||
|
#define PS_LARGE (1<<1)
|
||||||
|
#define PS_OPEN (1<<0)
|
||||||
|
|
||||||
switch(mode&0xc0)
|
if (mode & PS_NEW)
|
||||||
{
|
{
|
||||||
case 0x80:
|
state = mode&1;
|
||||||
if (mode&2)
|
if (!(mode & PS_AREANUMS) && !(mode & PS_PORTALNUM))
|
||||||
a1 = MSG_ReadShort();
|
mode |= PS_PORTALNUM; //legacy crap
|
||||||
else
|
|
||||||
a1 = MSG_ReadByte();
|
|
||||||
if (cl.worldmodel && cl.worldmodel->loadstate==MLS_LOADED && cl.worldmodel->fromgame == fg_quake2)
|
|
||||||
{
|
|
||||||
#ifdef Q2BSPS
|
|
||||||
CMQ2_SetAreaPortalState(cl.worldmodel, a1, !!(mode&1));
|
|
||||||
#else
|
|
||||||
(void)a1;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 0xc0:
|
|
||||||
if (mode&2)
|
|
||||||
{
|
|
||||||
a1 = MSG_ReadShort();
|
|
||||||
a2 = MSG_ReadShort();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
a1 = MSG_ReadByte();
|
|
||||||
a2 = MSG_ReadByte();
|
|
||||||
}
|
|
||||||
if (cl.worldmodel && cl.worldmodel->loadstate==MLS_LOADED && cl.worldmodel->fromgame == fg_quake3)
|
|
||||||
{
|
|
||||||
#ifdef Q3BSPS
|
|
||||||
CMQ3_SetAreaPortalState(cl.worldmodel, a1, a2, !!(mode&1));
|
|
||||||
#else
|
|
||||||
(void)a1;
|
|
||||||
(void)a2;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
if (mode & PS_PORTALNUM)
|
||||||
//to be phased out.
|
{ //q2 style
|
||||||
mode |= MSG_ReadByte()<<8;
|
if (mode&PS_LARGE)
|
||||||
if (cl.worldmodel && cl.worldmodel->loadstate==MLS_LOADED && cl.worldmodel->fromgame == fg_quake2)
|
p = MSG_ReadShort();
|
||||||
{
|
else
|
||||||
#ifdef Q2BSPS
|
p = MSG_ReadByte();
|
||||||
CMQ2_SetAreaPortalState(cl.worldmodel, mode & 0x7fff, !!(mode&0x8000));
|
}
|
||||||
#endif
|
if (mode & PS_AREANUMS)
|
||||||
|
{ //q3 style
|
||||||
|
if (mode&PS_LARGE)
|
||||||
|
{
|
||||||
|
a1 = MSG_ReadShort();
|
||||||
|
a2 = MSG_ReadShort();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
a1 = MSG_ReadByte();
|
||||||
|
a2 = MSG_ReadByte();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{ //legacy crap
|
||||||
|
Con_Printf(CON_WARNING"svc_setportalstate: legacy mode\n");
|
||||||
|
mode |= MSG_ReadByte()<<8;
|
||||||
|
p = (mode & 0x7fff);
|
||||||
|
state = !!(mode & 0x8000);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_SERVER
|
||||||
|
//reduce race conditions when we're both client+server.
|
||||||
|
if (sv.active)
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (cl.worldmodel && cl.worldmodel->loadstate==MLS_LOADED && cl.worldmodel->funcs.SetAreaPortalState)
|
||||||
|
cl.worldmodel->funcs.SetAreaPortalState(cl.worldmodel, p, a1, a2, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void CL_ParseBaseAngle(int seat)
|
static void CL_ParseBaseAngle(int seat)
|
||||||
|
|
|
@ -198,8 +198,9 @@ int VARGS CLQ2_PMpointcontents (vec3_t point)
|
||||||
int num;
|
int num;
|
||||||
model_t *cmodel;
|
model_t *cmodel;
|
||||||
int contents;
|
int contents;
|
||||||
|
vec3_t axis[3], relpos;
|
||||||
|
|
||||||
contents = CM_PointContents (cl.worldmodel, point);
|
contents = cl.worldmodel->funcs.PointContents(cl.worldmodel, NULL, point);
|
||||||
|
|
||||||
for (i=0 ; i<cl.q2frame.num_entities ; i++)
|
for (i=0 ; i<cl.q2frame.num_entities ; i++)
|
||||||
{
|
{
|
||||||
|
@ -213,7 +214,10 @@ int VARGS CLQ2_PMpointcontents (vec3_t point)
|
||||||
if (!cmodel)
|
if (!cmodel)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
contents |= CM_TransformedPointContents (cl.worldmodel, point, cmodel->hulls[0].firstclipnode, ent->origin, ent->angles);
|
AngleVectors (ent->angles, axis[0], axis[1], axis[2]);
|
||||||
|
VectorNegate(axis[1], axis[1]);
|
||||||
|
VectorSubtract(point, ent->origin, relpos);
|
||||||
|
contents |= cmodel->funcs.PointContents(cmodel, axis, relpos);
|
||||||
}
|
}
|
||||||
|
|
||||||
return contents;
|
return contents;
|
||||||
|
|
|
@ -178,7 +178,9 @@ extern struct model_s *mod_known; //for evil people that want to do evil indexin
|
||||||
const char *Mod_GetEntitiesString(struct model_s *mod);
|
const char *Mod_GetEntitiesString(struct model_s *mod);
|
||||||
void Mod_SetEntitiesStringLen(struct model_s *mod, const char *str, size_t strsize);
|
void Mod_SetEntitiesStringLen(struct model_s *mod, const char *str, size_t strsize);
|
||||||
void Mod_SetEntitiesString(struct model_s *mod, const char *str, qboolean docopy);
|
void Mod_SetEntitiesString(struct model_s *mod, const char *str, qboolean docopy);
|
||||||
|
qboolean Mod_LoadEntitiesBlob(struct model_s *mod, const char *entdata, size_t entdatasize); //initial read, with .ent file replacement etc
|
||||||
void Mod_ParseEntities(struct model_s *mod);
|
void Mod_ParseEntities(struct model_s *mod);
|
||||||
|
void Mod_LoadMapArchive(struct model_s *mod, void *archivedata, size_t archivesize);
|
||||||
extern void Mod_ClearAll (void);
|
extern void Mod_ClearAll (void);
|
||||||
extern void Mod_Purge (enum mod_purge_e type);
|
extern void Mod_Purge (enum mod_purge_e type);
|
||||||
extern qboolean Mod_PurgeModel (struct model_s *mod, enum mod_purge_e ptype);
|
extern qboolean Mod_PurgeModel (struct model_s *mod, enum mod_purge_e ptype);
|
||||||
|
|
|
@ -5386,31 +5386,12 @@ static void QCBUILTIN PF_cs_addprogs (pubprogfuncs_t *prinst, struct globalvars_
|
||||||
|
|
||||||
static void QCBUILTIN PF_cs_OpenPortal (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
static void QCBUILTIN PF_cs_OpenPortal (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||||
{
|
{
|
||||||
/*
|
int state = G_FLOAT(OFS_PARM1)!=0;
|
||||||
#ifdef Q2BSPS
|
wedict_t *ent = G_WEDICT(prinst, OFS_PARM0);
|
||||||
if (csqc_world.worldmodel->fromgame == fg_quake2)
|
int portal = ent->xv->style;
|
||||||
{
|
int area1 = ent->pvsinfo.areanum, area2 = ent->pvsinfo.areanum2;
|
||||||
int portal;
|
if (csqc_world.worldmodel->funcs.SetAreaPortalState)
|
||||||
int state = G_FLOAT(OFS_PARM1)!=0;
|
csqc_world.worldmodel->funcs.SetAreaPortalState(csqc_world.worldmodel, portal, area1, area2, state);
|
||||||
if (G_INT(OFS_PARM1) >= MAX_EDICTS)
|
|
||||||
portal = G_FLOAT(OFS_PARM0); //old legacy crap.
|
|
||||||
else
|
|
||||||
portal = G_WEDICT(prinst, OFS_PARM0)->xv->style; //read the func_areaportal's style field.
|
|
||||||
CMQ2_SetAreaPortalState(csqc_world.worldmodel, portal, state);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
*/
|
|
||||||
#ifdef Q3BSPS
|
|
||||||
if (csqc_world.worldmodel->fromgame == fg_quake3)
|
|
||||||
{
|
|
||||||
int state = G_FLOAT(OFS_PARM1)!=0;
|
|
||||||
wedict_t *portal = G_WEDICT(prinst, OFS_PARM0);
|
|
||||||
int area1 = portal->pvsinfo.areanum, area2 = portal->pvsinfo.areanum2;
|
|
||||||
if (area1 == area2 || area1<0 || area2<0)
|
|
||||||
return;
|
|
||||||
CMQ3_SetAreaPortalState(csqc_world.worldmodel, portal->pvsinfo.areanum, portal->pvsinfo.areanum2, state);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void QCBUILTIN PF_cs_droptofloor (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
static void QCBUILTIN PF_cs_droptofloor (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||||
|
|
|
@ -51,8 +51,6 @@ lightmapinfo_t **lightmap;
|
||||||
int numlightmaps;
|
int numlightmaps;
|
||||||
extern const float rgb9e5tab[32];
|
extern const float rgb9e5tab[32];
|
||||||
|
|
||||||
extern mleaf_t *r_vischain; // linked list of visible leafs
|
|
||||||
|
|
||||||
extern cvar_t r_stains;
|
extern cvar_t r_stains;
|
||||||
extern cvar_t r_loadlits;
|
extern cvar_t r_loadlits;
|
||||||
extern cvar_t r_stainfadetime;
|
extern cvar_t r_stainfadetime;
|
||||||
|
@ -2151,7 +2149,7 @@ static qbyte *Surf_MaskVis(qbyte *src, qbyte *dest)
|
||||||
if (cl.worldmodel->leafs[i].ma
|
if (cl.worldmodel->leafs[i].ma
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
qbyte *frustumvis;
|
static qbyte *q1frustumvis;
|
||||||
|
|
||||||
#ifdef Q1BSPS
|
#ifdef Q1BSPS
|
||||||
/*
|
/*
|
||||||
|
@ -2193,7 +2191,7 @@ start:
|
||||||
pleaf = (mleaf_t *)node;
|
pleaf = (mleaf_t *)node;
|
||||||
|
|
||||||
c = (pleaf - cl.worldmodel->leafs)-1;
|
c = (pleaf - cl.worldmodel->leafs)-1;
|
||||||
frustumvis[c>>3] |= 1<<(c&7);
|
q1frustumvis[c>>3] |= 1<<(c&7);
|
||||||
|
|
||||||
mark = pleaf->firstmarksurface;
|
mark = pleaf->firstmarksurface;
|
||||||
c = pleaf->nummarksurfaces;
|
c = pleaf->nummarksurfaces;
|
||||||
|
@ -2338,289 +2336,6 @@ static void Surf_OrthoRecursiveWorldNode (mnode_t *node, unsigned int clipflags)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef Q2BSPS
|
|
||||||
static void Surf_RecursiveQ2WorldNode (mnode_t *node)
|
|
||||||
{
|
|
||||||
int c, side;
|
|
||||||
mplane_t *plane;
|
|
||||||
msurface_t *surf, **mark;
|
|
||||||
mleaf_t *pleaf;
|
|
||||||
double dot;
|
|
||||||
|
|
||||||
int sidebit;
|
|
||||||
|
|
||||||
if (node->contents == Q2CONTENTS_SOLID)
|
|
||||||
return; // solid
|
|
||||||
|
|
||||||
if (node->visframe != r_visframecount)
|
|
||||||
return;
|
|
||||||
if (R_CullBox (node->minmaxs, node->minmaxs+3))
|
|
||||||
return;
|
|
||||||
|
|
||||||
// if a leaf node, draw stuff
|
|
||||||
if (node->contents != -1)
|
|
||||||
{
|
|
||||||
pleaf = (mleaf_t *)node;
|
|
||||||
|
|
||||||
// check for door connected areas
|
|
||||||
if (! (r_refdef.areabits[pleaf->area>>3] & (1<<(pleaf->area&7)) ) )
|
|
||||||
return; // not visible
|
|
||||||
|
|
||||||
c = pleaf->cluster;
|
|
||||||
if (c >= 0)
|
|
||||||
frustumvis[c>>3] |= 1<<(c&7);
|
|
||||||
|
|
||||||
mark = pleaf->firstmarksurface;
|
|
||||||
c = pleaf->nummarksurfaces;
|
|
||||||
|
|
||||||
if (c)
|
|
||||||
{
|
|
||||||
do
|
|
||||||
{
|
|
||||||
(*mark)->visframe = r_framecount;
|
|
||||||
mark++;
|
|
||||||
} while (--c);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// node is just a decision point, so go down the apropriate sides
|
|
||||||
|
|
||||||
// find which side of the node we are on
|
|
||||||
plane = node->plane;
|
|
||||||
|
|
||||||
switch (plane->type)
|
|
||||||
{
|
|
||||||
case PLANE_X:
|
|
||||||
dot = modelorg[0] - plane->dist;
|
|
||||||
break;
|
|
||||||
case PLANE_Y:
|
|
||||||
dot = modelorg[1] - plane->dist;
|
|
||||||
break;
|
|
||||||
case PLANE_Z:
|
|
||||||
dot = modelorg[2] - plane->dist;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
dot = DotProduct (modelorg, plane->normal) - plane->dist;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dot >= 0)
|
|
||||||
{
|
|
||||||
side = 0;
|
|
||||||
sidebit = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
side = 1;
|
|
||||||
sidebit = SURF_PLANEBACK;
|
|
||||||
}
|
|
||||||
|
|
||||||
// recurse down the children, front side first
|
|
||||||
Surf_RecursiveQ2WorldNode (node->children[side]);
|
|
||||||
|
|
||||||
// draw stuff
|
|
||||||
for ( c = node->numsurfaces, surf = currentmodel->surfaces + node->firstsurface; c ; c--, surf++)
|
|
||||||
{
|
|
||||||
if (surf->visframe != r_framecount)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if ( (surf->flags & SURF_PLANEBACK) != sidebit )
|
|
||||||
continue; // wrong side
|
|
||||||
|
|
||||||
surf->visframe = 0;//r_framecount+1;//-1;
|
|
||||||
|
|
||||||
Surf_RenderDynamicLightmaps (surf);
|
|
||||||
|
|
||||||
surf->sbatch->mesh[surf->sbatch->meshes++] = surf->mesh;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// recurse down the back side
|
|
||||||
Surf_RecursiveQ2WorldNode (node->children[!side]);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef Q3BSPS
|
|
||||||
#if 0
|
|
||||||
static void Surf_LeafWorldNode (void)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
int clipflags;
|
|
||||||
msurface_t **mark, *surf;
|
|
||||||
mleaf_t *pleaf;
|
|
||||||
|
|
||||||
|
|
||||||
int clipped;
|
|
||||||
mplane_t *clipplane;
|
|
||||||
|
|
||||||
|
|
||||||
for (pleaf = r_vischain; pleaf; pleaf = pleaf->vischain)
|
|
||||||
{
|
|
||||||
// check for door connected areas
|
|
||||||
// if (areabits)
|
|
||||||
{
|
|
||||||
// if (!(areabits[pleaf->area>>3] & (1<<(pleaf->area&7))))
|
|
||||||
// {
|
|
||||||
// continue; // not visible
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
clipflags = 15; // 1 | 2 | 4 | 8
|
|
||||||
// if (!r_nocull->value)
|
|
||||||
{
|
|
||||||
|
|
||||||
for (i=0,clipplane=frustum ; i<FRUSTUMPLANES ; i++,clipplane++)
|
|
||||||
{
|
|
||||||
clipped = BoxOnPlaneSide (pleaf->minmaxs, pleaf->minmaxs+3, clipplane);
|
|
||||||
if (clipped == 2)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if (clipped == 1)
|
|
||||||
{
|
|
||||||
clipflags &= ~(1<<i); // node is entirely on screen
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i != FRUSTUMPLANES)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
i = pleaf->nummarksurfaces;
|
|
||||||
mark = pleaf->firstmarksurface;
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
surf = *mark++;
|
|
||||||
if (surf->visframe != r_framecount) //sufraces exist in multiple leafs.
|
|
||||||
{
|
|
||||||
surf->visframe = r_framecount;
|
|
||||||
if (surf->mark)
|
|
||||||
*surf->mark = surf;
|
|
||||||
}
|
|
||||||
} while (--i);
|
|
||||||
|
|
||||||
// c_world_leafs++;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{
|
|
||||||
int j;
|
|
||||||
texture_t *tex;
|
|
||||||
for (i = 0; i < cl.worldmodel->numtextures; i++)
|
|
||||||
{
|
|
||||||
tex = cl.worldmodel->textures[i];
|
|
||||||
if (!tex)
|
|
||||||
continue;
|
|
||||||
for (j = 0; j < tex->vbo.meshcount; j++)
|
|
||||||
{
|
|
||||||
surf = tex->vbo.meshlist[j];
|
|
||||||
if (surf)
|
|
||||||
{
|
|
||||||
tex->vbo.meshlist[j] = NULL;
|
|
||||||
surf->sbatch->mesh[surf->sbatch->meshes++] = surf->mesh;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void Surf_RecursiveQ3WorldNode (mnode_t *node, unsigned int clipflags)
|
|
||||||
{
|
|
||||||
int c, side, clipped;
|
|
||||||
mplane_t *plane, *clipplane;
|
|
||||||
msurface_t *surf, **mark;
|
|
||||||
mleaf_t *pleaf;
|
|
||||||
double dot;
|
|
||||||
|
|
||||||
start:
|
|
||||||
|
|
||||||
if (node->visframe != r_visframecount)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (c = 0, clipplane = r_refdef.frustum; c < r_refdef.frustum_numworldplanes; c++, clipplane++)
|
|
||||||
{
|
|
||||||
if (!(clipflags & (1 << c)))
|
|
||||||
continue; // don't need to clip against it
|
|
||||||
|
|
||||||
clipped = BOX_ON_PLANE_SIDE (node->minmaxs, node->minmaxs + 3, clipplane);
|
|
||||||
if (clipped == 2)
|
|
||||||
return;
|
|
||||||
else if (clipped == 1)
|
|
||||||
clipflags -= (1<<c); // node is entirely on screen
|
|
||||||
}
|
|
||||||
|
|
||||||
// if a leaf node, draw stuff
|
|
||||||
if (node->contents != -1)
|
|
||||||
{
|
|
||||||
pleaf = (mleaf_t *)node;
|
|
||||||
|
|
||||||
if (! (r_refdef.areabits[pleaf->area>>3] & (1<<(pleaf->area&7)) ) )
|
|
||||||
return; // not visible
|
|
||||||
|
|
||||||
c = pleaf->cluster;
|
|
||||||
if (c >= 0)
|
|
||||||
frustumvis[c>>3] |= 1<<(c&7);
|
|
||||||
|
|
||||||
mark = pleaf->firstmarksurface;
|
|
||||||
for (c = pleaf->nummarksurfaces; c; c--)
|
|
||||||
{
|
|
||||||
surf = *mark++;
|
|
||||||
if (surf->visframe == r_framecount)
|
|
||||||
continue;
|
|
||||||
surf->visframe = r_framecount;
|
|
||||||
|
|
||||||
// if (((dot < 0) ^ !!(surf->flags & SURF_PLANEBACK)))
|
|
||||||
// continue; // wrong side
|
|
||||||
|
|
||||||
surf->sbatch->mesh[surf->sbatch->meshes++] = surf->mesh;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// node is just a decision point, so go down the apropriate sides
|
|
||||||
|
|
||||||
// find which side of the node we are on
|
|
||||||
plane = node->plane;
|
|
||||||
|
|
||||||
switch (plane->type)
|
|
||||||
{
|
|
||||||
case PLANE_X:
|
|
||||||
dot = modelorg[0] - plane->dist;
|
|
||||||
break;
|
|
||||||
case PLANE_Y:
|
|
||||||
dot = modelorg[1] - plane->dist;
|
|
||||||
break;
|
|
||||||
case PLANE_Z:
|
|
||||||
dot = modelorg[2] - plane->dist;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
dot = DotProduct (modelorg, plane->normal) - plane->dist;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dot >= 0)
|
|
||||||
side = 0;
|
|
||||||
else
|
|
||||||
side = 1;
|
|
||||||
|
|
||||||
// recurse down the children, front side first
|
|
||||||
Surf_RecursiveQ3WorldNode (node->children[side], clipflags);
|
|
||||||
|
|
||||||
// q3 nodes contain no drawables
|
|
||||||
|
|
||||||
// recurse down the back side
|
|
||||||
//GLR_RecursiveWorldNode (node->children[!side], clipflags);
|
|
||||||
node = node->children[!side];
|
|
||||||
goto start;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void Surf_PushChains(batch_t **batches)
|
static void Surf_PushChains(batch_t **batches)
|
||||||
{
|
{
|
||||||
batch_t *batch;
|
batch_t *batch;
|
||||||
|
@ -2695,8 +2410,7 @@ static void Surf_PopChains(batch_t **batches)
|
||||||
//most of this is a direct copy from gl
|
//most of this is a direct copy from gl
|
||||||
void Surf_SetupFrame(void)
|
void Surf_SetupFrame(void)
|
||||||
{
|
{
|
||||||
mleaf_t *leaf;
|
vec3_t pvsorg;
|
||||||
vec3_t temp, pvsorg;
|
|
||||||
int viewcontents;
|
int viewcontents;
|
||||||
|
|
||||||
if (!cl.worldmodel || cl.worldmodel->loadstate!=MLS_LOADED)
|
if (!cl.worldmodel || cl.worldmodel->loadstate!=MLS_LOADED)
|
||||||
|
@ -2720,91 +2434,34 @@ void Surf_SetupFrame(void)
|
||||||
if (r_refdef.flags & RDF_NOWORLDMODEL)
|
if (r_refdef.flags & RDF_NOWORLDMODEL)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
else if (!cl.worldmodel || cl.worldmodel->loadstate != MLS_LOADED || cl.worldmodel->fromgame == fg_doom3 )
|
else if (cl.worldmodel && cl.worldmodel->loadstate == MLS_LOADED && cl.worldmodel->funcs.InfoForPoint)
|
||||||
{
|
{
|
||||||
r_viewcluster = -1;
|
vec3_t temp;
|
||||||
r_viewcluster2 = -1;
|
unsigned int cont2;
|
||||||
}
|
int area2;
|
||||||
#if defined(Q2BSPS) || defined(Q3BSPS)
|
cl.worldmodel->funcs.InfoForPoint (cl.worldmodel, pvsorg, &r_viewarea, &r_viewcluster, &viewcontents);
|
||||||
else if (cl.worldmodel->fromgame == fg_quake2 || cl.worldmodel->fromgame == fg_quake3)
|
|
||||||
{
|
|
||||||
leaf = Mod_PointInLeaf (cl.worldmodel, pvsorg);
|
|
||||||
r_viewarea = leaf->area;
|
|
||||||
viewcontents = cl.worldmodel->funcs.PointContents(cl.worldmodel, NULL, pvsorg);
|
|
||||||
r_viewcluster = r_viewcluster2 = leaf->cluster;
|
|
||||||
|
|
||||||
// check above and below so crossing solid water doesn't draw wrong
|
// check above and below so crossing solid water doesn't draw wrong
|
||||||
if (!leaf->contents)
|
if (!viewcontents)
|
||||||
{ // look down a bit
|
{ // look down a bit
|
||||||
vec3_t temp;
|
|
||||||
|
|
||||||
VectorCopy (pvsorg, temp);
|
VectorCopy (pvsorg, temp);
|
||||||
temp[2] -= 16;
|
temp[2] -= 16;
|
||||||
leaf = Mod_PointInLeaf (cl.worldmodel, temp);
|
cl.worldmodel->funcs.InfoForPoint (cl.worldmodel, temp, &area2, &r_viewcluster2, &cont2);
|
||||||
if ( !(leaf->contents & Q2CONTENTS_SOLID) &&
|
if (cont2 & FTECONTENTS_SOLID)
|
||||||
(leaf->cluster != r_viewcluster2) )
|
r_viewcluster2 = r_viewcluster;
|
||||||
r_viewcluster2 = leaf->cluster;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{ // look up a bit
|
{ // look up a bit
|
||||||
vec3_t temp;
|
|
||||||
|
|
||||||
VectorCopy (pvsorg, temp);
|
VectorCopy (pvsorg, temp);
|
||||||
temp[2] += 16;
|
temp[2] += 16;
|
||||||
leaf = Mod_PointInLeaf (cl.worldmodel, temp);
|
cl.worldmodel->funcs.InfoForPoint (cl.worldmodel, temp, &area2, &r_viewcluster2, &cont2);
|
||||||
if ( !(leaf->contents & Q2CONTENTS_SOLID) &&
|
if (cont2 & FTECONTENTS_SOLID)
|
||||||
(leaf->cluster != r_viewcluster2) )
|
r_viewcluster2 = r_viewcluster;
|
||||||
r_viewcluster2 = leaf->cluster;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
leaf = Mod_PointInLeaf (cl.worldmodel, pvsorg);
|
r_viewcluster = -1;
|
||||||
r_viewcluster = (leaf - cl.worldmodel->leafs)-1;
|
|
||||||
r_viewcluster2 = -1;
|
r_viewcluster2 = -1;
|
||||||
if (leaf)
|
|
||||||
{
|
|
||||||
switch(leaf->contents)
|
|
||||||
{
|
|
||||||
case Q1CONTENTS_WATER:
|
|
||||||
viewcontents |= FTECONTENTS_WATER;
|
|
||||||
break;
|
|
||||||
case Q1CONTENTS_LAVA:
|
|
||||||
viewcontents |= FTECONTENTS_LAVA;
|
|
||||||
break;
|
|
||||||
case Q1CONTENTS_SLIME:
|
|
||||||
viewcontents |= FTECONTENTS_SLIME;
|
|
||||||
break;
|
|
||||||
case Q1CONTENTS_SKY:
|
|
||||||
viewcontents |= FTECONTENTS_SKY;
|
|
||||||
break;
|
|
||||||
case Q1CONTENTS_SOLID:
|
|
||||||
viewcontents |= FTECONTENTS_SOLID;
|
|
||||||
break;
|
|
||||||
case Q1CONTENTS_LADDER:
|
|
||||||
viewcontents |= FTECONTENTS_LADDER;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (leaf->contents == Q1CONTENTS_EMPTY)
|
|
||||||
{ //look down a bit
|
|
||||||
VectorCopy (pvsorg, temp);
|
|
||||||
temp[2] -= 16;
|
|
||||||
leaf = Mod_PointInLeaf (cl.worldmodel, temp);
|
|
||||||
if (leaf->contents <= Q1CONTENTS_WATER && leaf->contents >= Q1CONTENTS_LAVA)
|
|
||||||
r_viewcluster2 = (leaf - cl.worldmodel->leafs)-1;
|
|
||||||
}
|
|
||||||
else if (leaf->contents <= Q1CONTENTS_WATER && leaf->contents >= Q1CONTENTS_LAVA)
|
|
||||||
{ //in water, look up a bit.
|
|
||||||
|
|
||||||
VectorCopy (pvsorg, temp);
|
|
||||||
temp[2] += 16;
|
|
||||||
leaf = Mod_PointInLeaf (cl.worldmodel, temp);
|
|
||||||
if (leaf->contents == Q1CONTENTS_EMPTY)
|
|
||||||
r_viewcluster2 = (leaf - cl.worldmodel->leafs)-1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef TERRAIN
|
#ifdef TERRAIN
|
||||||
|
@ -3778,57 +3435,16 @@ void Surf_DrawWorld (void)
|
||||||
|
|
||||||
Surf_PushChains(currentmodel->batches);
|
Surf_PushChains(currentmodel->batches);
|
||||||
|
|
||||||
if (currentmodel->type != mod_brush)
|
if (currentmodel->funcs.PrepareFrame)
|
||||||
{
|
{
|
||||||
frustumvis = NULL;
|
int clusters[2] = {r_viewcluster, r_viewcluster2};
|
||||||
|
currentmodel->funcs.PrepareFrame(currentmodel, &r_refdef, r_viewarea, clusters, &surf_frustumvis[r_refdef.recurse], &entvis, &surfvis);
|
||||||
|
}
|
||||||
|
else if (currentmodel->type != mod_brush)
|
||||||
entvis = surfvis = NULL;
|
entvis = surfvis = NULL;
|
||||||
}
|
|
||||||
#if defined(Q2BSPS) || defined(Q3BSPS)
|
|
||||||
else if (currentmodel->fromgame == fg_quake2 || currentmodel->fromgame == fg_quake3)
|
|
||||||
{
|
|
||||||
pvsbuffer_t *vis = &surf_frustumvis[r_refdef.recurse];
|
|
||||||
if (vis->buffersize < currentmodel->pvsbytes)
|
|
||||||
vis->buffer = BZ_Realloc(vis->buffer, vis->buffersize=currentmodel->pvsbytes);
|
|
||||||
frustumvis = vis->buffer;
|
|
||||||
memset(frustumvis, 0, currentmodel->pvsbytes);
|
|
||||||
|
|
||||||
if (!r_refdef.areabitsknown)
|
|
||||||
{ //generate the info each frame, as the gamecode didn't tell us what to use.
|
|
||||||
int leafnum = CM_PointLeafnum (currentmodel, r_refdef.vieworg);
|
|
||||||
int clientarea = CM_LeafArea (currentmodel, leafnum);
|
|
||||||
CM_WriteAreaBits(currentmodel, r_refdef.areabits, clientarea, false);
|
|
||||||
r_refdef.areabitsknown = true;
|
|
||||||
}
|
|
||||||
#ifdef Q3BSPS
|
|
||||||
if (currentmodel->fromgame == fg_quake3)
|
|
||||||
{
|
|
||||||
entvis = surfvis = R_MarkLeaves_Q3 ();
|
|
||||||
Surf_RecursiveQ3WorldNode (currentmodel->nodes, (1<<r_refdef.frustum_numworldplanes)-1);
|
|
||||||
//Surf_LeafWorldNode ();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
#ifdef Q2BSPS
|
|
||||||
if (currentmodel->fromgame == fg_quake2)
|
|
||||||
{
|
|
||||||
entvis = surfvis = R_MarkLeaves_Q2 ();
|
|
||||||
VectorCopy (r_refdef.vieworg, modelorg);
|
|
||||||
Surf_RecursiveQ2WorldNode (currentmodel->nodes);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
entvis = surfvis = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
surfvis = frustumvis;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#ifdef MAP_PROC
|
#ifdef MAP_PROC
|
||||||
else if (currentmodel->fromgame == fg_doom3)
|
else if (currentmodel->fromgame == fg_doom3)
|
||||||
{
|
|
||||||
entvis = surfvis = D3_CalcVis(currentmodel, r_origin);
|
entvis = surfvis = D3_CalcVis(currentmodel, r_origin);
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef MAP_DOOM
|
#ifdef MAP_DOOM
|
||||||
else if (currentmodel->fromgame == fg_doom)
|
else if (currentmodel->fromgame == fg_doom)
|
||||||
|
@ -3838,37 +3454,28 @@ void Surf_DrawWorld (void)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifdef Q1BSPS
|
#ifdef Q1BSPS
|
||||||
else if (1)
|
else if (currentmodel->fromgame == fg_quake || currentmodel->fromgame == fg_halflife)
|
||||||
{
|
{
|
||||||
//extern cvar_t temp1;
|
pvsbuffer_t *vis = &surf_frustumvis[r_refdef.recurse];
|
||||||
// if (0)//temp1.value)
|
|
||||||
// entvis = surfvis = R_MarkLeafSurfaces_Q1();
|
|
||||||
// else
|
|
||||||
{
|
|
||||||
pvsbuffer_t *vis = &surf_frustumvis[r_refdef.recurse];
|
|
||||||
|
|
||||||
entvis = R_MarkLeaves_Q1 (false);
|
entvis = R_MarkLeaves_Q1 (false);
|
||||||
if (!(r_novis.ival & 2))
|
if (!(r_novis.ival & 2))
|
||||||
VectorCopy (r_origin, modelorg);
|
VectorCopy (r_origin, modelorg);
|
||||||
|
|
||||||
if (vis->buffersize < currentmodel->pvsbytes)
|
if (vis->buffersize < currentmodel->pvsbytes)
|
||||||
vis->buffer = BZ_Realloc(vis->buffer, vis->buffersize=currentmodel->pvsbytes);
|
vis->buffer = BZ_Realloc(vis->buffer, vis->buffersize=currentmodel->pvsbytes);
|
||||||
frustumvis = vis->buffer;
|
q1frustumvis = vis->buffer;
|
||||||
memset(frustumvis, 0, currentmodel->pvsbytes);
|
memset(q1frustumvis, 0, currentmodel->pvsbytes);
|
||||||
|
|
||||||
if (r_refdef.useperspective)
|
if (r_refdef.useperspective)
|
||||||
Surf_RecursiveWorldNode (currentmodel->nodes, 0x1f);
|
Surf_RecursiveWorldNode (currentmodel->nodes, 0x1f);
|
||||||
else
|
else
|
||||||
Surf_OrthoRecursiveWorldNode (currentmodel->nodes, 0x1f);
|
Surf_OrthoRecursiveWorldNode (currentmodel->nodes, 0x1f);
|
||||||
surfvis = frustumvis;
|
surfvis = q1frustumvis;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
else
|
else
|
||||||
{
|
|
||||||
frustumvis = NULL;
|
|
||||||
entvis = surfvis = NULL;
|
entvis = surfvis = NULL;
|
||||||
}
|
|
||||||
|
|
||||||
RSpeedEnd(RSPEED_WORLDNODE);
|
RSpeedEnd(RSPEED_WORLDNODE);
|
||||||
|
|
||||||
|
|
|
@ -550,8 +550,6 @@ void *Mod_Extradata (struct model_s *mod); // handles caching
|
||||||
void Mod_TouchModel (const char *name);
|
void Mod_TouchModel (const char *name);
|
||||||
void Mod_RebuildLightmaps (void);
|
void Mod_RebuildLightmaps (void);
|
||||||
|
|
||||||
struct mleaf_s *Mod_PointInLeaf (struct model_s *model, float *p);
|
|
||||||
|
|
||||||
void Mod_NowLoadExternal(struct model_s *loadmodel);
|
void Mod_NowLoadExternal(struct model_s *loadmodel);
|
||||||
void GLR_LoadSkys (void);
|
void GLR_LoadSkys (void);
|
||||||
void R_BloomRegister(void);
|
void R_BloomRegister(void);
|
||||||
|
|
|
@ -1900,11 +1900,11 @@ void R_ReloadRenderer_f (void)
|
||||||
if (qrenderer == QR_NONE || qrenderer == QR_HEADLESS)
|
if (qrenderer == QR_NONE || qrenderer == QR_HEADLESS)
|
||||||
return; //don't bother reloading the renderer if its not actually rendering anything anyway.
|
return; //don't bother reloading the renderer if its not actually rendering anything anyway.
|
||||||
|
|
||||||
#if !defined(CLIENTONLY) && (defined(Q2BSPS) || defined(Q3BSPS))
|
#if !defined(CLIENTONLY)
|
||||||
if (sv.state == ss_active && sv.world.worldmodel && sv.world.worldmodel->loadstate == MLS_LOADED)
|
if (sv.state == ss_active && sv.world.worldmodel && sv.world.worldmodel->loadstate == MLS_LOADED && sv.world.worldmodel->funcs.SaveAreaPortalBlob)
|
||||||
{
|
{
|
||||||
void *t;
|
void *t;
|
||||||
portalsize = CM_WritePortalState(sv.world.worldmodel, &t);
|
portalsize = sv.world.worldmodel->funcs.SaveAreaPortalBlob(sv.world.worldmodel, &t);
|
||||||
if (portalsize && (portalblob = BZ_Malloc(portalsize)))
|
if (portalsize && (portalblob = BZ_Malloc(portalsize)))
|
||||||
memcpy(portalblob, t, portalsize);
|
memcpy(portalblob, t, portalsize);
|
||||||
}
|
}
|
||||||
|
@ -1917,11 +1917,11 @@ void R_ReloadRenderer_f (void)
|
||||||
R_ApplyRenderer_Load(NULL);
|
R_ApplyRenderer_Load(NULL);
|
||||||
Cvar_ApplyCallbacks(CVAR_RENDERERCALLBACK);
|
Cvar_ApplyCallbacks(CVAR_RENDERERCALLBACK);
|
||||||
|
|
||||||
#if !defined(CLIENTONLY) && (defined(Q2BSPS) || defined(Q3BSPS))
|
#if !defined(CLIENTONLY)
|
||||||
if (portalblob)
|
if (portalblob)
|
||||||
{
|
{
|
||||||
if (sv.world.worldmodel && sv.world.worldmodel->loadstate == MLS_LOADED)
|
if (sv.world.worldmodel && sv.world.worldmodel->loadstate == MLS_LOADED && sv.world.worldmodel->funcs.LoadAreaPortalBlob)
|
||||||
CM_ReadPortalState(sv.world.worldmodel, portalblob, portalsize);
|
sv.world.worldmodel->funcs.LoadAreaPortalBlob(sv.world.worldmodel, portalblob, portalsize);
|
||||||
BZ_Free(portalblob);
|
BZ_Free(portalblob);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -2166,11 +2166,11 @@ void R_RestartRenderer (rendererstate_t *newr)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !defined(CLIENTONLY) && (defined(Q2BSPS) || defined(Q3BSPS))
|
#ifdef HAVE_SERVER
|
||||||
if (sv.state == ss_active && sv.world.worldmodel && sv.world.worldmodel->loadstate == MLS_LOADED)
|
if (sv.state == ss_active && sv.world.worldmodel && sv.world.worldmodel->loadstate == MLS_LOADED && sv.world.worldmodel->funcs.SaveAreaPortalBlob)
|
||||||
{
|
{
|
||||||
void *t;
|
void *t;
|
||||||
portalsize = CM_WritePortalState(sv.world.worldmodel, &t);
|
portalsize = sv.world.worldmodel->funcs.SaveAreaPortalBlob(sv.world.worldmodel, &t);
|
||||||
if (portalsize && (portalblob = BZ_Malloc(portalsize)))
|
if (portalsize && (portalblob = BZ_Malloc(portalsize)))
|
||||||
memcpy(portalblob, t, portalsize);
|
memcpy(portalblob, t, portalsize);
|
||||||
}
|
}
|
||||||
|
@ -2264,11 +2264,11 @@ void R_RestartRenderer (rendererstate_t *newr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !defined(CLIENTONLY) && (defined(Q2BSPS) || defined(Q3BSPS))
|
#ifdef HAVE_SERVER
|
||||||
if (portalblob)
|
if (portalblob)
|
||||||
{
|
{
|
||||||
if (sv.world.worldmodel && sv.world.worldmodel->loadstate == MLS_LOADED)
|
if (sv.world.worldmodel && sv.world.worldmodel->loadstate == MLS_LOADED && sv.world.worldmodel->funcs.LoadAreaPortalBlob)
|
||||||
CM_ReadPortalState(sv.world.worldmodel, portalblob, portalsize);
|
sv.world.worldmodel->funcs.LoadAreaPortalBlob(sv.world.worldmodel, portalblob, portalsize);
|
||||||
BZ_Free(portalblob);
|
BZ_Free(portalblob);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -2652,218 +2652,10 @@ unsigned int r_viewcontents;
|
||||||
int r_viewarea;
|
int r_viewarea;
|
||||||
int r_viewcluster, r_viewcluster2, r_oldviewcluster, r_oldviewcluster2;
|
int r_viewcluster, r_viewcluster2, r_oldviewcluster, r_oldviewcluster2;
|
||||||
int r_visframecount;
|
int r_visframecount;
|
||||||
mleaf_t *r_vischain; // linked list of visible leafs
|
|
||||||
static pvsbuffer_t curframevis[R_MAX_RECURSE];
|
static pvsbuffer_t curframevis[R_MAX_RECURSE];
|
||||||
|
|
||||||
/*
|
|
||||||
===============
|
|
||||||
R_MarkLeaves
|
|
||||||
===============
|
|
||||||
*/
|
|
||||||
#ifdef Q3BSPS
|
|
||||||
qbyte *R_MarkLeaves_Q3 (void)
|
|
||||||
{
|
|
||||||
static qbyte *cvis[R_MAX_RECURSE];
|
|
||||||
qbyte *vis;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
int cluster;
|
|
||||||
mleaf_t *leaf;
|
|
||||||
mnode_t *node;
|
|
||||||
int portal = r_refdef.recurse;
|
|
||||||
|
|
||||||
if (!portal)
|
|
||||||
{
|
|
||||||
if (r_oldviewcluster == r_viewcluster && !r_novis.value && r_viewcluster != -1)
|
|
||||||
return cvis[portal];
|
|
||||||
}
|
|
||||||
|
|
||||||
// development aid to let you run around and see exactly where
|
|
||||||
// the pvs ends
|
|
||||||
// if (r_lockpvs->value)
|
|
||||||
// return;
|
|
||||||
|
|
||||||
r_vischain = NULL;
|
|
||||||
r_visframecount++;
|
|
||||||
r_oldviewcluster = r_viewcluster;
|
|
||||||
|
|
||||||
if (r_novis.ival || r_viewcluster == -1 || !cl.worldmodel->vis )
|
|
||||||
{
|
|
||||||
vis = NULL;
|
|
||||||
// mark everything
|
|
||||||
for (i=0,leaf=cl.worldmodel->leafs ; i<cl.worldmodel->numleafs ; i++, leaf++)
|
|
||||||
{
|
|
||||||
// if (!leaf->nummarksurfaces)
|
|
||||||
// {
|
|
||||||
// continue;
|
|
||||||
// }
|
|
||||||
|
|
||||||
#if 1
|
|
||||||
for (node = (mnode_t*)leaf; node; node = node->parent)
|
|
||||||
{
|
|
||||||
if (node->visframe == r_visframecount)
|
|
||||||
break;
|
|
||||||
node->visframe = r_visframecount;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
leaf->visframe = r_visframecount;
|
|
||||||
leaf->vischain = r_vischain;
|
|
||||||
r_vischain = leaf;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
vis = CM_ClusterPVS (cl.worldmodel, r_viewcluster, &curframevis[portal], PVM_FAST);
|
|
||||||
for (i=0,leaf=cl.worldmodel->leafs ; i<cl.worldmodel->numleafs ; i++, leaf++)
|
|
||||||
{
|
|
||||||
cluster = leaf->cluster;
|
|
||||||
if (cluster == -1)// || !leaf->nummarksurfaces)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (vis[cluster>>3] & (1<<(cluster&7)))
|
|
||||||
{
|
|
||||||
#if 1
|
|
||||||
for (node = (mnode_t*)leaf; node; node = node->parent)
|
|
||||||
{
|
|
||||||
if (node->visframe == r_visframecount)
|
|
||||||
break;
|
|
||||||
node->visframe = r_visframecount;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
leaf->visframe = r_visframecount;
|
|
||||||
leaf->vischain = r_vischain;
|
|
||||||
r_vischain = leaf;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cvis[portal] = vis;
|
|
||||||
}
|
|
||||||
return vis;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef Q2BSPS
|
|
||||||
qbyte *R_MarkLeaves_Q2 (void)
|
|
||||||
{
|
|
||||||
static qbyte *cvis[R_MAX_RECURSE];
|
|
||||||
mnode_t *node;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
int cluster;
|
|
||||||
mleaf_t *leaf;
|
|
||||||
qbyte *vis;
|
|
||||||
|
|
||||||
int portal = r_refdef.recurse;
|
|
||||||
|
|
||||||
if (r_refdef.forcevis)
|
|
||||||
{
|
|
||||||
vis = cvis[portal] = r_refdef.forcedvis;
|
|
||||||
|
|
||||||
r_oldviewcluster = -1;
|
|
||||||
r_oldviewcluster2 = -1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
vis = cvis[portal];
|
|
||||||
if (!portal)
|
|
||||||
{
|
|
||||||
if (r_oldviewcluster == r_viewcluster && r_oldviewcluster2 == r_viewcluster2)
|
|
||||||
return vis;
|
|
||||||
|
|
||||||
r_oldviewcluster = r_viewcluster;
|
|
||||||
r_oldviewcluster2 = r_viewcluster2;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
r_oldviewcluster = -1;
|
|
||||||
r_oldviewcluster2 = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (r_novis.ival == 2)
|
|
||||||
return vis;
|
|
||||||
|
|
||||||
if (r_novis.ival || r_viewcluster == -1 || !cl.worldmodel->vis)
|
|
||||||
{
|
|
||||||
// mark everything
|
|
||||||
for (i=0 ; i<cl.worldmodel->numleafs ; i++)
|
|
||||||
cl.worldmodel->leafs[i].visframe = r_visframecount;
|
|
||||||
for (i=0 ; i<cl.worldmodel->numnodes ; i++)
|
|
||||||
cl.worldmodel->nodes[i].visframe = r_visframecount;
|
|
||||||
return vis;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (r_viewcluster2 != r_viewcluster) // may have to combine two clusters because of solid water boundaries
|
|
||||||
{
|
|
||||||
vis = CM_ClusterPVS (cl.worldmodel, r_viewcluster, &curframevis[portal], PVM_REPLACE);
|
|
||||||
vis = CM_ClusterPVS (cl.worldmodel, r_viewcluster2, &curframevis[portal], PVM_MERGE);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
vis = CM_ClusterPVS (cl.worldmodel, r_viewcluster, &curframevis[portal], PVM_FAST);
|
|
||||||
cvis[portal] = vis;
|
|
||||||
}
|
|
||||||
|
|
||||||
r_visframecount++;
|
|
||||||
|
|
||||||
for (i=0,leaf=cl.worldmodel->leafs ; i<cl.worldmodel->numleafs ; i++, leaf++)
|
|
||||||
{
|
|
||||||
cluster = leaf->cluster;
|
|
||||||
if (cluster == -1)
|
|
||||||
continue;
|
|
||||||
if (vis[cluster>>3] & (1<<(cluster&7)))
|
|
||||||
{
|
|
||||||
node = (mnode_t *)leaf;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
if (node->visframe == r_visframecount)
|
|
||||||
break;
|
|
||||||
node->visframe = r_visframecount;
|
|
||||||
node = node->parent;
|
|
||||||
} while (node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return vis;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef Q1BSPS
|
#ifdef Q1BSPS
|
||||||
#if 0
|
|
||||||
qbyte *R_CalcVis_Q1 (void)
|
|
||||||
{
|
|
||||||
unsigned int i;
|
|
||||||
static qbyte *vis;
|
|
||||||
r_visframecount++;
|
|
||||||
if (r_oldviewleaf == r_viewleaf && r_oldviewleaf2 == r_viewleaf2)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
r_oldviewleaf = r_viewleaf;
|
|
||||||
r_oldviewleaf2 = r_viewleaf2;
|
|
||||||
|
|
||||||
if (r_novis.ival&1)
|
|
||||||
{
|
|
||||||
vis = curframevis;
|
|
||||||
memset (vis, 0xff, (cl.worldmodel->numleafs+7)>>3);
|
|
||||||
}
|
|
||||||
else if (r_viewleaf2 && r_viewleaf2 != r_viewleaf)
|
|
||||||
{
|
|
||||||
int c;
|
|
||||||
Q1BSP_LeafPVS (cl.worldmodel, r_viewleaf2, curframevis, sizeof(curframevis));
|
|
||||||
vis = Q1BSP_LeafPVS (cl.worldmodel, r_viewleaf, NULL, sizeof(curframevis));
|
|
||||||
c = (cl.worldmodel->numclusters+31)/32;
|
|
||||||
for (i=0 ; i<c ; i++)
|
|
||||||
((int *)curframevis)[i] |= ((int *)vis)[i];
|
|
||||||
vis = curframevis;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
vis = Q1BSP_LeafPVS (cl.worldmodel, r_viewleaf, curframevis, sizeof(curframevis));
|
|
||||||
}
|
|
||||||
return vis;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
qbyte *R_MarkLeaves_Q1 (qboolean getvisonly)
|
qbyte *R_MarkLeaves_Q1 (qboolean getvisonly)
|
||||||
{
|
{
|
||||||
static qbyte *cvis[R_MAX_RECURSE];
|
static qbyte *cvis[R_MAX_RECURSE];
|
||||||
|
|
|
@ -931,11 +931,9 @@ typedef struct
|
||||||
#define MAX_ENT_LEAFS 32
|
#define MAX_ENT_LEAFS 32
|
||||||
typedef struct pvscache_s
|
typedef struct pvscache_s
|
||||||
{
|
{
|
||||||
int num_leafs;
|
int num_leafs; //negative generally means resort-to-headnode.
|
||||||
unsigned int leafnums[MAX_ENT_LEAFS];
|
unsigned int leafnums[MAX_ENT_LEAFS];
|
||||||
#if defined(Q2BSPS) || defined(Q3BSPS) || defined(TERRAIN)
|
int areanum;
|
||||||
int areanum; //q2bsp
|
int areanum2;
|
||||||
int areanum2; //q2bsp
|
int headnode;
|
||||||
int headnode; //q2bsp
|
|
||||||
#endif
|
|
||||||
} pvscache_t;
|
} pvscache_t;
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -2004,35 +2004,10 @@ static qbyte *Q1BSP_ClusterPVS (model_t *model, int cluster, pvsbuffer_t *buffer
|
||||||
return Q1BSP_DecompressVis (model->leafs[cluster].compressed_vis, model, buffer->buffer, buffer->buffersize, merge==PVM_MERGE);
|
return Q1BSP_DecompressVis (model->leafs[cluster].compressed_vis, model, buffer->buffer, buffer->buffersize, merge==PVM_MERGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*static qbyte *Q1BSP_ClusterPHS (model_t *model, int cluster, pvsbuffer_t *buffer, pvsmerge_t merge)
|
static qbyte *Q1BSP_ClusterPHS (model_t *model, int cluster, pvsbuffer_t *buffer)
|
||||||
{
|
{
|
||||||
if (cluster == -1 || !model->phs)
|
return model->phs + cluster*model->pvsbytes;
|
||||||
{
|
}
|
||||||
if (merge == PVM_FAST)
|
|
||||||
{
|
|
||||||
if (mod_novis.buffersize < model->pvsbytes)
|
|
||||||
{
|
|
||||||
mod_novis.buffer = BZ_Realloc(mod_novis.buffer, mod_novis.buffersize=model->pvsbytes);
|
|
||||||
memset(mod_novis.buffer, 0xff, mod_novis.buffersize);
|
|
||||||
}
|
|
||||||
return mod_novis.buffer;
|
|
||||||
}
|
|
||||||
if (buffer->buffersize < model->pvsbytes)
|
|
||||||
buffer->buffer = BZ_Realloc(buffer->buffer, buffer->buffersize=model->pvsbytes);
|
|
||||||
memset(buffer->buffer, 0xff, model->pvsbytes);
|
|
||||||
return buffer->buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (merge == PVM_FAST)
|
|
||||||
return model->pvs + cluster * model->pvsbytes;
|
|
||||||
|
|
||||||
if (!buffer)
|
|
||||||
buffer = &mod_tempvis;
|
|
||||||
if (buffer->buffersize < model->pvsbytes)
|
|
||||||
buffer->buffer = BZ_Realloc(buffer->buffer, buffer->buffersize=model->pvsbytes);
|
|
||||||
memcpy(buffer->buffer, model->pvs + cluster * model->pvsbytes, model->pvsbytes);
|
|
||||||
return buffer->buffer;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
//returns the leaf number, which is used as a bit index into the pvs.
|
//returns the leaf number, which is used as a bit index into the pvs.
|
||||||
static int Q1BSP_LeafnumForPoint (model_t *model, vec3_t p)
|
static int Q1BSP_LeafnumForPoint (model_t *model, vec3_t p)
|
||||||
|
@ -2043,7 +2018,7 @@ static int Q1BSP_LeafnumForPoint (model_t *model, vec3_t p)
|
||||||
|
|
||||||
if (!model)
|
if (!model)
|
||||||
{
|
{
|
||||||
Sys_Error ("Mod_PointInLeaf: bad model");
|
Sys_Error ("Q1BSP_LeafnumForPoint: bad model");
|
||||||
}
|
}
|
||||||
if (!model->nodes)
|
if (!model->nodes)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -2116,7 +2091,7 @@ static void Q1BSP_ClustersInSphere_Union(mleaf_t *firstleaf, const vec3_t center
|
||||||
static qbyte *Q1BSP_ClustersInSphere(model_t *mod, const vec3_t center, float radius, pvsbuffer_t *fte_restrict pvsbuffer, const qbyte *fte_restrict unionwith)
|
static qbyte *Q1BSP_ClustersInSphere(model_t *mod, const vec3_t center, float radius, pvsbuffer_t *fte_restrict pvsbuffer, const qbyte *fte_restrict unionwith)
|
||||||
{
|
{
|
||||||
if (!mod)
|
if (!mod)
|
||||||
Sys_Error ("Mod_PointInLeaf: bad model");
|
Sys_Error ("Q1BSP_ClustersInSphere: bad model");
|
||||||
if (!mod->nodes)
|
if (!mod->nodes)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -2137,7 +2112,7 @@ static int Q1BSP_ClusterForPoint (model_t *model, const vec3_t p, int *area)
|
||||||
|
|
||||||
if (!model)
|
if (!model)
|
||||||
{
|
{
|
||||||
Sys_Error ("Mod_PointInLeaf: bad model");
|
Sys_Error ("Q1BSP_ClusterForPoint: bad model");
|
||||||
}
|
}
|
||||||
if (area)
|
if (area)
|
||||||
*area = 0; //no areas with q1bsp.
|
*area = 0; //no areas with q1bsp.
|
||||||
|
@ -2161,6 +2136,37 @@ static int Q1BSP_ClusterForPoint (model_t *model, const vec3_t p, int *area)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void Q1BSP_InfoForPoint (struct model_s *mod, vec3_t pos, int *area, int *cluster, unsigned int *contentbits)
|
||||||
|
{
|
||||||
|
mnode_t *node;
|
||||||
|
float d;
|
||||||
|
mplane_t *plane;
|
||||||
|
|
||||||
|
*area = 0; //no areas with q1bsp.
|
||||||
|
*cluster = -1;
|
||||||
|
*contentbits = FTECONTENTS_SOLID;
|
||||||
|
if (!mod->nodes)
|
||||||
|
return;
|
||||||
|
|
||||||
|
node = mod->nodes;
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
if (node->contents < 0)
|
||||||
|
{
|
||||||
|
*cluster = ((mleaf_t *)node - mod->leafs) - 1;
|
||||||
|
*contentbits = Q1BSP_TranslateContents(((mleaf_t *)node)->contents);
|
||||||
|
return; //we're done
|
||||||
|
}
|
||||||
|
plane = node->plane;
|
||||||
|
d = DotProduct (pos,plane->normal) - plane->dist;
|
||||||
|
if (d > 0)
|
||||||
|
node = node->children[0];
|
||||||
|
else
|
||||||
|
node = node->children[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
PVS type stuff
|
PVS type stuff
|
||||||
|
|
||||||
|
@ -2178,7 +2184,7 @@ void Q1BSP_Init(void)
|
||||||
//fills in bspfuncs_t
|
//fills in bspfuncs_t
|
||||||
void Q1BSP_SetModelFuncs(model_t *mod)
|
void Q1BSP_SetModelFuncs(model_t *mod)
|
||||||
{
|
{
|
||||||
#ifndef CLIENTONLY
|
#ifdef HAVE_SERVER
|
||||||
mod->funcs.FatPVS = Q1BSP_FatPVS;
|
mod->funcs.FatPVS = Q1BSP_FatPVS;
|
||||||
#endif
|
#endif
|
||||||
mod->funcs.EdictInFatPVS = Q1BSP_EdictInFatPVS;
|
mod->funcs.EdictInFatPVS = Q1BSP_EdictInFatPVS;
|
||||||
|
@ -2187,15 +2193,20 @@ void Q1BSP_SetModelFuncs(model_t *mod)
|
||||||
mod->funcs.ClustersInSphere = Q1BSP_ClustersInSphere;
|
mod->funcs.ClustersInSphere = Q1BSP_ClustersInSphere;
|
||||||
mod->funcs.ClusterForPoint = Q1BSP_ClusterForPoint;
|
mod->funcs.ClusterForPoint = Q1BSP_ClusterForPoint;
|
||||||
mod->funcs.ClusterPVS = Q1BSP_ClusterPVS;
|
mod->funcs.ClusterPVS = Q1BSP_ClusterPVS;
|
||||||
// mod->funcs.ClusterPHS = Q1BSP_ClusterPHS;
|
mod->funcs.ClusterPHS = Q1BSP_ClusterPHS;
|
||||||
mod->funcs.NativeTrace = Q1BSP_Trace;
|
mod->funcs.NativeTrace = Q1BSP_Trace;
|
||||||
mod->funcs.PointContents = Q1BSP_PointContents;
|
mod->funcs.PointContents = Q1BSP_PointContents;
|
||||||
|
|
||||||
#ifndef SERVERONLY
|
#ifdef HAVE_CLIENT
|
||||||
mod->funcs.LightPointValues = GLQ1BSP_LightPointValues;
|
mod->funcs.LightPointValues = GLQ1BSP_LightPointValues;
|
||||||
mod->funcs.MarkLights = Q1BSP_MarkLights;
|
mod->funcs.MarkLights = Q1BSP_MarkLights;
|
||||||
mod->funcs.StainNode = Q1BSP_StainNode;
|
mod->funcs.StainNode = Q1BSP_StainNode;
|
||||||
|
#ifdef RTLIGHTS
|
||||||
|
mod->funcs.GenerateShadowMesh = Q1BSP_GenerateShadowMesh;
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
mod->funcs.InfoForPoint = Q1BSP_InfoForPoint;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -2288,16 +2299,7 @@ bspx_header_t *BSPX_Setup(model_t *mod, char *filebase, size_t filelen, lump_t *
|
||||||
|
|
||||||
if (offs < filelen && mod && !mod->archive && mod_loadmappackages.ival)
|
if (offs < filelen && mod && !mod->archive && mod_loadmappackages.ival)
|
||||||
{ //we have some sort of trailing junk... is it a zip?...
|
{ //we have some sort of trailing junk... is it a zip?...
|
||||||
vfsfile_t *f = VFSPIPE_Open(1,true);
|
Mod_LoadMapArchive(mod, filebase+offs, filelen-offs);
|
||||||
if (f)
|
|
||||||
{
|
|
||||||
VFS_WRITE(f, filebase+offs, filelen-offs);
|
|
||||||
mod->archive = FSZIP_LoadArchive(f, NULL, mod->name, mod->name, NULL);
|
|
||||||
if (mod->archive)
|
|
||||||
FS_LoadMapPackFile(mod->name, mod->archive); //give it to the filesystem to use.
|
|
||||||
else
|
|
||||||
VFS_CLOSE(f); //give up.
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return h;
|
return h;
|
||||||
|
|
|
@ -377,11 +377,6 @@ int VARGS WorldQ2_AreaEdicts (world_t *w, const vec3_t mins, const vec3_t maxs,
|
||||||
int maxcount, int areatype);
|
int maxcount, int areatype);
|
||||||
trace_t WorldQ2_Move (world_t *w, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int hitcontentsmask, q2edict_t *passedict);
|
trace_t WorldQ2_Move (world_t *w, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int hitcontentsmask, q2edict_t *passedict);
|
||||||
#endif
|
#endif
|
||||||
#if defined(Q2BSPS) || defined(Q3BSPS)
|
|
||||||
unsigned int Q23BSP_FatPVS(model_t *mod, const vec3_t org, pvsbuffer_t *buffer, qboolean merge);
|
|
||||||
qboolean Q23BSP_EdictInFatPVS(model_t *mod, const struct pvscache_s *ent, const qbyte *pvs, const int *areas);
|
|
||||||
void Q23BSP_FindTouchedLeafs(model_t *mod, struct pvscache_s *ent, const float *mins, const float *maxs);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/*sv_move.c*/
|
/*sv_move.c*/
|
||||||
|
|
|
@ -3019,7 +3019,6 @@ void Terr_DrawInBounds(struct tdibctx *ctx, int x, int y, int w, int h)
|
||||||
|
|
||||||
void Terr_DrawTerrainModel (batch_t **batches, entity_t *e)
|
void Terr_DrawTerrainModel (batch_t **batches, entity_t *e)
|
||||||
{
|
{
|
||||||
extern qbyte *frustumvis;
|
|
||||||
model_t *m = e->model;
|
model_t *m = e->model;
|
||||||
heightmap_t *hm = m->terrain;
|
heightmap_t *hm = m->terrain;
|
||||||
batch_t *b;
|
batch_t *b;
|
||||||
|
@ -3115,7 +3114,7 @@ void Terr_DrawTerrainModel (batch_t **batches, entity_t *e)
|
||||||
tdibctx.vx = (r_refdef.vieworg[0] + CHUNKBIAS*hm->sectionsize) / hm->sectionsize;
|
tdibctx.vx = (r_refdef.vieworg[0] + CHUNKBIAS*hm->sectionsize) / hm->sectionsize;
|
||||||
tdibctx.vy = (r_refdef.vieworg[1] + CHUNKBIAS*hm->sectionsize) / hm->sectionsize;
|
tdibctx.vy = (r_refdef.vieworg[1] + CHUNKBIAS*hm->sectionsize) / hm->sectionsize;
|
||||||
tdibctx.wmodel = e->model;
|
tdibctx.wmodel = e->model;
|
||||||
tdibctx.pvs = (e->model == cl.worldmodel)?frustumvis:NULL;
|
tdibctx.pvs = (e->model == cl.worldmodel)?r_refdef.scenevis:NULL;
|
||||||
validatelinks(&hm->recycle);
|
validatelinks(&hm->recycle);
|
||||||
Terr_DrawInBounds(&tdibctx, bounds[0], bounds[2], bounds[1]-bounds[0], bounds[3]-bounds[2]);
|
Terr_DrawInBounds(&tdibctx, bounds[0], bounds[2], bounds[1]-bounds[0], bounds[3]-bounds[2]);
|
||||||
|
|
||||||
|
|
|
@ -484,6 +484,24 @@ void Mod_ParseEntities(model_t *mod)
|
||||||
mod->numentityinfo = c;
|
mod->numentityinfo = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Mod_LoadMapArchive(model_t *mod, void *archivedata, size_t archivesize)
|
||||||
|
{
|
||||||
|
if (archivesize && mod && !mod->archive && mod_loadmappackages.ival)
|
||||||
|
{
|
||||||
|
vfsfile_t *f = VFSPIPE_Open(1,true);
|
||||||
|
if (f)
|
||||||
|
{
|
||||||
|
VFS_WRITE(f, archivedata, archivesize);
|
||||||
|
mod->archive = FSZIP_LoadArchive(f, NULL, mod->name, mod->name, NULL);
|
||||||
|
if (mod->archive)
|
||||||
|
FS_LoadMapPackFile(mod->name, mod->archive); //give it to the filesystem to use.
|
||||||
|
else
|
||||||
|
VFS_CLOSE(f); //give up.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
===================
|
===================
|
||||||
Mod_ClearAll
|
Mod_ClearAll
|
||||||
|
@ -763,50 +781,6 @@ void *Mod_Extradata (model_t *mod)
|
||||||
return mod->meshinfo;
|
return mod->meshinfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
===============
|
|
||||||
Mod_PointInLeaf
|
|
||||||
===============
|
|
||||||
*/
|
|
||||||
mleaf_t *Mod_PointInLeaf (model_t *model, vec3_t p)
|
|
||||||
{
|
|
||||||
mnode_t *node;
|
|
||||||
float d;
|
|
||||||
mplane_t *plane;
|
|
||||||
|
|
||||||
if (!model)
|
|
||||||
{
|
|
||||||
Sys_Error ("Mod_PointInLeaf: bad model");
|
|
||||||
}
|
|
||||||
if (!model->nodes)
|
|
||||||
return NULL;
|
|
||||||
#if defined(Q2BSPS) || defined(Q3BSPS)
|
|
||||||
if (model->fromgame == fg_quake2 || model->fromgame == fg_quake3)
|
|
||||||
{
|
|
||||||
return model->leafs + CM_PointLeafnum(model, p);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (model->fromgame == fg_doom)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
node = model->nodes;
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
if (node->contents < 0)
|
|
||||||
return (mleaf_t *)node;
|
|
||||||
plane = node->plane;
|
|
||||||
d = DotProduct (p,plane->normal) - plane->dist;
|
|
||||||
if (d > 0)
|
|
||||||
node = node->children[0];
|
|
||||||
else
|
|
||||||
node = node->children[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL; // never reached
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *Mod_FixName(const char *modname, const char *worldname)
|
const char *Mod_FixName(const char *modname, const char *worldname)
|
||||||
{
|
{
|
||||||
if (*modname == '*' && worldname && *worldname)
|
if (*modname == '*' && worldname && *worldname)
|
||||||
|
@ -866,9 +840,21 @@ model_t *Mod_FindName (const char *name)
|
||||||
{
|
{
|
||||||
#endif
|
#endif
|
||||||
if (mod_numknown == MAX_MOD_KNOWN)
|
if (mod_numknown == MAX_MOD_KNOWN)
|
||||||
|
{
|
||||||
|
#ifdef LOADERTHREAD
|
||||||
|
Sys_UnlockMutex(com_resourcemutex);
|
||||||
|
#endif
|
||||||
Sys_Error ("mod_numknown == MAX_MOD_KNOWN");
|
Sys_Error ("mod_numknown == MAX_MOD_KNOWN");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
if (strlen(name) >= sizeof(mod->publicname))
|
if (strlen(name) >= sizeof(mod->publicname))
|
||||||
|
{
|
||||||
|
#ifdef LOADERTHREAD
|
||||||
|
Sys_UnlockMutex(com_resourcemutex);
|
||||||
|
#endif
|
||||||
Sys_Error ("model name is too long: %s", name);
|
Sys_Error ("model name is too long: %s", name);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
memset(mod, 0, sizeof(model_t)); //clear the old model as the renderers use the same globals
|
memset(mod, 0, sizeof(model_t)); //clear the old model as the renderers use the same globals
|
||||||
Q_strncpyz (mod->publicname, name, sizeof(mod->publicname));
|
Q_strncpyz (mod->publicname, name, sizeof(mod->publicname));
|
||||||
Q_strncpyz (mod->name, name, sizeof(mod->name));
|
Q_strncpyz (mod->name, name, sizeof(mod->name));
|
||||||
|
@ -1485,7 +1471,7 @@ static void Mod_FinishTexture(model_t *mod, texture_t *tx, const char *loadname,
|
||||||
const char *origname = NULL;
|
const char *origname = NULL;
|
||||||
const char *shadername = tx->name;
|
const char *shadername = tx->name;
|
||||||
|
|
||||||
if (!safetoloadfromwads)
|
if (!safetoloadfromwads || !tx->shader)
|
||||||
{
|
{
|
||||||
//remap to avoid bugging out on textures with the same name and different images (vanilla content sucks)
|
//remap to avoid bugging out on textures with the same name and different images (vanilla content sucks)
|
||||||
shadername = Mod_RemapBuggyTexture(shadername, tx->srcdata, tx->srcwidth*tx->srcheight);
|
shadername = Mod_RemapBuggyTexture(shadername, tx->srcdata, tx->srcwidth*tx->srcheight);
|
||||||
|
@ -2273,7 +2259,7 @@ static void Mod_SaveEntFile_f(void)
|
||||||
Mod_LoadEntities
|
Mod_LoadEntities
|
||||||
=================
|
=================
|
||||||
*/
|
*/
|
||||||
void Mod_LoadEntities (model_t *loadmodel, qbyte *mod_base, lump_t *l)
|
qboolean Mod_LoadEntitiesBlob(struct model_s *mod, const char *entdata, size_t entdatasize)
|
||||||
{
|
{
|
||||||
char fname[MAX_QPATH];
|
char fname[MAX_QPATH];
|
||||||
size_t sz;
|
size_t sz;
|
||||||
|
@ -2282,15 +2268,15 @@ void Mod_LoadEntities (model_t *loadmodel, qbyte *mod_base, lump_t *l)
|
||||||
char *ents = NULL, *k;
|
char *ents = NULL, *k;
|
||||||
int t;
|
int t;
|
||||||
|
|
||||||
Mod_SetEntitiesString(loadmodel, NULL, false);
|
Mod_SetEntitiesString(mod, NULL, false);
|
||||||
if (!l->filelen)
|
if (!entdatasize)
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
if (mod_loadentfiles.value && !ents && *mod_loadentfiles_dir.string)
|
if (mod_loadentfiles.value && !ents && *mod_loadentfiles_dir.string)
|
||||||
{
|
{
|
||||||
if (!strncmp(loadmodel->name, "maps/", 5))
|
if (!strncmp(mod->name, "maps/", 5))
|
||||||
{
|
{
|
||||||
Q_snprintfz(fname, sizeof(fname), "maps/%s/%s", mod_loadentfiles_dir.string, loadmodel->name+5);
|
Q_snprintfz(fname, sizeof(fname), "maps/%s/%s", mod_loadentfiles_dir.string, mod->name+5);
|
||||||
COM_StripExtension(fname, fname, sizeof(fname));
|
COM_StripExtension(fname, fname, sizeof(fname));
|
||||||
Q_strncatz(fname, ".ent", sizeof(fname));
|
Q_strncatz(fname, ".ent", sizeof(fname));
|
||||||
ents = FS_LoadMallocFile(fname, &sz);
|
ents = FS_LoadMallocFile(fname, &sz);
|
||||||
|
@ -2298,26 +2284,27 @@ void Mod_LoadEntities (model_t *loadmodel, qbyte *mod_base, lump_t *l)
|
||||||
}
|
}
|
||||||
if (mod_loadentfiles.value && !ents)
|
if (mod_loadentfiles.value && !ents)
|
||||||
{
|
{
|
||||||
COM_StripExtension(loadmodel->name, fname, sizeof(fname));
|
COM_StripExtension(mod->name, fname, sizeof(fname));
|
||||||
Q_strncatz(fname, ".ent", sizeof(fname));
|
Q_strncatz(fname, ".ent", sizeof(fname));
|
||||||
ents = FS_LoadMallocFile(fname, &sz);
|
ents = FS_LoadMallocFile(fname, &sz);
|
||||||
}
|
}
|
||||||
if (mod_loadentfiles.value && !ents)
|
if (mod_loadentfiles.value && !ents)
|
||||||
{ //tenebrae compat
|
{ //tenebrae compat
|
||||||
COM_StripExtension(loadmodel->name, fname, sizeof(fname));
|
COM_StripExtension(mod->name, fname, sizeof(fname));
|
||||||
Q_strncatz(fname, ".edo", sizeof(fname));
|
Q_strncatz(fname, ".edo", sizeof(fname));
|
||||||
ents = FS_LoadMallocFile(fname, &sz);
|
ents = FS_LoadMallocFile(fname, &sz);
|
||||||
}
|
}
|
||||||
if (!ents)
|
if (!ents)
|
||||||
{
|
{
|
||||||
ents = Z_Malloc(l->filelen + 1);
|
ents = Z_Malloc(entdatasize + 1);
|
||||||
memcpy (ents, mod_base + l->fileofs, l->filelen);
|
memcpy (ents, entdata, entdatasize);
|
||||||
ents[l->filelen] = 0;
|
ents[entdatasize] = 0;
|
||||||
|
mod->entitiescrc = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
loadmodel->entitiescrc = CalcHashInt(&hash_crc16, ents, strlen(ents));
|
mod->entitiescrc = CalcHashInt(&hash_crc16, ents, strlen(ents));
|
||||||
|
|
||||||
Mod_SetEntitiesString(loadmodel, ents, false);
|
Mod_SetEntitiesString(mod, ents, false);
|
||||||
|
|
||||||
while(ents && *ents)
|
while(ents && *ents)
|
||||||
{
|
{
|
||||||
|
@ -2333,23 +2320,27 @@ void Mod_LoadEntities (model_t *loadmodel, qbyte *mod_base, lump_t *l)
|
||||||
if (!strncmp(keyname, "_texpart_", 9) || !strncmp(keyname, "texpart_", 8))
|
if (!strncmp(keyname, "_texpart_", 9) || !strncmp(keyname, "texpart_", 8))
|
||||||
{
|
{
|
||||||
k = keyname + ((*keyname=='_')?9:8);
|
k = keyname + ((*keyname=='_')?9:8);
|
||||||
for (t = 0; t < loadmodel->numtextures; t++)
|
for (t = 0; t < mod->numtextures; t++)
|
||||||
{
|
{
|
||||||
if (!strcmp(k, loadmodel->textures[t]->name))
|
if (!strcmp(k, mod->textures[t]->name))
|
||||||
{
|
{
|
||||||
loadmodel->textures[t]->partname = ZG_Malloc(&loadmodel->memgroup, strlen(value)+1);
|
mod->textures[t]->partname = ZG_Malloc(&mod->memgroup, strlen(value)+1);
|
||||||
strcpy(loadmodel->textures[t]->partname, value);
|
strcpy(mod->textures[t]->partname, value);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (t == loadmodel->numtextures)
|
if (t == mod->numtextures)
|
||||||
Con_Printf("\"%s\" is not valid for %s\n", keyname, loadmodel->name);
|
Con_Printf("\"%s\" is not valid for %s\n", keyname, mod->name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
void Mod_LoadEntities (model_t *loadmodel, qbyte *mod_base, lump_t *l)
|
||||||
|
{
|
||||||
|
Mod_LoadEntitiesBlob(loadmodel, mod_base+l->fileofs, l->filelen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
=================
|
=================
|
||||||
|
@ -3157,7 +3148,7 @@ static void Mod_Batches_AllocLightmaps(model_t *mod)
|
||||||
|
|
||||||
extern void Surf_CreateSurfaceLightmap (msurface_t *surf, int shift);
|
extern void Surf_CreateSurfaceLightmap (msurface_t *surf, int shift);
|
||||||
//if build is NULL, uses q1/q2 surf generation, and allocates lightmaps
|
//if build is NULL, uses q1/q2 surf generation, and allocates lightmaps
|
||||||
static void Mod_Batches_Build(model_t *mod, builddata_t *bd)
|
void Mod_Batches_Build(model_t *mod, builddata_t *bd)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
int numverts = 0, numindicies=0;
|
int numverts = 0, numindicies=0;
|
||||||
|
@ -3232,13 +3223,14 @@ static void Mod_Batches_Build(model_t *mod, builddata_t *bd)
|
||||||
Mod_Batches_BuildModelMeshes(mod, numverts, numindicies, ModQ1_Batches_BuildQ1Q2Poly, bd, merge);
|
Mod_Batches_BuildModelMeshes(mod, numverts, numindicies, ModQ1_Batches_BuildQ1Q2Poly, bd, merge);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#if defined(Q3BSPS)
|
|
||||||
if (bd)
|
if (bd)
|
||||||
{
|
{
|
||||||
Mod_Batches_SplitLightmaps(mod, merge);
|
if (bd->paintlightmaps)
|
||||||
|
Mod_Batches_AllocLightmaps(mod);
|
||||||
|
else
|
||||||
|
Mod_Batches_SplitLightmaps(mod, merge);
|
||||||
Mod_Batches_BuildModelMeshes(mod, numverts, numindicies, bd->buildfunc, bd, merge);
|
Mod_Batches_BuildModelMeshes(mod, numverts, numindicies, bd->buildfunc, bd, merge);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
if (BE_GenBrushModelVBO)
|
if (BE_GenBrushModelVBO)
|
||||||
BE_GenBrushModelVBO(mod);
|
BE_GenBrushModelVBO(mod);
|
||||||
|
|
|
@ -8,7 +8,7 @@ of the License, or (at your option) any later version.
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
This program is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
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.
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
@ -286,7 +286,18 @@ typedef struct {
|
||||||
|
|
||||||
int (*ClusterForPoint) (struct model_s *model, const vec3_t point, int *areaout); //pvs index (leaf-1 for q1bsp). may be negative (ie: no pvs).
|
int (*ClusterForPoint) (struct model_s *model, const vec3_t point, int *areaout); //pvs index (leaf-1 for q1bsp). may be negative (ie: no pvs).
|
||||||
qbyte *(*ClusterPVS) (struct model_s *model, int cluster, pvsbuffer_t *pvsbuffer, pvsmerge_t merge);
|
qbyte *(*ClusterPVS) (struct model_s *model, int cluster, pvsbuffer_t *pvsbuffer, pvsmerge_t merge);
|
||||||
|
qbyte *(*ClusterPHS) (struct model_s *model, int cluster, pvsbuffer_t *pvsbuffer);
|
||||||
qbyte *(*ClustersInSphere) (struct model_s *model, const vec3_t point, float radius, pvsbuffer_t *pvsbuffer, const qbyte *fte_restrict unionwith);
|
qbyte *(*ClustersInSphere) (struct model_s *model, const vec3_t point, float radius, pvsbuffer_t *pvsbuffer, const qbyte *fte_restrict unionwith);
|
||||||
|
|
||||||
|
size_t (*WriteAreaBits) (struct model_s *model, qbyte *buffer, size_t maxbytes, int area, qboolean merge); //writes a set of bits valid for a specific viewpoint's area.
|
||||||
|
qboolean (*AreasConnected) (struct model_s *model, unsigned int area1, unsigned int area2); //fails if there's no open doors
|
||||||
|
void (*SetAreaPortalState) (struct model_s *model, unsigned int portal, unsigned int area1, unsigned int area2, qboolean open); //a door moved...
|
||||||
|
size_t (*SaveAreaPortalBlob)(struct model_s *model, void **ptr); //for vid_reload to not break portals. dupe the ptrbefore freeing the model.
|
||||||
|
size_t (*LoadAreaPortalBlob)(struct model_s *model, void *ptr, size_t size); //for vid_reload to not break portals (has refcount info etc).
|
||||||
|
|
||||||
|
void (*PrepareFrame) (struct model_s *model, refdef_t *refdef, int area, int clusters[2], pvsbuffer_t *vis, qbyte **entvis_out, qbyte **surfvis_out);
|
||||||
|
void (*GenerateShadowMesh) (struct model_s *model, dlight_t *dl, const qbyte *lvis, qbyte *truevis, void(*callback)(struct msurface_s*));
|
||||||
|
void (*InfoForPoint) (struct model_s *model, vec3_t pos, int *area, int *cluster, unsigned int *contentbits);
|
||||||
} modelfuncs_t;
|
} modelfuncs_t;
|
||||||
|
|
||||||
|
|
||||||
|
@ -352,7 +363,7 @@ void GL_DeselectVAO(void);
|
||||||
|
|
||||||
typedef struct texture_s
|
typedef struct texture_s
|
||||||
{
|
{
|
||||||
char name[64];
|
char name[128];
|
||||||
unsigned vwidth, vheight; //used for lightmap coord generation
|
unsigned vwidth, vheight; //used for lightmap coord generation
|
||||||
|
|
||||||
struct shader_s *shader;
|
struct shader_s *shader;
|
||||||
|
@ -469,7 +480,7 @@ typedef struct msurface_s
|
||||||
int shadowframe;
|
int shadowframe;
|
||||||
#endif
|
#endif
|
||||||
// int clipcount;
|
// int clipcount;
|
||||||
|
|
||||||
// legacy lighting info
|
// legacy lighting info
|
||||||
dlightbitmask_t dlightbits;
|
dlightbitmask_t dlightbits;
|
||||||
int dlightframe;
|
int dlightframe;
|
||||||
|
@ -505,7 +516,7 @@ typedef struct mnode_s
|
||||||
int contents; // 0, to differentiate from leafs
|
int contents; // 0, to differentiate from leafs
|
||||||
int visframe; // node needs to be traversed if current
|
int visframe; // node needs to be traversed if current
|
||||||
int shadowframe;
|
int shadowframe;
|
||||||
|
|
||||||
float minmaxs[6]; // for bounding box culling
|
float minmaxs[6]; // for bounding box culling
|
||||||
|
|
||||||
struct mnode_s *parent;
|
struct mnode_s *parent;
|
||||||
|
@ -587,6 +598,7 @@ void Q1BSP_CheckHullNodes(hull_t *hull);
|
||||||
void Q1BSP_SetModelFuncs(struct model_s *mod);
|
void Q1BSP_SetModelFuncs(struct model_s *mod);
|
||||||
void Q1BSP_LoadBrushes(struct model_s *model, bspx_header_t *bspx, void *mod_base);
|
void Q1BSP_LoadBrushes(struct model_s *model, bspx_header_t *bspx, void *mod_base);
|
||||||
void Q1BSP_Init(void);
|
void Q1BSP_Init(void);
|
||||||
|
void Q1BSP_GenerateShadowMesh(struct model_s *model, struct dlight_s *dl, const qbyte *lightvis, qbyte *litvis, void (*callback)(msurface_t *surf));
|
||||||
|
|
||||||
void BSPX_LoadEnvmaps(struct model_s *mod, bspx_header_t *bspx, void *mod_base);
|
void BSPX_LoadEnvmaps(struct model_s *mod, bspx_header_t *bspx, void *mod_base);
|
||||||
void *BSPX_FindLump(bspx_header_t *bspxheader, void *mod_base, char *lumpname, int *lumpsize);
|
void *BSPX_FindLump(bspx_header_t *bspxheader, void *mod_base, char *lumpname, int *lumpsize);
|
||||||
|
@ -667,7 +679,7 @@ typedef struct
|
||||||
float interval;
|
float interval;
|
||||||
dtrivertx_t bboxmin;
|
dtrivertx_t bboxmin;
|
||||||
dtrivertx_t bboxmax;
|
dtrivertx_t bboxmax;
|
||||||
|
|
||||||
vec3_t scale;
|
vec3_t scale;
|
||||||
vec3_t scale_origin;
|
vec3_t scale_origin;
|
||||||
|
|
||||||
|
@ -693,7 +705,7 @@ typedef struct
|
||||||
typedef struct mtriangle_s {
|
typedef struct mtriangle_s {
|
||||||
int xyz_index[3];
|
int xyz_index[3];
|
||||||
int st_index[3];
|
int st_index[3];
|
||||||
|
|
||||||
int pad[2];
|
int pad[2];
|
||||||
} mtriangle_t;
|
} mtriangle_t;
|
||||||
|
|
||||||
|
@ -769,7 +781,7 @@ typedef struct
|
||||||
short t;
|
short t;
|
||||||
} md2stvert_t;
|
} md2stvert_t;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
short index_xyz[3];
|
short index_xyz[3];
|
||||||
short index_st[3];
|
short index_st[3];
|
||||||
|
@ -827,7 +839,7 @@ typedef struct
|
||||||
int ofs_st; // qbyte offset from start for stverts
|
int ofs_st; // qbyte offset from start for stverts
|
||||||
int ofs_tris; // offset for dtriangles
|
int ofs_tris; // offset for dtriangles
|
||||||
int ofs_frames; // offset for first frame
|
int ofs_frames; // offset for first frame
|
||||||
int ofs_glcmds;
|
int ofs_glcmds;
|
||||||
int ofs_end; // end of file
|
int ofs_end; // end of file
|
||||||
} md2_t;
|
} md2_t;
|
||||||
|
|
||||||
|
@ -953,7 +965,7 @@ typedef struct model_s
|
||||||
|
|
||||||
int numframes;
|
int numframes;
|
||||||
synctype_t synctype;
|
synctype_t synctype;
|
||||||
|
|
||||||
int flags;
|
int flags;
|
||||||
int engineflags;
|
int engineflags;
|
||||||
int particleeffect;
|
int particleeffect;
|
||||||
|
@ -962,14 +974,14 @@ typedef struct model_s
|
||||||
|
|
||||||
//
|
//
|
||||||
// volume occupied by the model graphics
|
// volume occupied by the model graphics
|
||||||
//
|
//
|
||||||
vec3_t mins, maxs;
|
vec3_t mins, maxs;
|
||||||
float radius;
|
float radius;
|
||||||
float clampscale;
|
float clampscale;
|
||||||
float maxlod;
|
float maxlod;
|
||||||
|
|
||||||
//
|
//
|
||||||
// solid volume for clipping
|
// solid volume for clipping
|
||||||
//
|
//
|
||||||
qboolean clipbox;
|
qboolean clipbox;
|
||||||
vec3_t clipmins, clipmaxs;
|
vec3_t clipmins, clipmaxs;
|
||||||
|
@ -1160,15 +1172,15 @@ qboolean Heightmap_Edit(model_t *mod, int action, float *pos, float radius, floa
|
||||||
|
|
||||||
|
|
||||||
#if defined(Q2BSPS) || defined(Q3BSPS)
|
#if defined(Q2BSPS) || defined(Q3BSPS)
|
||||||
|
void CM_Init(void);
|
||||||
void CM_InitBoxHull (void);
|
struct model_s *CM_TempBoxModel(const vec3_t mins, const vec3_t maxs);
|
||||||
|
#endif
|
||||||
|
#if 0
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
//#pragma warningmsg (" c++ stinks")
|
//#pragma warningmsg (" c++ stinks")
|
||||||
#else
|
#else
|
||||||
|
|
||||||
void CM_Init(void);
|
|
||||||
|
|
||||||
qboolean CM_SetAreaPortalState (struct model_s *mod, int portalnum, qboolean open);
|
qboolean CM_SetAreaPortalState (struct model_s *mod, int portalnum, qboolean open);
|
||||||
qboolean CM_HeadnodeVisible (struct model_s *mod, int nodenum, const qbyte *visbits);
|
qboolean CM_HeadnodeVisible (struct model_s *mod, int nodenum, const qbyte *visbits);
|
||||||
qboolean VARGS CM_AreasConnected (struct model_s *mod, unsigned int area1, unsigned int area2);
|
qboolean VARGS CM_AreasConnected (struct model_s *mod, unsigned int area1, unsigned int area2);
|
||||||
|
@ -1185,7 +1197,6 @@ int CM_PointContents (struct model_s *mod, const vec3_t p);
|
||||||
int CM_TransformedPointContents (struct model_s *mod, const vec3_t p, int headnode, const vec3_t origin, const vec3_t angles);
|
int CM_TransformedPointContents (struct model_s *mod, const vec3_t p, int headnode, const vec3_t origin, const vec3_t angles);
|
||||||
int CM_HeadnodeForBox (struct model_s *mod, const vec3_t mins, const vec3_t maxs);
|
int CM_HeadnodeForBox (struct model_s *mod, const vec3_t mins, const vec3_t maxs);
|
||||||
//struct trace_s CM_TransformedBoxTrace (struct model_s *mod, vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, int brushmask, vec3_t origin, vec3_t angles);
|
//struct trace_s CM_TransformedBoxTrace (struct model_s *mod, vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, int brushmask, vec3_t origin, vec3_t angles);
|
||||||
struct model_s *CM_TempBoxModel(const vec3_t mins, const vec3_t maxs);
|
|
||||||
|
|
||||||
//for gamecode to control portals/areas
|
//for gamecode to control portals/areas
|
||||||
void CMQ2_SetAreaPortalState (model_t *mod, unsigned int portalnum, qboolean open);
|
void CMQ2_SetAreaPortalState (model_t *mod, unsigned int portalnum, qboolean open);
|
||||||
|
|
|
@ -40,7 +40,7 @@ static void SHM_Shutdown(void);
|
||||||
|
|
||||||
#define SHADOWMAP_SIZE 512
|
#define SHADOWMAP_SIZE 512
|
||||||
|
|
||||||
#define PROJECTION_DISTANCE (float)(dl->radius*2)//0x7fffffff
|
#define PROJECTION_DISTANCE (float)(sh_shmesh->radius*2)//0x7fffffff
|
||||||
|
|
||||||
#ifdef BEF_PUSHDEPTH
|
#ifdef BEF_PUSHDEPTH
|
||||||
extern qboolean r_pushdepth;
|
extern qboolean r_pushdepth;
|
||||||
|
@ -113,6 +113,8 @@ typedef struct {
|
||||||
} shadowmeshbatch_t;
|
} shadowmeshbatch_t;
|
||||||
typedef struct shadowmesh_s
|
typedef struct shadowmesh_s
|
||||||
{
|
{
|
||||||
|
vec3_t origin;
|
||||||
|
float radius;
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
SMT_STENCILVOLUME, //build edges mesh (and surface list)
|
SMT_STENCILVOLUME, //build edges mesh (and surface list)
|
||||||
|
@ -536,6 +538,8 @@ static void SHM_BeginShadowMesh(dlight_t *dl, int type)
|
||||||
sh_shmesh->maxindicies = 0;
|
sh_shmesh->maxindicies = 0;
|
||||||
sh_shmesh->numindicies = 0;
|
sh_shmesh->numindicies = 0;
|
||||||
sh_shmesh->type = type;
|
sh_shmesh->type = type;
|
||||||
|
VectorCopy(dl->origin, sh_shmesh->origin);
|
||||||
|
sh_shmesh->radius = dl->radius;
|
||||||
|
|
||||||
if (!cl.worldmodel->numshadowbatches)
|
if (!cl.worldmodel->numshadowbatches)
|
||||||
{
|
{
|
||||||
|
@ -689,6 +693,7 @@ static struct {
|
||||||
} *edge;
|
} *edge;
|
||||||
static int firstedge;
|
static int firstedge;
|
||||||
static int maxedge;
|
static int maxedge;
|
||||||
|
static void (*genshadowmapcallback) (msurface_t *mesh);
|
||||||
|
|
||||||
static void SHM_RecursiveWorldNodeQ1_r (dlight_t *dl, mnode_t *node)
|
static void SHM_RecursiveWorldNodeQ1_r (dlight_t *dl, mnode_t *node)
|
||||||
{
|
{
|
||||||
|
@ -697,7 +702,6 @@ static void SHM_RecursiveWorldNodeQ1_r (dlight_t *dl, mnode_t *node)
|
||||||
msurface_t *surf, **mark;
|
msurface_t *surf, **mark;
|
||||||
mleaf_t *pleaf;
|
mleaf_t *pleaf;
|
||||||
double dot;
|
double dot;
|
||||||
int v;
|
|
||||||
|
|
||||||
float l, maxdist;
|
float l, maxdist;
|
||||||
int j, s, t;
|
int j, s, t;
|
||||||
|
@ -822,61 +826,7 @@ static void SHM_RecursiveWorldNodeQ1_r (dlight_t *dl, mnode_t *node)
|
||||||
t = (l - t)*surf->texinfo->vecscale[1];
|
t = (l - t)*surf->texinfo->vecscale[1];
|
||||||
// compare to minimum light
|
// compare to minimum light
|
||||||
if ((s*s+t*t+dot*dot) < maxdist)
|
if ((s*s+t*t+dot*dot) < maxdist)
|
||||||
{
|
genshadowmapcallback(surf);
|
||||||
SHM_Shadow_Cache_Surface(surf);
|
|
||||||
if (sh_shmesh->type == SMT_SHADOWMAP)
|
|
||||||
{
|
|
||||||
SHM_MeshFrontOnly(surf->mesh->numvertexes, surf->mesh->xyz_array, surf->mesh->numindexes, surf->mesh->indexes);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (sh_shmesh->type != SMT_STENCILVOLUME)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
//build a list of the edges that are to be drawn.
|
|
||||||
for (v = 0; v < surf->numedges; v++)
|
|
||||||
{
|
|
||||||
int e, delta;
|
|
||||||
e = cl.worldmodel->surfedges[surf->firstedge+v];
|
|
||||||
//negative edge means backwards edge.
|
|
||||||
if (e < 0)
|
|
||||||
{
|
|
||||||
e=-e;
|
|
||||||
delta = -1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
delta = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!edge[e].count)
|
|
||||||
{
|
|
||||||
if (firstedge)
|
|
||||||
edge[firstedge].prev = e;
|
|
||||||
edge[e].next = firstedge;
|
|
||||||
edge[e].prev = 0;
|
|
||||||
firstedge = e;
|
|
||||||
edge[e].count = delta;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
edge[e].count += delta;
|
|
||||||
|
|
||||||
if (!edge[e].count) //unlink
|
|
||||||
{
|
|
||||||
if (edge[e].next)
|
|
||||||
{
|
|
||||||
edge[edge[e].next].prev = edge[e].prev;
|
|
||||||
}
|
|
||||||
if (edge[e].prev)
|
|
||||||
edge[edge[e].prev].next = edge[e].next;
|
|
||||||
else
|
|
||||||
firstedge = edge[e].next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SHM_TriangleFan(surf->mesh->numvertexes, surf->mesh->xyz_array, dl->origin, PROJECTION_DISTANCE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -938,11 +888,8 @@ static void SHM_OrthoWorldLeafsQ1 (dlight_t *dl)
|
||||||
if (dot < 0)
|
if (dot < 0)
|
||||||
{
|
{
|
||||||
SHM_Shadow_Cache_Surface(surf);
|
SHM_Shadow_Cache_Surface(surf);
|
||||||
|
|
||||||
}
|
}
|
||||||
// else
|
SHM_MeshFrontOnly(surf->mesh->numvertexes, surf->mesh->xyz_array, surf->mesh->numindexes, surf->mesh->indexes);
|
||||||
// SHM_MeshBackOnly(surf->mesh->numvertexes, surf->mesh->xyz_array, surf->mesh->numindexes, surf->mesh->indexes);
|
|
||||||
SHM_MeshFrontOnly(surf->mesh->numvertexes, surf->mesh->xyz_array, surf->mesh->numindexes, surf->mesh->indexes);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -950,6 +897,44 @@ next:;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void SHM_MarkLeavesQ1(dlight_t *dl, const qbyte *lvis)
|
||||||
|
{
|
||||||
|
mnode_t *node;
|
||||||
|
int i;
|
||||||
|
sh_shadowframe++;
|
||||||
|
|
||||||
|
if (!lvis)
|
||||||
|
return;
|
||||||
|
|
||||||
|
//variation on mark leaves
|
||||||
|
for (i=0 ; i<cl.worldmodel->numclusters ; i++)
|
||||||
|
{
|
||||||
|
if (lvis[i>>3] & (1<<(i&7)))
|
||||||
|
{
|
||||||
|
node = (mnode_t *)&cl.worldmodel->leafs[i+1];
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (node->shadowframe == sh_shadowframe)
|
||||||
|
break;
|
||||||
|
node->shadowframe = sh_shadowframe;
|
||||||
|
node = node->parent;
|
||||||
|
} while (node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Q1BSP_GenerateShadowMesh(model_t *model, dlight_t *dl, const qbyte *lightvis, qbyte *litvis, void (*callback)(msurface_t *surf))
|
||||||
|
{
|
||||||
|
genshadowmapcallback = callback;
|
||||||
|
if (sh_shmesh->type == SMT_ORTHO)
|
||||||
|
SHM_OrthoWorldLeafsQ1(dl);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SHM_MarkLeavesQ1(dl, lightvis);
|
||||||
|
SHM_RecursiveWorldNodeQ1_r(dl, cl.worldmodel->nodes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void SHM_OrthoWorldLeafsQ3 (dlight_t *dl)
|
static void SHM_OrthoWorldLeafsQ3 (dlight_t *dl)
|
||||||
{
|
{
|
||||||
int c, i;
|
int c, i;
|
||||||
|
@ -1256,33 +1241,12 @@ static void SHM_MarkLeavesQ2(dlight_t *dl, unsigned char *lvis)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
void Q2BSP_GenerateShadowMesh(model_t *model, dlight_t *dl, qbyte *lvis, int type)
|
||||||
|
|
||||||
static void SHM_MarkLeavesQ1(dlight_t *dl, unsigned char *lvis)
|
|
||||||
{
|
{
|
||||||
mnode_t *node;
|
SHM_MarkLeavesQ2(dl, lvis);
|
||||||
int i;
|
SHM_RecursiveWorldNodeQ2_r(dl, model->nodes);
|
||||||
sh_shadowframe++;
|
|
||||||
|
|
||||||
if (!lvis)
|
|
||||||
return;
|
|
||||||
|
|
||||||
//variation on mark leaves
|
|
||||||
for (i=0 ; i<cl.worldmodel->numclusters ; i++)
|
|
||||||
{
|
|
||||||
if (lvis[i>>3] & (1<<(i&7)))
|
|
||||||
{
|
|
||||||
node = (mnode_t *)&cl.worldmodel->leafs[i+1];
|
|
||||||
do
|
|
||||||
{
|
|
||||||
if (node->shadowframe == sh_shadowframe)
|
|
||||||
break;
|
|
||||||
node->shadowframe = sh_shadowframe;
|
|
||||||
node = node->parent;
|
|
||||||
} while (node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef Q3BSPS
|
#ifdef Q3BSPS
|
||||||
static void SHM_RecursiveWorldNodeQ3_r (dlight_t *dl, mnode_t *node)
|
static void SHM_RecursiveWorldNodeQ3_r (dlight_t *dl, mnode_t *node)
|
||||||
|
@ -1626,8 +1590,78 @@ static void SHM_ComposeVolume_BruteForce(dlight_t *dl)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Q3BSP_GenerateShadowMesh(model_t *model, dlight_t *dl, const qbyte *lightvis, qbyte *litvis, void (*callback)(msurface_t *surf))
|
||||||
|
{
|
||||||
|
/*q3 doesn't have edge info*/
|
||||||
|
if (sh_shmesh->type == SMT_ORTHO)
|
||||||
|
SHM_OrthoWorldLeafsQ3(dl);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sh_shadowframe++;
|
||||||
|
SHM_RecursiveWorldNodeQ3_r(dl, model->nodes);
|
||||||
|
}
|
||||||
|
if (sh_shmesh->type == SMT_STENCILVOLUME)
|
||||||
|
SHM_ComposeVolume_BruteForce(dl);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static void SHM_Shadow_Surface_Shadowmap (msurface_t *surf)
|
||||||
|
{
|
||||||
|
SHM_Shadow_Cache_Surface(surf);
|
||||||
|
SHM_MeshFrontOnly(surf->mesh->numvertexes, surf->mesh->xyz_array, surf->mesh->numindexes, surf->mesh->indexes);
|
||||||
|
}
|
||||||
|
static void SHM_Shadow_Surface_StencilVolume (msurface_t *surf)
|
||||||
|
{
|
||||||
|
int v;
|
||||||
|
SHM_Shadow_Cache_Surface(surf);
|
||||||
|
|
||||||
|
//build a list of the edges that are to be drawn.
|
||||||
|
for (v = 0; v < surf->numedges; v++)
|
||||||
|
{
|
||||||
|
int e, delta;
|
||||||
|
e = cl.worldmodel->surfedges[surf->firstedge+v];
|
||||||
|
//negative edge means backwards edge.
|
||||||
|
if (e < 0)
|
||||||
|
{
|
||||||
|
e=-e;
|
||||||
|
delta = -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
delta = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!edge[e].count)
|
||||||
|
{
|
||||||
|
if (firstedge)
|
||||||
|
edge[firstedge].prev = e;
|
||||||
|
edge[e].next = firstedge;
|
||||||
|
edge[e].prev = 0;
|
||||||
|
firstedge = e;
|
||||||
|
edge[e].count = delta;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
edge[e].count += delta;
|
||||||
|
|
||||||
|
if (!edge[e].count) //unlink
|
||||||
|
{
|
||||||
|
if (edge[e].next)
|
||||||
|
{
|
||||||
|
edge[edge[e].next].prev = edge[e].prev;
|
||||||
|
}
|
||||||
|
if (edge[e].prev)
|
||||||
|
edge[edge[e].prev].next = edge[e].next;
|
||||||
|
else
|
||||||
|
firstedge = edge[e].next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SHM_TriangleFan(surf->mesh->numvertexes, surf->mesh->xyz_array, sh_shmesh->origin, PROJECTION_DISTANCE);
|
||||||
|
}
|
||||||
|
|
||||||
static struct shadowmesh_s *SHM_BuildShadowMesh(dlight_t *dl, unsigned char *lvis, int type)
|
static struct shadowmesh_s *SHM_BuildShadowMesh(dlight_t *dl, unsigned char *lvis, int type)
|
||||||
{
|
{
|
||||||
float *v1, *v2;
|
float *v1, *v2;
|
||||||
|
@ -1662,58 +1696,37 @@ static struct shadowmesh_s *SHM_BuildShadowMesh(dlight_t *dl, unsigned char *lvi
|
||||||
edge = Z_Malloc(sizeof(*edge) * maxedge);
|
edge = Z_Malloc(sizeof(*edge) * maxedge);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cl.worldmodel->type == mod_brush)
|
SHM_BeginShadowMesh(dl, type);
|
||||||
|
if (cl.worldmodel->funcs.GenerateShadowMesh)
|
||||||
|
{
|
||||||
|
switch(type)
|
||||||
|
{
|
||||||
|
case SMT_SHADOWMAP:
|
||||||
|
cl.worldmodel->funcs.GenerateShadowMesh(cl.worldmodel, dl, lvis, sh_shmesh->litleaves, SHM_Shadow_Surface_Shadowmap);
|
||||||
|
break;
|
||||||
|
case SMT_STENCILVOLUME:
|
||||||
|
cl.worldmodel->funcs.GenerateShadowMesh(cl.worldmodel, dl, lvis, sh_shmesh->litleaves, SHM_Shadow_Surface_StencilVolume);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
cl.worldmodel->funcs.GenerateShadowMesh(cl.worldmodel, dl, lvis, sh_shmesh->litleaves, SHM_Shadow_Cache_Surface);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (cl.worldmodel->type == mod_brush)
|
||||||
{
|
{
|
||||||
switch(cl.worldmodel->fromgame)
|
switch(cl.worldmodel->fromgame)
|
||||||
{
|
{
|
||||||
case fg_quake:
|
case fg_quake:
|
||||||
case fg_halflife:
|
case fg_halflife:
|
||||||
/*if (!dl->die)
|
|
||||||
{
|
|
||||||
SHM_BeginShadowMesh(dl, true);
|
|
||||||
SHM_MarkLeavesQ1(dl, lvis);
|
|
||||||
SHM_RecursiveWorldNodeQ1_r(dl, cl.worldmodel->nodes);
|
|
||||||
if (!surfonly)
|
|
||||||
SHM_ComposeVolume_BruteForce(dl);
|
|
||||||
}
|
|
||||||
else*/
|
|
||||||
{
|
|
||||||
SHM_BeginShadowMesh(dl, type);
|
|
||||||
|
|
||||||
if (type == SMT_ORTHO)
|
|
||||||
SHM_OrthoWorldLeafsQ1(dl);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SHM_MarkLeavesQ1(dl, lvis);
|
|
||||||
SHM_RecursiveWorldNodeQ1_r(dl, cl.worldmodel->nodes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
#ifdef Q2BSPS
|
|
||||||
case fg_quake2:
|
|
||||||
SHM_BeginShadowMesh(dl, type);
|
|
||||||
SHM_MarkLeavesQ2(dl, lvis);
|
|
||||||
SHM_RecursiveWorldNodeQ2_r(dl, cl.worldmodel->nodes);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
#ifdef Q3BSPS
|
|
||||||
case fg_quake3:
|
|
||||||
/*q3 doesn't have edge info*/
|
|
||||||
SHM_BeginShadowMesh(dl, type);
|
|
||||||
|
|
||||||
if (type == SMT_ORTHO)
|
if (type == SMT_ORTHO)
|
||||||
SHM_OrthoWorldLeafsQ3(dl);
|
SHM_OrthoWorldLeafsQ1(dl);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sh_shadowframe++;
|
SHM_MarkLeavesQ1(dl, lvis);
|
||||||
SHM_RecursiveWorldNodeQ3_r(dl, cl.worldmodel->nodes);
|
SHM_RecursiveWorldNodeQ1_r(dl, cl.worldmodel->nodes);
|
||||||
}
|
}
|
||||||
if (type == SMT_STENCILVOLUME)
|
|
||||||
SHM_ComposeVolume_BruteForce(dl);
|
|
||||||
break;
|
break;
|
||||||
#endif
|
|
||||||
default:
|
default:
|
||||||
SHM_BeginShadowMesh(dl, type);
|
|
||||||
sh_shadowframe++;
|
sh_shadowframe++;
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
@ -92,8 +92,8 @@ void R_SetSky(const char *sky)
|
||||||
memset(&tex, 0, sizeof(tex));
|
memset(&tex, 0, sizeof(tex));
|
||||||
|
|
||||||
tex.base = R_LoadHiResTexture(sky, "env:gfx/env", IF_LOADNOW|IF_NOMIPMAP);
|
tex.base = R_LoadHiResTexture(sky, "env:gfx/env", IF_LOADNOW|IF_NOMIPMAP);
|
||||||
if (tex.reflectcube && tex.reflectcube->status == TEX_LOADING)
|
if (tex.base && tex.base->status == TEX_LOADING)
|
||||||
COM_WorkerPartialSync(tex.reflectcube, &tex.reflectcube->status, TEX_LOADING);
|
COM_WorkerPartialSync(tex.base, &tex.base->status, TEX_LOADING);
|
||||||
if (tex.base->width && TEXLOADED(tex.base))
|
if (tex.base->width && TEXLOADED(tex.base))
|
||||||
{
|
{
|
||||||
forcedsky = R_RegisterShader(shadername, 0,
|
forcedsky = R_RegisterShader(shadername, 0,
|
||||||
|
|
|
@ -35,9 +35,12 @@ void ClearBounds (vec3_t mins, vec3_t maxs);
|
||||||
struct builddata_s
|
struct builddata_s
|
||||||
{
|
{
|
||||||
void (*buildfunc)(model_t *mod, msurface_t *surf, struct builddata_s *bd);
|
void (*buildfunc)(model_t *mod, msurface_t *surf, struct builddata_s *bd);
|
||||||
|
qboolean paintlightmaps;
|
||||||
void *facedata;
|
void *facedata;
|
||||||
};
|
};
|
||||||
void ModBrush_LoadGLStuff(void *ctx, void *data, size_t a, size_t b); //data === builddata_t
|
void ModBrush_LoadGLStuff(void *ctx, void *data, size_t a, size_t b); //data === builddata_t
|
||||||
|
void Mod_Batches_Build(model_t *mod, builddata_t *bd);
|
||||||
|
shader_t *Mod_RegisterBasicShader(struct model_s *mod, const char *texname, unsigned int usageflags, const char *shadertext, uploadfmt_t pixelfmt, unsigned int width, unsigned int height, void *pixeldata, void *palettedata);
|
||||||
|
|
||||||
#ifdef GLQUAKE
|
#ifdef GLQUAKE
|
||||||
#if defined(ANDROID) /*FIXME: actually just to use standard GLES headers instead of full GL*/
|
#if defined(ANDROID) /*FIXME: actually just to use standard GLES headers instead of full GL*/
|
||||||
|
|
|
@ -7682,73 +7682,35 @@ static void QCBUILTIN PF_redirectcmd (pubprogfuncs_t *prinst, struct globalvars_
|
||||||
|
|
||||||
static void QCBUILTIN PF_OpenPortal (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
static void QCBUILTIN PF_OpenPortal (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||||
{
|
{
|
||||||
#ifdef Q2BSPS
|
int i;
|
||||||
if (sv.world.worldmodel->fromgame == fg_quake2)
|
int state = G_FLOAT(OFS_PARM1)!=0;
|
||||||
|
client_t *client;
|
||||||
|
edict_t *ent = G_EDICT(prinst, OFS_PARM0);
|
||||||
|
int portal = G_EDICT(prinst, OFS_PARM0)->xv->style; //read the func_areaportal's style field (q2ism).
|
||||||
|
int area1 = ent->pvsinfo.areanum, area2 = ent->pvsinfo.areanum2;
|
||||||
|
for (client = svs.clients, i = 0; i < sv.allocated_client_slots; i++, client++)
|
||||||
{
|
{
|
||||||
int i, portal;
|
if (client->state >= cs_connected)
|
||||||
int state = G_FLOAT(OFS_PARM1)!=0;
|
|
||||||
client_t *client;
|
|
||||||
if (G_INT(OFS_PARM1) >= MAX_EDICTS)
|
|
||||||
portal = G_FLOAT(OFS_PARM0); //old legacy crap.
|
|
||||||
else
|
|
||||||
portal = G_EDICT(prinst, OFS_PARM0)->xv->style; //read the func_areaportal's style field.
|
|
||||||
for (client = svs.clients, i = 0; i < sv.allocated_client_slots; i++, client++)
|
|
||||||
{
|
{
|
||||||
if (client->state >= cs_connected)
|
ClientReliableWrite_Begin(client, svc_setportalstate, 4);
|
||||||
|
if (portal > 0xff || area1 > 0xff || area2 > 0xff)
|
||||||
{
|
{
|
||||||
ClientReliableWrite_Begin(client, svc_setportalstate, 4);
|
ClientReliableWrite_Byte(client, 0xe0 | 2 | state);
|
||||||
if (portal >= 0x80)
|
ClientReliableWrite_Short(client, portal);
|
||||||
{ //new pathway, to be enabled at some point
|
ClientReliableWrite_Short(client, area1);
|
||||||
if (portal > 0xff)
|
ClientReliableWrite_Short(client, area2);
|
||||||
{
|
}
|
||||||
ClientReliableWrite_Byte(client, 0x80 | 2 | state);
|
else
|
||||||
ClientReliableWrite_Short(client, portal);
|
{
|
||||||
}
|
ClientReliableWrite_Byte(client, 0xe0 | 0 | state);
|
||||||
else
|
ClientReliableWrite_Byte(client, portal);
|
||||||
{
|
ClientReliableWrite_Byte(client, area1);
|
||||||
ClientReliableWrite_Byte(client, 0x80 | 0 | state);
|
ClientReliableWrite_Byte(client, area2);
|
||||||
ClientReliableWrite_Byte(client, portal);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
ClientReliableWrite_Short(client, portal | (state<<15));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CMQ2_SetAreaPortalState(sv.world.worldmodel, portal, state);
|
|
||||||
}
|
}
|
||||||
#endif
|
if (sv.world.worldmodel->funcs.SetAreaPortalState)
|
||||||
#ifdef Q3BSPS
|
sv.world.worldmodel->funcs.SetAreaPortalState(sv.world.worldmodel, portal, area1, area2, state);
|
||||||
if (sv.world.worldmodel->fromgame == fg_quake3)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
int state = G_FLOAT(OFS_PARM1)!=0;
|
|
||||||
client_t *client;
|
|
||||||
edict_t *portal = G_EDICT(prinst, OFS_PARM0);
|
|
||||||
int area1 = portal->pvsinfo.areanum, area2 = portal->pvsinfo.areanum2;
|
|
||||||
if (area1 == area2 || area1<0 || area2<0)
|
|
||||||
return;
|
|
||||||
for (client = svs.clients, i = 0; i < sv.allocated_client_slots; i++, client++)
|
|
||||||
{
|
|
||||||
if (client->state >= cs_connected)
|
|
||||||
{
|
|
||||||
ClientReliableWrite_Begin(client, svc_setportalstate, 6);
|
|
||||||
if (area1 > 0xff || area2 > 0xff)
|
|
||||||
{
|
|
||||||
ClientReliableWrite_Byte(client, 0xc0 | 2 | state);
|
|
||||||
ClientReliableWrite_Short(client, area1);
|
|
||||||
ClientReliableWrite_Short(client, area2);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ClientReliableWrite_Byte(client, 0xc0 | 0 | state);
|
|
||||||
ClientReliableWrite_Byte(client, area1);
|
|
||||||
ClientReliableWrite_Byte(client, area2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
CMQ3_SetAreaPortalState(sv.world.worldmodel, portal->pvsinfo.areanum, portal->pvsinfo.areanum2, state);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//EXTENSION: KRIMZON_SV_PARSECLIENTCOMMAND
|
//EXTENSION: KRIMZON_SV_PARSECLIENTCOMMAND
|
||||||
|
|
|
@ -105,7 +105,7 @@ Q2SOLID_BSP // bsp clip, touch on edge
|
||||||
struct link_s *prev, *next;
|
struct link_s *prev, *next;
|
||||||
} link_t;*/
|
} link_t;*/
|
||||||
|
|
||||||
#define MAX_ENT_CLUSTERS 16
|
#define Q2MAX_ENT_CLUSTERS 16
|
||||||
|
|
||||||
|
|
||||||
//typedef struct edict_s edict_t;
|
//typedef struct edict_s edict_t;
|
||||||
|
@ -160,7 +160,7 @@ struct q2edict_s
|
||||||
link_t area; // linked to a division node or leaf
|
link_t area; // linked to a division node or leaf
|
||||||
|
|
||||||
int num_clusters; // if -1, use headnode instead
|
int num_clusters; // if -1, use headnode instead
|
||||||
int clusternums[MAX_ENT_CLUSTERS];
|
int clusternums[Q2MAX_ENT_CLUSTERS];
|
||||||
int headnode; // unused if num_clusters != -1
|
int headnode; // unused if num_clusters != -1
|
||||||
int areanum, areanum2;
|
int areanum, areanum2;
|
||||||
|
|
||||||
|
|
|
@ -574,7 +574,7 @@ qboolean SV_LoadLevelCache(const char *savename, const char *level, const char *
|
||||||
sv.strings.q2_extrasounds[i] = NULL;
|
sv.strings.q2_extrasounds[i] = NULL;
|
||||||
}
|
}
|
||||||
//Read portal state
|
//Read portal state
|
||||||
CM_ReadPortalState(sv.world.worldmodel, s, (file+filelen)-s);
|
sv.world.worldmodel->funcs.LoadAreaPortalBlob(sv.world.worldmodel, s, (file+filelen)-s);
|
||||||
FS_FreeFile(file);
|
FS_FreeFile(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1022,7 +1022,7 @@ void SV_SaveLevelCache(const char *savedir, qboolean dontharmgame)
|
||||||
}
|
}
|
||||||
VFS_WRITE(f, "", 1);
|
VFS_WRITE(f, "", 1);
|
||||||
|
|
||||||
portalblobsize = CM_WritePortalState(sv.world.worldmodel, &portalblob);
|
portalblobsize = sv.world.worldmodel->funcs.SaveAreaPortalBlob(sv.world.worldmodel, &portalblob);
|
||||||
VFS_WRITE(f, portalblob, portalblobsize);
|
VFS_WRITE(f, portalblob, portalblobsize);
|
||||||
|
|
||||||
VFS_CLOSE(f);
|
VFS_CLOSE(f);
|
||||||
|
|
|
@ -1055,6 +1055,10 @@ void SV_SpawnServer (const char *server, const char *startspot, qboolean noents,
|
||||||
if (sv.world.worldmodel)
|
if (sv.world.worldmodel)
|
||||||
FS_LoadMapPackFile(sv.world.worldmodel->name, sv.world.worldmodel->archive);
|
FS_LoadMapPackFile(sv.world.worldmodel->name, sv.world.worldmodel->archive);
|
||||||
|
|
||||||
|
//reset the map's areaportal state... it might be dirty from a restart or so.
|
||||||
|
if (sv.world.worldmodel->funcs.LoadAreaPortalBlob)
|
||||||
|
sv.world.worldmodel->funcs.LoadAreaPortalBlob(sv.world.worldmodel, NULL, 0);
|
||||||
|
|
||||||
#ifndef SERVERONLY
|
#ifndef SERVERONLY
|
||||||
current_loading_size+=10;
|
current_loading_size+=10;
|
||||||
// SCR_BeginLoadingPlaque();
|
// SCR_BeginLoadingPlaque();
|
||||||
|
@ -1158,7 +1162,7 @@ MSV_OpenUserDatabase();
|
||||||
newgametype = GT_QUAKE3;
|
newgametype = GT_QUAKE3;
|
||||||
#endif
|
#endif
|
||||||
#ifdef Q2SERVER
|
#ifdef Q2SERVER
|
||||||
else if ((sv.world.worldmodel->fromgame == fg_quake2 || sv.world.worldmodel->fromgame == fg_quake3) && !*pr_ssqc_progs.string && SVQ2_InitGameProgs()) //these are the rules for running a q2 server
|
else if ((sv.world.worldmodel->fromgame == fg_quake2 || sv.world.worldmodel->fromgame == fg_quake3) && sv.world.worldmodel->funcs.AreasConnected && !*pr_ssqc_progs.string && SVQ2_InitGameProgs()) //these are the rules for running a q2 server
|
||||||
newgametype = GT_QUAKE2; //we loaded the dll
|
newgametype = GT_QUAKE2; //we loaded the dll
|
||||||
#endif
|
#endif
|
||||||
#ifdef VM_LUA
|
#ifdef VM_LUA
|
||||||
|
|
|
@ -522,7 +522,7 @@ void SV_MulticastProtExt(vec3_t origin, multicast_t to, int dimension_mask, int
|
||||||
{
|
{
|
||||||
client_t *client;
|
client_t *client;
|
||||||
qbyte *mask;
|
qbyte *mask;
|
||||||
int cluster;
|
int cluster, area1, area2;
|
||||||
int j;
|
int j;
|
||||||
qboolean reliable;
|
qboolean reliable;
|
||||||
client_t *oneclient = NULL, *split;
|
client_t *oneclient = NULL, *split;
|
||||||
|
@ -569,204 +569,10 @@ void SV_MulticastProtExt(vec3_t origin, multicast_t to, int dimension_mask, int
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(Q2BSPS) || defined(Q3BSPS)
|
|
||||||
//in theory, this q2/q3 path is only still different thanks to areas, but it also supports q2 gamecode properly.
|
|
||||||
if (sv.world.worldmodel->fromgame == fg_quake2 || sv.world.worldmodel->fromgame == fg_quake3)
|
|
||||||
{
|
|
||||||
int area1, area2, leafnum;
|
|
||||||
|
|
||||||
reliable = false;
|
|
||||||
|
|
||||||
if (to != MULTICAST_ALL_R && to != MULTICAST_ALL)
|
|
||||||
{
|
|
||||||
leafnum = CM_PointLeafnum (sv.world.worldmodel, origin);
|
|
||||||
area1 = CM_LeafArea (sv.world.worldmodel, leafnum);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
leafnum = 0; // just to avoid compiler warnings
|
|
||||||
area1 = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (to)
|
|
||||||
{
|
|
||||||
case MULTICAST_ALL_R:
|
|
||||||
reliable = true; // intentional fallthrough
|
|
||||||
case MULTICAST_ALL:
|
|
||||||
leafnum = 0;
|
|
||||||
mask = NULL;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MULTICAST_PHS_R:
|
|
||||||
reliable = true; // intentional fallthrough
|
|
||||||
case MULTICAST_PHS:
|
|
||||||
leafnum = CM_PointLeafnum (sv.world.worldmodel, origin);
|
|
||||||
cluster = CM_LeafCluster (sv.world.worldmodel, leafnum);
|
|
||||||
mask = sv_nopvs.ival?NULL:CM_ClusterPHS (sv.world.worldmodel, cluster, NULL);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MULTICAST_PVS_R:
|
|
||||||
reliable = true; // intentional fallthrough
|
|
||||||
case MULTICAST_PVS:
|
|
||||||
leafnum = CM_PointLeafnum (sv.world.worldmodel, origin);
|
|
||||||
cluster = CM_LeafCluster (sv.world.worldmodel, leafnum);
|
|
||||||
mask = sv_nopvs.ival?NULL:CM_ClusterPVS (sv.world.worldmodel, cluster, NULL, PVM_FAST);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MULTICAST_ONE_R_NOSPECS:
|
|
||||||
case MULTICAST_ONE_R_SPECS:
|
|
||||||
reliable = true;
|
|
||||||
case MULTICAST_ONE_NOSPECS:
|
|
||||||
case MULTICAST_ONE_SPECS:
|
|
||||||
if (svprogfuncs)
|
|
||||||
{
|
|
||||||
edict_t *ent = PROG_TO_EDICT(svprogfuncs, pr_global_struct->msg_entity);
|
|
||||||
oneclient = svs.clients + NUM_FOR_EDICT(svprogfuncs, ent) - 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
oneclient = NULL; //unsupported in this game mode
|
|
||||||
mask = NULL;
|
|
||||||
andspecs = (to==MULTICAST_ONE_R_SPECS||to==MULTICAST_ONE_SPECS);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
mask = NULL;
|
|
||||||
SV_Error ("SV_Multicast: bad to:%i", to);
|
|
||||||
}
|
|
||||||
|
|
||||||
// send the data to all relevent clients
|
|
||||||
for (j = 0; j < svs.allocated_client_slots; j++)
|
|
||||||
{
|
|
||||||
client = &svs.clients[j];
|
|
||||||
if (client->state != cs_spawned)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (client->controller)
|
|
||||||
continue; //FIXME: send if at least one of the players is near enough.
|
|
||||||
|
|
||||||
for (split = client, seat = 0; split; split = split->controlled, seat++)
|
|
||||||
{
|
|
||||||
if (client->protocol == SCP_QUAKEWORLD)
|
|
||||||
{
|
|
||||||
if (client->fteprotocolextensions & without)
|
|
||||||
{
|
|
||||||
// Con_Printf ("Version supressed multicast - without pext\n");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!(~client->fteprotocolextensions & ~with))
|
|
||||||
{
|
|
||||||
// Con_Printf ("Version supressed multicast - with pext\n");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (oneclient)
|
|
||||||
{
|
|
||||||
if (oneclient != split)
|
|
||||||
{
|
|
||||||
if (andspecs && split->spectator && split->spec_track >= 0 && oneclient == &svs.clients[split->spec_track])
|
|
||||||
;
|
|
||||||
else
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (mask)
|
|
||||||
{
|
|
||||||
if (split->penalties & BAN_BLIND)
|
|
||||||
continue;
|
|
||||||
#ifdef Q2SERVER
|
|
||||||
if (ge)
|
|
||||||
leafnum = CM_PointLeafnum (sv.world.worldmodel, split->q2edict->s.origin);
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
if (svprogfuncs)
|
|
||||||
{
|
|
||||||
if (!((int)split->edict->xv->dimension_see & dimension_mask))
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
leafnum = CM_PointLeafnum (sv.world.worldmodel, split->edict->v->origin);
|
|
||||||
}
|
|
||||||
cluster = CM_LeafCluster (sv.world.worldmodel, leafnum);
|
|
||||||
area2 = CM_LeafArea (sv.world.worldmodel, leafnum);
|
|
||||||
if (!CM_AreasConnected (sv.world.worldmodel, area1, area2))
|
|
||||||
continue;
|
|
||||||
if ( mask && (!(mask[cluster>>3] & (1<<(cluster&7)) ) ) )
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!split)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
switch (client->protocol)
|
|
||||||
{
|
|
||||||
case SCP_BAD:
|
|
||||||
continue; //a bot.
|
|
||||||
|
|
||||||
default:
|
|
||||||
SV_Error("Multicast: Client is using a bad protocl");
|
|
||||||
|
|
||||||
case SCP_QUAKE3:
|
|
||||||
Con_Printf("Skipping multicast for q3 client\n");
|
|
||||||
break;
|
|
||||||
#ifdef NQPROT
|
|
||||||
case SCP_NETQUAKE:
|
|
||||||
case SCP_BJP3:
|
|
||||||
case SCP_FITZ666:
|
|
||||||
case SCP_DARKPLACES6:
|
|
||||||
case SCP_DARKPLACES7:
|
|
||||||
if (reliable)
|
|
||||||
{
|
|
||||||
ClientReliableCheckBlock(client, sv.nqmulticast.cursize);
|
|
||||||
ClientReliableWrite_SZ(client, sv.nqmulticast.data, sv.nqmulticast.cursize);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
SZ_Write (&client->datagram, sv.nqmulticast.data, sv.nqmulticast.cursize);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
#ifdef Q2SERVER
|
|
||||||
case SCP_QUAKE2:
|
|
||||||
if (reliable)
|
|
||||||
{
|
|
||||||
ClientReliableCheckBlock(client, sv.q2multicast.cursize);
|
|
||||||
ClientReliableWrite_SZ(client, sv.q2multicast.data, sv.q2multicast.cursize);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
SZ_Write (&client->datagram, sv.q2multicast.data, sv.q2multicast.cursize);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
case SCP_QUAKEWORLD:
|
|
||||||
if (reliable)
|
|
||||||
{
|
|
||||||
if (oneclient && seat)
|
|
||||||
{
|
|
||||||
ClientReliableCheckBlock(client, 2+sv.multicast.cursize);
|
|
||||||
ClientReliableWrite_Byte(client, svcfte_choosesplitclient);
|
|
||||||
ClientReliableWrite_Byte(client, seat);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
ClientReliableCheckBlock(client, sv.multicast.cursize);
|
|
||||||
|
|
||||||
ClientReliableWrite_SZ(client, sv.multicast.data, sv.multicast.cursize);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (oneclient && seat)
|
|
||||||
{
|
|
||||||
MSG_WriteByte (&client->datagram, svcfte_choosesplitclient);
|
|
||||||
MSG_WriteByte (&client->datagram, seat);
|
|
||||||
}
|
|
||||||
SZ_Write (&client->datagram, sv.multicast.data, sv.multicast.cursize);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
reliable = false;
|
reliable = false;
|
||||||
|
area1=-1;
|
||||||
|
area2=-1;
|
||||||
|
|
||||||
switch (to)
|
switch (to)
|
||||||
{
|
{
|
||||||
|
@ -779,13 +585,13 @@ void SV_MulticastProtExt(vec3_t origin, multicast_t to, int dimension_mask, int
|
||||||
case MULTICAST_PHS_R:
|
case MULTICAST_PHS_R:
|
||||||
reliable = true; // intentional fallthrough
|
reliable = true; // intentional fallthrough
|
||||||
case MULTICAST_PHS:
|
case MULTICAST_PHS:
|
||||||
if (!sv.world.worldmodel->phs) /*broadcast if no pvs*/
|
if (!sv.world.worldmodel->phs || sv_nopvs.ival) /*broadcast if no pvs*/
|
||||||
mask = NULL;
|
mask = NULL;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cluster = sv.world.worldmodel->funcs.ClusterForPoint(sv.world.worldmodel, origin, NULL);
|
cluster = sv.world.worldmodel->funcs.ClusterForPoint(sv.world.worldmodel, origin, &area1);
|
||||||
if (cluster >= 0)
|
if (cluster >= 0)
|
||||||
mask = sv.world.worldmodel->phs + cluster*sv.world.worldmodel->pvsbytes;
|
mask = sv.world.worldmodel->funcs.ClusterPHS(sv.world.worldmodel, cluster, NULL);
|
||||||
else
|
else
|
||||||
mask = NULL;
|
mask = NULL;
|
||||||
}
|
}
|
||||||
|
@ -794,11 +600,16 @@ void SV_MulticastProtExt(vec3_t origin, multicast_t to, int dimension_mask, int
|
||||||
case MULTICAST_PVS_R:
|
case MULTICAST_PVS_R:
|
||||||
reliable = true; // intentional fallthrough
|
reliable = true; // intentional fallthrough
|
||||||
case MULTICAST_PVS:
|
case MULTICAST_PVS:
|
||||||
cluster = sv.world.worldmodel->funcs.ClusterForPoint(sv.world.worldmodel, origin, NULL);
|
if (sv_nopvs.ival)
|
||||||
if (cluster >= 0)
|
|
||||||
mask = sv.world.worldmodel->funcs.ClusterPVS(sv.world.worldmodel, cluster, NULL, PVM_FAST);
|
|
||||||
else
|
|
||||||
mask = NULL;
|
mask = NULL;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cluster = sv.world.worldmodel->funcs.ClusterForPoint(sv.world.worldmodel, origin, &area1);
|
||||||
|
if (cluster >= 0)
|
||||||
|
mask = sv.world.worldmodel->funcs.ClusterPVS(sv.world.worldmodel, cluster, NULL, PVM_FAST);
|
||||||
|
else
|
||||||
|
mask = NULL;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MULTICAST_ONE_R_NOSPECS:
|
case MULTICAST_ONE_R_NOSPECS:
|
||||||
|
@ -860,10 +671,21 @@ void SV_MulticastProtExt(vec3_t origin, multicast_t to, int dimension_mask, int
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (svprogfuncs)
|
else
|
||||||
{
|
{
|
||||||
if (!((int)split->edict->xv->dimension_see & dimension_mask))
|
vec3_t pos;
|
||||||
continue;
|
if (svprogfuncs)
|
||||||
|
{
|
||||||
|
if (!((int)split->edict->xv->dimension_see & dimension_mask))
|
||||||
|
continue;
|
||||||
|
VectorAdd(split->edict->v->origin, split->edict->v->view_ofs, pos);
|
||||||
|
}
|
||||||
|
#ifdef Q2SERVER
|
||||||
|
else if (ge)
|
||||||
|
VectorCopy(split->q2edict->s.origin, pos);
|
||||||
|
#endif
|
||||||
|
else
|
||||||
|
continue; //no idea where the player is...
|
||||||
|
|
||||||
if (!mask) //no pvs? broadcast.
|
if (!mask) //no pvs? broadcast.
|
||||||
break;
|
break;
|
||||||
|
@ -871,20 +693,17 @@ void SV_MulticastProtExt(vec3_t origin, multicast_t to, int dimension_mask, int
|
||||||
if (to == MULTICAST_PHS_R || to == MULTICAST_PHS)
|
if (to == MULTICAST_PHS_R || to == MULTICAST_PHS)
|
||||||
{ //always in range if within 1024 units (consistent with quakeworld).
|
{ //always in range if within 1024 units (consistent with quakeworld).
|
||||||
vec3_t delta;
|
vec3_t delta;
|
||||||
VectorSubtract(origin, split->edict->v->origin, delta);
|
VectorSubtract(origin, pos, delta);
|
||||||
if (DotProduct(delta, delta) <= 1024*1024)
|
if (DotProduct(delta, delta) <= 1024*1024)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cluster = sv.world.worldmodel->funcs.ClusterForPoint (sv.world.worldmodel, pos, &area2);
|
||||||
|
if (cluster>= 0 && (!(mask[cluster>>3] & (1<<(cluster&7)) ) ||
|
||||||
|
(sv.world.worldmodel->funcs.AreasConnected && !sv.world.worldmodel->funcs.AreasConnected (sv.world.worldmodel, area1, area2))))
|
||||||
{
|
{
|
||||||
vec3_t pos;
|
// Con_Printf ("PVS supressed multicast\n");
|
||||||
VectorAdd(split->edict->v->origin, split->edict->v->view_ofs, pos);
|
continue;
|
||||||
cluster = sv.world.worldmodel->funcs.ClusterForPoint (sv.world.worldmodel, pos, NULL);
|
|
||||||
if (cluster>= 0 && !(mask[cluster>>3] & (1<<(cluster&7)) ) )
|
|
||||||
{
|
|
||||||
// Con_Printf ("PVS supressed multicast\n");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -2301,6 +2301,14 @@ void SV_Begin_Core(client_t *split)
|
||||||
split->edict->v->maxs[0] = 16;
|
split->edict->v->maxs[0] = 16;
|
||||||
split->edict->v->maxs[1] = 16;
|
split->edict->v->maxs[1] = 16;
|
||||||
split->edict->v->maxs[2] = 32;
|
split->edict->v->maxs[2] = 32;
|
||||||
|
split->edict->v->view_ofs[2] = DEFAULT_VIEWHEIGHT;
|
||||||
|
if (sv.world.worldmodel->fromgame == fg_quake3)
|
||||||
|
split->edict->v->view_ofs[2] = 26; //q3 defaults to slightly higher view heights (though same player size as quake).
|
||||||
|
if (sv.world.worldmodel->hulls[1].clip_maxs[2]-sv.world.worldmodel->hulls[1].clip_mins[2]>0)
|
||||||
|
{
|
||||||
|
VectorCopy(sv.world.worldmodel->hulls[1].clip_mins, split->edict->v->mins);
|
||||||
|
VectorCopy(sv.world.worldmodel->hulls[1].clip_maxs, split->edict->v->maxs);
|
||||||
|
}
|
||||||
split->edict->v->movetype = MOVETYPE_NOCLIP;
|
split->edict->v->movetype = MOVETYPE_NOCLIP;
|
||||||
}
|
}
|
||||||
VectorCopy(split->edict->v->origin, split->edict->v->oldorigin); //make sure oldorigin isn't 0 0 0 or anything too clumsy like that. stuck somewhere killable is better than stuck outside the map.
|
VectorCopy(split->edict->v->origin, split->edict->v->oldorigin); //make sure oldorigin isn't 0 0 0 or anything too clumsy like that. stuck somewhere killable is better than stuck outside the map.
|
||||||
|
|
|
@ -725,7 +725,6 @@ void SVQ2_BuildClientFrame (client_t *client)
|
||||||
for (seat = 0, split = client; split; split = split->controlled, seat++)
|
for (seat = 0, split = client; split; split = split->controlled, seat++)
|
||||||
{
|
{
|
||||||
int clientcluster;
|
int clientcluster;
|
||||||
int leafnum;
|
|
||||||
|
|
||||||
clent[seat] = split->q2edict;
|
clent[seat] = split->q2edict;
|
||||||
frame->clientnum[seat] = split - svs.clients;
|
frame->clientnum[seat] = split - svs.clients;
|
||||||
|
@ -743,16 +742,14 @@ void SVQ2_BuildClientFrame (client_t *client)
|
||||||
for (i=0 ; i<3 ; i++)
|
for (i=0 ; i<3 ; i++)
|
||||||
org[seat][i] = clent[seat]->client->ps.pmove.origin[i]*0.125 + clent[seat]->client->ps.viewoffset[i];
|
org[seat][i] = clent[seat]->client->ps.pmove.origin[i]*0.125 + clent[seat]->client->ps.viewoffset[i];
|
||||||
|
|
||||||
leafnum = CM_PointLeafnum (sv.world.worldmodel, org[seat]);
|
clientcluster = sv.world.worldmodel->funcs.ClusterForPoint (sv.world.worldmodel, org[seat], &clientarea[seat]);
|
||||||
clientarea[seat] = CM_LeafArea (sv.world.worldmodel, leafnum);
|
|
||||||
clientcluster = CM_LeafCluster (sv.world.worldmodel, leafnum);
|
|
||||||
|
|
||||||
// calculate the visible areas
|
// calculate the visible areas
|
||||||
frame->areabytes = CM_WriteAreaBits (sv.world.worldmodel, frame->areabits, clientarea[seat], seat != 0);
|
frame->areabytes = sv.world.worldmodel->funcs.WriteAreaBits (sv.world.worldmodel, frame->areabits, sizeof(frame->areabits), clientarea[seat], seat != 0);
|
||||||
|
|
||||||
sv.world.worldmodel->funcs.FatPVS(sv.world.worldmodel, org[seat], &clientpvs, seat!=0);
|
sv.world.worldmodel->funcs.FatPVS(sv.world.worldmodel, org[seat], &clientpvs, seat!=0);
|
||||||
if (seat==0) //FIXME
|
if (seat==0) //FIXME
|
||||||
clientphs = CM_ClusterPHS (sv.world.worldmodel, clientcluster, NULL);
|
clientphs = sv.world.worldmodel->funcs.ClusterPHS (sv.world.worldmodel, clientcluster, NULL);
|
||||||
|
|
||||||
frame->ps[seat] = clent[seat]->client->ps;
|
frame->ps[seat] = clent[seat]->client->ps;
|
||||||
if (sv.paused)
|
if (sv.paused)
|
||||||
|
@ -790,11 +787,11 @@ void SVQ2_BuildClientFrame (client_t *client)
|
||||||
if (ent != clent[seat])
|
if (ent != clent[seat])
|
||||||
{
|
{
|
||||||
// check area
|
// check area
|
||||||
if (!CM_AreasConnected (sv.world.worldmodel, clientarea[seat], ent->areanum))
|
if (!sv.world.worldmodel->funcs.AreasConnected (sv.world.worldmodel, clientarea[seat], ent->areanum))
|
||||||
{ // doors can legally straddle two areas, so
|
{ // doors can legally straddle two areas, so
|
||||||
// we may need to check another one
|
// we may need to check another one
|
||||||
if (!ent->areanum2
|
if (!ent->areanum2
|
||||||
|| !CM_AreasConnected (sv.world.worldmodel, clientarea[seat], ent->areanum2))
|
|| !sv.world.worldmodel->funcs.AreasConnected (sv.world.worldmodel, clientarea[seat], ent->areanum2))
|
||||||
continue; // blocked by a door
|
continue; // blocked by a door
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -812,7 +809,10 @@ void SVQ2_BuildClientFrame (client_t *client)
|
||||||
|
|
||||||
if (ent->num_clusters == -1)
|
if (ent->num_clusters == -1)
|
||||||
{ // too many leafs for individual check, go by headnode
|
{ // too many leafs for individual check, go by headnode
|
||||||
if (!CM_HeadnodeVisible (sv.world.worldmodel, ent->headnode, clientpvs.buffer))
|
pvscache_t cache;
|
||||||
|
cache.num_leafs = -1;
|
||||||
|
cache.headnode = ent->headnode;
|
||||||
|
if (!sv.world.worldmodel->funcs.EdictInFatPVS(sv.world.worldmodel, &cache, clientpvs.buffer, NULL))
|
||||||
continue;
|
continue;
|
||||||
c_fullsend++;
|
c_fullsend++;
|
||||||
}
|
}
|
||||||
|
|
|
@ -475,23 +475,17 @@ Also checks portalareas so that doors block sight
|
||||||
*/
|
*/
|
||||||
static qboolean VARGS PFQ2_inPVS (vec3_t p1, vec3_t p2)
|
static qboolean VARGS PFQ2_inPVS (vec3_t p1, vec3_t p2)
|
||||||
{
|
{
|
||||||
int leafnum;
|
|
||||||
int cluster;
|
int cluster;
|
||||||
int area1, area2;
|
int area1, area2;
|
||||||
qbyte *mask;
|
qbyte *mask;
|
||||||
|
|
||||||
//FIXME: requires q2/q3 bsp
|
cluster = sv.world.worldmodel->funcs.ClusterForPoint(sv.world.worldmodel, p1, &area1);
|
||||||
leafnum = CM_PointLeafnum (sv.world.worldmodel, p1);
|
mask = sv.world.worldmodel->funcs.ClusterPVS (sv.world.worldmodel, cluster, NULL, PVM_FAST);
|
||||||
cluster = CM_LeafCluster (sv.world.worldmodel, leafnum);
|
|
||||||
area1 = CM_LeafArea (sv.world.worldmodel, leafnum);
|
|
||||||
mask = CM_ClusterPVS (sv.world.worldmodel, cluster, NULL, PVM_FAST);
|
|
||||||
|
|
||||||
leafnum = CM_PointLeafnum (sv.world.worldmodel, p2);
|
cluster = sv.world.worldmodel->funcs.ClusterForPoint(sv.world.worldmodel, p2, &area2);
|
||||||
cluster = CM_LeafCluster (sv.world.worldmodel, leafnum);
|
|
||||||
area2 = CM_LeafArea (sv.world.worldmodel, leafnum);
|
|
||||||
if ( mask && (!(mask[cluster>>3] & (1<<(cluster&7)) ) ) )
|
if ( mask && (!(mask[cluster>>3] & (1<<(cluster&7)) ) ) )
|
||||||
return false;
|
return false;
|
||||||
if (!CM_AreasConnected (sv.world.worldmodel, area1, area2))
|
if (!sv.world.worldmodel->funcs.AreasConnected (sv.world.worldmodel, area1, area2))
|
||||||
return false; // a door blocks sight
|
return false; // a door blocks sight
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -506,23 +500,17 @@ Also checks portalareas so that doors block sound
|
||||||
*/
|
*/
|
||||||
static qboolean VARGS PFQ2_inPHS (vec3_t p1, vec3_t p2)
|
static qboolean VARGS PFQ2_inPHS (vec3_t p1, vec3_t p2)
|
||||||
{
|
{
|
||||||
int leafnum;
|
|
||||||
int cluster;
|
int cluster;
|
||||||
int area1, area2;
|
int area1, area2;
|
||||||
qbyte *mask;
|
qbyte *mask;
|
||||||
|
|
||||||
//FIXME: requires q2/q3 bsp
|
cluster = sv.world.worldmodel->funcs.ClusterForPoint(sv.world.worldmodel, p1, &area1);
|
||||||
leafnum = CM_PointLeafnum (sv.world.worldmodel, p1);
|
mask = sv.world.worldmodel->funcs.ClusterPHS (sv.world.worldmodel, cluster, NULL);
|
||||||
cluster = CM_LeafCluster (sv.world.worldmodel, leafnum);
|
|
||||||
area1 = CM_LeafArea (sv.world.worldmodel, leafnum);
|
|
||||||
mask = CM_ClusterPHS (sv.world.worldmodel, cluster, NULL);
|
|
||||||
|
|
||||||
leafnum = CM_PointLeafnum (sv.world.worldmodel, p2);
|
cluster = sv.world.worldmodel->funcs.ClusterForPoint(sv.world.worldmodel, p2, &area2);
|
||||||
cluster = CM_LeafCluster (sv.world.worldmodel, leafnum);
|
|
||||||
area2 = CM_LeafArea (sv.world.worldmodel, leafnum);
|
|
||||||
if ( mask && (!(mask[cluster>>3] & (1<<(cluster&7)) ) ) )
|
if ( mask && (!(mask[cluster>>3] & (1<<(cluster&7)) ) ) )
|
||||||
return false; // more than one bounce away
|
return false; // more than one bounce away
|
||||||
if (!CM_AreasConnected (sv.world.worldmodel, area1, area2))
|
if (!sv.world.worldmodel->funcs.AreasConnected (sv.world.worldmodel, area1, area2))
|
||||||
return false; // a door blocks hearing
|
return false; // a door blocks hearing
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -531,7 +519,7 @@ static qboolean VARGS PFQ2_inPHS (vec3_t p1, vec3_t p2)
|
||||||
qboolean VARGS PFQ2_AreasConnected(unsigned int area1, unsigned int area2)
|
qboolean VARGS PFQ2_AreasConnected(unsigned int area1, unsigned int area2)
|
||||||
{
|
{
|
||||||
//FIXME: requires q2/q3 bsp
|
//FIXME: requires q2/q3 bsp
|
||||||
return CM_AreasConnected(sv.world.worldmodel, area1, area2);
|
return sv.world.worldmodel->funcs.AreasConnected(sv.world.worldmodel, area1, area2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -823,7 +811,8 @@ void SVQ2_InitWorld(void)
|
||||||
|
|
||||||
static void QDECL PFQ2_SetAreaPortalState(unsigned int p, qboolean s)
|
static void QDECL PFQ2_SetAreaPortalState(unsigned int p, qboolean s)
|
||||||
{
|
{
|
||||||
CMQ2_SetAreaPortalState(sv.world.worldmodel, p, s);
|
if (sv.world.worldmodel->funcs.SetAreaPortalState)
|
||||||
|
sv.world.worldmodel->funcs.SetAreaPortalState(sv.world.worldmodel, p, -1, -1, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *VARGS ZQ2_TagMalloc(int size, int tag)
|
static void *VARGS ZQ2_TagMalloc(int size, int tag)
|
||||||
|
|
|
@ -5,10 +5,6 @@
|
||||||
|
|
||||||
#ifdef Q3SERVER
|
#ifdef Q3SERVER
|
||||||
|
|
||||||
#ifndef MAX_ENT_CLUSTERS
|
|
||||||
#define MAX_ENT_CLUSTERS 16
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define USEBOTLIB
|
#define USEBOTLIB
|
||||||
|
|
||||||
#ifdef USEBOTLIB
|
#ifdef USEBOTLIB
|
||||||
|
@ -135,11 +131,8 @@ typedef struct {
|
||||||
link_t area;
|
link_t area;
|
||||||
#endif
|
#endif
|
||||||
qboolean linked;
|
qboolean linked;
|
||||||
int areanum;
|
|
||||||
int areanum2;
|
pvscache_t pvscache;
|
||||||
int headnode;
|
|
||||||
int num_clusters;
|
|
||||||
int clusternums[MAX_ENT_CLUSTERS];
|
|
||||||
} q3serverEntity_t;
|
} q3serverEntity_t;
|
||||||
q3serverEntity_t *q3_sentities;
|
q3serverEntity_t *q3_sentities;
|
||||||
|
|
||||||
|
@ -211,12 +204,7 @@ static void Q3G_LinkEntity(q3sharedEntity_t *ent)
|
||||||
areanode_t *node;
|
areanode_t *node;
|
||||||
#endif
|
#endif
|
||||||
q3serverEntity_t *sent;
|
q3serverEntity_t *sent;
|
||||||
int leafs[MAX_TOTAL_ENT_LEAFS];
|
|
||||||
int clusters[MAX_TOTAL_ENT_LEAFS];
|
|
||||||
int num_leafs;
|
|
||||||
int i, j, k;
|
int i, j, k;
|
||||||
int area;
|
|
||||||
int topnode;
|
|
||||||
const float *origin;
|
const float *origin;
|
||||||
const float *angles;
|
const float *angles;
|
||||||
|
|
||||||
|
@ -291,83 +279,8 @@ static void Q3G_LinkEntity(q3sharedEntity_t *ent)
|
||||||
ent->r.absmax[2] += 1;
|
ent->r.absmax[2] += 1;
|
||||||
|
|
||||||
// link to PVS leafs
|
// link to PVS leafs
|
||||||
sent->num_clusters = 0;
|
sv.world.worldmodel->funcs.FindTouchedLeafs(sv.world.worldmodel, &sent->pvscache, ent->r.absmin, ent->r.absmax);
|
||||||
sent->areanum = -1;
|
//FIXME: return if no leafs
|
||||||
sent->areanum2 = -1;
|
|
||||||
|
|
||||||
//get all leafs, including solids
|
|
||||||
if (sv.world.worldmodel->type == mod_heightmap)
|
|
||||||
{
|
|
||||||
sent->areanum = 0;
|
|
||||||
num_leafs = 1;
|
|
||||||
sent->num_clusters = -1;
|
|
||||||
sent->headnode = 0;
|
|
||||||
clusters[0] = 0;
|
|
||||||
topnode = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
num_leafs = CM_BoxLeafnums(sv.world.worldmodel, ent->r.absmin, ent->r.absmax,
|
|
||||||
leafs, MAX_TOTAL_ENT_LEAFS, &topnode);
|
|
||||||
|
|
||||||
if(!num_leafs)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// set areas
|
|
||||||
for(i=0; i<num_leafs; i++)
|
|
||||||
{
|
|
||||||
clusters[i] = CM_LeafCluster(sv.world.worldmodel, leafs[i]);
|
|
||||||
area = CM_LeafArea(sv.world.worldmodel, leafs[i]);
|
|
||||||
if(area >= 0)
|
|
||||||
{
|
|
||||||
// doors may legally straggle two areas,
|
|
||||||
// but nothing should ever need more than that
|
|
||||||
if(sent->areanum >= 0 && sent->areanum != area)
|
|
||||||
{
|
|
||||||
if(sent->areanum2 >= 0 && sent->areanum2 != area && sv.state == ss_loading)
|
|
||||||
Con_DPrintf("Object touching 3 areas at %f %f %f\n", ent->r.absmin[0], ent->r.absmin[1], ent->r.absmin[2]);
|
|
||||||
|
|
||||||
sent->areanum2 = area;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
sent->areanum = area;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(num_leafs >= MAX_TOTAL_ENT_LEAFS)
|
|
||||||
{
|
|
||||||
// assume we missed some leafs, and mark by headnode
|
|
||||||
sent->num_clusters = -1;
|
|
||||||
sent->headnode = topnode;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sent->num_clusters = 0;
|
|
||||||
for(i=0; i<num_leafs; i++)
|
|
||||||
{
|
|
||||||
if(clusters[i] == -1)
|
|
||||||
continue; // not a visible leaf
|
|
||||||
|
|
||||||
for(j=0 ; j<i ; j++)
|
|
||||||
{
|
|
||||||
if(clusters[j] == clusters[i])
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if(j == i)
|
|
||||||
{
|
|
||||||
if(sent->num_clusters == MAX_ENT_CLUSTERS)
|
|
||||||
{
|
|
||||||
// assume we missed some leafs, and mark by headnode
|
|
||||||
sent->num_clusters = -1;
|
|
||||||
sent->headnode = topnode;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
sent->clusternums[sent->num_clusters++] = clusters[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ent->r.linkcount++;
|
ent->r.linkcount++;
|
||||||
ent->r.linked = true;
|
ent->r.linked = true;
|
||||||
|
@ -856,9 +769,9 @@ static int SVQ3_BotGetSnapshotEntity(int client, int entnum)
|
||||||
static void SVQ3_Adjust_Area_Portal_State(q3sharedEntity_t *ge, qboolean open)
|
static void SVQ3_Adjust_Area_Portal_State(q3sharedEntity_t *ge, qboolean open)
|
||||||
{
|
{
|
||||||
q3serverEntity_t *se = SENTITY_FOR_GENTITY(ge);
|
q3serverEntity_t *se = SENTITY_FOR_GENTITY(ge);
|
||||||
if (se->areanum == -1 || se->areanum2 == -1) //not linked properly.
|
if (se->pvscache.areanum == -1 || se->pvscache.areanum2 == -1) //not linked properly.
|
||||||
return;
|
return;
|
||||||
CMQ3_SetAreaPortalState(sv.world.worldmodel, se->areanum, se->areanum2, open);
|
sv.world.worldmodel->funcs.SetAreaPortalState(sv.world.worldmodel, -1, se->pvscache.areanum, se->pvscache.areanum2, open);
|
||||||
}
|
}
|
||||||
|
|
||||||
static qboolean SV_InPVS(vec3_t p1, vec3_t p2)
|
static qboolean SV_InPVS(vec3_t p1, vec3_t p2)
|
||||||
|
@ -871,37 +784,18 @@ static qboolean SV_InPVS(vec3_t p1, vec3_t p2)
|
||||||
return true; //no pvs info, assume everything is visible
|
return true; //no pvs info, assume everything is visible
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
#if 1
|
int a1, c1 = worldmodel->funcs.ClusterForPoint(worldmodel, p1, &a1);
|
||||||
int l1 = CM_PointLeafnum(worldmodel, p1);
|
int a2, c2 = worldmodel->funcs.ClusterForPoint(worldmodel, p2, &a2);
|
||||||
int l2 = CM_PointLeafnum(worldmodel, p2);
|
|
||||||
int c1 = CM_LeafCluster(worldmodel, l1);
|
|
||||||
int c2 = CM_LeafCluster(worldmodel, l2);
|
|
||||||
qbyte *pvs;
|
qbyte *pvs;
|
||||||
if (c1 < 0 || c2 < 0)
|
if (c1 < 0 || c2 < 0)
|
||||||
return (c1<0); //outside can see in, inside cannot (normally) see out.
|
return (c1<0); //outside can see in, inside cannot (normally) see out.
|
||||||
pvs = CM_ClusterPVS(worldmodel, c1, NULL, PVM_FAST);
|
pvs = worldmodel->funcs.ClusterPVS(worldmodel, c1, NULL, PVM_FAST);
|
||||||
if (pvs[c2>>3] & (1<<(c2&7)))
|
if (pvs[c2>>3] & (1<<(c2&7)))
|
||||||
{
|
{
|
||||||
int a1 = CM_LeafArea(worldmodel, l1);
|
if (worldmodel->funcs.AreasConnected(worldmodel, a1, a2))
|
||||||
int a2 = CM_LeafArea(worldmodel, l2);
|
|
||||||
if (CM_AreasConnected(worldmodel, a1, a2))
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
#else
|
|
||||||
const qbyte *mask;
|
|
||||||
int c1 = worldmodel->funcs.ClusterForPoint(worldmodel, p1);
|
|
||||||
int c2 = worldmodel->funcs.ClusterForPoint(worldmodel, p2);
|
|
||||||
if (c1 < 0 || c2 < 0)
|
|
||||||
return true; //one is outside of the world, so can see inside.
|
|
||||||
mask = worldmodel->funcs.ClusterPVS(worldmodel, c1, NULL, PVM_FAST);
|
|
||||||
if (mask[c2>>3] & (1<<(c2&7)))
|
|
||||||
{
|
|
||||||
//FIXME: check areas/portals too
|
|
||||||
return true; //visible
|
|
||||||
}
|
|
||||||
return false; //nope. :(
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2015,8 +1909,6 @@ qboolean SVQ3_InitGame(qboolean restart)
|
||||||
mapentspointer = Mod_GetEntitiesString(sv.world.worldmodel);
|
mapentspointer = Mod_GetEntitiesString(sv.world.worldmodel);
|
||||||
VM_Call(q3gamevm, GAME_INIT, (intptr_t)(sv.time*1000), (int)rand(), restart);
|
VM_Call(q3gamevm, GAME_INIT, (intptr_t)(sv.time*1000), (int)rand(), restart);
|
||||||
|
|
||||||
CM_InitBoxHull();
|
|
||||||
|
|
||||||
if (!restart)
|
if (!restart)
|
||||||
{
|
{
|
||||||
SVQ3_CreateBaseline();
|
SVQ3_CreateBaseline();
|
||||||
|
@ -2312,9 +2204,6 @@ static int VARGS SVQ3_QsortEntityStates( const void *arg1, const void *arg2 )
|
||||||
static qboolean SVQ3_EntityIsVisible(q3client_frame_t *snap, q3sharedEntity_t *ent)
|
static qboolean SVQ3_EntityIsVisible(q3client_frame_t *snap, q3sharedEntity_t *ent)
|
||||||
{
|
{
|
||||||
q3serverEntity_t *sent;
|
q3serverEntity_t *sent;
|
||||||
int i;
|
|
||||||
int l;
|
|
||||||
|
|
||||||
if (!ent->r.linked)
|
if (!ent->r.linked)
|
||||||
{
|
{
|
||||||
return false; // not active entity
|
return false; // not active entity
|
||||||
|
@ -2367,56 +2256,17 @@ static qboolean SVQ3_EntityIsVisible(q3client_frame_t *snap, q3sharedEntity_t *e
|
||||||
sent = SENTITY_FOR_GENTITY( ent );
|
sent = SENTITY_FOR_GENTITY( ent );
|
||||||
|
|
||||||
// check area
|
// check area
|
||||||
if (sent->areanum < 0 || !(snap->areabits[sent->areanum >> 3] & (1 << (sent->areanum & 7))))
|
if (sent->pvscache.areanum < 0 || !(snap->areabits[sent->pvscache.areanum >> 3] & (1 << (sent->pvscache.areanum & 7))))
|
||||||
{
|
{
|
||||||
// doors can legally straddle two areas, so
|
// doors can legally straddle two areas, so
|
||||||
// we may need to check another one
|
// we may need to check another one
|
||||||
if (sent->areanum2 < 0 || !(snap->areabits[sent->areanum2 >> 3] & (1 << (sent->areanum2 & 7))))
|
if (sent->pvscache.areanum2 < 0 || !(snap->areabits[sent->pvscache.areanum2 >> 3] & (1 << (sent->pvscache.areanum2 & 7))))
|
||||||
{
|
{
|
||||||
return false; // blocked by a door
|
return false; // blocked by a door
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
return sv.world.worldmodel->funcs.EdictInFatPVS(sv.world.worldmodel, &sent->pvscache, bitvector, NULL/*using the snapshots areabits rather than the bsp's*/);
|
||||||
// check area
|
|
||||||
if( !CM_AreasConnected( clientarea, sent->areanum ) )
|
|
||||||
{
|
|
||||||
// doors can legally straddle two areas, so
|
|
||||||
// we may need to check another one
|
|
||||||
if( !CM_AreasConnected( clientarea, sent->areanum2 ) )
|
|
||||||
{
|
|
||||||
return false; // blocked by a door
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
if (sent->num_clusters == -1)
|
|
||||||
{
|
|
||||||
// too many leafs for individual check, go by headnode
|
|
||||||
if (!CM_HeadnodeVisible(sv.world.worldmodel, sent->headnode, bitvector))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// check individual leafs
|
|
||||||
for (i=0; i < sent->num_clusters; i++)
|
|
||||||
{
|
|
||||||
l = sent->clusternums[i];
|
|
||||||
if (bitvector[l >> 3] & (1 << (l & 7)))
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (i == sent->num_clusters)
|
|
||||||
{
|
|
||||||
return false; // not visible
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef Q3OVERQW
|
#ifdef Q3OVERQW
|
||||||
|
@ -2530,9 +2380,7 @@ void SVQ3_BuildClientSnapshot( client_t *client )
|
||||||
VectorCopy( ps->origin, org );
|
VectorCopy( ps->origin, org );
|
||||||
org[2] += ps->viewheight;
|
org[2] += ps->viewheight;
|
||||||
|
|
||||||
clientarea = CM_PointLeafnum(sv.world.worldmodel, org);
|
bitvector = sv.world.worldmodel->funcs.ClusterPVS(sv.world.worldmodel, sv.world.worldmodel->funcs.ClusterForPoint(sv.world.worldmodel, org, &clientarea), &pvsbuffer, PVM_REPLACE);
|
||||||
bitvector = sv.world.worldmodel->funcs.ClusterPVS(sv.world.worldmodel, CM_LeafCluster(sv.world.worldmodel, clientarea), &pvsbuffer, PVM_REPLACE);
|
|
||||||
clientarea = CM_LeafArea(sv.world.worldmodel, clientarea);
|
|
||||||
/*
|
/*
|
||||||
if (client->areanum != clientarea)
|
if (client->areanum != clientarea)
|
||||||
{
|
{
|
||||||
|
@ -2542,7 +2390,7 @@ void SVQ3_BuildClientSnapshot( client_t *client )
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// calculate the visible areas
|
// calculate the visible areas
|
||||||
snap->areabytes = CM_WriteAreaBits(sv.world.worldmodel, snap->areabits, clientarea, false);
|
snap->areabytes = sv.world.worldmodel->funcs.WriteAreaBits(sv.world.worldmodel, snap->areabits, sizeof(snap->areabits), clientarea, false);
|
||||||
|
|
||||||
// grab the current playerState_t
|
// grab the current playerState_t
|
||||||
memcpy(&snap->ps, ps, sizeof(snap->ps));
|
memcpy(&snap->ps, ps, sizeof(snap->ps));
|
||||||
|
@ -2565,13 +2413,10 @@ void SVQ3_BuildClientSnapshot( client_t *client )
|
||||||
if(!SVQ3_EntityIsVisible(snap, ent))
|
if(!SVQ3_EntityIsVisible(snap, ent))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// merge PVS if portal
|
|
||||||
portalarea = CM_PointLeafnum(sv.world.worldmodel, ent->s.origin2);
|
|
||||||
//merge pvs bits so we can see other ents through it
|
//merge pvs bits so we can see other ents through it
|
||||||
sv.world.worldmodel->funcs.ClusterPVS(sv.world.worldmodel, CM_LeafCluster(sv.world.worldmodel, portalarea), &pvsbuffer, PVM_MERGE);
|
sv.world.worldmodel->funcs.ClusterPVS(sv.world.worldmodel, sv.world.worldmodel->funcs.ClusterForPoint(sv.world.worldmodel, ent->s.origin2, &portalarea), &pvsbuffer, PVM_MERGE);
|
||||||
//and merge areas, so we can see the world too (client will calc its own pvs)
|
//and areabits too
|
||||||
portalarea = CM_LeafArea(sv.world.worldmodel, portalarea);
|
sv.world.worldmodel->funcs.WriteAreaBits(sv.world.worldmodel, snap->areabits, snap->areabytes, portalarea, true);
|
||||||
CM_WriteAreaBits(sv.world.worldmodel, snap->areabits, portalarea, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// add all visible entities
|
// add all visible entities
|
||||||
|
|
|
@ -729,12 +729,6 @@ void VARGS WorldQ2_UnlinkEdict(world_t *w, q2edict_t *ent)
|
||||||
void VARGS WorldQ2_LinkEdict(world_t *w, q2edict_t *ent)
|
void VARGS WorldQ2_LinkEdict(world_t *w, q2edict_t *ent)
|
||||||
{
|
{
|
||||||
areanode_t *node;
|
areanode_t *node;
|
||||||
int leafs[128];
|
|
||||||
int clusters[countof(leafs)];
|
|
||||||
int num_leafs;
|
|
||||||
int i, j;
|
|
||||||
int area;
|
|
||||||
int topnode;
|
|
||||||
|
|
||||||
if (ent->area.prev)
|
if (ent->area.prev)
|
||||||
WorldQ2_UnlinkEdict (w, ent); // unlink from old position
|
WorldQ2_UnlinkEdict (w, ent); // unlink from old position
|
||||||
|
@ -822,56 +816,18 @@ void VARGS WorldQ2_LinkEdict(world_t *w, q2edict_t *ent)
|
||||||
ent->absmax[2] += 1;
|
ent->absmax[2] += 1;
|
||||||
|
|
||||||
// link to PVS leafs
|
// link to PVS leafs
|
||||||
ent->num_clusters = 0;
|
|
||||||
ent->areanum = 0;
|
|
||||||
ent->areanum2 = 0;
|
|
||||||
|
|
||||||
//get all leafs, including solids
|
|
||||||
num_leafs = CM_BoxLeafnums (w->worldmodel, ent->absmin, ent->absmax,
|
|
||||||
leafs, countof(leafs), &topnode);
|
|
||||||
|
|
||||||
// set areas
|
|
||||||
for (i=0 ; i<num_leafs ; i++)
|
|
||||||
{
|
{
|
||||||
clusters[i] = CM_LeafCluster (w->worldmodel, leafs[i]);
|
pvscache_t cache;
|
||||||
area = CM_LeafArea (w->worldmodel, leafs[i]);
|
w->worldmodel->funcs.FindTouchedLeafs(w->worldmodel, &cache, ent->absmin, ent->absmax);
|
||||||
if (area)
|
|
||||||
{ // doors may legally straggle two areas,
|
|
||||||
// but nothing should evern need more than that
|
|
||||||
if (ent->areanum && ent->areanum != area)
|
|
||||||
ent->areanum2 = area;
|
|
||||||
else
|
|
||||||
ent->areanum = area;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (num_leafs >= countof(leafs))
|
//evilness: copy into the q2 state (we don't have anywhere else to store it, and there's a chance that the gamecode will care).
|
||||||
{ // assume we missed some leafs, and mark by headnode
|
ent->num_clusters = cache.num_leafs;
|
||||||
ent->num_clusters = -1;
|
if (ent->num_clusters > (int)countof(ent->clusternums))
|
||||||
ent->headnode = topnode;
|
ent->num_clusters = (int)countof(ent->clusternums);
|
||||||
}
|
memcpy(ent->clusternums, cache.leafnums, min(sizeof(ent->clusternums), sizeof(cache.leafnums)));
|
||||||
else
|
ent->headnode = cache.headnode;
|
||||||
{
|
ent->areanum = cache.areanum;
|
||||||
ent->num_clusters = 0;
|
ent->areanum2 = cache.areanum2;
|
||||||
for (i=0 ; i<num_leafs ; i++)
|
|
||||||
{
|
|
||||||
if (clusters[i] == -1)
|
|
||||||
continue; // not a visible leaf
|
|
||||||
for (j=0 ; j<i ; j++)
|
|
||||||
if (clusters[j] == clusters[i])
|
|
||||||
break;
|
|
||||||
if (j == i)
|
|
||||||
{
|
|
||||||
if (ent->num_clusters == MAX_ENT_CLUSTERS)
|
|
||||||
{ // assume we missed some leafs, and mark by headnode
|
|
||||||
ent->num_clusters = -1;
|
|
||||||
ent->headnode = topnode;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ent->clusternums[ent->num_clusters++] = clusters[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// if first time, make sure old_origin is valid
|
// if first time, make sure old_origin is valid
|
||||||
|
@ -901,255 +857,11 @@ void VARGS WorldQ2_LinkEdict(world_t *w, q2edict_t *ent)
|
||||||
// link it in
|
// link it in
|
||||||
InsertLinkBefore (&ent->area, &node->edicts);
|
InsertLinkBefore (&ent->area, &node->edicts);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldQ2_Q1BSP_LinkEdict(world_t *w, q2edict_t *ent)
|
|
||||||
{
|
|
||||||
areanode_t *node;
|
|
||||||
int i, j, k;
|
|
||||||
|
|
||||||
if (ent->area.prev)
|
|
||||||
WorldQ2_UnlinkEdict (w, ent); // unlink from old position
|
|
||||||
|
|
||||||
if (ent == ge->edicts)
|
|
||||||
return; // don't add the world
|
|
||||||
|
|
||||||
if (!ent->inuse)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// set the size
|
|
||||||
VectorSubtract (ent->maxs, ent->mins, ent->size);
|
|
||||||
|
|
||||||
// encode the size into the entity_state for client prediction
|
|
||||||
if (ent->solid == Q2SOLID_BBOX && !(ent->svflags & SVF_DEADMONSTER))
|
|
||||||
{ // assume that x/y are equal and symetric
|
|
||||||
i = ent->maxs[0]/8;
|
|
||||||
if (i<1)
|
|
||||||
i = 1;
|
|
||||||
if (i>31)
|
|
||||||
i = 31;
|
|
||||||
|
|
||||||
// z is not symetric
|
|
||||||
j = (-ent->mins[2])/8;
|
|
||||||
if (j<1)
|
|
||||||
j = 1;
|
|
||||||
if (j>31)
|
|
||||||
j = 31;
|
|
||||||
|
|
||||||
// and z maxs can be negative...
|
|
||||||
k = (ent->maxs[2]+32)/8;
|
|
||||||
if (k<1)
|
|
||||||
k = 1;
|
|
||||||
if (k>63)
|
|
||||||
k = 63;
|
|
||||||
|
|
||||||
ent->s.solid = (k<<10) | (j<<5) | i;
|
|
||||||
}
|
|
||||||
else if (ent->solid == Q2SOLID_BSP)
|
|
||||||
{
|
|
||||||
ent->s.solid = 31; // a solid_bbox will never create this value
|
|
||||||
}
|
|
||||||
else
|
|
||||||
ent->s.solid = 0;
|
|
||||||
|
|
||||||
// set the abs box
|
|
||||||
if (ent->solid == Q2SOLID_BSP &&
|
|
||||||
(ent->s.angles[0] || ent->s.angles[1] || ent->s.angles[2]) )
|
|
||||||
{ // expand for rotation
|
|
||||||
float max, v;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
max = 0;
|
|
||||||
for (i=0 ; i<3 ; i++)
|
|
||||||
{
|
|
||||||
v =fabs( ent->mins[i]);
|
|
||||||
if (v > max)
|
|
||||||
max = v;
|
|
||||||
v =fabs( ent->maxs[i]);
|
|
||||||
if (v > max)
|
|
||||||
max = v;
|
|
||||||
}
|
|
||||||
for (i=0 ; i<3 ; i++)
|
|
||||||
{
|
|
||||||
ent->absmin[i] = ent->s.origin[i] - max;
|
|
||||||
ent->absmax[i] = ent->s.origin[i] + max;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{ // normal
|
|
||||||
VectorAdd (ent->s.origin, ent->mins, ent->absmin);
|
|
||||||
VectorAdd (ent->s.origin, ent->maxs, ent->absmax);
|
|
||||||
}
|
|
||||||
|
|
||||||
// because movement is clipped an epsilon away from an actual edge,
|
|
||||||
// we must fully check even when bounding boxes don't quite touch
|
|
||||||
ent->absmin[0] -= 1;
|
|
||||||
ent->absmin[1] -= 1;
|
|
||||||
ent->absmin[2] -= 1;
|
|
||||||
ent->absmax[0] += 1;
|
|
||||||
ent->absmax[1] += 1;
|
|
||||||
ent->absmax[2] += 1;
|
|
||||||
|
|
||||||
// link to PVS leafs
|
|
||||||
ent->num_clusters = 0;
|
|
||||||
ent->areanum = 0;
|
|
||||||
ent->areanum2 = 0;
|
|
||||||
|
|
||||||
|
|
||||||
ent->areanum = 1;
|
|
||||||
/*
|
|
||||||
//get all leafs, including solids
|
|
||||||
num_leafs = CM_BoxLeafnums (ent->absmin, ent->absmax,
|
|
||||||
leafs, MAX_TOTAL_ENT_LEAFS, &topnode);
|
|
||||||
|
|
||||||
// set areas
|
|
||||||
for (i=0 ; i<num_leafs ; i++)
|
|
||||||
{
|
|
||||||
clusters[i] = CM_LeafCluster (leafs[i]);
|
|
||||||
area = CM_LeafArea (leafs[i]);
|
|
||||||
if (area)
|
|
||||||
{ // doors may legally straggle two areas,
|
|
||||||
// but nothing should evern need more than that
|
|
||||||
if (ent->areanum && ent->areanum != area)
|
|
||||||
{
|
|
||||||
ent->areanum2 = area;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
ent->areanum = area;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (num_leafs >= MAX_TOTAL_ENT_LEAFS)
|
|
||||||
{ // assume we missed some leafs, and mark by headnode
|
|
||||||
ent->num_clusters = -1;
|
|
||||||
ent->headnode = topnode;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ent->num_clusters = 0;
|
|
||||||
for (i=0 ; i<num_leafs ; i++)
|
|
||||||
{
|
|
||||||
if (clusters[i] == -1)
|
|
||||||
continue; // not a visible leaf
|
|
||||||
for (j=0 ; j<i ; j++)
|
|
||||||
if (clusters[j] == clusters[i])
|
|
||||||
break;
|
|
||||||
if (j == i)
|
|
||||||
{
|
|
||||||
if (ent->num_clusters == MAX_ENT_CLUSTERS)
|
|
||||||
{ // assume we missed some leafs, and mark by headnode
|
|
||||||
ent->num_clusters = -1;
|
|
||||||
ent->headnode = topnode;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ent->clusternums[ent->num_clusters++] = clusters[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// if first time, make sure old_origin is valid
|
|
||||||
if (!ent->linkcount)
|
|
||||||
{
|
|
||||||
VectorCopy (ent->s.origin, ent->s.old_origin);
|
|
||||||
}
|
|
||||||
ent->linkcount++;
|
|
||||||
|
|
||||||
if (ent->solid == Q2SOLID_NOT)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// find the first node that the ent's box crosses
|
|
||||||
node = w->areanodes;
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
if (node->axis == -1)
|
|
||||||
break;
|
|
||||||
if (ent->absmin[node->axis] > node->dist)
|
|
||||||
node = node->children[0];
|
|
||||||
else if (ent->absmax[node->axis] < node->dist)
|
|
||||||
node = node->children[1];
|
|
||||||
else
|
|
||||||
break; // crosses the node
|
|
||||||
}
|
|
||||||
|
|
||||||
// link it in
|
|
||||||
InsertLinkBefore (&ent->area, &node->edicts);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#if defined(Q2BSPS) || defined(Q3BSPS)
|
|
||||||
void Q23BSP_FindTouchedLeafs(model_t *model, struct pvscache_s *ent, const float *mins, const float *maxs)
|
|
||||||
{
|
|
||||||
#define MAX_TOTAL_ENT_LEAFS 128
|
|
||||||
int leafs[MAX_TOTAL_ENT_LEAFS];
|
|
||||||
int clusters[MAX_TOTAL_ENT_LEAFS];
|
|
||||||
int num_leafs;
|
|
||||||
int topnode;
|
|
||||||
int i, j;
|
|
||||||
int area;
|
|
||||||
int nullarea = (model->fromgame == fg_quake2)?0:-1;
|
|
||||||
|
|
||||||
//ent->num_leafs == q2's ent->num_clusters
|
|
||||||
ent->num_leafs = 0;
|
|
||||||
ent->areanum = nullarea;
|
|
||||||
ent->areanum2 = nullarea;
|
|
||||||
|
|
||||||
if (!mins || !maxs)
|
|
||||||
return;
|
|
||||||
|
|
||||||
//get all leafs, including solids
|
|
||||||
num_leafs = CM_BoxLeafnums (model, mins, maxs,
|
|
||||||
leafs, MAX_TOTAL_ENT_LEAFS, &topnode);
|
|
||||||
|
|
||||||
// set areas
|
|
||||||
for (i=0 ; i<num_leafs ; i++)
|
|
||||||
{
|
|
||||||
clusters[i] = CM_LeafCluster (model, leafs[i]);
|
|
||||||
area = CM_LeafArea (model, leafs[i]);
|
|
||||||
if (area != nullarea)
|
|
||||||
{ // doors may legally straggle two areas,
|
|
||||||
// but nothing should ever need more than that
|
|
||||||
if (ent->areanum != nullarea && ent->areanum != area)
|
|
||||||
ent->areanum2 = area;
|
|
||||||
else
|
|
||||||
ent->areanum = area;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (num_leafs >= MAX_TOTAL_ENT_LEAFS)
|
|
||||||
{ // assume we missed some leafs, and mark by headnode
|
|
||||||
ent->num_leafs = -1;
|
|
||||||
ent->headnode = topnode;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ent->num_leafs = 0;
|
|
||||||
for (i=0 ; i<num_leafs ; i++)
|
|
||||||
{
|
|
||||||
if (clusters[i] == -1)
|
|
||||||
continue; // not a visible leaf
|
|
||||||
for (j=0 ; j<i ; j++)
|
|
||||||
if (clusters[j] == clusters[i])
|
|
||||||
break;
|
|
||||||
if (j == i)
|
|
||||||
{
|
|
||||||
if (ent->num_leafs == MAX_ENT_LEAFS)
|
|
||||||
{ // assume we missed some leafs, and mark by headnode
|
|
||||||
ent->num_leafs = -1;
|
|
||||||
ent->headnode = topnode;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ent->leafnums[ent->num_leafs++] = clusters[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
===============================================================================
|
===============================================================================
|
||||||
|
|
||||||
|
@ -1905,9 +1617,13 @@ static void World_ClipToEverything (world_t *w, moveclip_t *clip)
|
||||||
trace = World_ClipMoveToEntity (w, touch, touch->v->origin, touch->v->angles, clip->start, clip->mins2, clip->maxs2, clip->end, clip->hullnum, clip->type & MOVE_HITMODEL, clip->capsule, clip->hitcontentsmask);
|
trace = World_ClipMoveToEntity (w, touch, touch->v->origin, touch->v->angles, clip->start, clip->mins2, clip->maxs2, clip->end, clip->hullnum, clip->type & MOVE_HITMODEL, clip->capsule, clip->hitcontentsmask);
|
||||||
else
|
else
|
||||||
trace = World_ClipMoveToEntity (w, touch, touch->v->origin, touch->v->angles, clip->start, clip->mins, clip->maxs, clip->end, clip->hullnum, clip->type & MOVE_HITMODEL, clip->capsule, clip->hitcontentsmask);
|
trace = World_ClipMoveToEntity (w, touch, touch->v->origin, touch->v->angles, clip->start, clip->mins, clip->maxs, clip->end, clip->hullnum, clip->type & MOVE_HITMODEL, clip->capsule, clip->hitcontentsmask);
|
||||||
if (trace.allsolid || trace.startsolid ||
|
|
||||||
trace.fraction < clip->trace.fraction)
|
if (trace.fraction < clip->trace.fraction)
|
||||||
{
|
{
|
||||||
|
//trace traveled less, but don't forget if we started in a solid.
|
||||||
|
trace.startsolid |= clip->trace.startsolid;
|
||||||
|
trace.allsolid |= clip->trace.allsolid;
|
||||||
|
|
||||||
if (clip->type & MOVE_ENTCHAIN)
|
if (clip->type & MOVE_ENTCHAIN)
|
||||||
{
|
{
|
||||||
touch->v->chain = EDICT_TO_PROG(w->progs, clip->trace.ent?clip->trace.ent:w->edicts);
|
touch->v->chain = EDICT_TO_PROG(w->progs, clip->trace.ent?clip->trace.ent:w->edicts);
|
||||||
|
@ -1915,10 +1631,24 @@ static void World_ClipToEverything (world_t *w, moveclip_t *clip)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
trace.ent = touch;
|
if (clip->trace.startsolid && !trace.startsolid)
|
||||||
|
trace.ent = clip->trace.ent; //something else hit earlier, that one gets the trace entity, but not the fraction. yeah, combining traces like this was always going to be weird.
|
||||||
|
else
|
||||||
|
trace.ent = touch;
|
||||||
clip->trace = trace;
|
clip->trace = trace;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (trace.startsolid || trace.allsolid)
|
||||||
|
{
|
||||||
|
//even if the trace traveled less, we still care if it was in a solid.
|
||||||
|
clip->trace.startsolid |= trace.startsolid;
|
||||||
|
clip->trace.allsolid |= trace.allsolid;
|
||||||
|
clip->trace.contents |= trace.contents;
|
||||||
|
if (!clip->trace.ent || trace.fraction == clip->trace.fraction) //xonotic requires that second test (DP has no check at all, which would end up reporting mismatched fraction/ent results, so yuck).
|
||||||
|
{
|
||||||
|
clip->trace.ent = touch;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2519,7 +2249,7 @@ static void World_ClipToNetwork (world_t *w, moveclip_t *clip)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
//lets say that ssqc ents are in dimension 0x1, as far as the csqc can see.
|
//lets say that ssqc ents are in dimension 0x1, as far as the csqc can see.
|
||||||
if (!((int)clip->passedict->xv->dimension_hit & 1))
|
if (clip->passedict && !((int)clip->passedict->xv->dimension_hit & 1))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
framestate.g[FS_REG].frame[0] = touch->frame;
|
framestate.g[FS_REG].frame[0] = touch->frame;
|
||||||
|
|
Loading…
Reference in a new issue