1
0
Fork 0
forked from fte/fteqw

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

@ -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;
@ -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);
@ -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,232 +816,20 @@ 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, //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).
// but nothing should evern need more than that ent->num_clusters = cache.num_leafs;
if (ent->areanum && ent->areanum != area) if (ent->num_clusters > (int)countof(ent->clusternums))
ent->areanum2 = area; ent->num_clusters = (int)countof(ent->clusternums);
else memcpy(ent->clusternums, cache.leafnums, min(sizeof(ent->clusternums), sizeof(cache.leafnums)));
ent->areanum = area; ent->headnode = cache.headnode;
} ent->areanum = cache.areanum;
ent->areanum2 = cache.areanum2;
} }
if (num_leafs >= countof(leafs))
{ // assume we missed some leafs, and mark by headnode
ent->num_clusters = -1;
ent->headnode = topnode;
}
else
{
ent->num_clusters = 0;
for (i=0 ; i<num_leafs ; i++)
{
if (clusters[i] == -1)
continue; // not a visible leaf
for (j=0 ; j<i ; j++)
if (clusters[j] == clusters[i])
break;
if (j == i)
{
if (ent->num_clusters == MAX_ENT_CLUSTERS)
{ // assume we missed some leafs, and mark by headnode
ent->num_clusters = -1;
ent->headnode = topnode;
break;
}
ent->clusternums[ent->num_clusters++] = clusters[i];
}
}
}
// 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);
}
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 first time, make sure old_origin is valid
if (!ent->linkcount) if (!ent->linkcount)
{ {
@ -1080,76 +862,6 @@ void WorldQ2_Q1BSP_LinkEdict(world_t *w, q2edict_t *ent)
#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;