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_FROMSHANDLE(a) ((a&&(unsigned int)a<=r_numshaders)?r_shaders[a-1]:NULL)
#define VM_TOSHANDLE(a) (a?a->id+1:0) #define VM_TOSHANDLE(a) (a?a->id+1:0)
extern model_t box_model; static model_t *box_model;
typedef enum { typedef enum {
CG_PRINT, CG_PRINT,
@ -696,7 +696,7 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con
// if (modhandle == MAX_PRECACHE_MODELS+1) // if (modhandle == MAX_PRECACHE_MODELS+1)
// mod = &capsule_model; // mod = &capsule_model;
// else // else
mod = &box_model; mod = box_model;
} }
else else
mod = cl.model_precache[modhandle+1]; mod = cl.model_precache[modhandle+1];
@ -721,7 +721,7 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con
// if (modhandle == MAX_PRECACHE_MODELS+1) // if (modhandle == MAX_PRECACHE_MODELS+1)
// mod = &capsule_model; // mod = &capsule_model;
// else // else
mod = &box_model; mod = box_model;
} }
else else
mod = cl.model_precache[modhandle+1]; mod = cl.model_precache[modhandle+1];
@ -773,7 +773,7 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con
// if (modhandle == MAX_PRECACHE_MODELS+1) // if (modhandle == MAX_PRECACHE_MODELS+1)
// mod = &capsule_model; // mod = &capsule_model;
// else // else
mod = &box_model; mod = box_model;
} }
else else
mod = cl.model_precache[modhandle+1]; mod = cl.model_precache[modhandle+1];
@ -836,7 +836,7 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con
// if (modhandle == MAX_PRECACHE_MODELS+1) // if (modhandle == MAX_PRECACHE_MODELS+1)
// mod = &capsule_model; // mod = &capsule_model;
// else // else
mod = &box_model; mod = box_model;
} }
else else
mod = cl.model_precache[modhandle+1]; mod = cl.model_precache[modhandle+1];
@ -848,7 +848,7 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con
if (mod->loadstate == MLS_LOADING) if (mod->loadstate == MLS_LOADING)
COM_WorkerPartialSync(mod, &mod->loadstate, MLS_LOADING); COM_WorkerPartialSync(mod, &mod->loadstate, MLS_LOADING);
if (mod->loadstate != MLS_LOADED) if (mod->loadstate != MLS_LOADED)
mod = &box_model; //stop crashes, even if this is wrong. mod = box_model; //stop crashes, even if this is wrong.
} }
if (!mins) if (!mins)
@ -901,11 +901,11 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con
break; break;
case CG_CM_TEMPBOXMODEL: case CG_CM_TEMPBOXMODEL:
CM_TempBoxModel(VM_POINTER(arg[0]), VM_POINTER(arg[1])); box_model = CM_TempBoxModel(VM_POINTER(arg[0]), VM_POINTER(arg[1]));
VM_LONG(ret) = MAX_PRECACHE_MODELS; VM_LONG(ret) = MAX_PRECACHE_MODELS;
break; break;
case CG_CM_TEMPCAPSULEMODEL: case CG_CM_TEMPCAPSULEMODEL:
CM_TempBoxModel(VM_POINTER(arg[0]), VM_POINTER(arg[1])); box_model = CM_TempBoxModel(VM_POINTER(arg[0]), VM_POINTER(arg[1]));
VM_LONG(ret) = MAX_PRECACHE_MODELS+1; VM_LONG(ret) = MAX_PRECACHE_MODELS+1;
break; break;
@ -1359,6 +1359,8 @@ void CG_Start (void)
Z_FreeTags(CGTAGNUM); Z_FreeTags(CGTAGNUM);
SCR_BeginLoadingPlaque(); SCR_BeginLoadingPlaque();
box_model = CM_TempBoxModel(vec3_origin, vec3_origin);
cgvm = VM_Create("cgame", com_nogamedirnativecode.ival?NULL:CG_SystemCallsNative, "vm/cgame", CG_SystemCallsVM); cgvm = VM_Create("cgame", com_nogamedirnativecode.ival?NULL:CG_SystemCallsNative, "vm/cgame", CG_SystemCallsVM);
if (cgvm) if (cgvm)
{ //hu... cgame doesn't appear to have a query version call! { //hu... cgame doesn't appear to have a query version call!

View File

@ -6902,57 +6902,56 @@ void CL_DumpPacket(void)
static void CL_ParsePortalState(void) static void CL_ParsePortalState(void)
{ {
int mode = MSG_ReadByte(); int mode = MSG_ReadByte();
int a1, a2; int p = -1, a1 = -1, a2 = -1, state = -1;
#define PS_NEW (1<<7)
#define PS_AREANUMS (1<<6) //q3 style
#define PS_PORTALNUM (1<<5) //q2 style
#define PS_LARGE (1<<1)
#define PS_OPEN (1<<0)
switch(mode&0xc0) if (mode & PS_NEW)
{ {
case 0x80: state = mode&1;
if (mode&2) if (!(mode & PS_AREANUMS) && !(mode & PS_PORTALNUM))
a1 = MSG_ReadShort(); mode |= PS_PORTALNUM; //legacy crap
else
a1 = MSG_ReadByte();
if (cl.worldmodel && cl.worldmodel->loadstate==MLS_LOADED && cl.worldmodel->fromgame == fg_quake2)
{
#ifdef Q2BSPS
CMQ2_SetAreaPortalState(cl.worldmodel, a1, !!(mode&1));
#else
(void)a1;
#endif
}
break;
case 0xc0:
if (mode&2)
{
a1 = MSG_ReadShort();
a2 = MSG_ReadShort();
}
else
{
a1 = MSG_ReadByte();
a2 = MSG_ReadByte();
}
if (cl.worldmodel && cl.worldmodel->loadstate==MLS_LOADED && cl.worldmodel->fromgame == fg_quake3)
{
#ifdef Q3BSPS
CMQ3_SetAreaPortalState(cl.worldmodel, a1, a2, !!(mode&1));
#else
(void)a1;
(void)a2;
#endif
}
break;
default: if (mode & PS_PORTALNUM)
//to be phased out. { //q2 style
mode |= MSG_ReadByte()<<8; if (mode&PS_LARGE)
if (cl.worldmodel && cl.worldmodel->loadstate==MLS_LOADED && cl.worldmodel->fromgame == fg_quake2) p = MSG_ReadShort();
{ else
#ifdef Q2BSPS p = MSG_ReadByte();
CMQ2_SetAreaPortalState(cl.worldmodel, mode & 0x7fff, !!(mode&0x8000)); }
#endif if (mode & PS_AREANUMS)
{ //q3 style
if (mode&PS_LARGE)
{
a1 = MSG_ReadShort();
a2 = MSG_ReadShort();
}
else
{
a1 = MSG_ReadByte();
a2 = MSG_ReadByte();
}
} }
break;
} }
else
{ //legacy crap
Con_Printf(CON_WARNING"svc_setportalstate: legacy mode\n");
mode |= MSG_ReadByte()<<8;
p = (mode & 0x7fff);
state = !!(mode & 0x8000);
}
#ifdef HAVE_SERVER
//reduce race conditions when we're both client+server.
if (sv.active)
return;
#endif
if (cl.worldmodel && cl.worldmodel->loadstate==MLS_LOADED && cl.worldmodel->funcs.SetAreaPortalState)
cl.worldmodel->funcs.SetAreaPortalState(cl.worldmodel, p, a1, a2, state);
} }
static void CL_ParseBaseAngle(int seat) static void CL_ParseBaseAngle(int seat)

View File

@ -198,8 +198,9 @@ int VARGS CLQ2_PMpointcontents (vec3_t point)
int num; int num;
model_t *cmodel; model_t *cmodel;
int contents; int contents;
vec3_t axis[3], relpos;
contents = CM_PointContents (cl.worldmodel, point); contents = cl.worldmodel->funcs.PointContents(cl.worldmodel, NULL, point);
for (i=0 ; i<cl.q2frame.num_entities ; i++) for (i=0 ; i<cl.q2frame.num_entities ; i++)
{ {
@ -213,7 +214,10 @@ int VARGS CLQ2_PMpointcontents (vec3_t point)
if (!cmodel) if (!cmodel)
continue; continue;
contents |= CM_TransformedPointContents (cl.worldmodel, point, cmodel->hulls[0].firstclipnode, ent->origin, ent->angles); AngleVectors (ent->angles, axis[0], axis[1], axis[2]);
VectorNegate(axis[1], axis[1]);
VectorSubtract(point, ent->origin, relpos);
contents |= cmodel->funcs.PointContents(cmodel, axis, relpos);
} }
return contents; return contents;

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); const char *Mod_GetEntitiesString(struct model_s *mod);
void Mod_SetEntitiesStringLen(struct model_s *mod, const char *str, size_t strsize); void Mod_SetEntitiesStringLen(struct model_s *mod, const char *str, size_t strsize);
void Mod_SetEntitiesString(struct model_s *mod, const char *str, qboolean docopy); void Mod_SetEntitiesString(struct model_s *mod, const char *str, qboolean docopy);
qboolean Mod_LoadEntitiesBlob(struct model_s *mod, const char *entdata, size_t entdatasize); //initial read, with .ent file replacement etc
void Mod_ParseEntities(struct model_s *mod); void Mod_ParseEntities(struct model_s *mod);
void Mod_LoadMapArchive(struct model_s *mod, void *archivedata, size_t archivesize);
extern void Mod_ClearAll (void); extern void Mod_ClearAll (void);
extern void Mod_Purge (enum mod_purge_e type); extern void Mod_Purge (enum mod_purge_e type);
extern qboolean Mod_PurgeModel (struct model_s *mod, enum mod_purge_e ptype); extern qboolean Mod_PurgeModel (struct model_s *mod, enum mod_purge_e ptype);

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) static void QCBUILTIN PF_cs_OpenPortal (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{ {
/* int state = G_FLOAT(OFS_PARM1)!=0;
#ifdef Q2BSPS wedict_t *ent = G_WEDICT(prinst, OFS_PARM0);
if (csqc_world.worldmodel->fromgame == fg_quake2) int portal = ent->xv->style;
{ int area1 = ent->pvsinfo.areanum, area2 = ent->pvsinfo.areanum2;
int portal; if (csqc_world.worldmodel->funcs.SetAreaPortalState)
int state = G_FLOAT(OFS_PARM1)!=0; csqc_world.worldmodel->funcs.SetAreaPortalState(csqc_world.worldmodel, portal, area1, area2, state);
if (G_INT(OFS_PARM1) >= MAX_EDICTS)
portal = G_FLOAT(OFS_PARM0); //old legacy crap.
else
portal = G_WEDICT(prinst, OFS_PARM0)->xv->style; //read the func_areaportal's style field.
CMQ2_SetAreaPortalState(csqc_world.worldmodel, portal, state);
}
#endif
*/
#ifdef Q3BSPS
if (csqc_world.worldmodel->fromgame == fg_quake3)
{
int state = G_FLOAT(OFS_PARM1)!=0;
wedict_t *portal = G_WEDICT(prinst, OFS_PARM0);
int area1 = portal->pvsinfo.areanum, area2 = portal->pvsinfo.areanum2;
if (area1 == area2 || area1<0 || area2<0)
return;
CMQ3_SetAreaPortalState(csqc_world.worldmodel, portal->pvsinfo.areanum, portal->pvsinfo.areanum2, state);
}
#endif
} }
static void QCBUILTIN PF_cs_droptofloor (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) static void QCBUILTIN PF_cs_droptofloor (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)

View File

@ -51,8 +51,6 @@ lightmapinfo_t **lightmap;
int numlightmaps; int numlightmaps;
extern const float rgb9e5tab[32]; extern const float rgb9e5tab[32];
extern mleaf_t *r_vischain; // linked list of visible leafs
extern cvar_t r_stains; extern cvar_t r_stains;
extern cvar_t r_loadlits; extern cvar_t r_loadlits;
extern cvar_t r_stainfadetime; extern cvar_t r_stainfadetime;
@ -2151,7 +2149,7 @@ static qbyte *Surf_MaskVis(qbyte *src, qbyte *dest)
if (cl.worldmodel->leafs[i].ma if (cl.worldmodel->leafs[i].ma
} }
*/ */
qbyte *frustumvis; static qbyte *q1frustumvis;
#ifdef Q1BSPS #ifdef Q1BSPS
/* /*
@ -2193,7 +2191,7 @@ start:
pleaf = (mleaf_t *)node; pleaf = (mleaf_t *)node;
c = (pleaf - cl.worldmodel->leafs)-1; c = (pleaf - cl.worldmodel->leafs)-1;
frustumvis[c>>3] |= 1<<(c&7); q1frustumvis[c>>3] |= 1<<(c&7);
mark = pleaf->firstmarksurface; mark = pleaf->firstmarksurface;
c = pleaf->nummarksurfaces; c = pleaf->nummarksurfaces;
@ -2338,289 +2336,6 @@ static void Surf_OrthoRecursiveWorldNode (mnode_t *node, unsigned int clipflags)
} }
#endif #endif
#ifdef Q2BSPS
static void Surf_RecursiveQ2WorldNode (mnode_t *node)
{
int c, side;
mplane_t *plane;
msurface_t *surf, **mark;
mleaf_t *pleaf;
double dot;
int sidebit;
if (node->contents == Q2CONTENTS_SOLID)
return; // solid
if (node->visframe != r_visframecount)
return;
if (R_CullBox (node->minmaxs, node->minmaxs+3))
return;
// if a leaf node, draw stuff
if (node->contents != -1)
{
pleaf = (mleaf_t *)node;
// check for door connected areas
if (! (r_refdef.areabits[pleaf->area>>3] & (1<<(pleaf->area&7)) ) )
return; // not visible
c = pleaf->cluster;
if (c >= 0)
frustumvis[c>>3] |= 1<<(c&7);
mark = pleaf->firstmarksurface;
c = pleaf->nummarksurfaces;
if (c)
{
do
{
(*mark)->visframe = r_framecount;
mark++;
} while (--c);
}
return;
}
// node is just a decision point, so go down the apropriate sides
// find which side of the node we are on
plane = node->plane;
switch (plane->type)
{
case PLANE_X:
dot = modelorg[0] - plane->dist;
break;
case PLANE_Y:
dot = modelorg[1] - plane->dist;
break;
case PLANE_Z:
dot = modelorg[2] - plane->dist;
break;
default:
dot = DotProduct (modelorg, plane->normal) - plane->dist;
break;
}
if (dot >= 0)
{
side = 0;
sidebit = 0;
}
else
{
side = 1;
sidebit = SURF_PLANEBACK;
}
// recurse down the children, front side first
Surf_RecursiveQ2WorldNode (node->children[side]);
// draw stuff
for ( c = node->numsurfaces, surf = currentmodel->surfaces + node->firstsurface; c ; c--, surf++)
{
if (surf->visframe != r_framecount)
continue;
if ( (surf->flags & SURF_PLANEBACK) != sidebit )
continue; // wrong side
surf->visframe = 0;//r_framecount+1;//-1;
Surf_RenderDynamicLightmaps (surf);
surf->sbatch->mesh[surf->sbatch->meshes++] = surf->mesh;
}
// recurse down the back side
Surf_RecursiveQ2WorldNode (node->children[!side]);
}
#endif
#ifdef Q3BSPS
#if 0
static void Surf_LeafWorldNode (void)
{
int i;
int clipflags;
msurface_t **mark, *surf;
mleaf_t *pleaf;
int clipped;
mplane_t *clipplane;
for (pleaf = r_vischain; pleaf; pleaf = pleaf->vischain)
{
// check for door connected areas
// if (areabits)
{
// if (!(areabits[pleaf->area>>3] & (1<<(pleaf->area&7))))
// {
// continue; // not visible
// }
}
clipflags = 15; // 1 | 2 | 4 | 8
// if (!r_nocull->value)
{
for (i=0,clipplane=frustum ; i<FRUSTUMPLANES ; i++,clipplane++)
{
clipped = BoxOnPlaneSide (pleaf->minmaxs, pleaf->minmaxs+3, clipplane);
if (clipped == 2)
{
break;
}
else if (clipped == 1)
{
clipflags &= ~(1<<i); // node is entirely on screen
}
}
if (i != FRUSTUMPLANES)
{
continue;
}
}
i = pleaf->nummarksurfaces;
mark = pleaf->firstmarksurface;
do
{
surf = *mark++;
if (surf->visframe != r_framecount) //sufraces exist in multiple leafs.
{
surf->visframe = r_framecount;
if (surf->mark)
*surf->mark = surf;
}
} while (--i);
// c_world_leafs++;
}
{
int j;
texture_t *tex;
for (i = 0; i < cl.worldmodel->numtextures; i++)
{
tex = cl.worldmodel->textures[i];
if (!tex)
continue;
for (j = 0; j < tex->vbo.meshcount; j++)
{
surf = tex->vbo.meshlist[j];
if (surf)
{
tex->vbo.meshlist[j] = NULL;
surf->sbatch->mesh[surf->sbatch->meshes++] = surf->mesh;
}
}
}
}
}
#endif
static void Surf_RecursiveQ3WorldNode (mnode_t *node, unsigned int clipflags)
{
int c, side, clipped;
mplane_t *plane, *clipplane;
msurface_t *surf, **mark;
mleaf_t *pleaf;
double dot;
start:
if (node->visframe != r_visframecount)
return;
for (c = 0, clipplane = r_refdef.frustum; c < r_refdef.frustum_numworldplanes; c++, clipplane++)
{
if (!(clipflags & (1 << c)))
continue; // don't need to clip against it
clipped = BOX_ON_PLANE_SIDE (node->minmaxs, node->minmaxs + 3, clipplane);
if (clipped == 2)
return;
else if (clipped == 1)
clipflags -= (1<<c); // node is entirely on screen
}
// if a leaf node, draw stuff
if (node->contents != -1)
{
pleaf = (mleaf_t *)node;
if (! (r_refdef.areabits[pleaf->area>>3] & (1<<(pleaf->area&7)) ) )
return; // not visible
c = pleaf->cluster;
if (c >= 0)
frustumvis[c>>3] |= 1<<(c&7);
mark = pleaf->firstmarksurface;
for (c = pleaf->nummarksurfaces; c; c--)
{
surf = *mark++;
if (surf->visframe == r_framecount)
continue;
surf->visframe = r_framecount;
// if (((dot < 0) ^ !!(surf->flags & SURF_PLANEBACK)))
// continue; // wrong side
surf->sbatch->mesh[surf->sbatch->meshes++] = surf->mesh;
}
return;
}
// node is just a decision point, so go down the apropriate sides
// find which side of the node we are on
plane = node->plane;
switch (plane->type)
{
case PLANE_X:
dot = modelorg[0] - plane->dist;
break;
case PLANE_Y:
dot = modelorg[1] - plane->dist;
break;
case PLANE_Z:
dot = modelorg[2] - plane->dist;
break;
default:
dot = DotProduct (modelorg, plane->normal) - plane->dist;
break;
}
if (dot >= 0)
side = 0;
else
side = 1;
// recurse down the children, front side first
Surf_RecursiveQ3WorldNode (node->children[side], clipflags);
// q3 nodes contain no drawables
// recurse down the back side
//GLR_RecursiveWorldNode (node->children[!side], clipflags);
node = node->children[!side];
goto start;
}
#endif
static void Surf_PushChains(batch_t **batches) static void Surf_PushChains(batch_t **batches)
{ {
batch_t *batch; batch_t *batch;
@ -2695,8 +2410,7 @@ static void Surf_PopChains(batch_t **batches)
//most of this is a direct copy from gl //most of this is a direct copy from gl
void Surf_SetupFrame(void) void Surf_SetupFrame(void)
{ {
mleaf_t *leaf; vec3_t pvsorg;
vec3_t temp, pvsorg;
int viewcontents; int viewcontents;
if (!cl.worldmodel || cl.worldmodel->loadstate!=MLS_LOADED) if (!cl.worldmodel || cl.worldmodel->loadstate!=MLS_LOADED)
@ -2720,91 +2434,34 @@ void Surf_SetupFrame(void)
if (r_refdef.flags & RDF_NOWORLDMODEL) if (r_refdef.flags & RDF_NOWORLDMODEL)
{ {
} }
else if (!cl.worldmodel || cl.worldmodel->loadstate != MLS_LOADED || cl.worldmodel->fromgame == fg_doom3 ) else if (cl.worldmodel && cl.worldmodel->loadstate == MLS_LOADED && cl.worldmodel->funcs.InfoForPoint)
{ {
r_viewcluster = -1; vec3_t temp;
r_viewcluster2 = -1; unsigned int cont2;
} int area2;
#if defined(Q2BSPS) || defined(Q3BSPS) cl.worldmodel->funcs.InfoForPoint (cl.worldmodel, pvsorg, &r_viewarea, &r_viewcluster, &viewcontents);
else if (cl.worldmodel->fromgame == fg_quake2 || cl.worldmodel->fromgame == fg_quake3)
{
leaf = Mod_PointInLeaf (cl.worldmodel, pvsorg);
r_viewarea = leaf->area;
viewcontents = cl.worldmodel->funcs.PointContents(cl.worldmodel, NULL, pvsorg);
r_viewcluster = r_viewcluster2 = leaf->cluster;
// check above and below so crossing solid water doesn't draw wrong // check above and below so crossing solid water doesn't draw wrong
if (!leaf->contents) if (!viewcontents)
{ // look down a bit { // look down a bit
vec3_t temp;
VectorCopy (pvsorg, temp); VectorCopy (pvsorg, temp);
temp[2] -= 16; temp[2] -= 16;
leaf = Mod_PointInLeaf (cl.worldmodel, temp); cl.worldmodel->funcs.InfoForPoint (cl.worldmodel, temp, &area2, &r_viewcluster2, &cont2);
if ( !(leaf->contents & Q2CONTENTS_SOLID) && if (cont2 & FTECONTENTS_SOLID)
(leaf->cluster != r_viewcluster2) ) r_viewcluster2 = r_viewcluster;
r_viewcluster2 = leaf->cluster;
} }
else else
{ // look up a bit { // look up a bit
vec3_t temp;
VectorCopy (pvsorg, temp); VectorCopy (pvsorg, temp);
temp[2] += 16; temp[2] += 16;
leaf = Mod_PointInLeaf (cl.worldmodel, temp); cl.worldmodel->funcs.InfoForPoint (cl.worldmodel, temp, &area2, &r_viewcluster2, &cont2);
if ( !(leaf->contents & Q2CONTENTS_SOLID) && if (cont2 & FTECONTENTS_SOLID)
(leaf->cluster != r_viewcluster2) ) r_viewcluster2 = r_viewcluster;
r_viewcluster2 = leaf->cluster;
} }
} }
#endif
else else
{ {
leaf = Mod_PointInLeaf (cl.worldmodel, pvsorg); r_viewcluster = -1;
r_viewcluster = (leaf - cl.worldmodel->leafs)-1;
r_viewcluster2 = -1; r_viewcluster2 = -1;
if (leaf)
{
switch(leaf->contents)
{
case Q1CONTENTS_WATER:
viewcontents |= FTECONTENTS_WATER;
break;
case Q1CONTENTS_LAVA:
viewcontents |= FTECONTENTS_LAVA;
break;
case Q1CONTENTS_SLIME:
viewcontents |= FTECONTENTS_SLIME;
break;
case Q1CONTENTS_SKY:
viewcontents |= FTECONTENTS_SKY;
break;
case Q1CONTENTS_SOLID:
viewcontents |= FTECONTENTS_SOLID;
break;
case Q1CONTENTS_LADDER:
viewcontents |= FTECONTENTS_LADDER;
break;
}
if (leaf->contents == Q1CONTENTS_EMPTY)
{ //look down a bit
VectorCopy (pvsorg, temp);
temp[2] -= 16;
leaf = Mod_PointInLeaf (cl.worldmodel, temp);
if (leaf->contents <= Q1CONTENTS_WATER && leaf->contents >= Q1CONTENTS_LAVA)
r_viewcluster2 = (leaf - cl.worldmodel->leafs)-1;
}
else if (leaf->contents <= Q1CONTENTS_WATER && leaf->contents >= Q1CONTENTS_LAVA)
{ //in water, look up a bit.
VectorCopy (pvsorg, temp);
temp[2] += 16;
leaf = Mod_PointInLeaf (cl.worldmodel, temp);
if (leaf->contents == Q1CONTENTS_EMPTY)
r_viewcluster2 = (leaf - cl.worldmodel->leafs)-1;
}
}
} }
#ifdef TERRAIN #ifdef TERRAIN
@ -3778,57 +3435,16 @@ void Surf_DrawWorld (void)
Surf_PushChains(currentmodel->batches); Surf_PushChains(currentmodel->batches);
if (currentmodel->type != mod_brush) if (currentmodel->funcs.PrepareFrame)
{ {
frustumvis = NULL; int clusters[2] = {r_viewcluster, r_viewcluster2};
currentmodel->funcs.PrepareFrame(currentmodel, &r_refdef, r_viewarea, clusters, &surf_frustumvis[r_refdef.recurse], &entvis, &surfvis);
}
else if (currentmodel->type != mod_brush)
entvis = surfvis = NULL; entvis = surfvis = NULL;
}
#if defined(Q2BSPS) || defined(Q3BSPS)
else if (currentmodel->fromgame == fg_quake2 || currentmodel->fromgame == fg_quake3)
{
pvsbuffer_t *vis = &surf_frustumvis[r_refdef.recurse];
if (vis->buffersize < currentmodel->pvsbytes)
vis->buffer = BZ_Realloc(vis->buffer, vis->buffersize=currentmodel->pvsbytes);
frustumvis = vis->buffer;
memset(frustumvis, 0, currentmodel->pvsbytes);
if (!r_refdef.areabitsknown)
{ //generate the info each frame, as the gamecode didn't tell us what to use.
int leafnum = CM_PointLeafnum (currentmodel, r_refdef.vieworg);
int clientarea = CM_LeafArea (currentmodel, leafnum);
CM_WriteAreaBits(currentmodel, r_refdef.areabits, clientarea, false);
r_refdef.areabitsknown = true;
}
#ifdef Q3BSPS
if (currentmodel->fromgame == fg_quake3)
{
entvis = surfvis = R_MarkLeaves_Q3 ();
Surf_RecursiveQ3WorldNode (currentmodel->nodes, (1<<r_refdef.frustum_numworldplanes)-1);
//Surf_LeafWorldNode ();
}
else
#endif
#ifdef Q2BSPS
if (currentmodel->fromgame == fg_quake2)
{
entvis = surfvis = R_MarkLeaves_Q2 ();
VectorCopy (r_refdef.vieworg, modelorg);
Surf_RecursiveQ2WorldNode (currentmodel->nodes);
}
else
#endif
{
entvis = surfvis = NULL;
}
surfvis = frustumvis;
}
#endif
#ifdef MAP_PROC #ifdef MAP_PROC
else if (currentmodel->fromgame == fg_doom3) else if (currentmodel->fromgame == fg_doom3)
{
entvis = surfvis = D3_CalcVis(currentmodel, r_origin); entvis = surfvis = D3_CalcVis(currentmodel, r_origin);
}
#endif #endif
#ifdef MAP_DOOM #ifdef MAP_DOOM
else if (currentmodel->fromgame == fg_doom) else if (currentmodel->fromgame == fg_doom)
@ -3838,37 +3454,28 @@ void Surf_DrawWorld (void)
} }
#endif #endif
#ifdef Q1BSPS #ifdef Q1BSPS
else if (1) else if (currentmodel->fromgame == fg_quake || currentmodel->fromgame == fg_halflife)
{ {
//extern cvar_t temp1; pvsbuffer_t *vis = &surf_frustumvis[r_refdef.recurse];
// if (0)//temp1.value)
// entvis = surfvis = R_MarkLeafSurfaces_Q1();
// else
{
pvsbuffer_t *vis = &surf_frustumvis[r_refdef.recurse];
entvis = R_MarkLeaves_Q1 (false); entvis = R_MarkLeaves_Q1 (false);
if (!(r_novis.ival & 2)) if (!(r_novis.ival & 2))
VectorCopy (r_origin, modelorg); VectorCopy (r_origin, modelorg);
if (vis->buffersize < currentmodel->pvsbytes) if (vis->buffersize < currentmodel->pvsbytes)
vis->buffer = BZ_Realloc(vis->buffer, vis->buffersize=currentmodel->pvsbytes); vis->buffer = BZ_Realloc(vis->buffer, vis->buffersize=currentmodel->pvsbytes);
frustumvis = vis->buffer; q1frustumvis = vis->buffer;
memset(frustumvis, 0, currentmodel->pvsbytes); memset(q1frustumvis, 0, currentmodel->pvsbytes);
if (r_refdef.useperspective) if (r_refdef.useperspective)
Surf_RecursiveWorldNode (currentmodel->nodes, 0x1f); Surf_RecursiveWorldNode (currentmodel->nodes, 0x1f);
else else
Surf_OrthoRecursiveWorldNode (currentmodel->nodes, 0x1f); Surf_OrthoRecursiveWorldNode (currentmodel->nodes, 0x1f);
surfvis = frustumvis; surfvis = q1frustumvis;
}
} }
#endif #endif
else else
{
frustumvis = NULL;
entvis = surfvis = NULL; entvis = surfvis = NULL;
}
RSpeedEnd(RSPEED_WORLDNODE); RSpeedEnd(RSPEED_WORLDNODE);

View File

@ -550,8 +550,6 @@ void *Mod_Extradata (struct model_s *mod); // handles caching
void Mod_TouchModel (const char *name); void Mod_TouchModel (const char *name);
void Mod_RebuildLightmaps (void); void Mod_RebuildLightmaps (void);
struct mleaf_s *Mod_PointInLeaf (struct model_s *model, float *p);
void Mod_NowLoadExternal(struct model_s *loadmodel); void Mod_NowLoadExternal(struct model_s *loadmodel);
void GLR_LoadSkys (void); void GLR_LoadSkys (void);
void R_BloomRegister(void); void R_BloomRegister(void);

View File

@ -1900,11 +1900,11 @@ void R_ReloadRenderer_f (void)
if (qrenderer == QR_NONE || qrenderer == QR_HEADLESS) if (qrenderer == QR_NONE || qrenderer == QR_HEADLESS)
return; //don't bother reloading the renderer if its not actually rendering anything anyway. return; //don't bother reloading the renderer if its not actually rendering anything anyway.
#if !defined(CLIENTONLY) && (defined(Q2BSPS) || defined(Q3BSPS)) #if !defined(CLIENTONLY)
if (sv.state == ss_active && sv.world.worldmodel && sv.world.worldmodel->loadstate == MLS_LOADED) if (sv.state == ss_active && sv.world.worldmodel && sv.world.worldmodel->loadstate == MLS_LOADED && sv.world.worldmodel->funcs.SaveAreaPortalBlob)
{ {
void *t; void *t;
portalsize = CM_WritePortalState(sv.world.worldmodel, &t); portalsize = sv.world.worldmodel->funcs.SaveAreaPortalBlob(sv.world.worldmodel, &t);
if (portalsize && (portalblob = BZ_Malloc(portalsize))) if (portalsize && (portalblob = BZ_Malloc(portalsize)))
memcpy(portalblob, t, portalsize); memcpy(portalblob, t, portalsize);
} }
@ -1917,11 +1917,11 @@ void R_ReloadRenderer_f (void)
R_ApplyRenderer_Load(NULL); R_ApplyRenderer_Load(NULL);
Cvar_ApplyCallbacks(CVAR_RENDERERCALLBACK); Cvar_ApplyCallbacks(CVAR_RENDERERCALLBACK);
#if !defined(CLIENTONLY) && (defined(Q2BSPS) || defined(Q3BSPS)) #if !defined(CLIENTONLY)
if (portalblob) if (portalblob)
{ {
if (sv.world.worldmodel && sv.world.worldmodel->loadstate == MLS_LOADED) if (sv.world.worldmodel && sv.world.worldmodel->loadstate == MLS_LOADED && sv.world.worldmodel->funcs.LoadAreaPortalBlob)
CM_ReadPortalState(sv.world.worldmodel, portalblob, portalsize); sv.world.worldmodel->funcs.LoadAreaPortalBlob(sv.world.worldmodel, portalblob, portalsize);
BZ_Free(portalblob); BZ_Free(portalblob);
} }
#endif #endif
@ -2166,11 +2166,11 @@ void R_RestartRenderer (rendererstate_t *newr)
return; return;
} }
#if !defined(CLIENTONLY) && (defined(Q2BSPS) || defined(Q3BSPS)) #ifdef HAVE_SERVER
if (sv.state == ss_active && sv.world.worldmodel && sv.world.worldmodel->loadstate == MLS_LOADED) if (sv.state == ss_active && sv.world.worldmodel && sv.world.worldmodel->loadstate == MLS_LOADED && sv.world.worldmodel->funcs.SaveAreaPortalBlob)
{ {
void *t; void *t;
portalsize = CM_WritePortalState(sv.world.worldmodel, &t); portalsize = sv.world.worldmodel->funcs.SaveAreaPortalBlob(sv.world.worldmodel, &t);
if (portalsize && (portalblob = BZ_Malloc(portalsize))) if (portalsize && (portalblob = BZ_Malloc(portalsize)))
memcpy(portalblob, t, portalsize); memcpy(portalblob, t, portalsize);
} }
@ -2264,11 +2264,11 @@ void R_RestartRenderer (rendererstate_t *newr)
} }
} }
#if !defined(CLIENTONLY) && (defined(Q2BSPS) || defined(Q3BSPS)) #ifdef HAVE_SERVER
if (portalblob) if (portalblob)
{ {
if (sv.world.worldmodel && sv.world.worldmodel->loadstate == MLS_LOADED) if (sv.world.worldmodel && sv.world.worldmodel->loadstate == MLS_LOADED && sv.world.worldmodel->funcs.LoadAreaPortalBlob)
CM_ReadPortalState(sv.world.worldmodel, portalblob, portalsize); sv.world.worldmodel->funcs.LoadAreaPortalBlob(sv.world.worldmodel, portalblob, portalsize);
BZ_Free(portalblob); BZ_Free(portalblob);
} }
#endif #endif
@ -2652,218 +2652,10 @@ unsigned int r_viewcontents;
int r_viewarea; int r_viewarea;
int r_viewcluster, r_viewcluster2, r_oldviewcluster, r_oldviewcluster2; int r_viewcluster, r_viewcluster2, r_oldviewcluster, r_oldviewcluster2;
int r_visframecount; int r_visframecount;
mleaf_t *r_vischain; // linked list of visible leafs
static pvsbuffer_t curframevis[R_MAX_RECURSE]; static pvsbuffer_t curframevis[R_MAX_RECURSE];
/*
===============
R_MarkLeaves
===============
*/
#ifdef Q3BSPS
qbyte *R_MarkLeaves_Q3 (void)
{
static qbyte *cvis[R_MAX_RECURSE];
qbyte *vis;
int i;
int cluster;
mleaf_t *leaf;
mnode_t *node;
int portal = r_refdef.recurse;
if (!portal)
{
if (r_oldviewcluster == r_viewcluster && !r_novis.value && r_viewcluster != -1)
return cvis[portal];
}
// development aid to let you run around and see exactly where
// the pvs ends
// if (r_lockpvs->value)
// return;
r_vischain = NULL;
r_visframecount++;
r_oldviewcluster = r_viewcluster;
if (r_novis.ival || r_viewcluster == -1 || !cl.worldmodel->vis )
{
vis = NULL;
// mark everything
for (i=0,leaf=cl.worldmodel->leafs ; i<cl.worldmodel->numleafs ; i++, leaf++)
{
// if (!leaf->nummarksurfaces)
// {
// continue;
// }
#if 1
for (node = (mnode_t*)leaf; node; node = node->parent)
{
if (node->visframe == r_visframecount)
break;
node->visframe = r_visframecount;
}
#else
leaf->visframe = r_visframecount;
leaf->vischain = r_vischain;
r_vischain = leaf;
#endif
}
}
else
{
vis = CM_ClusterPVS (cl.worldmodel, r_viewcluster, &curframevis[portal], PVM_FAST);
for (i=0,leaf=cl.worldmodel->leafs ; i<cl.worldmodel->numleafs ; i++, leaf++)
{
cluster = leaf->cluster;
if (cluster == -1)// || !leaf->nummarksurfaces)
{
continue;
}
if (vis[cluster>>3] & (1<<(cluster&7)))
{
#if 1
for (node = (mnode_t*)leaf; node; node = node->parent)
{
if (node->visframe == r_visframecount)
break;
node->visframe = r_visframecount;
}
#else
leaf->visframe = r_visframecount;
leaf->vischain = r_vischain;
r_vischain = leaf;
#endif
}
}
cvis[portal] = vis;
}
return vis;
}
#endif
#ifdef Q2BSPS
qbyte *R_MarkLeaves_Q2 (void)
{
static qbyte *cvis[R_MAX_RECURSE];
mnode_t *node;
int i;
int cluster;
mleaf_t *leaf;
qbyte *vis;
int portal = r_refdef.recurse;
if (r_refdef.forcevis)
{
vis = cvis[portal] = r_refdef.forcedvis;
r_oldviewcluster = -1;
r_oldviewcluster2 = -1;
}
else
{
vis = cvis[portal];
if (!portal)
{
if (r_oldviewcluster == r_viewcluster && r_oldviewcluster2 == r_viewcluster2)
return vis;
r_oldviewcluster = r_viewcluster;
r_oldviewcluster2 = r_viewcluster2;
}
else
{
r_oldviewcluster = -1;
r_oldviewcluster2 = -1;
}
if (r_novis.ival == 2)
return vis;
if (r_novis.ival || r_viewcluster == -1 || !cl.worldmodel->vis)
{
// mark everything
for (i=0 ; i<cl.worldmodel->numleafs ; i++)
cl.worldmodel->leafs[i].visframe = r_visframecount;
for (i=0 ; i<cl.worldmodel->numnodes ; i++)
cl.worldmodel->nodes[i].visframe = r_visframecount;
return vis;
}
if (r_viewcluster2 != r_viewcluster) // may have to combine two clusters because of solid water boundaries
{
vis = CM_ClusterPVS (cl.worldmodel, r_viewcluster, &curframevis[portal], PVM_REPLACE);
vis = CM_ClusterPVS (cl.worldmodel, r_viewcluster2, &curframevis[portal], PVM_MERGE);
}
else
vis = CM_ClusterPVS (cl.worldmodel, r_viewcluster, &curframevis[portal], PVM_FAST);
cvis[portal] = vis;
}
r_visframecount++;
for (i=0,leaf=cl.worldmodel->leafs ; i<cl.worldmodel->numleafs ; i++, leaf++)
{
cluster = leaf->cluster;
if (cluster == -1)
continue;
if (vis[cluster>>3] & (1<<(cluster&7)))
{
node = (mnode_t *)leaf;
do
{
if (node->visframe == r_visframecount)
break;
node->visframe = r_visframecount;
node = node->parent;
} while (node);
}
}
return vis;
}
#endif
#ifdef Q1BSPS #ifdef Q1BSPS
#if 0
qbyte *R_CalcVis_Q1 (void)
{
unsigned int i;
static qbyte *vis;
r_visframecount++;
if (r_oldviewleaf == r_viewleaf && r_oldviewleaf2 == r_viewleaf2)
{
}
else
{
r_oldviewleaf = r_viewleaf;
r_oldviewleaf2 = r_viewleaf2;
if (r_novis.ival&1)
{
vis = curframevis;
memset (vis, 0xff, (cl.worldmodel->numleafs+7)>>3);
}
else if (r_viewleaf2 && r_viewleaf2 != r_viewleaf)
{
int c;
Q1BSP_LeafPVS (cl.worldmodel, r_viewleaf2, curframevis, sizeof(curframevis));
vis = Q1BSP_LeafPVS (cl.worldmodel, r_viewleaf, NULL, sizeof(curframevis));
c = (cl.worldmodel->numclusters+31)/32;
for (i=0 ; i<c ; i++)
((int *)curframevis)[i] |= ((int *)vis)[i];
vis = curframevis;
}
else
vis = Q1BSP_LeafPVS (cl.worldmodel, r_viewleaf, curframevis, sizeof(curframevis));
}
return vis;
}
#endif
qbyte *R_MarkLeaves_Q1 (qboolean getvisonly) qbyte *R_MarkLeaves_Q1 (qboolean getvisonly)
{ {
static qbyte *cvis[R_MAX_RECURSE]; static qbyte *cvis[R_MAX_RECURSE];

View File

@ -931,11 +931,9 @@ typedef struct
#define MAX_ENT_LEAFS 32 #define MAX_ENT_LEAFS 32
typedef struct pvscache_s typedef struct pvscache_s
{ {
int num_leafs; int num_leafs; //negative generally means resort-to-headnode.
unsigned int leafnums[MAX_ENT_LEAFS]; unsigned int leafnums[MAX_ENT_LEAFS];
#if defined(Q2BSPS) || defined(Q3BSPS) || defined(TERRAIN) int areanum;
int areanum; //q2bsp int areanum2;
int areanum2; //q2bsp int headnode;
int headnode; //q2bsp
#endif
} pvscache_t; } pvscache_t;

File diff suppressed because it is too large Load Diff

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); return Q1BSP_DecompressVis (model->leafs[cluster].compressed_vis, model, buffer->buffer, buffer->buffersize, merge==PVM_MERGE);
} }
/*static qbyte *Q1BSP_ClusterPHS (model_t *model, int cluster, pvsbuffer_t *buffer, pvsmerge_t merge) static qbyte *Q1BSP_ClusterPHS (model_t *model, int cluster, pvsbuffer_t *buffer)
{ {
if (cluster == -1 || !model->phs) return model->phs + cluster*model->pvsbytes;
{ }
if (merge == PVM_FAST)
{
if (mod_novis.buffersize < model->pvsbytes)
{
mod_novis.buffer = BZ_Realloc(mod_novis.buffer, mod_novis.buffersize=model->pvsbytes);
memset(mod_novis.buffer, 0xff, mod_novis.buffersize);
}
return mod_novis.buffer;
}
if (buffer->buffersize < model->pvsbytes)
buffer->buffer = BZ_Realloc(buffer->buffer, buffer->buffersize=model->pvsbytes);
memset(buffer->buffer, 0xff, model->pvsbytes);
return buffer->buffer;
}
if (merge == PVM_FAST)
return model->pvs + cluster * model->pvsbytes;
if (!buffer)
buffer = &mod_tempvis;
if (buffer->buffersize < model->pvsbytes)
buffer->buffer = BZ_Realloc(buffer->buffer, buffer->buffersize=model->pvsbytes);
memcpy(buffer->buffer, model->pvs + cluster * model->pvsbytes, model->pvsbytes);
return buffer->buffer;
}*/
//returns the leaf number, which is used as a bit index into the pvs. //returns the leaf number, which is used as a bit index into the pvs.
static int Q1BSP_LeafnumForPoint (model_t *model, vec3_t p) static int Q1BSP_LeafnumForPoint (model_t *model, vec3_t p)
@ -2043,7 +2018,7 @@ static int Q1BSP_LeafnumForPoint (model_t *model, vec3_t p)
if (!model) if (!model)
{ {
Sys_Error ("Mod_PointInLeaf: bad model"); Sys_Error ("Q1BSP_LeafnumForPoint: bad model");
} }
if (!model->nodes) if (!model->nodes)
return 0; return 0;
@ -2116,7 +2091,7 @@ static void Q1BSP_ClustersInSphere_Union(mleaf_t *firstleaf, const vec3_t center
static qbyte *Q1BSP_ClustersInSphere(model_t *mod, const vec3_t center, float radius, pvsbuffer_t *fte_restrict pvsbuffer, const qbyte *fte_restrict unionwith) static qbyte *Q1BSP_ClustersInSphere(model_t *mod, const vec3_t center, float radius, pvsbuffer_t *fte_restrict pvsbuffer, const qbyte *fte_restrict unionwith)
{ {
if (!mod) if (!mod)
Sys_Error ("Mod_PointInLeaf: bad model"); Sys_Error ("Q1BSP_ClustersInSphere: bad model");
if (!mod->nodes) if (!mod->nodes)
return NULL; return NULL;
@ -2137,7 +2112,7 @@ static int Q1BSP_ClusterForPoint (model_t *model, const vec3_t p, int *area)
if (!model) if (!model)
{ {
Sys_Error ("Mod_PointInLeaf: bad model"); Sys_Error ("Q1BSP_ClusterForPoint: bad model");
} }
if (area) if (area)
*area = 0; //no areas with q1bsp. *area = 0; //no areas with q1bsp.
@ -2161,6 +2136,37 @@ static int Q1BSP_ClusterForPoint (model_t *model, const vec3_t p, int *area)
} }
static void Q1BSP_InfoForPoint (struct model_s *mod, vec3_t pos, int *area, int *cluster, unsigned int *contentbits)
{
mnode_t *node;
float d;
mplane_t *plane;
*area = 0; //no areas with q1bsp.
*cluster = -1;
*contentbits = FTECONTENTS_SOLID;
if (!mod->nodes)
return;
node = mod->nodes;
while (1)
{
if (node->contents < 0)
{
*cluster = ((mleaf_t *)node - mod->leafs) - 1;
*contentbits = Q1BSP_TranslateContents(((mleaf_t *)node)->contents);
return; //we're done
}
plane = node->plane;
d = DotProduct (pos,plane->normal) - plane->dist;
if (d > 0)
node = node->children[0];
else
node = node->children[1];
}
}
/* /*
PVS type stuff PVS type stuff
@ -2178,7 +2184,7 @@ void Q1BSP_Init(void)
//fills in bspfuncs_t //fills in bspfuncs_t
void Q1BSP_SetModelFuncs(model_t *mod) void Q1BSP_SetModelFuncs(model_t *mod)
{ {
#ifndef CLIENTONLY #ifdef HAVE_SERVER
mod->funcs.FatPVS = Q1BSP_FatPVS; mod->funcs.FatPVS = Q1BSP_FatPVS;
#endif #endif
mod->funcs.EdictInFatPVS = Q1BSP_EdictInFatPVS; mod->funcs.EdictInFatPVS = Q1BSP_EdictInFatPVS;
@ -2187,15 +2193,20 @@ void Q1BSP_SetModelFuncs(model_t *mod)
mod->funcs.ClustersInSphere = Q1BSP_ClustersInSphere; mod->funcs.ClustersInSphere = Q1BSP_ClustersInSphere;
mod->funcs.ClusterForPoint = Q1BSP_ClusterForPoint; mod->funcs.ClusterForPoint = Q1BSP_ClusterForPoint;
mod->funcs.ClusterPVS = Q1BSP_ClusterPVS; mod->funcs.ClusterPVS = Q1BSP_ClusterPVS;
// mod->funcs.ClusterPHS = Q1BSP_ClusterPHS; mod->funcs.ClusterPHS = Q1BSP_ClusterPHS;
mod->funcs.NativeTrace = Q1BSP_Trace; mod->funcs.NativeTrace = Q1BSP_Trace;
mod->funcs.PointContents = Q1BSP_PointContents; mod->funcs.PointContents = Q1BSP_PointContents;
#ifndef SERVERONLY #ifdef HAVE_CLIENT
mod->funcs.LightPointValues = GLQ1BSP_LightPointValues; mod->funcs.LightPointValues = GLQ1BSP_LightPointValues;
mod->funcs.MarkLights = Q1BSP_MarkLights; mod->funcs.MarkLights = Q1BSP_MarkLights;
mod->funcs.StainNode = Q1BSP_StainNode; mod->funcs.StainNode = Q1BSP_StainNode;
#ifdef RTLIGHTS
mod->funcs.GenerateShadowMesh = Q1BSP_GenerateShadowMesh;
#endif #endif
#endif
mod->funcs.InfoForPoint = Q1BSP_InfoForPoint;
} }
#endif #endif
@ -2288,16 +2299,7 @@ bspx_header_t *BSPX_Setup(model_t *mod, char *filebase, size_t filelen, lump_t *
if (offs < filelen && mod && !mod->archive && mod_loadmappackages.ival) if (offs < filelen && mod && !mod->archive && mod_loadmappackages.ival)
{ //we have some sort of trailing junk... is it a zip?... { //we have some sort of trailing junk... is it a zip?...
vfsfile_t *f = VFSPIPE_Open(1,true); Mod_LoadMapArchive(mod, filebase+offs, filelen-offs);
if (f)
{
VFS_WRITE(f, filebase+offs, filelen-offs);
mod->archive = FSZIP_LoadArchive(f, NULL, mod->name, mod->name, NULL);
if (mod->archive)
FS_LoadMapPackFile(mod->name, mod->archive); //give it to the filesystem to use.
else
VFS_CLOSE(f); //give up.
}
} }
return h; return h;

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); int maxcount, int areatype);
trace_t WorldQ2_Move (world_t *w, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int hitcontentsmask, q2edict_t *passedict); trace_t WorldQ2_Move (world_t *w, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int hitcontentsmask, q2edict_t *passedict);
#endif #endif
#if defined(Q2BSPS) || defined(Q3BSPS)
unsigned int Q23BSP_FatPVS(model_t *mod, const vec3_t org, pvsbuffer_t *buffer, qboolean merge);
qboolean Q23BSP_EdictInFatPVS(model_t *mod, const struct pvscache_s *ent, const qbyte *pvs, const int *areas);
void Q23BSP_FindTouchedLeafs(model_t *mod, struct pvscache_s *ent, const float *mins, const float *maxs);
#endif
/*sv_move.c*/ /*sv_move.c*/

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) void Terr_DrawTerrainModel (batch_t **batches, entity_t *e)
{ {
extern qbyte *frustumvis;
model_t *m = e->model; model_t *m = e->model;
heightmap_t *hm = m->terrain; heightmap_t *hm = m->terrain;
batch_t *b; batch_t *b;
@ -3115,7 +3114,7 @@ void Terr_DrawTerrainModel (batch_t **batches, entity_t *e)
tdibctx.vx = (r_refdef.vieworg[0] + CHUNKBIAS*hm->sectionsize) / hm->sectionsize; tdibctx.vx = (r_refdef.vieworg[0] + CHUNKBIAS*hm->sectionsize) / hm->sectionsize;
tdibctx.vy = (r_refdef.vieworg[1] + CHUNKBIAS*hm->sectionsize) / hm->sectionsize; tdibctx.vy = (r_refdef.vieworg[1] + CHUNKBIAS*hm->sectionsize) / hm->sectionsize;
tdibctx.wmodel = e->model; tdibctx.wmodel = e->model;
tdibctx.pvs = (e->model == cl.worldmodel)?frustumvis:NULL; tdibctx.pvs = (e->model == cl.worldmodel)?r_refdef.scenevis:NULL;
validatelinks(&hm->recycle); validatelinks(&hm->recycle);
Terr_DrawInBounds(&tdibctx, bounds[0], bounds[2], bounds[1]-bounds[0], bounds[3]-bounds[2]); Terr_DrawInBounds(&tdibctx, bounds[0], bounds[2], bounds[1]-bounds[0], bounds[3]-bounds[2]);

View File

@ -484,6 +484,24 @@ void Mod_ParseEntities(model_t *mod)
mod->numentityinfo = c; mod->numentityinfo = c;
} }
void Mod_LoadMapArchive(model_t *mod, void *archivedata, size_t archivesize)
{
if (archivesize && mod && !mod->archive && mod_loadmappackages.ival)
{
vfsfile_t *f = VFSPIPE_Open(1,true);
if (f)
{
VFS_WRITE(f, archivedata, archivesize);
mod->archive = FSZIP_LoadArchive(f, NULL, mod->name, mod->name, NULL);
if (mod->archive)
FS_LoadMapPackFile(mod->name, mod->archive); //give it to the filesystem to use.
else
VFS_CLOSE(f); //give up.
}
}
}
/* /*
=================== ===================
Mod_ClearAll Mod_ClearAll
@ -763,50 +781,6 @@ void *Mod_Extradata (model_t *mod)
return mod->meshinfo; return mod->meshinfo;
} }
/*
===============
Mod_PointInLeaf
===============
*/
mleaf_t *Mod_PointInLeaf (model_t *model, vec3_t p)
{
mnode_t *node;
float d;
mplane_t *plane;
if (!model)
{
Sys_Error ("Mod_PointInLeaf: bad model");
}
if (!model->nodes)
return NULL;
#if defined(Q2BSPS) || defined(Q3BSPS)
if (model->fromgame == fg_quake2 || model->fromgame == fg_quake3)
{
return model->leafs + CM_PointLeafnum(model, p);
}
#endif
if (model->fromgame == fg_doom)
{
return NULL;
}
node = model->nodes;
while (1)
{
if (node->contents < 0)
return (mleaf_t *)node;
plane = node->plane;
d = DotProduct (p,plane->normal) - plane->dist;
if (d > 0)
node = node->children[0];
else
node = node->children[1];
}
return NULL; // never reached
}
const char *Mod_FixName(const char *modname, const char *worldname) const char *Mod_FixName(const char *modname, const char *worldname)
{ {
if (*modname == '*' && worldname && *worldname) if (*modname == '*' && worldname && *worldname)
@ -866,9 +840,21 @@ model_t *Mod_FindName (const char *name)
{ {
#endif #endif
if (mod_numknown == MAX_MOD_KNOWN) if (mod_numknown == MAX_MOD_KNOWN)
{
#ifdef LOADERTHREAD
Sys_UnlockMutex(com_resourcemutex);
#endif
Sys_Error ("mod_numknown == MAX_MOD_KNOWN"); Sys_Error ("mod_numknown == MAX_MOD_KNOWN");
return NULL;
}
if (strlen(name) >= sizeof(mod->publicname)) if (strlen(name) >= sizeof(mod->publicname))
{
#ifdef LOADERTHREAD
Sys_UnlockMutex(com_resourcemutex);
#endif
Sys_Error ("model name is too long: %s", name); Sys_Error ("model name is too long: %s", name);
return NULL;
}
memset(mod, 0, sizeof(model_t)); //clear the old model as the renderers use the same globals memset(mod, 0, sizeof(model_t)); //clear the old model as the renderers use the same globals
Q_strncpyz (mod->publicname, name, sizeof(mod->publicname)); Q_strncpyz (mod->publicname, name, sizeof(mod->publicname));
Q_strncpyz (mod->name, name, sizeof(mod->name)); Q_strncpyz (mod->name, name, sizeof(mod->name));
@ -1485,7 +1471,7 @@ static void Mod_FinishTexture(model_t *mod, texture_t *tx, const char *loadname,
const char *origname = NULL; const char *origname = NULL;
const char *shadername = tx->name; const char *shadername = tx->name;
if (!safetoloadfromwads) if (!safetoloadfromwads || !tx->shader)
{ {
//remap to avoid bugging out on textures with the same name and different images (vanilla content sucks) //remap to avoid bugging out on textures with the same name and different images (vanilla content sucks)
shadername = Mod_RemapBuggyTexture(shadername, tx->srcdata, tx->srcwidth*tx->srcheight); shadername = Mod_RemapBuggyTexture(shadername, tx->srcdata, tx->srcwidth*tx->srcheight);
@ -2273,7 +2259,7 @@ static void Mod_SaveEntFile_f(void)
Mod_LoadEntities Mod_LoadEntities
================= =================
*/ */
void Mod_LoadEntities (model_t *loadmodel, qbyte *mod_base, lump_t *l) qboolean Mod_LoadEntitiesBlob(struct model_s *mod, const char *entdata, size_t entdatasize)
{ {
char fname[MAX_QPATH]; char fname[MAX_QPATH];
size_t sz; size_t sz;
@ -2282,15 +2268,15 @@ void Mod_LoadEntities (model_t *loadmodel, qbyte *mod_base, lump_t *l)
char *ents = NULL, *k; char *ents = NULL, *k;
int t; int t;
Mod_SetEntitiesString(loadmodel, NULL, false); Mod_SetEntitiesString(mod, NULL, false);
if (!l->filelen) if (!entdatasize)
return; return false;
if (mod_loadentfiles.value && !ents && *mod_loadentfiles_dir.string) if (mod_loadentfiles.value && !ents && *mod_loadentfiles_dir.string)
{ {
if (!strncmp(loadmodel->name, "maps/", 5)) if (!strncmp(mod->name, "maps/", 5))
{ {
Q_snprintfz(fname, sizeof(fname), "maps/%s/%s", mod_loadentfiles_dir.string, loadmodel->name+5); Q_snprintfz(fname, sizeof(fname), "maps/%s/%s", mod_loadentfiles_dir.string, mod->name+5);
COM_StripExtension(fname, fname, sizeof(fname)); COM_StripExtension(fname, fname, sizeof(fname));
Q_strncatz(fname, ".ent", sizeof(fname)); Q_strncatz(fname, ".ent", sizeof(fname));
ents = FS_LoadMallocFile(fname, &sz); ents = FS_LoadMallocFile(fname, &sz);
@ -2298,26 +2284,27 @@ void Mod_LoadEntities (model_t *loadmodel, qbyte *mod_base, lump_t *l)
} }
if (mod_loadentfiles.value && !ents) if (mod_loadentfiles.value && !ents)
{ {
COM_StripExtension(loadmodel->name, fname, sizeof(fname)); COM_StripExtension(mod->name, fname, sizeof(fname));
Q_strncatz(fname, ".ent", sizeof(fname)); Q_strncatz(fname, ".ent", sizeof(fname));
ents = FS_LoadMallocFile(fname, &sz); ents = FS_LoadMallocFile(fname, &sz);
} }
if (mod_loadentfiles.value && !ents) if (mod_loadentfiles.value && !ents)
{ //tenebrae compat { //tenebrae compat
COM_StripExtension(loadmodel->name, fname, sizeof(fname)); COM_StripExtension(mod->name, fname, sizeof(fname));
Q_strncatz(fname, ".edo", sizeof(fname)); Q_strncatz(fname, ".edo", sizeof(fname));
ents = FS_LoadMallocFile(fname, &sz); ents = FS_LoadMallocFile(fname, &sz);
} }
if (!ents) if (!ents)
{ {
ents = Z_Malloc(l->filelen + 1); ents = Z_Malloc(entdatasize + 1);
memcpy (ents, mod_base + l->fileofs, l->filelen); memcpy (ents, entdata, entdatasize);
ents[l->filelen] = 0; ents[entdatasize] = 0;
mod->entitiescrc = 0;
} }
else else
loadmodel->entitiescrc = CalcHashInt(&hash_crc16, ents, strlen(ents)); mod->entitiescrc = CalcHashInt(&hash_crc16, ents, strlen(ents));
Mod_SetEntitiesString(loadmodel, ents, false); Mod_SetEntitiesString(mod, ents, false);
while(ents && *ents) while(ents && *ents)
{ {
@ -2333,23 +2320,27 @@ void Mod_LoadEntities (model_t *loadmodel, qbyte *mod_base, lump_t *l)
if (!strncmp(keyname, "_texpart_", 9) || !strncmp(keyname, "texpart_", 8)) if (!strncmp(keyname, "_texpart_", 9) || !strncmp(keyname, "texpart_", 8))
{ {
k = keyname + ((*keyname=='_')?9:8); k = keyname + ((*keyname=='_')?9:8);
for (t = 0; t < loadmodel->numtextures; t++) for (t = 0; t < mod->numtextures; t++)
{ {
if (!strcmp(k, loadmodel->textures[t]->name)) if (!strcmp(k, mod->textures[t]->name))
{ {
loadmodel->textures[t]->partname = ZG_Malloc(&loadmodel->memgroup, strlen(value)+1); mod->textures[t]->partname = ZG_Malloc(&mod->memgroup, strlen(value)+1);
strcpy(loadmodel->textures[t]->partname, value); strcpy(mod->textures[t]->partname, value);
break; break;
} }
} }
if (t == loadmodel->numtextures) if (t == mod->numtextures)
Con_Printf("\"%s\" is not valid for %s\n", keyname, loadmodel->name); Con_Printf("\"%s\" is not valid for %s\n", keyname, mod->name);
} }
} }
} }
} }
return true;
}
void Mod_LoadEntities (model_t *loadmodel, qbyte *mod_base, lump_t *l)
{
Mod_LoadEntitiesBlob(loadmodel, mod_base+l->fileofs, l->filelen);
} }
/* /*
================= =================
@ -3157,7 +3148,7 @@ static void Mod_Batches_AllocLightmaps(model_t *mod)
extern void Surf_CreateSurfaceLightmap (msurface_t *surf, int shift); extern void Surf_CreateSurfaceLightmap (msurface_t *surf, int shift);
//if build is NULL, uses q1/q2 surf generation, and allocates lightmaps //if build is NULL, uses q1/q2 surf generation, and allocates lightmaps
static void Mod_Batches_Build(model_t *mod, builddata_t *bd) void Mod_Batches_Build(model_t *mod, builddata_t *bd)
{ {
int i; int i;
int numverts = 0, numindicies=0; int numverts = 0, numindicies=0;
@ -3232,13 +3223,14 @@ static void Mod_Batches_Build(model_t *mod, builddata_t *bd)
Mod_Batches_BuildModelMeshes(mod, numverts, numindicies, ModQ1_Batches_BuildQ1Q2Poly, bd, merge); Mod_Batches_BuildModelMeshes(mod, numverts, numindicies, ModQ1_Batches_BuildQ1Q2Poly, bd, merge);
} }
#endif #endif
#if defined(Q3BSPS)
if (bd) if (bd)
{ {
Mod_Batches_SplitLightmaps(mod, merge); if (bd->paintlightmaps)
Mod_Batches_AllocLightmaps(mod);
else
Mod_Batches_SplitLightmaps(mod, merge);
Mod_Batches_BuildModelMeshes(mod, numverts, numindicies, bd->buildfunc, bd, merge); Mod_Batches_BuildModelMeshes(mod, numverts, numindicies, bd->buildfunc, bd, merge);
} }
#endif
if (BE_GenBrushModelVBO) if (BE_GenBrushModelVBO)
BE_GenBrushModelVBO(mod); BE_GenBrushModelVBO(mod);

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, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details. See the GNU General Public License for more details.
@ -286,7 +286,18 @@ typedef struct {
int (*ClusterForPoint) (struct model_s *model, const vec3_t point, int *areaout); //pvs index (leaf-1 for q1bsp). may be negative (ie: no pvs). int (*ClusterForPoint) (struct model_s *model, const vec3_t point, int *areaout); //pvs index (leaf-1 for q1bsp). may be negative (ie: no pvs).
qbyte *(*ClusterPVS) (struct model_s *model, int cluster, pvsbuffer_t *pvsbuffer, pvsmerge_t merge); qbyte *(*ClusterPVS) (struct model_s *model, int cluster, pvsbuffer_t *pvsbuffer, pvsmerge_t merge);
qbyte *(*ClusterPHS) (struct model_s *model, int cluster, pvsbuffer_t *pvsbuffer);
qbyte *(*ClustersInSphere) (struct model_s *model, const vec3_t point, float radius, pvsbuffer_t *pvsbuffer, const qbyte *fte_restrict unionwith); qbyte *(*ClustersInSphere) (struct model_s *model, const vec3_t point, float radius, pvsbuffer_t *pvsbuffer, const qbyte *fte_restrict unionwith);
size_t (*WriteAreaBits) (struct model_s *model, qbyte *buffer, size_t maxbytes, int area, qboolean merge); //writes a set of bits valid for a specific viewpoint's area.
qboolean (*AreasConnected) (struct model_s *model, unsigned int area1, unsigned int area2); //fails if there's no open doors
void (*SetAreaPortalState) (struct model_s *model, unsigned int portal, unsigned int area1, unsigned int area2, qboolean open); //a door moved...
size_t (*SaveAreaPortalBlob)(struct model_s *model, void **ptr); //for vid_reload to not break portals. dupe the ptrbefore freeing the model.
size_t (*LoadAreaPortalBlob)(struct model_s *model, void *ptr, size_t size); //for vid_reload to not break portals (has refcount info etc).
void (*PrepareFrame) (struct model_s *model, refdef_t *refdef, int area, int clusters[2], pvsbuffer_t *vis, qbyte **entvis_out, qbyte **surfvis_out);
void (*GenerateShadowMesh) (struct model_s *model, dlight_t *dl, const qbyte *lvis, qbyte *truevis, void(*callback)(struct msurface_s*));
void (*InfoForPoint) (struct model_s *model, vec3_t pos, int *area, int *cluster, unsigned int *contentbits);
} modelfuncs_t; } modelfuncs_t;
@ -352,7 +363,7 @@ void GL_DeselectVAO(void);
typedef struct texture_s typedef struct texture_s
{ {
char name[64]; char name[128];
unsigned vwidth, vheight; //used for lightmap coord generation unsigned vwidth, vheight; //used for lightmap coord generation
struct shader_s *shader; struct shader_s *shader;
@ -469,7 +480,7 @@ typedef struct msurface_s
int shadowframe; int shadowframe;
#endif #endif
// int clipcount; // int clipcount;
// legacy lighting info // legacy lighting info
dlightbitmask_t dlightbits; dlightbitmask_t dlightbits;
int dlightframe; int dlightframe;
@ -505,7 +516,7 @@ typedef struct mnode_s
int contents; // 0, to differentiate from leafs int contents; // 0, to differentiate from leafs
int visframe; // node needs to be traversed if current int visframe; // node needs to be traversed if current
int shadowframe; int shadowframe;
float minmaxs[6]; // for bounding box culling float minmaxs[6]; // for bounding box culling
struct mnode_s *parent; struct mnode_s *parent;
@ -587,6 +598,7 @@ void Q1BSP_CheckHullNodes(hull_t *hull);
void Q1BSP_SetModelFuncs(struct model_s *mod); void Q1BSP_SetModelFuncs(struct model_s *mod);
void Q1BSP_LoadBrushes(struct model_s *model, bspx_header_t *bspx, void *mod_base); void Q1BSP_LoadBrushes(struct model_s *model, bspx_header_t *bspx, void *mod_base);
void Q1BSP_Init(void); void Q1BSP_Init(void);
void Q1BSP_GenerateShadowMesh(struct model_s *model, struct dlight_s *dl, const qbyte *lightvis, qbyte *litvis, void (*callback)(msurface_t *surf));
void BSPX_LoadEnvmaps(struct model_s *mod, bspx_header_t *bspx, void *mod_base); void BSPX_LoadEnvmaps(struct model_s *mod, bspx_header_t *bspx, void *mod_base);
void *BSPX_FindLump(bspx_header_t *bspxheader, void *mod_base, char *lumpname, int *lumpsize); void *BSPX_FindLump(bspx_header_t *bspxheader, void *mod_base, char *lumpname, int *lumpsize);
@ -667,7 +679,7 @@ typedef struct
float interval; float interval;
dtrivertx_t bboxmin; dtrivertx_t bboxmin;
dtrivertx_t bboxmax; dtrivertx_t bboxmax;
vec3_t scale; vec3_t scale;
vec3_t scale_origin; vec3_t scale_origin;
@ -693,7 +705,7 @@ typedef struct
typedef struct mtriangle_s { typedef struct mtriangle_s {
int xyz_index[3]; int xyz_index[3];
int st_index[3]; int st_index[3];
int pad[2]; int pad[2];
} mtriangle_t; } mtriangle_t;
@ -769,7 +781,7 @@ typedef struct
short t; short t;
} md2stvert_t; } md2stvert_t;
typedef struct typedef struct
{ {
short index_xyz[3]; short index_xyz[3];
short index_st[3]; short index_st[3];
@ -827,7 +839,7 @@ typedef struct
int ofs_st; // qbyte offset from start for stverts int ofs_st; // qbyte offset from start for stverts
int ofs_tris; // offset for dtriangles int ofs_tris; // offset for dtriangles
int ofs_frames; // offset for first frame int ofs_frames; // offset for first frame
int ofs_glcmds; int ofs_glcmds;
int ofs_end; // end of file int ofs_end; // end of file
} md2_t; } md2_t;
@ -953,7 +965,7 @@ typedef struct model_s
int numframes; int numframes;
synctype_t synctype; synctype_t synctype;
int flags; int flags;
int engineflags; int engineflags;
int particleeffect; int particleeffect;
@ -962,14 +974,14 @@ typedef struct model_s
// //
// volume occupied by the model graphics // volume occupied by the model graphics
// //
vec3_t mins, maxs; vec3_t mins, maxs;
float radius; float radius;
float clampscale; float clampscale;
float maxlod; float maxlod;
// //
// solid volume for clipping // solid volume for clipping
// //
qboolean clipbox; qboolean clipbox;
vec3_t clipmins, clipmaxs; vec3_t clipmins, clipmaxs;
@ -1160,15 +1172,15 @@ qboolean Heightmap_Edit(model_t *mod, int action, float *pos, float radius, floa
#if defined(Q2BSPS) || defined(Q3BSPS) #if defined(Q2BSPS) || defined(Q3BSPS)
void CM_Init(void);
void CM_InitBoxHull (void); struct model_s *CM_TempBoxModel(const vec3_t mins, const vec3_t maxs);
#endif
#if 0
#ifdef __cplusplus #ifdef __cplusplus
//#pragma warningmsg (" c++ stinks") //#pragma warningmsg (" c++ stinks")
#else #else
void CM_Init(void);
qboolean CM_SetAreaPortalState (struct model_s *mod, int portalnum, qboolean open); qboolean CM_SetAreaPortalState (struct model_s *mod, int portalnum, qboolean open);
qboolean CM_HeadnodeVisible (struct model_s *mod, int nodenum, const qbyte *visbits); qboolean CM_HeadnodeVisible (struct model_s *mod, int nodenum, const qbyte *visbits);
qboolean VARGS CM_AreasConnected (struct model_s *mod, unsigned int area1, unsigned int area2); qboolean VARGS CM_AreasConnected (struct model_s *mod, unsigned int area1, unsigned int area2);
@ -1185,7 +1197,6 @@ int CM_PointContents (struct model_s *mod, const vec3_t p);
int CM_TransformedPointContents (struct model_s *mod, const vec3_t p, int headnode, const vec3_t origin, const vec3_t angles); int CM_TransformedPointContents (struct model_s *mod, const vec3_t p, int headnode, const vec3_t origin, const vec3_t angles);
int CM_HeadnodeForBox (struct model_s *mod, const vec3_t mins, const vec3_t maxs); int CM_HeadnodeForBox (struct model_s *mod, const vec3_t mins, const vec3_t maxs);
//struct trace_s CM_TransformedBoxTrace (struct model_s *mod, vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, int brushmask, vec3_t origin, vec3_t angles); //struct trace_s CM_TransformedBoxTrace (struct model_s *mod, vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, int brushmask, vec3_t origin, vec3_t angles);
struct model_s *CM_TempBoxModel(const vec3_t mins, const vec3_t maxs);
//for gamecode to control portals/areas //for gamecode to control portals/areas
void CMQ2_SetAreaPortalState (model_t *mod, unsigned int portalnum, qboolean open); void CMQ2_SetAreaPortalState (model_t *mod, unsigned int portalnum, qboolean open);

View File

@ -40,7 +40,7 @@ static void SHM_Shutdown(void);
#define SHADOWMAP_SIZE 512 #define SHADOWMAP_SIZE 512
#define PROJECTION_DISTANCE (float)(dl->radius*2)//0x7fffffff #define PROJECTION_DISTANCE (float)(sh_shmesh->radius*2)//0x7fffffff
#ifdef BEF_PUSHDEPTH #ifdef BEF_PUSHDEPTH
extern qboolean r_pushdepth; extern qboolean r_pushdepth;
@ -113,6 +113,8 @@ typedef struct {
} shadowmeshbatch_t; } shadowmeshbatch_t;
typedef struct shadowmesh_s typedef struct shadowmesh_s
{ {
vec3_t origin;
float radius;
enum enum
{ {
SMT_STENCILVOLUME, //build edges mesh (and surface list) SMT_STENCILVOLUME, //build edges mesh (and surface list)
@ -536,6 +538,8 @@ static void SHM_BeginShadowMesh(dlight_t *dl, int type)
sh_shmesh->maxindicies = 0; sh_shmesh->maxindicies = 0;
sh_shmesh->numindicies = 0; sh_shmesh->numindicies = 0;
sh_shmesh->type = type; sh_shmesh->type = type;
VectorCopy(dl->origin, sh_shmesh->origin);
sh_shmesh->radius = dl->radius;
if (!cl.worldmodel->numshadowbatches) if (!cl.worldmodel->numshadowbatches)
{ {
@ -689,6 +693,7 @@ static struct {
} *edge; } *edge;
static int firstedge; static int firstedge;
static int maxedge; static int maxedge;
static void (*genshadowmapcallback) (msurface_t *mesh);
static void SHM_RecursiveWorldNodeQ1_r (dlight_t *dl, mnode_t *node) static void SHM_RecursiveWorldNodeQ1_r (dlight_t *dl, mnode_t *node)
{ {
@ -697,7 +702,6 @@ static void SHM_RecursiveWorldNodeQ1_r (dlight_t *dl, mnode_t *node)
msurface_t *surf, **mark; msurface_t *surf, **mark;
mleaf_t *pleaf; mleaf_t *pleaf;
double dot; double dot;
int v;
float l, maxdist; float l, maxdist;
int j, s, t; int j, s, t;
@ -822,61 +826,7 @@ static void SHM_RecursiveWorldNodeQ1_r (dlight_t *dl, mnode_t *node)
t = (l - t)*surf->texinfo->vecscale[1]; t = (l - t)*surf->texinfo->vecscale[1];
// compare to minimum light // compare to minimum light
if ((s*s+t*t+dot*dot) < maxdist) if ((s*s+t*t+dot*dot) < maxdist)
{ genshadowmapcallback(surf);
SHM_Shadow_Cache_Surface(surf);
if (sh_shmesh->type == SMT_SHADOWMAP)
{
SHM_MeshFrontOnly(surf->mesh->numvertexes, surf->mesh->xyz_array, surf->mesh->numindexes, surf->mesh->indexes);
continue;
}
if (sh_shmesh->type != SMT_STENCILVOLUME)
continue;
//build a list of the edges that are to be drawn.
for (v = 0; v < surf->numedges; v++)
{
int e, delta;
e = cl.worldmodel->surfedges[surf->firstedge+v];
//negative edge means backwards edge.
if (e < 0)
{
e=-e;
delta = -1;
}
else
{
delta = 1;
}
if (!edge[e].count)
{
if (firstedge)
edge[firstedge].prev = e;
edge[e].next = firstedge;
edge[e].prev = 0;
firstedge = e;
edge[e].count = delta;
}
else
{
edge[e].count += delta;
if (!edge[e].count) //unlink
{
if (edge[e].next)
{
edge[edge[e].next].prev = edge[e].prev;
}
if (edge[e].prev)
edge[edge[e].prev].next = edge[e].next;
else
firstedge = edge[e].next;
}
}
}
SHM_TriangleFan(surf->mesh->numvertexes, surf->mesh->xyz_array, dl->origin, PROJECTION_DISTANCE);
}
} }
} }
} }
@ -938,11 +888,8 @@ static void SHM_OrthoWorldLeafsQ1 (dlight_t *dl)
if (dot < 0) if (dot < 0)
{ {
SHM_Shadow_Cache_Surface(surf); SHM_Shadow_Cache_Surface(surf);
} }
// else SHM_MeshFrontOnly(surf->mesh->numvertexes, surf->mesh->xyz_array, surf->mesh->numindexes, surf->mesh->indexes);
// SHM_MeshBackOnly(surf->mesh->numvertexes, surf->mesh->xyz_array, surf->mesh->numindexes, surf->mesh->indexes);
SHM_MeshFrontOnly(surf->mesh->numvertexes, surf->mesh->xyz_array, surf->mesh->numindexes, surf->mesh->indexes);
} }
} }
@ -950,6 +897,44 @@ next:;
} }
} }
static void SHM_MarkLeavesQ1(dlight_t *dl, const qbyte *lvis)
{
mnode_t *node;
int i;
sh_shadowframe++;
if (!lvis)
return;
//variation on mark leaves
for (i=0 ; i<cl.worldmodel->numclusters ; i++)
{
if (lvis[i>>3] & (1<<(i&7)))
{
node = (mnode_t *)&cl.worldmodel->leafs[i+1];
do
{
if (node->shadowframe == sh_shadowframe)
break;
node->shadowframe = sh_shadowframe;
node = node->parent;
} while (node);
}
}
}
void Q1BSP_GenerateShadowMesh(model_t *model, dlight_t *dl, const qbyte *lightvis, qbyte *litvis, void (*callback)(msurface_t *surf))
{
genshadowmapcallback = callback;
if (sh_shmesh->type == SMT_ORTHO)
SHM_OrthoWorldLeafsQ1(dl);
else
{
SHM_MarkLeavesQ1(dl, lightvis);
SHM_RecursiveWorldNodeQ1_r(dl, cl.worldmodel->nodes);
}
}
static void SHM_OrthoWorldLeafsQ3 (dlight_t *dl) static void SHM_OrthoWorldLeafsQ3 (dlight_t *dl)
{ {
int c, i; int c, i;
@ -1256,33 +1241,12 @@ static void SHM_MarkLeavesQ2(dlight_t *dl, unsigned char *lvis)
} }
} }
} }
#endif void Q2BSP_GenerateShadowMesh(model_t *model, dlight_t *dl, qbyte *lvis, int type)
static void SHM_MarkLeavesQ1(dlight_t *dl, unsigned char *lvis)
{ {
mnode_t *node; SHM_MarkLeavesQ2(dl, lvis);
int i; SHM_RecursiveWorldNodeQ2_r(dl, model->nodes);
sh_shadowframe++;
if (!lvis)
return;
//variation on mark leaves
for (i=0 ; i<cl.worldmodel->numclusters ; i++)
{
if (lvis[i>>3] & (1<<(i&7)))
{
node = (mnode_t *)&cl.worldmodel->leafs[i+1];
do
{
if (node->shadowframe == sh_shadowframe)
break;
node->shadowframe = sh_shadowframe;
node = node->parent;
} while (node);
}
}
} }
#endif
#ifdef Q3BSPS #ifdef Q3BSPS
static void SHM_RecursiveWorldNodeQ3_r (dlight_t *dl, mnode_t *node) static void SHM_RecursiveWorldNodeQ3_r (dlight_t *dl, mnode_t *node)
@ -1626,8 +1590,78 @@ static void SHM_ComposeVolume_BruteForce(dlight_t *dl)
} }
} }
} }
void Q3BSP_GenerateShadowMesh(model_t *model, dlight_t *dl, const qbyte *lightvis, qbyte *litvis, void (*callback)(msurface_t *surf))
{
/*q3 doesn't have edge info*/
if (sh_shmesh->type == SMT_ORTHO)
SHM_OrthoWorldLeafsQ3(dl);
else
{
sh_shadowframe++;
SHM_RecursiveWorldNodeQ3_r(dl, model->nodes);
}
if (sh_shmesh->type == SMT_STENCILVOLUME)
SHM_ComposeVolume_BruteForce(dl);
}
#endif #endif
static void SHM_Shadow_Surface_Shadowmap (msurface_t *surf)
{
SHM_Shadow_Cache_Surface(surf);
SHM_MeshFrontOnly(surf->mesh->numvertexes, surf->mesh->xyz_array, surf->mesh->numindexes, surf->mesh->indexes);
}
static void SHM_Shadow_Surface_StencilVolume (msurface_t *surf)
{
int v;
SHM_Shadow_Cache_Surface(surf);
//build a list of the edges that are to be drawn.
for (v = 0; v < surf->numedges; v++)
{
int e, delta;
e = cl.worldmodel->surfedges[surf->firstedge+v];
//negative edge means backwards edge.
if (e < 0)
{
e=-e;
delta = -1;
}
else
{
delta = 1;
}
if (!edge[e].count)
{
if (firstedge)
edge[firstedge].prev = e;
edge[e].next = firstedge;
edge[e].prev = 0;
firstedge = e;
edge[e].count = delta;
}
else
{
edge[e].count += delta;
if (!edge[e].count) //unlink
{
if (edge[e].next)
{
edge[edge[e].next].prev = edge[e].prev;
}
if (edge[e].prev)
edge[edge[e].prev].next = edge[e].next;
else
firstedge = edge[e].next;
}
}
}
SHM_TriangleFan(surf->mesh->numvertexes, surf->mesh->xyz_array, sh_shmesh->origin, PROJECTION_DISTANCE);
}
static struct shadowmesh_s *SHM_BuildShadowMesh(dlight_t *dl, unsigned char *lvis, int type) static struct shadowmesh_s *SHM_BuildShadowMesh(dlight_t *dl, unsigned char *lvis, int type)
{ {
float *v1, *v2; float *v1, *v2;
@ -1662,58 +1696,37 @@ static struct shadowmesh_s *SHM_BuildShadowMesh(dlight_t *dl, unsigned char *lvi
edge = Z_Malloc(sizeof(*edge) * maxedge); edge = Z_Malloc(sizeof(*edge) * maxedge);
} }
if (cl.worldmodel->type == mod_brush) SHM_BeginShadowMesh(dl, type);
if (cl.worldmodel->funcs.GenerateShadowMesh)
{
switch(type)
{
case SMT_SHADOWMAP:
cl.worldmodel->funcs.GenerateShadowMesh(cl.worldmodel, dl, lvis, sh_shmesh->litleaves, SHM_Shadow_Surface_Shadowmap);
break;
case SMT_STENCILVOLUME:
cl.worldmodel->funcs.GenerateShadowMesh(cl.worldmodel, dl, lvis, sh_shmesh->litleaves, SHM_Shadow_Surface_StencilVolume);
break;
default:
cl.worldmodel->funcs.GenerateShadowMesh(cl.worldmodel, dl, lvis, sh_shmesh->litleaves, SHM_Shadow_Cache_Surface);
break;
}
}
else if (cl.worldmodel->type == mod_brush)
{ {
switch(cl.worldmodel->fromgame) switch(cl.worldmodel->fromgame)
{ {
case fg_quake: case fg_quake:
case fg_halflife: case fg_halflife:
/*if (!dl->die)
{
SHM_BeginShadowMesh(dl, true);
SHM_MarkLeavesQ1(dl, lvis);
SHM_RecursiveWorldNodeQ1_r(dl, cl.worldmodel->nodes);
if (!surfonly)
SHM_ComposeVolume_BruteForce(dl);
}
else*/
{
SHM_BeginShadowMesh(dl, type);
if (type == SMT_ORTHO)
SHM_OrthoWorldLeafsQ1(dl);
else
{
SHM_MarkLeavesQ1(dl, lvis);
SHM_RecursiveWorldNodeQ1_r(dl, cl.worldmodel->nodes);
}
}
break;
#ifdef Q2BSPS
case fg_quake2:
SHM_BeginShadowMesh(dl, type);
SHM_MarkLeavesQ2(dl, lvis);
SHM_RecursiveWorldNodeQ2_r(dl, cl.worldmodel->nodes);
break;
#endif
#ifdef Q3BSPS
case fg_quake3:
/*q3 doesn't have edge info*/
SHM_BeginShadowMesh(dl, type);
if (type == SMT_ORTHO) if (type == SMT_ORTHO)
SHM_OrthoWorldLeafsQ3(dl); SHM_OrthoWorldLeafsQ1(dl);
else else
{ {
sh_shadowframe++; SHM_MarkLeavesQ1(dl, lvis);
SHM_RecursiveWorldNodeQ3_r(dl, cl.worldmodel->nodes); SHM_RecursiveWorldNodeQ1_r(dl, cl.worldmodel->nodes);
} }
if (type == SMT_STENCILVOLUME)
SHM_ComposeVolume_BruteForce(dl);
break; break;
#endif
default: default:
SHM_BeginShadowMesh(dl, type);
sh_shadowframe++; sh_shadowframe++;
{ {

View File

@ -92,8 +92,8 @@ void R_SetSky(const char *sky)
memset(&tex, 0, sizeof(tex)); memset(&tex, 0, sizeof(tex));
tex.base = R_LoadHiResTexture(sky, "env:gfx/env", IF_LOADNOW|IF_NOMIPMAP); tex.base = R_LoadHiResTexture(sky, "env:gfx/env", IF_LOADNOW|IF_NOMIPMAP);
if (tex.reflectcube && tex.reflectcube->status == TEX_LOADING) if (tex.base && tex.base->status == TEX_LOADING)
COM_WorkerPartialSync(tex.reflectcube, &tex.reflectcube->status, TEX_LOADING); COM_WorkerPartialSync(tex.base, &tex.base->status, TEX_LOADING);
if (tex.base->width && TEXLOADED(tex.base)) if (tex.base->width && TEXLOADED(tex.base))
{ {
forcedsky = R_RegisterShader(shadername, 0, forcedsky = R_RegisterShader(shadername, 0,

View File

@ -35,9 +35,12 @@ void ClearBounds (vec3_t mins, vec3_t maxs);
struct builddata_s struct builddata_s
{ {
void (*buildfunc)(model_t *mod, msurface_t *surf, struct builddata_s *bd); void (*buildfunc)(model_t *mod, msurface_t *surf, struct builddata_s *bd);
qboolean paintlightmaps;
void *facedata; void *facedata;
}; };
void ModBrush_LoadGLStuff(void *ctx, void *data, size_t a, size_t b); //data === builddata_t void ModBrush_LoadGLStuff(void *ctx, void *data, size_t a, size_t b); //data === builddata_t
void Mod_Batches_Build(model_t *mod, builddata_t *bd);
shader_t *Mod_RegisterBasicShader(struct model_s *mod, const char *texname, unsigned int usageflags, const char *shadertext, uploadfmt_t pixelfmt, unsigned int width, unsigned int height, void *pixeldata, void *palettedata);
#ifdef GLQUAKE #ifdef GLQUAKE
#if defined(ANDROID) /*FIXME: actually just to use standard GLES headers instead of full GL*/ #if defined(ANDROID) /*FIXME: actually just to use standard GLES headers instead of full GL*/

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) static void QCBUILTIN PF_OpenPortal (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{ {
#ifdef Q2BSPS int i;
if (sv.world.worldmodel->fromgame == fg_quake2) int state = G_FLOAT(OFS_PARM1)!=0;
client_t *client;
edict_t *ent = G_EDICT(prinst, OFS_PARM0);
int portal = G_EDICT(prinst, OFS_PARM0)->xv->style; //read the func_areaportal's style field (q2ism).
int area1 = ent->pvsinfo.areanum, area2 = ent->pvsinfo.areanum2;
for (client = svs.clients, i = 0; i < sv.allocated_client_slots; i++, client++)
{ {
int i, portal; if (client->state >= cs_connected)
int state = G_FLOAT(OFS_PARM1)!=0;
client_t *client;
if (G_INT(OFS_PARM1) >= MAX_EDICTS)
portal = G_FLOAT(OFS_PARM0); //old legacy crap.
else
portal = G_EDICT(prinst, OFS_PARM0)->xv->style; //read the func_areaportal's style field.
for (client = svs.clients, i = 0; i < sv.allocated_client_slots; i++, client++)
{ {
if (client->state >= cs_connected) ClientReliableWrite_Begin(client, svc_setportalstate, 4);
if (portal > 0xff || area1 > 0xff || area2 > 0xff)
{ {
ClientReliableWrite_Begin(client, svc_setportalstate, 4); ClientReliableWrite_Byte(client, 0xe0 | 2 | state);
if (portal >= 0x80) ClientReliableWrite_Short(client, portal);
{ //new pathway, to be enabled at some point ClientReliableWrite_Short(client, area1);
if (portal > 0xff) ClientReliableWrite_Short(client, area2);
{ }
ClientReliableWrite_Byte(client, 0x80 | 2 | state); else
ClientReliableWrite_Short(client, portal); {
} ClientReliableWrite_Byte(client, 0xe0 | 0 | state);
else ClientReliableWrite_Byte(client, portal);
{ ClientReliableWrite_Byte(client, area1);
ClientReliableWrite_Byte(client, 0x80 | 0 | state); ClientReliableWrite_Byte(client, area2);
ClientReliableWrite_Byte(client, portal);
}
}
else
ClientReliableWrite_Short(client, portal | (state<<15));
} }
} }
CMQ2_SetAreaPortalState(sv.world.worldmodel, portal, state);
} }
#endif if (sv.world.worldmodel->funcs.SetAreaPortalState)
#ifdef Q3BSPS sv.world.worldmodel->funcs.SetAreaPortalState(sv.world.worldmodel, portal, area1, area2, state);
if (sv.world.worldmodel->fromgame == fg_quake3)
{
int i;
int state = G_FLOAT(OFS_PARM1)!=0;
client_t *client;
edict_t *portal = G_EDICT(prinst, OFS_PARM0);
int area1 = portal->pvsinfo.areanum, area2 = portal->pvsinfo.areanum2;
if (area1 == area2 || area1<0 || area2<0)
return;
for (client = svs.clients, i = 0; i < sv.allocated_client_slots; i++, client++)
{
if (client->state >= cs_connected)
{
ClientReliableWrite_Begin(client, svc_setportalstate, 6);
if (area1 > 0xff || area2 > 0xff)
{
ClientReliableWrite_Byte(client, 0xc0 | 2 | state);
ClientReliableWrite_Short(client, area1);
ClientReliableWrite_Short(client, area2);
}
else
{
ClientReliableWrite_Byte(client, 0xc0 | 0 | state);
ClientReliableWrite_Byte(client, area1);
ClientReliableWrite_Byte(client, area2);
}
}
}
CMQ3_SetAreaPortalState(sv.world.worldmodel, portal->pvsinfo.areanum, portal->pvsinfo.areanum2, state);
}
#endif
} }
//EXTENSION: KRIMZON_SV_PARSECLIENTCOMMAND //EXTENSION: KRIMZON_SV_PARSECLIENTCOMMAND

View File

@ -105,7 +105,7 @@ Q2SOLID_BSP // bsp clip, touch on edge
struct link_s *prev, *next; struct link_s *prev, *next;
} link_t;*/ } link_t;*/
#define MAX_ENT_CLUSTERS 16 #define Q2MAX_ENT_CLUSTERS 16
//typedef struct edict_s edict_t; //typedef struct edict_s edict_t;
@ -160,7 +160,7 @@ struct q2edict_s
link_t area; // linked to a division node or leaf link_t area; // linked to a division node or leaf
int num_clusters; // if -1, use headnode instead int num_clusters; // if -1, use headnode instead
int clusternums[MAX_ENT_CLUSTERS]; int clusternums[Q2MAX_ENT_CLUSTERS];
int headnode; // unused if num_clusters != -1 int headnode; // unused if num_clusters != -1
int areanum, areanum2; int areanum, areanum2;

View File

@ -574,7 +574,7 @@ qboolean SV_LoadLevelCache(const char *savename, const char *level, const char *
sv.strings.q2_extrasounds[i] = NULL; sv.strings.q2_extrasounds[i] = NULL;
} }
//Read portal state //Read portal state
CM_ReadPortalState(sv.world.worldmodel, s, (file+filelen)-s); sv.world.worldmodel->funcs.LoadAreaPortalBlob(sv.world.worldmodel, s, (file+filelen)-s);
FS_FreeFile(file); FS_FreeFile(file);
} }
@ -1022,7 +1022,7 @@ void SV_SaveLevelCache(const char *savedir, qboolean dontharmgame)
} }
VFS_WRITE(f, "", 1); VFS_WRITE(f, "", 1);
portalblobsize = CM_WritePortalState(sv.world.worldmodel, &portalblob); portalblobsize = sv.world.worldmodel->funcs.SaveAreaPortalBlob(sv.world.worldmodel, &portalblob);
VFS_WRITE(f, portalblob, portalblobsize); VFS_WRITE(f, portalblob, portalblobsize);
VFS_CLOSE(f); VFS_CLOSE(f);

View File

@ -1055,6 +1055,10 @@ void SV_SpawnServer (const char *server, const char *startspot, qboolean noents,
if (sv.world.worldmodel) if (sv.world.worldmodel)
FS_LoadMapPackFile(sv.world.worldmodel->name, sv.world.worldmodel->archive); FS_LoadMapPackFile(sv.world.worldmodel->name, sv.world.worldmodel->archive);
//reset the map's areaportal state... it might be dirty from a restart or so.
if (sv.world.worldmodel->funcs.LoadAreaPortalBlob)
sv.world.worldmodel->funcs.LoadAreaPortalBlob(sv.world.worldmodel, NULL, 0);
#ifndef SERVERONLY #ifndef SERVERONLY
current_loading_size+=10; current_loading_size+=10;
// SCR_BeginLoadingPlaque(); // SCR_BeginLoadingPlaque();
@ -1158,7 +1162,7 @@ MSV_OpenUserDatabase();
newgametype = GT_QUAKE3; newgametype = GT_QUAKE3;
#endif #endif
#ifdef Q2SERVER #ifdef Q2SERVER
else if ((sv.world.worldmodel->fromgame == fg_quake2 || sv.world.worldmodel->fromgame == fg_quake3) && !*pr_ssqc_progs.string && SVQ2_InitGameProgs()) //these are the rules for running a q2 server else if ((sv.world.worldmodel->fromgame == fg_quake2 || sv.world.worldmodel->fromgame == fg_quake3) && sv.world.worldmodel->funcs.AreasConnected && !*pr_ssqc_progs.string && SVQ2_InitGameProgs()) //these are the rules for running a q2 server
newgametype = GT_QUAKE2; //we loaded the dll newgametype = GT_QUAKE2; //we loaded the dll
#endif #endif
#ifdef VM_LUA #ifdef VM_LUA

View File

@ -522,7 +522,7 @@ void SV_MulticastProtExt(vec3_t origin, multicast_t to, int dimension_mask, int
{ {
client_t *client; client_t *client;
qbyte *mask; qbyte *mask;
int cluster; int cluster, area1, area2;
int j; int j;
qboolean reliable; qboolean reliable;
client_t *oneclient = NULL, *split; client_t *oneclient = NULL, *split;
@ -569,204 +569,10 @@ void SV_MulticastProtExt(vec3_t origin, multicast_t to, int dimension_mask, int
} }
} }
#if defined(Q2BSPS) || defined(Q3BSPS)
//in theory, this q2/q3 path is only still different thanks to areas, but it also supports q2 gamecode properly.
if (sv.world.worldmodel->fromgame == fg_quake2 || sv.world.worldmodel->fromgame == fg_quake3)
{
int area1, area2, leafnum;
reliable = false;
if (to != MULTICAST_ALL_R && to != MULTICAST_ALL)
{
leafnum = CM_PointLeafnum (sv.world.worldmodel, origin);
area1 = CM_LeafArea (sv.world.worldmodel, leafnum);
}
else
{
leafnum = 0; // just to avoid compiler warnings
area1 = 0;
}
switch (to)
{
case MULTICAST_ALL_R:
reliable = true; // intentional fallthrough
case MULTICAST_ALL:
leafnum = 0;
mask = NULL;
break;
case MULTICAST_PHS_R:
reliable = true; // intentional fallthrough
case MULTICAST_PHS:
leafnum = CM_PointLeafnum (sv.world.worldmodel, origin);
cluster = CM_LeafCluster (sv.world.worldmodel, leafnum);
mask = sv_nopvs.ival?NULL:CM_ClusterPHS (sv.world.worldmodel, cluster, NULL);
break;
case MULTICAST_PVS_R:
reliable = true; // intentional fallthrough
case MULTICAST_PVS:
leafnum = CM_PointLeafnum (sv.world.worldmodel, origin);
cluster = CM_LeafCluster (sv.world.worldmodel, leafnum);
mask = sv_nopvs.ival?NULL:CM_ClusterPVS (sv.world.worldmodel, cluster, NULL, PVM_FAST);
break;
case MULTICAST_ONE_R_NOSPECS:
case MULTICAST_ONE_R_SPECS:
reliable = true;
case MULTICAST_ONE_NOSPECS:
case MULTICAST_ONE_SPECS:
if (svprogfuncs)
{
edict_t *ent = PROG_TO_EDICT(svprogfuncs, pr_global_struct->msg_entity);
oneclient = svs.clients + NUM_FOR_EDICT(svprogfuncs, ent) - 1;
}
else
oneclient = NULL; //unsupported in this game mode
mask = NULL;
andspecs = (to==MULTICAST_ONE_R_SPECS||to==MULTICAST_ONE_SPECS);
break;
default:
mask = NULL;
SV_Error ("SV_Multicast: bad to:%i", to);
}
// send the data to all relevent clients
for (j = 0; j < svs.allocated_client_slots; j++)
{
client = &svs.clients[j];
if (client->state != cs_spawned)
continue;
if (client->controller)
continue; //FIXME: send if at least one of the players is near enough.
for (split = client, seat = 0; split; split = split->controlled, seat++)
{
if (client->protocol == SCP_QUAKEWORLD)
{
if (client->fteprotocolextensions & without)
{
// Con_Printf ("Version supressed multicast - without pext\n");
continue;
}
if (!(~client->fteprotocolextensions & ~with))
{
// Con_Printf ("Version supressed multicast - with pext\n");
continue;
}
}
if (oneclient)
{
if (oneclient != split)
{
if (andspecs && split->spectator && split->spec_track >= 0 && oneclient == &svs.clients[split->spec_track])
;
else
continue;
}
}
else if (mask)
{
if (split->penalties & BAN_BLIND)
continue;
#ifdef Q2SERVER
if (ge)
leafnum = CM_PointLeafnum (sv.world.worldmodel, split->q2edict->s.origin);
else
#endif
{
if (svprogfuncs)
{
if (!((int)split->edict->xv->dimension_see & dimension_mask))
continue;
}
leafnum = CM_PointLeafnum (sv.world.worldmodel, split->edict->v->origin);
}
cluster = CM_LeafCluster (sv.world.worldmodel, leafnum);
area2 = CM_LeafArea (sv.world.worldmodel, leafnum);
if (!CM_AreasConnected (sv.world.worldmodel, area1, area2))
continue;
if ( mask && (!(mask[cluster>>3] & (1<<(cluster&7)) ) ) )
continue;
}
break;
}
if (!split)
continue;
switch (client->protocol)
{
case SCP_BAD:
continue; //a bot.
default:
SV_Error("Multicast: Client is using a bad protocl");
case SCP_QUAKE3:
Con_Printf("Skipping multicast for q3 client\n");
break;
#ifdef NQPROT
case SCP_NETQUAKE:
case SCP_BJP3:
case SCP_FITZ666:
case SCP_DARKPLACES6:
case SCP_DARKPLACES7:
if (reliable)
{
ClientReliableCheckBlock(client, sv.nqmulticast.cursize);
ClientReliableWrite_SZ(client, sv.nqmulticast.data, sv.nqmulticast.cursize);
}
else
SZ_Write (&client->datagram, sv.nqmulticast.data, sv.nqmulticast.cursize);
break;
#endif
#ifdef Q2SERVER
case SCP_QUAKE2:
if (reliable)
{
ClientReliableCheckBlock(client, sv.q2multicast.cursize);
ClientReliableWrite_SZ(client, sv.q2multicast.data, sv.q2multicast.cursize);
}
else
SZ_Write (&client->datagram, sv.q2multicast.data, sv.q2multicast.cursize);
break;
#endif
case SCP_QUAKEWORLD:
if (reliable)
{
if (oneclient && seat)
{
ClientReliableCheckBlock(client, 2+sv.multicast.cursize);
ClientReliableWrite_Byte(client, svcfte_choosesplitclient);
ClientReliableWrite_Byte(client, seat);
}
else
ClientReliableCheckBlock(client, sv.multicast.cursize);
ClientReliableWrite_SZ(client, sv.multicast.data, sv.multicast.cursize);
}
else
{
if (oneclient && seat)
{
MSG_WriteByte (&client->datagram, svcfte_choosesplitclient);
MSG_WriteByte (&client->datagram, seat);
}
SZ_Write (&client->datagram, sv.multicast.data, sv.multicast.cursize);
}
break;
}
}
}
else
#endif
{ {
reliable = false; reliable = false;
area1=-1;
area2=-1;
switch (to) switch (to)
{ {
@ -779,13 +585,13 @@ void SV_MulticastProtExt(vec3_t origin, multicast_t to, int dimension_mask, int
case MULTICAST_PHS_R: case MULTICAST_PHS_R:
reliable = true; // intentional fallthrough reliable = true; // intentional fallthrough
case MULTICAST_PHS: case MULTICAST_PHS:
if (!sv.world.worldmodel->phs) /*broadcast if no pvs*/ if (!sv.world.worldmodel->phs || sv_nopvs.ival) /*broadcast if no pvs*/
mask = NULL; mask = NULL;
else else
{ {
cluster = sv.world.worldmodel->funcs.ClusterForPoint(sv.world.worldmodel, origin, NULL); cluster = sv.world.worldmodel->funcs.ClusterForPoint(sv.world.worldmodel, origin, &area1);
if (cluster >= 0) if (cluster >= 0)
mask = sv.world.worldmodel->phs + cluster*sv.world.worldmodel->pvsbytes; mask = sv.world.worldmodel->funcs.ClusterPHS(sv.world.worldmodel, cluster, NULL);
else else
mask = NULL; mask = NULL;
} }
@ -794,11 +600,16 @@ void SV_MulticastProtExt(vec3_t origin, multicast_t to, int dimension_mask, int
case MULTICAST_PVS_R: case MULTICAST_PVS_R:
reliable = true; // intentional fallthrough reliable = true; // intentional fallthrough
case MULTICAST_PVS: case MULTICAST_PVS:
cluster = sv.world.worldmodel->funcs.ClusterForPoint(sv.world.worldmodel, origin, NULL); if (sv_nopvs.ival)
if (cluster >= 0)
mask = sv.world.worldmodel->funcs.ClusterPVS(sv.world.worldmodel, cluster, NULL, PVM_FAST);
else
mask = NULL; mask = NULL;
else
{
cluster = sv.world.worldmodel->funcs.ClusterForPoint(sv.world.worldmodel, origin, &area1);
if (cluster >= 0)
mask = sv.world.worldmodel->funcs.ClusterPVS(sv.world.worldmodel, cluster, NULL, PVM_FAST);
else
mask = NULL;
}
break; break;
case MULTICAST_ONE_R_NOSPECS: case MULTICAST_ONE_R_NOSPECS:
@ -860,10 +671,21 @@ void SV_MulticastProtExt(vec3_t origin, multicast_t to, int dimension_mask, int
continue; continue;
} }
} }
else if (svprogfuncs) else
{ {
if (!((int)split->edict->xv->dimension_see & dimension_mask)) vec3_t pos;
continue; if (svprogfuncs)
{
if (!((int)split->edict->xv->dimension_see & dimension_mask))
continue;
VectorAdd(split->edict->v->origin, split->edict->v->view_ofs, pos);
}
#ifdef Q2SERVER
else if (ge)
VectorCopy(split->q2edict->s.origin, pos);
#endif
else
continue; //no idea where the player is...
if (!mask) //no pvs? broadcast. if (!mask) //no pvs? broadcast.
break; break;
@ -871,20 +693,17 @@ void SV_MulticastProtExt(vec3_t origin, multicast_t to, int dimension_mask, int
if (to == MULTICAST_PHS_R || to == MULTICAST_PHS) if (to == MULTICAST_PHS_R || to == MULTICAST_PHS)
{ //always in range if within 1024 units (consistent with quakeworld). { //always in range if within 1024 units (consistent with quakeworld).
vec3_t delta; vec3_t delta;
VectorSubtract(origin, split->edict->v->origin, delta); VectorSubtract(origin, pos, delta);
if (DotProduct(delta, delta) <= 1024*1024) if (DotProduct(delta, delta) <= 1024*1024)
break; break;
} }
cluster = sv.world.worldmodel->funcs.ClusterForPoint (sv.world.worldmodel, pos, &area2);
if (cluster>= 0 && (!(mask[cluster>>3] & (1<<(cluster&7)) ) ||
(sv.world.worldmodel->funcs.AreasConnected && !sv.world.worldmodel->funcs.AreasConnected (sv.world.worldmodel, area1, area2))))
{ {
vec3_t pos; // Con_Printf ("PVS supressed multicast\n");
VectorAdd(split->edict->v->origin, split->edict->v->view_ofs, pos); continue;
cluster = sv.world.worldmodel->funcs.ClusterForPoint (sv.world.worldmodel, pos, NULL);
if (cluster>= 0 && !(mask[cluster>>3] & (1<<(cluster&7)) ) )
{
// Con_Printf ("PVS supressed multicast\n");
continue;
}
} }
} }
break; break;

View File

@ -2301,6 +2301,14 @@ void SV_Begin_Core(client_t *split)
split->edict->v->maxs[0] = 16; split->edict->v->maxs[0] = 16;
split->edict->v->maxs[1] = 16; split->edict->v->maxs[1] = 16;
split->edict->v->maxs[2] = 32; split->edict->v->maxs[2] = 32;
split->edict->v->view_ofs[2] = DEFAULT_VIEWHEIGHT;
if (sv.world.worldmodel->fromgame == fg_quake3)
split->edict->v->view_ofs[2] = 26; //q3 defaults to slightly higher view heights (though same player size as quake).
if (sv.world.worldmodel->hulls[1].clip_maxs[2]-sv.world.worldmodel->hulls[1].clip_mins[2]>0)
{
VectorCopy(sv.world.worldmodel->hulls[1].clip_mins, split->edict->v->mins);
VectorCopy(sv.world.worldmodel->hulls[1].clip_maxs, split->edict->v->maxs);
}
split->edict->v->movetype = MOVETYPE_NOCLIP; split->edict->v->movetype = MOVETYPE_NOCLIP;
} }
VectorCopy(split->edict->v->origin, split->edict->v->oldorigin); //make sure oldorigin isn't 0 0 0 or anything too clumsy like that. stuck somewhere killable is better than stuck outside the map. VectorCopy(split->edict->v->origin, split->edict->v->oldorigin); //make sure oldorigin isn't 0 0 0 or anything too clumsy like that. stuck somewhere killable is better than stuck outside the map.

View File

@ -725,7 +725,6 @@ void SVQ2_BuildClientFrame (client_t *client)
for (seat = 0, split = client; split; split = split->controlled, seat++) for (seat = 0, split = client; split; split = split->controlled, seat++)
{ {
int clientcluster; int clientcluster;
int leafnum;
clent[seat] = split->q2edict; clent[seat] = split->q2edict;
frame->clientnum[seat] = split - svs.clients; frame->clientnum[seat] = split - svs.clients;
@ -743,16 +742,14 @@ void SVQ2_BuildClientFrame (client_t *client)
for (i=0 ; i<3 ; i++) for (i=0 ; i<3 ; i++)
org[seat][i] = clent[seat]->client->ps.pmove.origin[i]*0.125 + clent[seat]->client->ps.viewoffset[i]; org[seat][i] = clent[seat]->client->ps.pmove.origin[i]*0.125 + clent[seat]->client->ps.viewoffset[i];
leafnum = CM_PointLeafnum (sv.world.worldmodel, org[seat]); clientcluster = sv.world.worldmodel->funcs.ClusterForPoint (sv.world.worldmodel, org[seat], &clientarea[seat]);
clientarea[seat] = CM_LeafArea (sv.world.worldmodel, leafnum);
clientcluster = CM_LeafCluster (sv.world.worldmodel, leafnum);
// calculate the visible areas // calculate the visible areas
frame->areabytes = CM_WriteAreaBits (sv.world.worldmodel, frame->areabits, clientarea[seat], seat != 0); frame->areabytes = sv.world.worldmodel->funcs.WriteAreaBits (sv.world.worldmodel, frame->areabits, sizeof(frame->areabits), clientarea[seat], seat != 0);
sv.world.worldmodel->funcs.FatPVS(sv.world.worldmodel, org[seat], &clientpvs, seat!=0); sv.world.worldmodel->funcs.FatPVS(sv.world.worldmodel, org[seat], &clientpvs, seat!=0);
if (seat==0) //FIXME if (seat==0) //FIXME
clientphs = CM_ClusterPHS (sv.world.worldmodel, clientcluster, NULL); clientphs = sv.world.worldmodel->funcs.ClusterPHS (sv.world.worldmodel, clientcluster, NULL);
frame->ps[seat] = clent[seat]->client->ps; frame->ps[seat] = clent[seat]->client->ps;
if (sv.paused) if (sv.paused)
@ -790,11 +787,11 @@ void SVQ2_BuildClientFrame (client_t *client)
if (ent != clent[seat]) if (ent != clent[seat])
{ {
// check area // check area
if (!CM_AreasConnected (sv.world.worldmodel, clientarea[seat], ent->areanum)) if (!sv.world.worldmodel->funcs.AreasConnected (sv.world.worldmodel, clientarea[seat], ent->areanum))
{ // doors can legally straddle two areas, so { // doors can legally straddle two areas, so
// we may need to check another one // we may need to check another one
if (!ent->areanum2 if (!ent->areanum2
|| !CM_AreasConnected (sv.world.worldmodel, clientarea[seat], ent->areanum2)) || !sv.world.worldmodel->funcs.AreasConnected (sv.world.worldmodel, clientarea[seat], ent->areanum2))
continue; // blocked by a door continue; // blocked by a door
} }
@ -812,7 +809,10 @@ void SVQ2_BuildClientFrame (client_t *client)
if (ent->num_clusters == -1) if (ent->num_clusters == -1)
{ // too many leafs for individual check, go by headnode { // too many leafs for individual check, go by headnode
if (!CM_HeadnodeVisible (sv.world.worldmodel, ent->headnode, clientpvs.buffer)) pvscache_t cache;
cache.num_leafs = -1;
cache.headnode = ent->headnode;
if (!sv.world.worldmodel->funcs.EdictInFatPVS(sv.world.worldmodel, &cache, clientpvs.buffer, NULL))
continue; continue;
c_fullsend++; c_fullsend++;
} }

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) static qboolean VARGS PFQ2_inPVS (vec3_t p1, vec3_t p2)
{ {
int leafnum;
int cluster; int cluster;
int area1, area2; int area1, area2;
qbyte *mask; qbyte *mask;
//FIXME: requires q2/q3 bsp cluster = sv.world.worldmodel->funcs.ClusterForPoint(sv.world.worldmodel, p1, &area1);
leafnum = CM_PointLeafnum (sv.world.worldmodel, p1); mask = sv.world.worldmodel->funcs.ClusterPVS (sv.world.worldmodel, cluster, NULL, PVM_FAST);
cluster = CM_LeafCluster (sv.world.worldmodel, leafnum);
area1 = CM_LeafArea (sv.world.worldmodel, leafnum);
mask = CM_ClusterPVS (sv.world.worldmodel, cluster, NULL, PVM_FAST);
leafnum = CM_PointLeafnum (sv.world.worldmodel, p2); cluster = sv.world.worldmodel->funcs.ClusterForPoint(sv.world.worldmodel, p2, &area2);
cluster = CM_LeafCluster (sv.world.worldmodel, leafnum);
area2 = CM_LeafArea (sv.world.worldmodel, leafnum);
if ( mask && (!(mask[cluster>>3] & (1<<(cluster&7)) ) ) ) if ( mask && (!(mask[cluster>>3] & (1<<(cluster&7)) ) ) )
return false; return false;
if (!CM_AreasConnected (sv.world.worldmodel, area1, area2)) if (!sv.world.worldmodel->funcs.AreasConnected (sv.world.worldmodel, area1, area2))
return false; // a door blocks sight return false; // a door blocks sight
return true; return true;
} }
@ -506,23 +500,17 @@ Also checks portalareas so that doors block sound
*/ */
static qboolean VARGS PFQ2_inPHS (vec3_t p1, vec3_t p2) static qboolean VARGS PFQ2_inPHS (vec3_t p1, vec3_t p2)
{ {
int leafnum;
int cluster; int cluster;
int area1, area2; int area1, area2;
qbyte *mask; qbyte *mask;
//FIXME: requires q2/q3 bsp cluster = sv.world.worldmodel->funcs.ClusterForPoint(sv.world.worldmodel, p1, &area1);
leafnum = CM_PointLeafnum (sv.world.worldmodel, p1); mask = sv.world.worldmodel->funcs.ClusterPHS (sv.world.worldmodel, cluster, NULL);
cluster = CM_LeafCluster (sv.world.worldmodel, leafnum);
area1 = CM_LeafArea (sv.world.worldmodel, leafnum);
mask = CM_ClusterPHS (sv.world.worldmodel, cluster, NULL);
leafnum = CM_PointLeafnum (sv.world.worldmodel, p2); cluster = sv.world.worldmodel->funcs.ClusterForPoint(sv.world.worldmodel, p2, &area2);
cluster = CM_LeafCluster (sv.world.worldmodel, leafnum);
area2 = CM_LeafArea (sv.world.worldmodel, leafnum);
if ( mask && (!(mask[cluster>>3] & (1<<(cluster&7)) ) ) ) if ( mask && (!(mask[cluster>>3] & (1<<(cluster&7)) ) ) )
return false; // more than one bounce away return false; // more than one bounce away
if (!CM_AreasConnected (sv.world.worldmodel, area1, area2)) if (!sv.world.worldmodel->funcs.AreasConnected (sv.world.worldmodel, area1, area2))
return false; // a door blocks hearing return false; // a door blocks hearing
return true; return true;
@ -531,7 +519,7 @@ static qboolean VARGS PFQ2_inPHS (vec3_t p1, vec3_t p2)
qboolean VARGS PFQ2_AreasConnected(unsigned int area1, unsigned int area2) qboolean VARGS PFQ2_AreasConnected(unsigned int area1, unsigned int area2)
{ {
//FIXME: requires q2/q3 bsp //FIXME: requires q2/q3 bsp
return CM_AreasConnected(sv.world.worldmodel, area1, area2); return sv.world.worldmodel->funcs.AreasConnected(sv.world.worldmodel, area1, area2);
} }
@ -823,7 +811,8 @@ void SVQ2_InitWorld(void)
static void QDECL PFQ2_SetAreaPortalState(unsigned int p, qboolean s) static void QDECL PFQ2_SetAreaPortalState(unsigned int p, qboolean s)
{ {
CMQ2_SetAreaPortalState(sv.world.worldmodel, p, s); if (sv.world.worldmodel->funcs.SetAreaPortalState)
sv.world.worldmodel->funcs.SetAreaPortalState(sv.world.worldmodel, p, -1, -1, s);
} }
static void *VARGS ZQ2_TagMalloc(int size, int tag) static void *VARGS ZQ2_TagMalloc(int size, int tag)

View File

@ -5,10 +5,6 @@
#ifdef Q3SERVER #ifdef Q3SERVER
#ifndef MAX_ENT_CLUSTERS
#define MAX_ENT_CLUSTERS 16
#endif
#define USEBOTLIB #define USEBOTLIB
#ifdef USEBOTLIB #ifdef USEBOTLIB
@ -135,11 +131,8 @@ typedef struct {
link_t area; link_t area;
#endif #endif
qboolean linked; qboolean linked;
int areanum;
int areanum2; pvscache_t pvscache;
int headnode;
int num_clusters;
int clusternums[MAX_ENT_CLUSTERS];
} q3serverEntity_t; } q3serverEntity_t;
q3serverEntity_t *q3_sentities; q3serverEntity_t *q3_sentities;
@ -211,12 +204,7 @@ static void Q3G_LinkEntity(q3sharedEntity_t *ent)
areanode_t *node; areanode_t *node;
#endif #endif
q3serverEntity_t *sent; q3serverEntity_t *sent;
int leafs[MAX_TOTAL_ENT_LEAFS];
int clusters[MAX_TOTAL_ENT_LEAFS];
int num_leafs;
int i, j, k; int i, j, k;
int area;
int topnode;
const float *origin; const float *origin;
const float *angles; const float *angles;
@ -291,83 +279,8 @@ static void Q3G_LinkEntity(q3sharedEntity_t *ent)
ent->r.absmax[2] += 1; ent->r.absmax[2] += 1;
// link to PVS leafs // link to PVS leafs
sent->num_clusters = 0; sv.world.worldmodel->funcs.FindTouchedLeafs(sv.world.worldmodel, &sent->pvscache, ent->r.absmin, ent->r.absmax);
sent->areanum = -1; //FIXME: return if no leafs
sent->areanum2 = -1;
//get all leafs, including solids
if (sv.world.worldmodel->type == mod_heightmap)
{
sent->areanum = 0;
num_leafs = 1;
sent->num_clusters = -1;
sent->headnode = 0;
clusters[0] = 0;
topnode = 0;
}
else
{
num_leafs = CM_BoxLeafnums(sv.world.worldmodel, ent->r.absmin, ent->r.absmax,
leafs, MAX_TOTAL_ENT_LEAFS, &topnode);
if(!num_leafs)
return;
// set areas
for(i=0; i<num_leafs; i++)
{
clusters[i] = CM_LeafCluster(sv.world.worldmodel, leafs[i]);
area = CM_LeafArea(sv.world.worldmodel, leafs[i]);
if(area >= 0)
{
// doors may legally straggle two areas,
// but nothing should ever need more than that
if(sent->areanum >= 0 && sent->areanum != area)
{
if(sent->areanum2 >= 0 && sent->areanum2 != area && sv.state == ss_loading)
Con_DPrintf("Object touching 3 areas at %f %f %f\n", ent->r.absmin[0], ent->r.absmin[1], ent->r.absmin[2]);
sent->areanum2 = area;
}
else
sent->areanum = area;
}
}
}
if(num_leafs >= MAX_TOTAL_ENT_LEAFS)
{
// assume we missed some leafs, and mark by headnode
sent->num_clusters = -1;
sent->headnode = topnode;
}
else
{
sent->num_clusters = 0;
for(i=0; i<num_leafs; i++)
{
if(clusters[i] == -1)
continue; // not a visible leaf
for(j=0 ; j<i ; j++)
{
if(clusters[j] == clusters[i])
break;
}
if(j == i)
{
if(sent->num_clusters == MAX_ENT_CLUSTERS)
{
// assume we missed some leafs, and mark by headnode
sent->num_clusters = -1;
sent->headnode = topnode;
break;
}
sent->clusternums[sent->num_clusters++] = clusters[i];
}
}
}
ent->r.linkcount++; ent->r.linkcount++;
ent->r.linked = true; ent->r.linked = true;
@ -856,9 +769,9 @@ static int SVQ3_BotGetSnapshotEntity(int client, int entnum)
static void SVQ3_Adjust_Area_Portal_State(q3sharedEntity_t *ge, qboolean open) static void SVQ3_Adjust_Area_Portal_State(q3sharedEntity_t *ge, qboolean open)
{ {
q3serverEntity_t *se = SENTITY_FOR_GENTITY(ge); q3serverEntity_t *se = SENTITY_FOR_GENTITY(ge);
if (se->areanum == -1 || se->areanum2 == -1) //not linked properly. if (se->pvscache.areanum == -1 || se->pvscache.areanum2 == -1) //not linked properly.
return; return;
CMQ3_SetAreaPortalState(sv.world.worldmodel, se->areanum, se->areanum2, open); sv.world.worldmodel->funcs.SetAreaPortalState(sv.world.worldmodel, -1, se->pvscache.areanum, se->pvscache.areanum2, open);
} }
static qboolean SV_InPVS(vec3_t p1, vec3_t p2) static qboolean SV_InPVS(vec3_t p1, vec3_t p2)
@ -871,37 +784,18 @@ static qboolean SV_InPVS(vec3_t p1, vec3_t p2)
return true; //no pvs info, assume everything is visible return true; //no pvs info, assume everything is visible
else else
{ {
#if 1 int a1, c1 = worldmodel->funcs.ClusterForPoint(worldmodel, p1, &a1);
int l1 = CM_PointLeafnum(worldmodel, p1); int a2, c2 = worldmodel->funcs.ClusterForPoint(worldmodel, p2, &a2);
int l2 = CM_PointLeafnum(worldmodel, p2);
int c1 = CM_LeafCluster(worldmodel, l1);
int c2 = CM_LeafCluster(worldmodel, l2);
qbyte *pvs; qbyte *pvs;
if (c1 < 0 || c2 < 0) if (c1 < 0 || c2 < 0)
return (c1<0); //outside can see in, inside cannot (normally) see out. return (c1<0); //outside can see in, inside cannot (normally) see out.
pvs = CM_ClusterPVS(worldmodel, c1, NULL, PVM_FAST); pvs = worldmodel->funcs.ClusterPVS(worldmodel, c1, NULL, PVM_FAST);
if (pvs[c2>>3] & (1<<(c2&7))) if (pvs[c2>>3] & (1<<(c2&7)))
{ {
int a1 = CM_LeafArea(worldmodel, l1); if (worldmodel->funcs.AreasConnected(worldmodel, a1, a2))
int a2 = CM_LeafArea(worldmodel, l2);
if (CM_AreasConnected(worldmodel, a1, a2))
return true; return true;
} }
return false; return false;
#else
const qbyte *mask;
int c1 = worldmodel->funcs.ClusterForPoint(worldmodel, p1);
int c2 = worldmodel->funcs.ClusterForPoint(worldmodel, p2);
if (c1 < 0 || c2 < 0)
return true; //one is outside of the world, so can see inside.
mask = worldmodel->funcs.ClusterPVS(worldmodel, c1, NULL, PVM_FAST);
if (mask[c2>>3] & (1<<(c2&7)))
{
//FIXME: check areas/portals too
return true; //visible
}
return false; //nope. :(
#endif
} }
} }
@ -2015,8 +1909,6 @@ qboolean SVQ3_InitGame(qboolean restart)
mapentspointer = Mod_GetEntitiesString(sv.world.worldmodel); mapentspointer = Mod_GetEntitiesString(sv.world.worldmodel);
VM_Call(q3gamevm, GAME_INIT, (intptr_t)(sv.time*1000), (int)rand(), restart); VM_Call(q3gamevm, GAME_INIT, (intptr_t)(sv.time*1000), (int)rand(), restart);
CM_InitBoxHull();
if (!restart) if (!restart)
{ {
SVQ3_CreateBaseline(); SVQ3_CreateBaseline();
@ -2312,9 +2204,6 @@ static int VARGS SVQ3_QsortEntityStates( const void *arg1, const void *arg2 )
static qboolean SVQ3_EntityIsVisible(q3client_frame_t *snap, q3sharedEntity_t *ent) static qboolean SVQ3_EntityIsVisible(q3client_frame_t *snap, q3sharedEntity_t *ent)
{ {
q3serverEntity_t *sent; q3serverEntity_t *sent;
int i;
int l;
if (!ent->r.linked) if (!ent->r.linked)
{ {
return false; // not active entity return false; // not active entity
@ -2367,56 +2256,17 @@ static qboolean SVQ3_EntityIsVisible(q3client_frame_t *snap, q3sharedEntity_t *e
sent = SENTITY_FOR_GENTITY( ent ); sent = SENTITY_FOR_GENTITY( ent );
// check area // check area
if (sent->areanum < 0 || !(snap->areabits[sent->areanum >> 3] & (1 << (sent->areanum & 7)))) if (sent->pvscache.areanum < 0 || !(snap->areabits[sent->pvscache.areanum >> 3] & (1 << (sent->pvscache.areanum & 7))))
{ {
// doors can legally straddle two areas, so // doors can legally straddle two areas, so
// we may need to check another one // we may need to check another one
if (sent->areanum2 < 0 || !(snap->areabits[sent->areanum2 >> 3] & (1 << (sent->areanum2 & 7)))) if (sent->pvscache.areanum2 < 0 || !(snap->areabits[sent->pvscache.areanum2 >> 3] & (1 << (sent->pvscache.areanum2 & 7))))
{ {
return false; // blocked by a door return false; // blocked by a door
} }
} }
/* return sv.world.worldmodel->funcs.EdictInFatPVS(sv.world.worldmodel, &sent->pvscache, bitvector, NULL/*using the snapshots areabits rather than the bsp's*/);
// check area
if( !CM_AreasConnected( clientarea, sent->areanum ) )
{
// doors can legally straddle two areas, so
// we may need to check another one
if( !CM_AreasConnected( clientarea, sent->areanum2 ) )
{
return false; // blocked by a door
}
}
*/
if (sent->num_clusters == -1)
{
// too many leafs for individual check, go by headnode
if (!CM_HeadnodeVisible(sv.world.worldmodel, sent->headnode, bitvector))
{
return false;
}
}
else
{
// check individual leafs
for (i=0; i < sent->num_clusters; i++)
{
l = sent->clusternums[i];
if (bitvector[l >> 3] & (1 << (l & 7)))
{
break;
}
}
if (i == sent->num_clusters)
{
return false; // not visible
}
}
return true;
} }
#ifdef Q3OVERQW #ifdef Q3OVERQW
@ -2530,9 +2380,7 @@ void SVQ3_BuildClientSnapshot( client_t *client )
VectorCopy( ps->origin, org ); VectorCopy( ps->origin, org );
org[2] += ps->viewheight; org[2] += ps->viewheight;
clientarea = CM_PointLeafnum(sv.world.worldmodel, org); bitvector = sv.world.worldmodel->funcs.ClusterPVS(sv.world.worldmodel, sv.world.worldmodel->funcs.ClusterForPoint(sv.world.worldmodel, org, &clientarea), &pvsbuffer, PVM_REPLACE);
bitvector = sv.world.worldmodel->funcs.ClusterPVS(sv.world.worldmodel, CM_LeafCluster(sv.world.worldmodel, clientarea), &pvsbuffer, PVM_REPLACE);
clientarea = CM_LeafArea(sv.world.worldmodel, clientarea);
/* /*
if (client->areanum != clientarea) if (client->areanum != clientarea)
{ {
@ -2542,7 +2390,7 @@ void SVQ3_BuildClientSnapshot( client_t *client )
*/ */
// calculate the visible areas // calculate the visible areas
snap->areabytes = CM_WriteAreaBits(sv.world.worldmodel, snap->areabits, clientarea, false); snap->areabytes = sv.world.worldmodel->funcs.WriteAreaBits(sv.world.worldmodel, snap->areabits, sizeof(snap->areabits), clientarea, false);
// grab the current playerState_t // grab the current playerState_t
memcpy(&snap->ps, ps, sizeof(snap->ps)); memcpy(&snap->ps, ps, sizeof(snap->ps));
@ -2565,13 +2413,10 @@ void SVQ3_BuildClientSnapshot( client_t *client )
if(!SVQ3_EntityIsVisible(snap, ent)) if(!SVQ3_EntityIsVisible(snap, ent))
continue; continue;
// merge PVS if portal
portalarea = CM_PointLeafnum(sv.world.worldmodel, ent->s.origin2);
//merge pvs bits so we can see other ents through it //merge pvs bits so we can see other ents through it
sv.world.worldmodel->funcs.ClusterPVS(sv.world.worldmodel, CM_LeafCluster(sv.world.worldmodel, portalarea), &pvsbuffer, PVM_MERGE); sv.world.worldmodel->funcs.ClusterPVS(sv.world.worldmodel, sv.world.worldmodel->funcs.ClusterForPoint(sv.world.worldmodel, ent->s.origin2, &portalarea), &pvsbuffer, PVM_MERGE);
//and merge areas, so we can see the world too (client will calc its own pvs) //and areabits too
portalarea = CM_LeafArea(sv.world.worldmodel, portalarea); sv.world.worldmodel->funcs.WriteAreaBits(sv.world.worldmodel, snap->areabits, snap->areabytes, portalarea, true);
CM_WriteAreaBits(sv.world.worldmodel, snap->areabits, portalarea, true);
} }
// add all visible entities // add all visible entities

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) void VARGS WorldQ2_LinkEdict(world_t *w, q2edict_t *ent)
{ {
areanode_t *node; areanode_t *node;
int leafs[128];
int clusters[countof(leafs)];
int num_leafs;
int i, j;
int area;
int topnode;
if (ent->area.prev) if (ent->area.prev)
WorldQ2_UnlinkEdict (w, ent); // unlink from old position WorldQ2_UnlinkEdict (w, ent); // unlink from old position
@ -822,56 +816,18 @@ void VARGS WorldQ2_LinkEdict(world_t *w, q2edict_t *ent)
ent->absmax[2] += 1; ent->absmax[2] += 1;
// link to PVS leafs // link to PVS leafs
ent->num_clusters = 0;
ent->areanum = 0;
ent->areanum2 = 0;
//get all leafs, including solids
num_leafs = CM_BoxLeafnums (w->worldmodel, ent->absmin, ent->absmax,
leafs, countof(leafs), &topnode);
// set areas
for (i=0 ; i<num_leafs ; i++)
{ {
clusters[i] = CM_LeafCluster (w->worldmodel, leafs[i]); pvscache_t cache;
area = CM_LeafArea (w->worldmodel, leafs[i]); w->worldmodel->funcs.FindTouchedLeafs(w->worldmodel, &cache, ent->absmin, ent->absmax);
if (area)
{ // doors may legally straggle two areas,
// but nothing should evern need more than that
if (ent->areanum && ent->areanum != area)
ent->areanum2 = area;
else
ent->areanum = area;
}
}
if (num_leafs >= countof(leafs)) //evilness: copy into the q2 state (we don't have anywhere else to store it, and there's a chance that the gamecode will care).
{ // assume we missed some leafs, and mark by headnode ent->num_clusters = cache.num_leafs;
ent->num_clusters = -1; if (ent->num_clusters > (int)countof(ent->clusternums))
ent->headnode = topnode; ent->num_clusters = (int)countof(ent->clusternums);
} memcpy(ent->clusternums, cache.leafnums, min(sizeof(ent->clusternums), sizeof(cache.leafnums)));
else ent->headnode = cache.headnode;
{ ent->areanum = cache.areanum;
ent->num_clusters = 0; ent->areanum2 = cache.areanum2;
for (i=0 ; i<num_leafs ; i++)
{
if (clusters[i] == -1)
continue; // not a visible leaf
for (j=0 ; j<i ; j++)
if (clusters[j] == clusters[i])
break;
if (j == i)
{
if (ent->num_clusters == MAX_ENT_CLUSTERS)
{ // assume we missed some leafs, and mark by headnode
ent->num_clusters = -1;
ent->headnode = topnode;
break;
}
ent->clusternums[ent->num_clusters++] = clusters[i];
}
}
} }
// if first time, make sure old_origin is valid // if first time, make sure old_origin is valid
@ -901,255 +857,11 @@ void VARGS WorldQ2_LinkEdict(world_t *w, q2edict_t *ent)
// link it in // link it in
InsertLinkBefore (&ent->area, &node->edicts); InsertLinkBefore (&ent->area, &node->edicts);
} }
void WorldQ2_Q1BSP_LinkEdict(world_t *w, q2edict_t *ent)
{
areanode_t *node;
int i, j, k;
if (ent->area.prev)
WorldQ2_UnlinkEdict (w, ent); // unlink from old position
if (ent == ge->edicts)
return; // don't add the world
if (!ent->inuse)
return;
// set the size
VectorSubtract (ent->maxs, ent->mins, ent->size);
// encode the size into the entity_state for client prediction
if (ent->solid == Q2SOLID_BBOX && !(ent->svflags & SVF_DEADMONSTER))
{ // assume that x/y are equal and symetric
i = ent->maxs[0]/8;
if (i<1)
i = 1;
if (i>31)
i = 31;
// z is not symetric
j = (-ent->mins[2])/8;
if (j<1)
j = 1;
if (j>31)
j = 31;
// and z maxs can be negative...
k = (ent->maxs[2]+32)/8;
if (k<1)
k = 1;
if (k>63)
k = 63;
ent->s.solid = (k<<10) | (j<<5) | i;
}
else if (ent->solid == Q2SOLID_BSP)
{
ent->s.solid = 31; // a solid_bbox will never create this value
}
else
ent->s.solid = 0;
// set the abs box
if (ent->solid == Q2SOLID_BSP &&
(ent->s.angles[0] || ent->s.angles[1] || ent->s.angles[2]) )
{ // expand for rotation
float max, v;
int i;
max = 0;
for (i=0 ; i<3 ; i++)
{
v =fabs( ent->mins[i]);
if (v > max)
max = v;
v =fabs( ent->maxs[i]);
if (v > max)
max = v;
}
for (i=0 ; i<3 ; i++)
{
ent->absmin[i] = ent->s.origin[i] - max;
ent->absmax[i] = ent->s.origin[i] + max;
}
}
else
{ // normal
VectorAdd (ent->s.origin, ent->mins, ent->absmin);
VectorAdd (ent->s.origin, ent->maxs, ent->absmax);
}
// because movement is clipped an epsilon away from an actual edge,
// we must fully check even when bounding boxes don't quite touch
ent->absmin[0] -= 1;
ent->absmin[1] -= 1;
ent->absmin[2] -= 1;
ent->absmax[0] += 1;
ent->absmax[1] += 1;
ent->absmax[2] += 1;
// link to PVS leafs
ent->num_clusters = 0;
ent->areanum = 0;
ent->areanum2 = 0;
ent->areanum = 1;
/*
//get all leafs, including solids
num_leafs = CM_BoxLeafnums (ent->absmin, ent->absmax,
leafs, MAX_TOTAL_ENT_LEAFS, &topnode);
// set areas
for (i=0 ; i<num_leafs ; i++)
{
clusters[i] = CM_LeafCluster (leafs[i]);
area = CM_LeafArea (leafs[i]);
if (area)
{ // doors may legally straggle two areas,
// but nothing should evern need more than that
if (ent->areanum && ent->areanum != area)
{
ent->areanum2 = area;
}
else
ent->areanum = area;
}
}
if (num_leafs >= MAX_TOTAL_ENT_LEAFS)
{ // assume we missed some leafs, and mark by headnode
ent->num_clusters = -1;
ent->headnode = topnode;
}
else
{
ent->num_clusters = 0;
for (i=0 ; i<num_leafs ; i++)
{
if (clusters[i] == -1)
continue; // not a visible leaf
for (j=0 ; j<i ; j++)
if (clusters[j] == clusters[i])
break;
if (j == i)
{
if (ent->num_clusters == MAX_ENT_CLUSTERS)
{ // assume we missed some leafs, and mark by headnode
ent->num_clusters = -1;
ent->headnode = topnode;
break;
}
ent->clusternums[ent->num_clusters++] = clusters[i];
}
}
}
*/
// if first time, make sure old_origin is valid
if (!ent->linkcount)
{
VectorCopy (ent->s.origin, ent->s.old_origin);
}
ent->linkcount++;
if (ent->solid == Q2SOLID_NOT)
return;
// find the first node that the ent's box crosses
node = w->areanodes;
while (1)
{
if (node->axis == -1)
break;
if (ent->absmin[node->axis] > node->dist)
node = node->children[0];
else if (ent->absmax[node->axis] < node->dist)
node = node->children[1];
else
break; // crosses the node
}
// link it in
InsertLinkBefore (&ent->area, &node->edicts);
}
#endif #endif
#if defined(Q2BSPS) || defined(Q3BSPS)
void Q23BSP_FindTouchedLeafs(model_t *model, struct pvscache_s *ent, const float *mins, const float *maxs)
{
#define MAX_TOTAL_ENT_LEAFS 128
int leafs[MAX_TOTAL_ENT_LEAFS];
int clusters[MAX_TOTAL_ENT_LEAFS];
int num_leafs;
int topnode;
int i, j;
int area;
int nullarea = (model->fromgame == fg_quake2)?0:-1;
//ent->num_leafs == q2's ent->num_clusters
ent->num_leafs = 0;
ent->areanum = nullarea;
ent->areanum2 = nullarea;
if (!mins || !maxs)
return;
//get all leafs, including solids
num_leafs = CM_BoxLeafnums (model, mins, maxs,
leafs, MAX_TOTAL_ENT_LEAFS, &topnode);
// set areas
for (i=0 ; i<num_leafs ; i++)
{
clusters[i] = CM_LeafCluster (model, leafs[i]);
area = CM_LeafArea (model, leafs[i]);
if (area != nullarea)
{ // doors may legally straggle two areas,
// but nothing should ever need more than that
if (ent->areanum != nullarea && ent->areanum != area)
ent->areanum2 = area;
else
ent->areanum = area;
}
}
if (num_leafs >= MAX_TOTAL_ENT_LEAFS)
{ // assume we missed some leafs, and mark by headnode
ent->num_leafs = -1;
ent->headnode = topnode;
}
else
{
ent->num_leafs = 0;
for (i=0 ; i<num_leafs ; i++)
{
if (clusters[i] == -1)
continue; // not a visible leaf
for (j=0 ; j<i ; j++)
if (clusters[j] == clusters[i])
break;
if (j == i)
{
if (ent->num_leafs == MAX_ENT_LEAFS)
{ // assume we missed some leafs, and mark by headnode
ent->num_leafs = -1;
ent->headnode = topnode;
break;
}
ent->leafnums[ent->num_leafs++] = clusters[i];
}
}
}
}
#endif
/* /*
=============================================================================== ===============================================================================
@ -1905,9 +1617,13 @@ static void World_ClipToEverything (world_t *w, moveclip_t *clip)
trace = World_ClipMoveToEntity (w, touch, touch->v->origin, touch->v->angles, clip->start, clip->mins2, clip->maxs2, clip->end, clip->hullnum, clip->type & MOVE_HITMODEL, clip->capsule, clip->hitcontentsmask); trace = World_ClipMoveToEntity (w, touch, touch->v->origin, touch->v->angles, clip->start, clip->mins2, clip->maxs2, clip->end, clip->hullnum, clip->type & MOVE_HITMODEL, clip->capsule, clip->hitcontentsmask);
else else
trace = World_ClipMoveToEntity (w, touch, touch->v->origin, touch->v->angles, clip->start, clip->mins, clip->maxs, clip->end, clip->hullnum, clip->type & MOVE_HITMODEL, clip->capsule, clip->hitcontentsmask); trace = World_ClipMoveToEntity (w, touch, touch->v->origin, touch->v->angles, clip->start, clip->mins, clip->maxs, clip->end, clip->hullnum, clip->type & MOVE_HITMODEL, clip->capsule, clip->hitcontentsmask);
if (trace.allsolid || trace.startsolid ||
trace.fraction < clip->trace.fraction) if (trace.fraction < clip->trace.fraction)
{ {
//trace traveled less, but don't forget if we started in a solid.
trace.startsolid |= clip->trace.startsolid;
trace.allsolid |= clip->trace.allsolid;
if (clip->type & MOVE_ENTCHAIN) if (clip->type & MOVE_ENTCHAIN)
{ {
touch->v->chain = EDICT_TO_PROG(w->progs, clip->trace.ent?clip->trace.ent:w->edicts); touch->v->chain = EDICT_TO_PROG(w->progs, clip->trace.ent?clip->trace.ent:w->edicts);
@ -1915,10 +1631,24 @@ static void World_ClipToEverything (world_t *w, moveclip_t *clip)
} }
else else
{ {
trace.ent = touch; if (clip->trace.startsolid && !trace.startsolid)
trace.ent = clip->trace.ent; //something else hit earlier, that one gets the trace entity, but not the fraction. yeah, combining traces like this was always going to be weird.
else
trace.ent = touch;
clip->trace = trace; clip->trace = trace;
} }
} }
else if (trace.startsolid || trace.allsolid)
{
//even if the trace traveled less, we still care if it was in a solid.
clip->trace.startsolid |= trace.startsolid;
clip->trace.allsolid |= trace.allsolid;
clip->trace.contents |= trace.contents;
if (!clip->trace.ent || trace.fraction == clip->trace.fraction) //xonotic requires that second test (DP has no check at all, which would end up reporting mismatched fraction/ent results, so yuck).
{
clip->trace.ent = touch;
}
}
} }
} }
@ -2519,7 +2249,7 @@ static void World_ClipToNetwork (world_t *w, moveclip_t *clip)
continue; continue;
//lets say that ssqc ents are in dimension 0x1, as far as the csqc can see. //lets say that ssqc ents are in dimension 0x1, as far as the csqc can see.
if (!((int)clip->passedict->xv->dimension_hit & 1)) if (clip->passedict && !((int)clip->passedict->xv->dimension_hit & 1))
continue; continue;
framestate.g[FS_REG].frame[0] = touch->frame; framestate.g[FS_REG].frame[0] = touch->frame;