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