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:
Spoike 2021-11-03 20:30:40 +00:00
parent 23196df675
commit 2b81527a69
28 changed files with 1180 additions and 1959 deletions

View File

@ -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!

View File

@ -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)

View File

@ -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;

View File

@ -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);

View File

@ -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)

View File

@ -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);

View File

@ -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);

View File

@ -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];

View File

@ -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

View File

@ -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;

View File

@ -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*/

View File

@ -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]);

View File

@ -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);

View File

@ -8,7 +8,7 @@ of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
@ -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);

View File

@ -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++;
{

View File

@ -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,

View File

@ -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*/

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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.

View File

@ -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++;
}

View File

@ -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)

View File

@ -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

View File

@ -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;