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_TOSHANDLE(a) (a?a->id+1:0)
|
||||
|
||||
extern model_t box_model;
|
||||
static model_t *box_model;
|
||||
|
||||
typedef enum {
|
||||
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)
|
||||
// mod = &capsule_model;
|
||||
// else
|
||||
mod = &box_model;
|
||||
mod = box_model;
|
||||
}
|
||||
else
|
||||
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)
|
||||
// mod = &capsule_model;
|
||||
// else
|
||||
mod = &box_model;
|
||||
mod = box_model;
|
||||
}
|
||||
else
|
||||
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)
|
||||
// mod = &capsule_model;
|
||||
// else
|
||||
mod = &box_model;
|
||||
mod = box_model;
|
||||
}
|
||||
else
|
||||
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)
|
||||
// mod = &capsule_model;
|
||||
// else
|
||||
mod = &box_model;
|
||||
mod = box_model;
|
||||
}
|
||||
else
|
||||
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)
|
||||
COM_WorkerPartialSync(mod, &mod->loadstate, MLS_LOADING);
|
||||
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)
|
||||
|
@ -901,11 +901,11 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con
|
|||
break;
|
||||
|
||||
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;
|
||||
break;
|
||||
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;
|
||||
break;
|
||||
|
||||
|
@ -1359,6 +1359,8 @@ void CG_Start (void)
|
|||
Z_FreeTags(CGTAGNUM);
|
||||
SCR_BeginLoadingPlaque();
|
||||
|
||||
box_model = CM_TempBoxModel(vec3_origin, vec3_origin);
|
||||
|
||||
cgvm = VM_Create("cgame", com_nogamedirnativecode.ival?NULL:CG_SystemCallsNative, "vm/cgame", CG_SystemCallsVM);
|
||||
if (cgvm)
|
||||
{ //hu... cgame doesn't appear to have a query version call!
|
||||
|
|
|
@ -6902,57 +6902,56 @@ void CL_DumpPacket(void)
|
|||
static void CL_ParsePortalState(void)
|
||||
{
|
||||
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:
|
||||
if (mode&2)
|
||||
a1 = MSG_ReadShort();
|
||||
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;
|
||||
state = mode&1;
|
||||
if (!(mode & PS_AREANUMS) && !(mode & PS_PORTALNUM))
|
||||
mode |= PS_PORTALNUM; //legacy crap
|
||||
|
||||
default:
|
||||
//to be phased out.
|
||||
mode |= MSG_ReadByte()<<8;
|
||||
if (cl.worldmodel && cl.worldmodel->loadstate==MLS_LOADED && cl.worldmodel->fromgame == fg_quake2)
|
||||
{
|
||||
#ifdef Q2BSPS
|
||||
CMQ2_SetAreaPortalState(cl.worldmodel, mode & 0x7fff, !!(mode&0x8000));
|
||||
#endif
|
||||
if (mode & PS_PORTALNUM)
|
||||
{ //q2 style
|
||||
if (mode&PS_LARGE)
|
||||
p = MSG_ReadShort();
|
||||
else
|
||||
p = MSG_ReadByte();
|
||||
}
|
||||
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)
|
||||
|
|
|
@ -198,8 +198,9 @@ int VARGS CLQ2_PMpointcontents (vec3_t point)
|
|||
int num;
|
||||
model_t *cmodel;
|
||||
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++)
|
||||
{
|
||||
|
@ -213,7 +214,10 @@ int VARGS CLQ2_PMpointcontents (vec3_t point)
|
|||
if (!cmodel)
|
||||
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;
|
||||
|
|
|
@ -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);
|
||||
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);
|
||||
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_LoadMapArchive(struct model_s *mod, void *archivedata, size_t archivesize);
|
||||
extern void Mod_ClearAll (void);
|
||||
extern void Mod_Purge (enum mod_purge_e type);
|
||||
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)
|
||||
{
|
||||
/*
|
||||
#ifdef Q2BSPS
|
||||
if (csqc_world.worldmodel->fromgame == fg_quake2)
|
||||
{
|
||||
int portal;
|
||||
int state = G_FLOAT(OFS_PARM1)!=0;
|
||||
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
|
||||
int state = G_FLOAT(OFS_PARM1)!=0;
|
||||
wedict_t *ent = G_WEDICT(prinst, OFS_PARM0);
|
||||
int portal = ent->xv->style;
|
||||
int area1 = ent->pvsinfo.areanum, area2 = ent->pvsinfo.areanum2;
|
||||
if (csqc_world.worldmodel->funcs.SetAreaPortalState)
|
||||
csqc_world.worldmodel->funcs.SetAreaPortalState(csqc_world.worldmodel, portal, area1, area2, state);
|
||||
}
|
||||
|
||||
static void QCBUILTIN PF_cs_droptofloor (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||
|
|
|
@ -51,8 +51,6 @@ lightmapinfo_t **lightmap;
|
|||
int numlightmaps;
|
||||
extern const float rgb9e5tab[32];
|
||||
|
||||
extern mleaf_t *r_vischain; // linked list of visible leafs
|
||||
|
||||
extern cvar_t r_stains;
|
||||
extern cvar_t r_loadlits;
|
||||
extern cvar_t r_stainfadetime;
|
||||
|
@ -2151,7 +2149,7 @@ static qbyte *Surf_MaskVis(qbyte *src, qbyte *dest)
|
|||
if (cl.worldmodel->leafs[i].ma
|
||||
}
|
||||
*/
|
||||
qbyte *frustumvis;
|
||||
static qbyte *q1frustumvis;
|
||||
|
||||
#ifdef Q1BSPS
|
||||
/*
|
||||
|
@ -2193,7 +2191,7 @@ start:
|
|||
pleaf = (mleaf_t *)node;
|
||||
|
||||
c = (pleaf - cl.worldmodel->leafs)-1;
|
||||
frustumvis[c>>3] |= 1<<(c&7);
|
||||
q1frustumvis[c>>3] |= 1<<(c&7);
|
||||
|
||||
mark = pleaf->firstmarksurface;
|
||||
c = pleaf->nummarksurfaces;
|
||||
|
@ -2338,289 +2336,6 @@ static void Surf_OrthoRecursiveWorldNode (mnode_t *node, unsigned int clipflags)
|
|||
}
|
||||
#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)
|
||||
{
|
||||
batch_t *batch;
|
||||
|
@ -2695,8 +2410,7 @@ static void Surf_PopChains(batch_t **batches)
|
|||
//most of this is a direct copy from gl
|
||||
void Surf_SetupFrame(void)
|
||||
{
|
||||
mleaf_t *leaf;
|
||||
vec3_t temp, pvsorg;
|
||||
vec3_t pvsorg;
|
||||
int viewcontents;
|
||||
|
||||
if (!cl.worldmodel || cl.worldmodel->loadstate!=MLS_LOADED)
|
||||
|
@ -2720,91 +2434,34 @@ void Surf_SetupFrame(void)
|
|||
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;
|
||||
r_viewcluster2 = -1;
|
||||
}
|
||||
#if defined(Q2BSPS) || defined(Q3BSPS)
|
||||
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;
|
||||
|
||||
vec3_t temp;
|
||||
unsigned int cont2;
|
||||
int area2;
|
||||
cl.worldmodel->funcs.InfoForPoint (cl.worldmodel, pvsorg, &r_viewarea, &r_viewcluster, &viewcontents);
|
||||
// check above and below so crossing solid water doesn't draw wrong
|
||||
if (!leaf->contents)
|
||||
if (!viewcontents)
|
||||
{ // look down a bit
|
||||
vec3_t temp;
|
||||
|
||||
VectorCopy (pvsorg, temp);
|
||||
temp[2] -= 16;
|
||||
leaf = Mod_PointInLeaf (cl.worldmodel, temp);
|
||||
if ( !(leaf->contents & Q2CONTENTS_SOLID) &&
|
||||
(leaf->cluster != r_viewcluster2) )
|
||||
r_viewcluster2 = leaf->cluster;
|
||||
cl.worldmodel->funcs.InfoForPoint (cl.worldmodel, temp, &area2, &r_viewcluster2, &cont2);
|
||||
if (cont2 & FTECONTENTS_SOLID)
|
||||
r_viewcluster2 = r_viewcluster;
|
||||
}
|
||||
else
|
||||
{ // look up a bit
|
||||
vec3_t temp;
|
||||
|
||||
VectorCopy (pvsorg, temp);
|
||||
temp[2] += 16;
|
||||
leaf = Mod_PointInLeaf (cl.worldmodel, temp);
|
||||
if ( !(leaf->contents & Q2CONTENTS_SOLID) &&
|
||||
(leaf->cluster != r_viewcluster2) )
|
||||
r_viewcluster2 = leaf->cluster;
|
||||
cl.worldmodel->funcs.InfoForPoint (cl.worldmodel, temp, &area2, &r_viewcluster2, &cont2);
|
||||
if (cont2 & FTECONTENTS_SOLID)
|
||||
r_viewcluster2 = r_viewcluster;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
leaf = Mod_PointInLeaf (cl.worldmodel, pvsorg);
|
||||
r_viewcluster = (leaf - cl.worldmodel->leafs)-1;
|
||||
r_viewcluster = -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
|
||||
|
@ -3778,57 +3435,16 @@ void Surf_DrawWorld (void)
|
|||
|
||||
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;
|
||||
}
|
||||
#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
|
||||
else if (currentmodel->fromgame == fg_doom3)
|
||||
{
|
||||
entvis = surfvis = D3_CalcVis(currentmodel, r_origin);
|
||||
}
|
||||
#endif
|
||||
#ifdef MAP_DOOM
|
||||
else if (currentmodel->fromgame == fg_doom)
|
||||
|
@ -3838,37 +3454,28 @@ void Surf_DrawWorld (void)
|
|||
}
|
||||
#endif
|
||||
#ifdef Q1BSPS
|
||||
else if (1)
|
||||
else if (currentmodel->fromgame == fg_quake || currentmodel->fromgame == fg_halflife)
|
||||
{
|
||||
//extern cvar_t temp1;
|
||||
// if (0)//temp1.value)
|
||||
// entvis = surfvis = R_MarkLeafSurfaces_Q1();
|
||||
// else
|
||||
{
|
||||
pvsbuffer_t *vis = &surf_frustumvis[r_refdef.recurse];
|
||||
pvsbuffer_t *vis = &surf_frustumvis[r_refdef.recurse];
|
||||
|
||||
entvis = R_MarkLeaves_Q1 (false);
|
||||
if (!(r_novis.ival & 2))
|
||||
VectorCopy (r_origin, modelorg);
|
||||
entvis = R_MarkLeaves_Q1 (false);
|
||||
if (!(r_novis.ival & 2))
|
||||
VectorCopy (r_origin, modelorg);
|
||||
|
||||
if (vis->buffersize < currentmodel->pvsbytes)
|
||||
vis->buffer = BZ_Realloc(vis->buffer, vis->buffersize=currentmodel->pvsbytes);
|
||||
frustumvis = vis->buffer;
|
||||
memset(frustumvis, 0, currentmodel->pvsbytes);
|
||||
if (vis->buffersize < currentmodel->pvsbytes)
|
||||
vis->buffer = BZ_Realloc(vis->buffer, vis->buffersize=currentmodel->pvsbytes);
|
||||
q1frustumvis = vis->buffer;
|
||||
memset(q1frustumvis, 0, currentmodel->pvsbytes);
|
||||
|
||||
if (r_refdef.useperspective)
|
||||
Surf_RecursiveWorldNode (currentmodel->nodes, 0x1f);
|
||||
else
|
||||
Surf_OrthoRecursiveWorldNode (currentmodel->nodes, 0x1f);
|
||||
surfvis = frustumvis;
|
||||
}
|
||||
if (r_refdef.useperspective)
|
||||
Surf_RecursiveWorldNode (currentmodel->nodes, 0x1f);
|
||||
else
|
||||
Surf_OrthoRecursiveWorldNode (currentmodel->nodes, 0x1f);
|
||||
surfvis = q1frustumvis;
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
frustumvis = NULL;
|
||||
entvis = surfvis = NULL;
|
||||
}
|
||||
|
||||
RSpeedEnd(RSPEED_WORLDNODE);
|
||||
|
||||
|
|
|
@ -550,8 +550,6 @@ void *Mod_Extradata (struct model_s *mod); // handles caching
|
|||
void Mod_TouchModel (const char *name);
|
||||
void Mod_RebuildLightmaps (void);
|
||||
|
||||
struct mleaf_s *Mod_PointInLeaf (struct model_s *model, float *p);
|
||||
|
||||
void Mod_NowLoadExternal(struct model_s *loadmodel);
|
||||
void GLR_LoadSkys (void);
|
||||
void R_BloomRegister(void);
|
||||
|
|
|
@ -1900,11 +1900,11 @@ void R_ReloadRenderer_f (void)
|
|||
if (qrenderer == QR_NONE || qrenderer == QR_HEADLESS)
|
||||
return; //don't bother reloading the renderer if its not actually rendering anything anyway.
|
||||
|
||||
#if !defined(CLIENTONLY) && (defined(Q2BSPS) || defined(Q3BSPS))
|
||||
if (sv.state == ss_active && sv.world.worldmodel && sv.world.worldmodel->loadstate == MLS_LOADED)
|
||||
#if !defined(CLIENTONLY)
|
||||
if (sv.state == ss_active && sv.world.worldmodel && sv.world.worldmodel->loadstate == MLS_LOADED && sv.world.worldmodel->funcs.SaveAreaPortalBlob)
|
||||
{
|
||||
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)))
|
||||
memcpy(portalblob, t, portalsize);
|
||||
}
|
||||
|
@ -1917,11 +1917,11 @@ void R_ReloadRenderer_f (void)
|
|||
R_ApplyRenderer_Load(NULL);
|
||||
Cvar_ApplyCallbacks(CVAR_RENDERERCALLBACK);
|
||||
|
||||
#if !defined(CLIENTONLY) && (defined(Q2BSPS) || defined(Q3BSPS))
|
||||
#if !defined(CLIENTONLY)
|
||||
if (portalblob)
|
||||
{
|
||||
if (sv.world.worldmodel && sv.world.worldmodel->loadstate == MLS_LOADED)
|
||||
CM_ReadPortalState(sv.world.worldmodel, portalblob, portalsize);
|
||||
if (sv.world.worldmodel && sv.world.worldmodel->loadstate == MLS_LOADED && sv.world.worldmodel->funcs.LoadAreaPortalBlob)
|
||||
sv.world.worldmodel->funcs.LoadAreaPortalBlob(sv.world.worldmodel, portalblob, portalsize);
|
||||
BZ_Free(portalblob);
|
||||
}
|
||||
#endif
|
||||
|
@ -2166,11 +2166,11 @@ void R_RestartRenderer (rendererstate_t *newr)
|
|||
return;
|
||||
}
|
||||
|
||||
#if !defined(CLIENTONLY) && (defined(Q2BSPS) || defined(Q3BSPS))
|
||||
if (sv.state == ss_active && sv.world.worldmodel && sv.world.worldmodel->loadstate == MLS_LOADED)
|
||||
#ifdef HAVE_SERVER
|
||||
if (sv.state == ss_active && sv.world.worldmodel && sv.world.worldmodel->loadstate == MLS_LOADED && sv.world.worldmodel->funcs.SaveAreaPortalBlob)
|
||||
{
|
||||
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)))
|
||||
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 (sv.world.worldmodel && sv.world.worldmodel->loadstate == MLS_LOADED)
|
||||
CM_ReadPortalState(sv.world.worldmodel, portalblob, portalsize);
|
||||
if (sv.world.worldmodel && sv.world.worldmodel->loadstate == MLS_LOADED && sv.world.worldmodel->funcs.LoadAreaPortalBlob)
|
||||
sv.world.worldmodel->funcs.LoadAreaPortalBlob(sv.world.worldmodel, portalblob, portalsize);
|
||||
BZ_Free(portalblob);
|
||||
}
|
||||
#endif
|
||||
|
@ -2652,218 +2652,10 @@ unsigned int r_viewcontents;
|
|||
int r_viewarea;
|
||||
int r_viewcluster, r_viewcluster2, r_oldviewcluster, r_oldviewcluster2;
|
||||
int r_visframecount;
|
||||
mleaf_t *r_vischain; // linked list of visible leafs
|
||||
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
|
||||
#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)
|
||||
{
|
||||
static qbyte *cvis[R_MAX_RECURSE];
|
||||
|
|
|
@ -931,11 +931,9 @@ typedef struct
|
|||
#define MAX_ENT_LEAFS 32
|
||||
typedef struct pvscache_s
|
||||
{
|
||||
int num_leafs;
|
||||
int num_leafs; //negative generally means resort-to-headnode.
|
||||
unsigned int leafnums[MAX_ENT_LEAFS];
|
||||
#if defined(Q2BSPS) || defined(Q3BSPS) || defined(TERRAIN)
|
||||
int areanum; //q2bsp
|
||||
int areanum2; //q2bsp
|
||||
int headnode; //q2bsp
|
||||
#endif
|
||||
int areanum;
|
||||
int areanum2;
|
||||
int headnode;
|
||||
} 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);
|
||||
}
|
||||
|
||||
/*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)
|
||||
{
|
||||
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;
|
||||
}*/
|
||||
return model->phs + cluster*model->pvsbytes;
|
||||
}
|
||||
|
||||
//returns the leaf number, which is used as a bit index into the pvs.
|
||||
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)
|
||||
{
|
||||
Sys_Error ("Mod_PointInLeaf: bad model");
|
||||
Sys_Error ("Q1BSP_LeafnumForPoint: bad model");
|
||||
}
|
||||
if (!model->nodes)
|
||||
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)
|
||||
{
|
||||
if (!mod)
|
||||
Sys_Error ("Mod_PointInLeaf: bad model");
|
||||
Sys_Error ("Q1BSP_ClustersInSphere: bad model");
|
||||
if (!mod->nodes)
|
||||
return NULL;
|
||||
|
||||
|
@ -2137,7 +2112,7 @@ static int Q1BSP_ClusterForPoint (model_t *model, const vec3_t p, int *area)
|
|||
|
||||
if (!model)
|
||||
{
|
||||
Sys_Error ("Mod_PointInLeaf: bad model");
|
||||
Sys_Error ("Q1BSP_ClusterForPoint: bad model");
|
||||
}
|
||||
if (area)
|
||||
*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
|
||||
|
||||
|
@ -2178,7 +2184,7 @@ void Q1BSP_Init(void)
|
|||
//fills in bspfuncs_t
|
||||
void Q1BSP_SetModelFuncs(model_t *mod)
|
||||
{
|
||||
#ifndef CLIENTONLY
|
||||
#ifdef HAVE_SERVER
|
||||
mod->funcs.FatPVS = Q1BSP_FatPVS;
|
||||
#endif
|
||||
mod->funcs.EdictInFatPVS = Q1BSP_EdictInFatPVS;
|
||||
|
@ -2187,15 +2193,20 @@ void Q1BSP_SetModelFuncs(model_t *mod)
|
|||
mod->funcs.ClustersInSphere = Q1BSP_ClustersInSphere;
|
||||
mod->funcs.ClusterForPoint = Q1BSP_ClusterForPoint;
|
||||
mod->funcs.ClusterPVS = Q1BSP_ClusterPVS;
|
||||
// mod->funcs.ClusterPHS = Q1BSP_ClusterPHS;
|
||||
mod->funcs.ClusterPHS = Q1BSP_ClusterPHS;
|
||||
mod->funcs.NativeTrace = Q1BSP_Trace;
|
||||
mod->funcs.PointContents = Q1BSP_PointContents;
|
||||
|
||||
#ifndef SERVERONLY
|
||||
#ifdef HAVE_CLIENT
|
||||
mod->funcs.LightPointValues = GLQ1BSP_LightPointValues;
|
||||
mod->funcs.MarkLights = Q1BSP_MarkLights;
|
||||
mod->funcs.StainNode = Q1BSP_StainNode;
|
||||
#ifdef RTLIGHTS
|
||||
mod->funcs.GenerateShadowMesh = Q1BSP_GenerateShadowMesh;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
mod->funcs.InfoForPoint = Q1BSP_InfoForPoint;
|
||||
}
|
||||
#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)
|
||||
{ //we have some sort of trailing junk... is it a zip?...
|
||||
vfsfile_t *f = VFSPIPE_Open(1,true);
|
||||
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.
|
||||
}
|
||||
Mod_LoadMapArchive(mod, filebase+offs, filelen-offs);
|
||||
}
|
||||
|
||||
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);
|
||||
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
|
||||
#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*/
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
extern qbyte *frustumvis;
|
||||
model_t *m = e->model;
|
||||
heightmap_t *hm = m->terrain;
|
||||
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.vy = (r_refdef.vieworg[1] + CHUNKBIAS*hm->sectionsize) / hm->sectionsize;
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
|
@ -763,50 +781,6 @@ void *Mod_Extradata (model_t *mod)
|
|||
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)
|
||||
{
|
||||
if (*modname == '*' && worldname && *worldname)
|
||||
|
@ -866,9 +840,21 @@ model_t *Mod_FindName (const char *name)
|
|||
{
|
||||
#endif
|
||||
if (mod_numknown == MAX_MOD_KNOWN)
|
||||
{
|
||||
#ifdef LOADERTHREAD
|
||||
Sys_UnlockMutex(com_resourcemutex);
|
||||
#endif
|
||||
Sys_Error ("mod_numknown == MAX_MOD_KNOWN");
|
||||
return NULL;
|
||||
}
|
||||
if (strlen(name) >= sizeof(mod->publicname))
|
||||
{
|
||||
#ifdef LOADERTHREAD
|
||||
Sys_UnlockMutex(com_resourcemutex);
|
||||
#endif
|
||||
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
|
||||
Q_strncpyz (mod->publicname, name, sizeof(mod->publicname));
|
||||
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 *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)
|
||||
shadername = Mod_RemapBuggyTexture(shadername, tx->srcdata, tx->srcwidth*tx->srcheight);
|
||||
|
@ -2273,7 +2259,7 @@ static void Mod_SaveEntFile_f(void)
|
|||
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];
|
||||
size_t sz;
|
||||
|
@ -2282,15 +2268,15 @@ void Mod_LoadEntities (model_t *loadmodel, qbyte *mod_base, lump_t *l)
|
|||
char *ents = NULL, *k;
|
||||
int t;
|
||||
|
||||
Mod_SetEntitiesString(loadmodel, NULL, false);
|
||||
if (!l->filelen)
|
||||
return;
|
||||
Mod_SetEntitiesString(mod, NULL, false);
|
||||
if (!entdatasize)
|
||||
return false;
|
||||
|
||||
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));
|
||||
Q_strncatz(fname, ".ent", sizeof(fname));
|
||||
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)
|
||||
{
|
||||
COM_StripExtension(loadmodel->name, fname, sizeof(fname));
|
||||
COM_StripExtension(mod->name, fname, sizeof(fname));
|
||||
Q_strncatz(fname, ".ent", sizeof(fname));
|
||||
ents = FS_LoadMallocFile(fname, &sz);
|
||||
}
|
||||
if (mod_loadentfiles.value && !ents)
|
||||
{ //tenebrae compat
|
||||
COM_StripExtension(loadmodel->name, fname, sizeof(fname));
|
||||
COM_StripExtension(mod->name, fname, sizeof(fname));
|
||||
Q_strncatz(fname, ".edo", sizeof(fname));
|
||||
ents = FS_LoadMallocFile(fname, &sz);
|
||||
}
|
||||
if (!ents)
|
||||
{
|
||||
ents = Z_Malloc(l->filelen + 1);
|
||||
memcpy (ents, mod_base + l->fileofs, l->filelen);
|
||||
ents[l->filelen] = 0;
|
||||
ents = Z_Malloc(entdatasize + 1);
|
||||
memcpy (ents, entdata, entdatasize);
|
||||
ents[entdatasize] = 0;
|
||||
mod->entitiescrc = 0;
|
||||
}
|
||||
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)
|
||||
{
|
||||
|
@ -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))
|
||||
{
|
||||
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);
|
||||
strcpy(loadmodel->textures[t]->partname, value);
|
||||
mod->textures[t]->partname = ZG_Malloc(&mod->memgroup, strlen(value)+1);
|
||||
strcpy(mod->textures[t]->partname, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (t == loadmodel->numtextures)
|
||||
Con_Printf("\"%s\" is not valid for %s\n", keyname, loadmodel->name);
|
||||
if (t == mod->numtextures)
|
||||
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);
|
||||
//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 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);
|
||||
}
|
||||
#endif
|
||||
#if defined(Q3BSPS)
|
||||
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);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (BE_GenBrushModelVBO)
|
||||
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,
|
||||
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.
|
||||
|
||||
|
@ -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).
|
||||
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);
|
||||
|
||||
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;
|
||||
|
||||
|
||||
|
@ -352,7 +363,7 @@ void GL_DeselectVAO(void);
|
|||
|
||||
typedef struct texture_s
|
||||
{
|
||||
char name[64];
|
||||
char name[128];
|
||||
unsigned vwidth, vheight; //used for lightmap coord generation
|
||||
|
||||
struct shader_s *shader;
|
||||
|
@ -469,7 +480,7 @@ typedef struct msurface_s
|
|||
int shadowframe;
|
||||
#endif
|
||||
// int clipcount;
|
||||
|
||||
|
||||
// legacy lighting info
|
||||
dlightbitmask_t dlightbits;
|
||||
int dlightframe;
|
||||
|
@ -505,7 +516,7 @@ typedef struct mnode_s
|
|||
int contents; // 0, to differentiate from leafs
|
||||
int visframe; // node needs to be traversed if current
|
||||
int shadowframe;
|
||||
|
||||
|
||||
float minmaxs[6]; // for bounding box culling
|
||||
|
||||
struct mnode_s *parent;
|
||||
|
@ -587,6 +598,7 @@ void Q1BSP_CheckHullNodes(hull_t *hull);
|
|||
void Q1BSP_SetModelFuncs(struct model_s *mod);
|
||||
void Q1BSP_LoadBrushes(struct model_s *model, bspx_header_t *bspx, void *mod_base);
|
||||
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_FindLump(bspx_header_t *bspxheader, void *mod_base, char *lumpname, int *lumpsize);
|
||||
|
@ -667,7 +679,7 @@ typedef struct
|
|||
float interval;
|
||||
dtrivertx_t bboxmin;
|
||||
dtrivertx_t bboxmax;
|
||||
|
||||
|
||||
vec3_t scale;
|
||||
vec3_t scale_origin;
|
||||
|
||||
|
@ -693,7 +705,7 @@ typedef struct
|
|||
typedef struct mtriangle_s {
|
||||
int xyz_index[3];
|
||||
int st_index[3];
|
||||
|
||||
|
||||
int pad[2];
|
||||
} mtriangle_t;
|
||||
|
||||
|
@ -769,7 +781,7 @@ typedef struct
|
|||
short t;
|
||||
} md2stvert_t;
|
||||
|
||||
typedef struct
|
||||
typedef struct
|
||||
{
|
||||
short index_xyz[3];
|
||||
short index_st[3];
|
||||
|
@ -827,7 +839,7 @@ typedef struct
|
|||
int ofs_st; // qbyte offset from start for stverts
|
||||
int ofs_tris; // offset for dtriangles
|
||||
int ofs_frames; // offset for first frame
|
||||
int ofs_glcmds;
|
||||
int ofs_glcmds;
|
||||
int ofs_end; // end of file
|
||||
} md2_t;
|
||||
|
||||
|
@ -953,7 +965,7 @@ typedef struct model_s
|
|||
|
||||
int numframes;
|
||||
synctype_t synctype;
|
||||
|
||||
|
||||
int flags;
|
||||
int engineflags;
|
||||
int particleeffect;
|
||||
|
@ -962,14 +974,14 @@ typedef struct model_s
|
|||
|
||||
//
|
||||
// volume occupied by the model graphics
|
||||
//
|
||||
//
|
||||
vec3_t mins, maxs;
|
||||
float radius;
|
||||
float clampscale;
|
||||
float maxlod;
|
||||
|
||||
//
|
||||
// solid volume for clipping
|
||||
// solid volume for clipping
|
||||
//
|
||||
qboolean clipbox;
|
||||
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)
|
||||
|
||||
void CM_InitBoxHull (void);
|
||||
void CM_Init(void);
|
||||
struct model_s *CM_TempBoxModel(const vec3_t mins, const vec3_t maxs);
|
||||
#endif
|
||||
#if 0
|
||||
|
||||
#ifdef __cplusplus
|
||||
//#pragma warningmsg (" c++ stinks")
|
||||
#else
|
||||
|
||||
void CM_Init(void);
|
||||
|
||||
qboolean CM_SetAreaPortalState (struct model_s *mod, int portalnum, qboolean open);
|
||||
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);
|
||||
|
@ -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_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 model_s *CM_TempBoxModel(const vec3_t mins, const vec3_t maxs);
|
||||
|
||||
//for gamecode to control portals/areas
|
||||
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 PROJECTION_DISTANCE (float)(dl->radius*2)//0x7fffffff
|
||||
#define PROJECTION_DISTANCE (float)(sh_shmesh->radius*2)//0x7fffffff
|
||||
|
||||
#ifdef BEF_PUSHDEPTH
|
||||
extern qboolean r_pushdepth;
|
||||
|
@ -113,6 +113,8 @@ typedef struct {
|
|||
} shadowmeshbatch_t;
|
||||
typedef struct shadowmesh_s
|
||||
{
|
||||
vec3_t origin;
|
||||
float radius;
|
||||
enum
|
||||
{
|
||||
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->numindicies = 0;
|
||||
sh_shmesh->type = type;
|
||||
VectorCopy(dl->origin, sh_shmesh->origin);
|
||||
sh_shmesh->radius = dl->radius;
|
||||
|
||||
if (!cl.worldmodel->numshadowbatches)
|
||||
{
|
||||
|
@ -689,6 +693,7 @@ static struct {
|
|||
} *edge;
|
||||
static int firstedge;
|
||||
static int maxedge;
|
||||
static void (*genshadowmapcallback) (msurface_t *mesh);
|
||||
|
||||
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;
|
||||
mleaf_t *pleaf;
|
||||
double dot;
|
||||
int v;
|
||||
|
||||
float l, maxdist;
|
||||
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];
|
||||
// compare to minimum light
|
||||
if ((s*s+t*t+dot*dot) < maxdist)
|
||||
{
|
||||
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);
|
||||
}
|
||||
genshadowmapcallback(surf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -938,11 +888,8 @@ static void SHM_OrthoWorldLeafsQ1 (dlight_t *dl)
|
|||
if (dot < 0)
|
||||
{
|
||||
SHM_Shadow_Cache_Surface(surf);
|
||||
|
||||
}
|
||||
// else
|
||||
// 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);
|
||||
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)
|
||||
{
|
||||
int c, i;
|
||||
|
@ -1256,33 +1241,12 @@ static void SHM_MarkLeavesQ2(dlight_t *dl, unsigned char *lvis)
|
|||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void SHM_MarkLeavesQ1(dlight_t *dl, unsigned char *lvis)
|
||||
void Q2BSP_GenerateShadowMesh(model_t *model, dlight_t *dl, qbyte *lvis, int type)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
SHM_MarkLeavesQ2(dl, lvis);
|
||||
SHM_RecursiveWorldNodeQ2_r(dl, model->nodes);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef Q3BSPS
|
||||
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
|
||||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
case fg_quake:
|
||||
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)
|
||||
SHM_OrthoWorldLeafsQ3(dl);
|
||||
SHM_OrthoWorldLeafsQ1(dl);
|
||||
else
|
||||
{
|
||||
sh_shadowframe++;
|
||||
SHM_RecursiveWorldNodeQ3_r(dl, cl.worldmodel->nodes);
|
||||
SHM_MarkLeavesQ1(dl, lvis);
|
||||
SHM_RecursiveWorldNodeQ1_r(dl, cl.worldmodel->nodes);
|
||||
}
|
||||
if (type == SMT_STENCILVOLUME)
|
||||
SHM_ComposeVolume_BruteForce(dl);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
SHM_BeginShadowMesh(dl, type);
|
||||
sh_shadowframe++;
|
||||
|
||||
{
|
||||
|
|
|
@ -92,8 +92,8 @@ void R_SetSky(const char *sky)
|
|||
memset(&tex, 0, sizeof(tex));
|
||||
|
||||
tex.base = R_LoadHiResTexture(sky, "env:gfx/env", IF_LOADNOW|IF_NOMIPMAP);
|
||||
if (tex.reflectcube && tex.reflectcube->status == TEX_LOADING)
|
||||
COM_WorkerPartialSync(tex.reflectcube, &tex.reflectcube->status, TEX_LOADING);
|
||||
if (tex.base && tex.base->status == TEX_LOADING)
|
||||
COM_WorkerPartialSync(tex.base, &tex.base->status, TEX_LOADING);
|
||||
if (tex.base->width && TEXLOADED(tex.base))
|
||||
{
|
||||
forcedsky = R_RegisterShader(shadername, 0,
|
||||
|
|
|
@ -35,9 +35,12 @@ void ClearBounds (vec3_t mins, vec3_t maxs);
|
|||
struct builddata_s
|
||||
{
|
||||
void (*buildfunc)(model_t *mod, msurface_t *surf, struct builddata_s *bd);
|
||||
qboolean paintlightmaps;
|
||||
void *facedata;
|
||||
};
|
||||
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
|
||||
#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)
|
||||
{
|
||||
#ifdef Q2BSPS
|
||||
if (sv.world.worldmodel->fromgame == fg_quake2)
|
||||
int i;
|
||||
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;
|
||||
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)
|
||||
{
|
||||
if (client->state >= cs_connected)
|
||||
ClientReliableWrite_Begin(client, svc_setportalstate, 4);
|
||||
if (portal > 0xff || area1 > 0xff || area2 > 0xff)
|
||||
{
|
||||
ClientReliableWrite_Begin(client, svc_setportalstate, 4);
|
||||
if (portal >= 0x80)
|
||||
{ //new pathway, to be enabled at some point
|
||||
if (portal > 0xff)
|
||||
{
|
||||
ClientReliableWrite_Byte(client, 0x80 | 2 | state);
|
||||
ClientReliableWrite_Short(client, portal);
|
||||
}
|
||||
else
|
||||
{
|
||||
ClientReliableWrite_Byte(client, 0x80 | 0 | state);
|
||||
ClientReliableWrite_Byte(client, portal);
|
||||
}
|
||||
}
|
||||
else
|
||||
ClientReliableWrite_Short(client, portal | (state<<15));
|
||||
ClientReliableWrite_Byte(client, 0xe0 | 2 | state);
|
||||
ClientReliableWrite_Short(client, portal);
|
||||
ClientReliableWrite_Short(client, area1);
|
||||
ClientReliableWrite_Short(client, area2);
|
||||
}
|
||||
else
|
||||
{
|
||||
ClientReliableWrite_Byte(client, 0xe0 | 0 | state);
|
||||
ClientReliableWrite_Byte(client, portal);
|
||||
ClientReliableWrite_Byte(client, area1);
|
||||
ClientReliableWrite_Byte(client, area2);
|
||||
}
|
||||
}
|
||||
CMQ2_SetAreaPortalState(sv.world.worldmodel, portal, state);
|
||||
}
|
||||
#endif
|
||||
#ifdef Q3BSPS
|
||||
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
|
||||
if (sv.world.worldmodel->funcs.SetAreaPortalState)
|
||||
sv.world.worldmodel->funcs.SetAreaPortalState(sv.world.worldmodel, portal, area1, area2, state);
|
||||
}
|
||||
|
||||
//EXTENSION: KRIMZON_SV_PARSECLIENTCOMMAND
|
||||
|
|
|
@ -105,7 +105,7 @@ Q2SOLID_BSP // bsp clip, touch on edge
|
|||
struct link_s *prev, *next;
|
||||
} link_t;*/
|
||||
|
||||
#define MAX_ENT_CLUSTERS 16
|
||||
#define Q2MAX_ENT_CLUSTERS 16
|
||||
|
||||
|
||||
//typedef struct edict_s edict_t;
|
||||
|
@ -160,7 +160,7 @@ struct q2edict_s
|
|||
link_t area; // linked to a division node or leaf
|
||||
|
||||
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 areanum, areanum2;
|
||||
|
||||
|
|
|
@ -574,7 +574,7 @@ qboolean SV_LoadLevelCache(const char *savename, const char *level, const char *
|
|||
sv.strings.q2_extrasounds[i] = NULL;
|
||||
}
|
||||
//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);
|
||||
}
|
||||
|
||||
|
@ -1022,7 +1022,7 @@ void SV_SaveLevelCache(const char *savedir, qboolean dontharmgame)
|
|||
}
|
||||
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_CLOSE(f);
|
||||
|
|
|
@ -1055,6 +1055,10 @@ void SV_SpawnServer (const char *server, const char *startspot, qboolean noents,
|
|||
if (sv.world.worldmodel)
|
||||
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
|
||||
current_loading_size+=10;
|
||||
// SCR_BeginLoadingPlaque();
|
||||
|
@ -1158,7 +1162,7 @@ MSV_OpenUserDatabase();
|
|||
newgametype = GT_QUAKE3;
|
||||
#endif
|
||||
#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
|
||||
#endif
|
||||
#ifdef VM_LUA
|
||||
|
|
|
@ -522,7 +522,7 @@ void SV_MulticastProtExt(vec3_t origin, multicast_t to, int dimension_mask, int
|
|||
{
|
||||
client_t *client;
|
||||
qbyte *mask;
|
||||
int cluster;
|
||||
int cluster, area1, area2;
|
||||
int j;
|
||||
qboolean reliable;
|
||||
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;
|
||||
area1=-1;
|
||||
area2=-1;
|
||||
|
||||
switch (to)
|
||||
{
|
||||
|
@ -779,13 +585,13 @@ void SV_MulticastProtExt(vec3_t origin, multicast_t to, int dimension_mask, int
|
|||
case MULTICAST_PHS_R:
|
||||
reliable = true; // intentional fallthrough
|
||||
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;
|
||||
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)
|
||||
mask = sv.world.worldmodel->phs + cluster*sv.world.worldmodel->pvsbytes;
|
||||
mask = sv.world.worldmodel->funcs.ClusterPHS(sv.world.worldmodel, cluster, NULL);
|
||||
else
|
||||
mask = NULL;
|
||||
}
|
||||
|
@ -794,11 +600,16 @@ void SV_MulticastProtExt(vec3_t origin, multicast_t to, int dimension_mask, int
|
|||
case MULTICAST_PVS_R:
|
||||
reliable = true; // intentional fallthrough
|
||||
case MULTICAST_PVS:
|
||||
cluster = sv.world.worldmodel->funcs.ClusterForPoint(sv.world.worldmodel, origin, NULL);
|
||||
if (cluster >= 0)
|
||||
mask = sv.world.worldmodel->funcs.ClusterPVS(sv.world.worldmodel, cluster, NULL, PVM_FAST);
|
||||
else
|
||||
if (sv_nopvs.ival)
|
||||
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;
|
||||
|
||||
case MULTICAST_ONE_R_NOSPECS:
|
||||
|
@ -860,10 +671,21 @@ void SV_MulticastProtExt(vec3_t origin, multicast_t to, int dimension_mask, int
|
|||
continue;
|
||||
}
|
||||
}
|
||||
else if (svprogfuncs)
|
||||
else
|
||||
{
|
||||
if (!((int)split->edict->xv->dimension_see & dimension_mask))
|
||||
continue;
|
||||
vec3_t pos;
|
||||
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.
|
||||
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)
|
||||
{ //always in range if within 1024 units (consistent with quakeworld).
|
||||
vec3_t delta;
|
||||
VectorSubtract(origin, split->edict->v->origin, delta);
|
||||
VectorSubtract(origin, pos, delta);
|
||||
if (DotProduct(delta, delta) <= 1024*1024)
|
||||
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;
|
||||
VectorAdd(split->edict->v->origin, split->edict->v->view_ofs, pos);
|
||||
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;
|
||||
}
|
||||
// Con_Printf ("PVS supressed multicast\n");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -2301,6 +2301,14 @@ void SV_Begin_Core(client_t *split)
|
|||
split->edict->v->maxs[0] = 16;
|
||||
split->edict->v->maxs[1] = 16;
|
||||
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;
|
||||
}
|
||||
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++)
|
||||
{
|
||||
int clientcluster;
|
||||
int leafnum;
|
||||
|
||||
clent[seat] = split->q2edict;
|
||||
frame->clientnum[seat] = split - svs.clients;
|
||||
|
@ -743,16 +742,14 @@ void SVQ2_BuildClientFrame (client_t *client)
|
|||
for (i=0 ; i<3 ; 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]);
|
||||
clientarea[seat] = CM_LeafArea (sv.world.worldmodel, leafnum);
|
||||
clientcluster = CM_LeafCluster (sv.world.worldmodel, leafnum);
|
||||
clientcluster = sv.world.worldmodel->funcs.ClusterForPoint (sv.world.worldmodel, org[seat], &clientarea[seat]);
|
||||
|
||||
// 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);
|
||||
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;
|
||||
if (sv.paused)
|
||||
|
@ -790,11 +787,11 @@ void SVQ2_BuildClientFrame (client_t *client)
|
|||
if (ent != clent[seat])
|
||||
{
|
||||
// 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
|
||||
// we may need to check another one
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -812,7 +809,10 @@ void SVQ2_BuildClientFrame (client_t *client)
|
|||
|
||||
if (ent->num_clusters == -1)
|
||||
{ // 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;
|
||||
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)
|
||||
{
|
||||
int leafnum;
|
||||
int cluster;
|
||||
int area1, area2;
|
||||
qbyte *mask;
|
||||
|
||||
//FIXME: requires q2/q3 bsp
|
||||
leafnum = CM_PointLeafnum (sv.world.worldmodel, p1);
|
||||
cluster = CM_LeafCluster (sv.world.worldmodel, leafnum);
|
||||
area1 = CM_LeafArea (sv.world.worldmodel, leafnum);
|
||||
mask = CM_ClusterPVS (sv.world.worldmodel, cluster, NULL, PVM_FAST);
|
||||
cluster = sv.world.worldmodel->funcs.ClusterForPoint(sv.world.worldmodel, p1, &area1);
|
||||
mask = sv.world.worldmodel->funcs.ClusterPVS (sv.world.worldmodel, cluster, NULL, PVM_FAST);
|
||||
|
||||
leafnum = CM_PointLeafnum (sv.world.worldmodel, p2);
|
||||
cluster = CM_LeafCluster (sv.world.worldmodel, leafnum);
|
||||
area2 = CM_LeafArea (sv.world.worldmodel, leafnum);
|
||||
cluster = sv.world.worldmodel->funcs.ClusterForPoint(sv.world.worldmodel, p2, &area2);
|
||||
if ( mask && (!(mask[cluster>>3] & (1<<(cluster&7)) ) ) )
|
||||
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 true;
|
||||
}
|
||||
|
@ -506,23 +500,17 @@ Also checks portalareas so that doors block sound
|
|||
*/
|
||||
static qboolean VARGS PFQ2_inPHS (vec3_t p1, vec3_t p2)
|
||||
{
|
||||
int leafnum;
|
||||
int cluster;
|
||||
int area1, area2;
|
||||
qbyte *mask;
|
||||
|
||||
//FIXME: requires q2/q3 bsp
|
||||
leafnum = CM_PointLeafnum (sv.world.worldmodel, p1);
|
||||
cluster = CM_LeafCluster (sv.world.worldmodel, leafnum);
|
||||
area1 = CM_LeafArea (sv.world.worldmodel, leafnum);
|
||||
mask = CM_ClusterPHS (sv.world.worldmodel, cluster, NULL);
|
||||
cluster = sv.world.worldmodel->funcs.ClusterForPoint(sv.world.worldmodel, p1, &area1);
|
||||
mask = sv.world.worldmodel->funcs.ClusterPHS (sv.world.worldmodel, cluster, NULL);
|
||||
|
||||
leafnum = CM_PointLeafnum (sv.world.worldmodel, p2);
|
||||
cluster = CM_LeafCluster (sv.world.worldmodel, leafnum);
|
||||
area2 = CM_LeafArea (sv.world.worldmodel, leafnum);
|
||||
cluster = sv.world.worldmodel->funcs.ClusterForPoint(sv.world.worldmodel, p2, &area2);
|
||||
if ( mask && (!(mask[cluster>>3] & (1<<(cluster&7)) ) ) )
|
||||
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 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)
|
||||
{
|
||||
//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)
|
||||
{
|
||||
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)
|
||||
|
|
|
@ -5,10 +5,6 @@
|
|||
|
||||
#ifdef Q3SERVER
|
||||
|
||||
#ifndef MAX_ENT_CLUSTERS
|
||||
#define MAX_ENT_CLUSTERS 16
|
||||
#endif
|
||||
|
||||
#define USEBOTLIB
|
||||
|
||||
#ifdef USEBOTLIB
|
||||
|
@ -135,11 +131,8 @@ typedef struct {
|
|||
link_t area;
|
||||
#endif
|
||||
qboolean linked;
|
||||
int areanum;
|
||||
int areanum2;
|
||||
int headnode;
|
||||
int num_clusters;
|
||||
int clusternums[MAX_ENT_CLUSTERS];
|
||||
|
||||
pvscache_t pvscache;
|
||||
} q3serverEntity_t;
|
||||
q3serverEntity_t *q3_sentities;
|
||||
|
||||
|
@ -211,12 +204,7 @@ static void Q3G_LinkEntity(q3sharedEntity_t *ent)
|
|||
areanode_t *node;
|
||||
#endif
|
||||
q3serverEntity_t *sent;
|
||||
int leafs[MAX_TOTAL_ENT_LEAFS];
|
||||
int clusters[MAX_TOTAL_ENT_LEAFS];
|
||||
int num_leafs;
|
||||
int i, j, k;
|
||||
int area;
|
||||
int topnode;
|
||||
const float *origin;
|
||||
const float *angles;
|
||||
|
||||
|
@ -291,83 +279,8 @@ static void Q3G_LinkEntity(q3sharedEntity_t *ent)
|
|||
ent->r.absmax[2] += 1;
|
||||
|
||||
// link to PVS leafs
|
||||
sent->num_clusters = 0;
|
||||
sent->areanum = -1;
|
||||
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];
|
||||
}
|
||||
}
|
||||
}
|
||||
sv.world.worldmodel->funcs.FindTouchedLeafs(sv.world.worldmodel, &sent->pvscache, ent->r.absmin, ent->r.absmax);
|
||||
//FIXME: return if no leafs
|
||||
|
||||
ent->r.linkcount++;
|
||||
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)
|
||||
{
|
||||
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;
|
||||
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)
|
||||
|
@ -871,37 +784,18 @@ static qboolean SV_InPVS(vec3_t p1, vec3_t p2)
|
|||
return true; //no pvs info, assume everything is visible
|
||||
else
|
||||
{
|
||||
#if 1
|
||||
int l1 = CM_PointLeafnum(worldmodel, p1);
|
||||
int l2 = CM_PointLeafnum(worldmodel, p2);
|
||||
int c1 = CM_LeafCluster(worldmodel, l1);
|
||||
int c2 = CM_LeafCluster(worldmodel, l2);
|
||||
int a1, c1 = worldmodel->funcs.ClusterForPoint(worldmodel, p1, &a1);
|
||||
int a2, c2 = worldmodel->funcs.ClusterForPoint(worldmodel, p2, &a2);
|
||||
qbyte *pvs;
|
||||
if (c1 < 0 || c2 < 0)
|
||||
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)))
|
||||
{
|
||||
int a1 = CM_LeafArea(worldmodel, l1);
|
||||
int a2 = CM_LeafArea(worldmodel, l2);
|
||||
if (CM_AreasConnected(worldmodel, a1, a2))
|
||||
if (worldmodel->funcs.AreasConnected(worldmodel, a1, a2))
|
||||
return true;
|
||||
}
|
||||
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);
|
||||
VM_Call(q3gamevm, GAME_INIT, (intptr_t)(sv.time*1000), (int)rand(), restart);
|
||||
|
||||
CM_InitBoxHull();
|
||||
|
||||
if (!restart)
|
||||
{
|
||||
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)
|
||||
{
|
||||
q3serverEntity_t *sent;
|
||||
int i;
|
||||
int l;
|
||||
|
||||
if (!ent->r.linked)
|
||||
{
|
||||
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 );
|
||||
|
||||
// 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
|
||||
// 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
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// 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;
|
||||
return sv.world.worldmodel->funcs.EdictInFatPVS(sv.world.worldmodel, &sent->pvscache, bitvector, NULL/*using the snapshots areabits rather than the bsp's*/);
|
||||
}
|
||||
|
||||
#ifdef Q3OVERQW
|
||||
|
@ -2530,9 +2380,7 @@ void SVQ3_BuildClientSnapshot( client_t *client )
|
|||
VectorCopy( ps->origin, org );
|
||||
org[2] += ps->viewheight;
|
||||
|
||||
clientarea = CM_PointLeafnum(sv.world.worldmodel, org);
|
||||
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);
|
||||
bitvector = sv.world.worldmodel->funcs.ClusterPVS(sv.world.worldmodel, sv.world.worldmodel->funcs.ClusterForPoint(sv.world.worldmodel, org, &clientarea), &pvsbuffer, PVM_REPLACE);
|
||||
/*
|
||||
if (client->areanum != clientarea)
|
||||
{
|
||||
|
@ -2542,7 +2390,7 @@ void SVQ3_BuildClientSnapshot( client_t *client )
|
|||
*/
|
||||
|
||||
// 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
|
||||
memcpy(&snap->ps, ps, sizeof(snap->ps));
|
||||
|
@ -2565,13 +2413,10 @@ void SVQ3_BuildClientSnapshot( client_t *client )
|
|||
if(!SVQ3_EntityIsVisible(snap, ent))
|
||||
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
|
||||
sv.world.worldmodel->funcs.ClusterPVS(sv.world.worldmodel, CM_LeafCluster(sv.world.worldmodel, portalarea), &pvsbuffer, PVM_MERGE);
|
||||
//and merge areas, so we can see the world too (client will calc its own pvs)
|
||||
portalarea = CM_LeafArea(sv.world.worldmodel, portalarea);
|
||||
CM_WriteAreaBits(sv.world.worldmodel, snap->areabits, portalarea, true);
|
||||
sv.world.worldmodel->funcs.ClusterPVS(sv.world.worldmodel, sv.world.worldmodel->funcs.ClusterForPoint(sv.world.worldmodel, ent->s.origin2, &portalarea), &pvsbuffer, PVM_MERGE);
|
||||
//and areabits too
|
||||
sv.world.worldmodel->funcs.WriteAreaBits(sv.world.worldmodel, snap->areabits, snap->areabytes, portalarea, true);
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
areanode_t *node;
|
||||
int leafs[128];
|
||||
int clusters[countof(leafs)];
|
||||
int num_leafs;
|
||||
int i, j;
|
||||
int area;
|
||||
int topnode;
|
||||
|
||||
if (ent->area.prev)
|
||||
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;
|
||||
|
||||
// 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]);
|
||||
area = CM_LeafArea (w->worldmodel, 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;
|
||||
}
|
||||
}
|
||||
pvscache_t cache;
|
||||
w->worldmodel->funcs.FindTouchedLeafs(w->worldmodel, &cache, ent->absmin, ent->absmax);
|
||||
|
||||
if (num_leafs >= countof(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];
|
||||
}
|
||||
}
|
||||
//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).
|
||||
ent->num_clusters = cache.num_leafs;
|
||||
if (ent->num_clusters > (int)countof(ent->clusternums))
|
||||
ent->num_clusters = (int)countof(ent->clusternums);
|
||||
memcpy(ent->clusternums, cache.leafnums, min(sizeof(ent->clusternums), sizeof(cache.leafnums)));
|
||||
ent->headnode = cache.headnode;
|
||||
ent->areanum = cache.areanum;
|
||||
ent->areanum2 = cache.areanum2;
|
||||
}
|
||||
|
||||
// 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
|
||||
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
|
||||
|
||||
|
||||
|
||||
|
||||
#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);
|
||||
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);
|
||||
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)
|
||||
{
|
||||
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
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
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;
|
||||
|
||||
//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;
|
||||
|
||||
framestate.g[FS_REG].frame[0] = touch->frame;
|
||||
|
|
Loading…
Reference in a new issue