From b3fa6d6dbda10adc660897366247ac9991cf0905 Mon Sep 17 00:00:00 2001 From: g-cont Date: Fri, 18 Jan 2008 00:00:00 +0300 Subject: [PATCH] 18 Jan 2008 --- changelog.log | 4 +- engine/client/cl_pred.c | 16 +- engine/pmove.c | 97 ++++--- engine/server/server.h | 11 +- engine/server/sv_cmds.c | 2 + engine/server/sv_edict.h | 13 +- engine/server/sv_ents.c | 43 +-- engine/server/sv_init.c | 2 +- engine/server/sv_phys.c | 16 +- engine/server/sv_spawn.c | 2 +- engine/server/sv_utils.c | 8 +- engine/server/sv_world.c | 579 ++++++++++++++++++++------------------- physic/cm_local.h | 13 +- physic/cm_model.c | 97 ++++++- physic/cm_test.c | 21 +- physic/cm_trace.c | 36 +-- physic/cm_utils.h | 9 +- pr_server/client.c | 1 + pr_server/func_mover.c | 6 + pr_server/funcs.c | 6 + pr_server/player.c | 4 + public/dllapi.h | 8 +- public/mathlib.h | 17 ++ public/stdref.h | 13 +- render/gl_model.c | 19 -- 25 files changed, 585 insertions(+), 458 deletions(-) diff --git a/changelog.log b/changelog.log index 4ff6006f..14818bd3 100644 --- a/changelog.log +++ b/changelog.log @@ -12,7 +12,6 @@ fopen // замеченные баги 1. viewer ничего не пишет в лог (сцуко) -2. Модели не рисуются для неотвизеных карт (даже самых мелких) // из неоконченного 0. Приделать бы всем утилитам разные иконки @@ -35,7 +34,8 @@ physic.dll 12.Подключить его к серверу и клиенту OK 13.Билдер коллижн мешей для бсп-моделей OK 14.Переписать трасинг OK - 15.Доделать трасинг + 15.Доделать трасинг OK + 16.Переписать pmove } Создание sdk_main diff --git a/engine/client/cl_pred.c b/engine/client/cl_pred.c index 3321c5be..e3452549 100644 --- a/engine/client/cl_pred.c +++ b/engine/client/cl_pred.c @@ -106,7 +106,7 @@ void CL_ClipMoveToEntities ( vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, } if( tr->allsolid ) return; - trace = pe->TransformedBoxTrace( start, end, mins, maxs, MASK_PLAYERSOLID, ent->origin, angles ); + trace = pe->TransformedBoxTrace( start, end, mins, maxs, cmodel, MASK_PLAYERSOLID, ent->origin, angles ); if( trace.allsolid || trace.startsolid || trace.fraction < tr->fraction ) { @@ -133,7 +133,7 @@ trace_t CL_PMTrace (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end) trace_t t; // check against world - t = pe->BoxTrace( start, end, mins, maxs, MASK_PLAYERSOLID ); + t = pe->BoxTrace( start, end, mins, maxs, NULL, MASK_PLAYERSOLID ); if (t.fraction < 1.0) t.ent = (edict_t *)1; // check all other solid models @@ -142,15 +142,15 @@ trace_t CL_PMTrace (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end) return t; } -int CL_PMpointcontents (vec3_t point) +int CL_PMpointcontents( vec3_t point ) { - int i; + int i; entity_state_t *ent; - int num; + int num; cmodel_t *cmodel; - int contents; + int contents; - contents = pe->PointContents( point ); + contents = pe->PointContents( point, NULL ); for( i = 0; i < cl.frame.num_entities; i++ ) { @@ -163,7 +163,7 @@ int CL_PMpointcontents (vec3_t point) cmodel = cl.model_clip[ent->modelindex]; if (!cmodel) continue; - contents |= pe->TransformedPointContents( point, ent->origin, ent->angles ); + contents |= pe->TransformedPointContents( point, cmodel, ent->origin, ent->angles ); } return contents; } diff --git a/engine/pmove.c b/engine/pmove.c index 602ff154..eec3ec3f 100644 --- a/engine/pmove.c +++ b/engine/pmove.c @@ -30,19 +30,26 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. typedef struct { - vec3_t origin; // full float precision - vec3_t velocity; // full float precision + vec3_t origin; + vec3_t velocity; + vec3_t previous_origin; + vec3_t previous_velocity; + int previous_waterlevel; vec3_t forward, right, up; float frametime; + int msec; + bool walking; + bool onladder; + trace_t groundtrace; + float impact_speed; csurface_t *groundsurface; cplane_t groundplane; int groundcontents; - vec3_t previous_origin; - bool ladder; + } pml_t; pmove_t *pm; @@ -81,14 +88,15 @@ void PM_ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce) float change; int i; - backoff = DotProduct (in, normal) * overbounce; + backoff = DotProduct (in, normal); - for (i=0 ; i<3 ; i++) + if( backoff < 0 ) backoff *= overbounce; + else backoff /= overbounce; + + for( i = 0; i < 3; i++ ) { change = normal[i]*backoff; out[i] = in[i] - change; - if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON) - out[i] = 0; } } @@ -286,48 +294,47 @@ Handles both ground friction and water friction ================== */ -void PM_Friction (void) +void PM_Friction( void ) { + vec3_t vec; float *vel; float speed, newspeed, control; - float friction; float drop; vel = pml.velocity; - - speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1] + vel[2]*vel[2]); - if (speed < 1) + + VectorCopy( vel, vec ); + if( pml.walking ) vec[2] = 0; // ignore slope movement + + speed = VectorLength( vec ); + Msg("speed %g\n", speed ); + if( speed < 1 ) { - vel[0] = 0; - vel[1] = 0; + vel[0] = vel[1] = 0; // allow sinking underwater + // FIXME: still have z friction underwater? return; } - drop = 0; // apply ground friction - if ((pm->groundentity && pml.groundsurface && !(pml.groundsurface->flags & SURF_SLICK) ) || (pml.ladder) ) + if( pm->waterlevel <= 1 ) { - friction = pm_friction; - control = speed < pm_stopspeed ? pm_stopspeed : speed; - drop += control*friction*pml.frametime; + if( pml.walking && !(pml.groundtrace.flags & SURF_SLICK) || (pml.onladder)) + { + control = speed < pm_stopspeed ? pm_stopspeed : speed; + drop += control * pm_friction * pml.frametime; + } } // apply water friction - if (pm->waterlevel && !pml.ladder) - drop += speed*pm_waterfriction*pm->waterlevel*pml.frametime; + if( pm->waterlevel && !pml.onladder ) drop += speed * pm_waterfriction * pm->waterlevel * pml.frametime; // scale the velocity newspeed = speed - drop; - if (newspeed < 0) - { - newspeed = 0; - } + if (newspeed < 0) newspeed = 0; newspeed /= speed; - vel[0] = vel[0] * newspeed; - vel[1] = vel[1] * newspeed; - vel[2] = vel[2] * newspeed; + VectorScale( vel, newspeed, vel ); } @@ -340,19 +347,17 @@ Handles user intended acceleration */ void PM_Accelerate (vec3_t wishdir, float wishspeed, float accel) { - int i; - float addspeed, accelspeed, currentspeed; + int i; + float addspeed, accelspeed, currentspeed; currentspeed = DotProduct (pml.velocity, wishdir); addspeed = wishspeed - currentspeed; - if (addspeed <= 0) - return; - accelspeed = accel*pml.frametime*wishspeed; - if (accelspeed > addspeed) - accelspeed = addspeed; + if( addspeed <= 0 ) return; + accelspeed = accel * pml.frametime * wishspeed; + if( accelspeed > addspeed ) accelspeed = addspeed; - for (i=0 ; i<3 ; i++) - pml.velocity[i] += accelspeed*wishdir[i]; + for( i = 0; i < 3; i++ ) + pml.velocity[i] += accelspeed * wishdir[i]; } void PM_AirAccelerate (vec3_t wishdir, float wishspeed, float accel) @@ -384,8 +389,8 @@ void PM_AddCurrents (vec3_t wishvel) vec3_t v; float s; - // account for ladders - if (pml.ladder && fabs(pml.velocity[2]) <= 200) + // account for onladders + if (pml.onladder && fabs(pml.velocity[2]) <= 200) { if ((pm->viewangles[PITCH] <= -15) && (pm->cmd.forwardmove > 0)) wishvel[2] = 200; @@ -397,7 +402,7 @@ void PM_AddCurrents (vec3_t wishvel) wishvel[2] = -200; else wishvel[2] = 0; - // limit horizontal speed when on a ladder + // limit horizontal speed when on a onladder if (wishvel[0] < -25) wishvel[0] = -25; else if (wishvel[0] > 25) @@ -539,7 +544,7 @@ void PM_AirMove (void) wishspeed = maxspeed; } - if ( pml.ladder ) + if ( pml.onladder ) { PM_Accelerate (wishdir, wishspeed, pm_accelerate); if (!wishvel[2]) @@ -612,6 +617,7 @@ void PM_CatagorizePosition (void) else { trace = pm->trace (pml.origin, pm->mins, pm->maxs, point); + groundtrace = trace; pml.groundplane = trace.plane; pml.groundsurface = trace.surface; pml.groundcontents = trace.contents; @@ -747,9 +753,9 @@ void PM_CheckSpecialMovement (void) if (pm->s.pm_time) return; - pml.ladder = false; + pml.onladder = false; - // check for ladder + // check for onladder flatforward[0] = pml.forward[0]; flatforward[1] = pml.forward[1]; flatforward[2] = 0; @@ -758,7 +764,7 @@ void PM_CheckSpecialMovement (void) VectorMA (pml.origin, 1, flatforward, spot); trace = pm->trace (pml.origin, pm->mins, pm->maxs, spot); if ((trace.fraction < 1) && (trace.contents & CONTENTS_LADDER)) - pml.ladder = true; + pml.onladder = true; // check for water jump if (pm->waterlevel != 2) return; @@ -964,6 +970,7 @@ bool PM_GoodPosition (void) for (i = 0; i < 3; i++) origin[i] = end[i] = pm->s.origin[i] * CL_COORD_FRAC; trace = pm->trace (origin, pm->mins, pm->maxs, end); + pml.groundtrace = trace; return !trace.allsolid; } diff --git a/engine/server/server.h b/engine/server/server.h index f0aa4076..be36a319 100644 --- a/engine/server/server.h +++ b/engine/server/server.h @@ -50,7 +50,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define FL_WORLDBRUSH (1<<3) // Not moveable/removeable brush entity #define FL_DORMANT (1<<4) // Entity is dormant, no updates to client #define FL_FRAMETHINK (1<<5) // entity will be thinking every frame -#define FL_GRAPHED (1<<6) // worldgraph has this ent listed as something that blocks a connection +#define FL_GRAPHED (1<<6) // worldgraph has this ent listed as something that blocks a conection #define FL_FLOAT (1<<7) // this entity can be floating. FIXME: remove this ? #define FL_TRACKTRAIN (1<<8) // old stuff... @@ -299,7 +299,8 @@ void SV_ExecuteClientMessage (client_state_t *cl); // // sv_ccmds.c // -void SV_Status_f (void); +void SV_Status_f( void ); +void SV_SectorList_f( void ); // // sv_ents.c @@ -375,7 +376,7 @@ void SV_LinkEdict (edict_t *ent); // sets ent->leafnums[] for pvs determination even if the entity // is not solid -int SV_AreaEdicts (vec3_t mins, vec3_t maxs, edict_t **list, int maxcount, int areatype); +int SV_AreaEdicts( const vec3_t mins, const vec3_t maxs, edict_t **list, int maxcount ); // fills in a table of edict pointers with edicts that have bounding boxes // that intersect the given area. It is possible for a non-axial bmodel // to be returned that doesn't actually intersect the area on an exact @@ -388,13 +389,13 @@ int SV_AreaEdicts (vec3_t mins, vec3_t maxs, edict_t **list, int maxcount, int a // // functions that interact with everything apropriate // -int SV_PointContents (vec3_t p); +int SV_PointContents( const vec3_t p, edict_t *passedict ); // returns the CONTENTS_* value from the world at the given point. // Quake 2 extends this to also check entities, to allow moving liquids trace_t SV_ClipMoveToEntity(edict_t *ent, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int contentsmask ); -trace_t SV_Trace (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, edict_t *passedict, int contentmask); +trace_t SV_Trace( const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, edict_t *passedict, int contentmask ); trace_t SV_TraceToss (edict_t *tossent, edict_t *ignore); // mins and maxs are relative diff --git a/engine/server/sv_cmds.c b/engine/server/sv_cmds.c index b1702aba..3da17f09 100644 --- a/engine/server/sv_cmds.c +++ b/engine/server/sv_cmds.c @@ -515,6 +515,7 @@ void SV_InitOperatorCommands( void ) Cmd_AddCommand("movie", SV_Movie_f, "playing video file" ); Cmd_AddCommand("changelevel", SV_ChangeLevel_f, "changing level" ); Cmd_AddCommand("restart", SV_Restart_f, "restarting current level" ); + Cmd_AddCommand("sectorlist", SV_SectorList_f, "display pvs sectors" ); if( dedicated->value ) { @@ -540,6 +541,7 @@ void SV_KillOperatorCommands( void ) Cmd_RemoveCommand("movie"); Cmd_RemoveCommand("changelevel"); Cmd_RemoveCommand("restart"); + Cmd_RemoveCommand("sectorlist"); if( dedicated->value ) { diff --git a/engine/server/sv_edict.h b/engine/server/sv_edict.h index 8799245a..018c0f61 100644 --- a/engine/server/sv_edict.h +++ b/engine/server/sv_edict.h @@ -30,6 +30,14 @@ typedef struct link_s int entnum; // get edict by number } link_t; +typedef struct worldsector_s +{ + int axis; // -1 = leaf node + float dist; + struct worldsector_s *children[2]; + sv_edict_t *entities; +} worldsector_t; + struct gclient_s { player_state_t ps; // communicated by server to clients @@ -51,13 +59,16 @@ struct sv_edict_s float freetime; // sv.time when the object was freed // sv_private_edict_t + worldsector_t *worldsector; // member of current wolrdsector + struct sv_edict_s *nextedict; // next edict in world sector link_t area; // linked to a division node or leaf int clipmask; // trace info - int headnode; // unused if num_clusters != -1 + int lastcluster; // unused if num_clusters != -1 int linkcount; int num_clusters; // if -1, use headnode instead int clusternums[MAX_ENT_CLUSTERS]; int areanum, areanum2; + int serialnumber; // unical entity #id int solid; // see entity_state_t for details int event; // apply sv.events too diff --git a/engine/server/sv_ents.c b/engine/server/sv_ents.c index 4f78dd8e..90590e37 100644 --- a/engine/server/sv_ents.c +++ b/engine/server/sv_ents.c @@ -92,8 +92,7 @@ void SV_EmitPacketEntities (client_frame_t *from, client_frame_t *to, sizebuf_t newnum = newent->number; } - if (oldindex >= from_num_entities) - oldnum = 9999; + if (oldindex >= from_num_entities) oldnum = 9999; else { oldent = &svs.client_entities[(from->first_entity+oldindex)%svs.num_client_entities]; @@ -409,6 +408,7 @@ void SV_BuildClientFrame (client_state_t *client) int clientarea, clientcluster; int leafnum; int c_fullsend; + byte *clientpvs; byte *clientphs; byte *bitvector; @@ -434,8 +434,8 @@ void SV_BuildClientFrame (client_state_t *client) // grab the current player_state_t frame->ps = clent->priv.sv->client->ps; - SV_FatPVS (org); - clientphs = pe->ClusterPHS (clientcluster); + clientpvs = pe->ClusterPVS( clientcluster ); + clientphs = pe->ClusterPHS( clientcluster ); // build up the list of visible entities frame->num_entities = 0; @@ -474,14 +474,11 @@ void SV_BuildClientFrame (client_state_t *client) { // FIXME: if an ent has a model and a sound, but isn't // in the PVS, only the PHS, clear the model - if (ent->progs.sv->noise3) - { - bitvector = fatpvs; //clientphs; - } - else bitvector = fatpvs; + if (ent->progs.sv->noise3) bitvector = clientphs; + else bitvector = clientpvs; // check individual leafs - /*if( !ent->priv.sv->num_clusters ) + if( !ent->priv.sv->num_clusters ) { continue; } @@ -495,38 +492,18 @@ void SV_BuildClientFrame (client_state_t *client) // check overflow clusters that coudln't be stored if( i == ent->priv.sv->num_clusters ) { - if( svEnt->lastCluster ) + if( ent->priv.sv->lastcluster ) { - for( ; l <= svEnt->lastCluster; l++ ) + for( ; l <= ent->priv.sv->lastcluster; l++ ) { if( bitvector[l>>3] & (1<<(l&7))) break; } - if ( l == svEnt->lastCluster ) + if( l == ent->priv.sv->lastcluster ) continue; // not visible } else continue; - }*/ - - if (ent->priv.sv->num_clusters == -1) - { - // too many leafs for individual check, go by headnode - //if(!pe->HeadnodeVisible (ent->priv.sv->headnode, bitvector)) - // continue; - c_fullsend++; } - else - { // check individual leafs - for (i=0 ; i < ent->priv.sv->num_clusters ; i++) - { - l = ent->priv.sv->clusternums[i]; - if (bitvector[l >> 3] & (1 << (l&7) )) - break; - } - if (i == ent->priv.sv->num_clusters) - continue; // not visible - } - if (!ent->progs.sv->modelindex) { // don't send sounds if they will be attenuated away diff --git a/engine/server/sv_init.c b/engine/server/sv_init.c index 4fe90227..10d2fcf9 100644 --- a/engine/server/sv_init.c +++ b/engine/server/sv_init.c @@ -194,7 +194,7 @@ void SV_SpawnServer (char *server, char *savename, sv_state_t serverstate ) if (serverstate != ss_game) { - sv.models[1] = pe->BeginRegistration("", false, &checksum); // no real map + sv.models[1] = pe->BeginRegistration( "", false, &checksum); // no real map } else { diff --git a/engine/server/sv_phys.c b/engine/server/sv_phys.c index 35206129..5c804ef0 100644 --- a/engine/server/sv_phys.c +++ b/engine/server/sv_phys.c @@ -85,7 +85,7 @@ bool SV_CheckBottom (edict_t *ent) { start[0] = x ? maxs[0] : mins[0]; start[1] = y ? maxs[1] : mins[1]; - if (SV_PointContents(start) != CONTENTS_SOLID) + if (SV_PointContents(start, ent ) != CONTENTS_SOLID) goto realcheck; } } @@ -224,7 +224,7 @@ void SV_Impact (edict_t *e1, trace_t *trace) prog->globals.sv->trace_plane_dist = trace->plane.dist; if (trace->ent) prog->globals.sv->trace_ent = PRVM_EDICT_TO_PROG(trace->ent); else prog->globals.sv->trace_ent = PRVM_EDICT_TO_PROG(prog->edicts); - PRVM_ExecuteProgram (e1->progs.sv->touch, "QC function pev->touch is missing"); + PRVM_ExecuteProgram (e1->progs.sv->touch, "QC function pev->touch is missing\n"); } if (!e1->priv.sv->free && !e2->priv.sv->free && e2->progs.sv->touch && e2->progs.sv->solid != SOLID_NOT) { @@ -239,7 +239,7 @@ void SV_Impact (edict_t *e1, trace_t *trace) VectorSet (prog->globals.sv->trace_plane_normal, 0, 0, 1); prog->globals.sv->trace_plane_dist = 0; prog->globals.sv->trace_ent = PRVM_EDICT_TO_PROG(e1); - PRVM_ExecuteProgram (e2->progs.sv->touch, "QC function pev->touch is missing"); + PRVM_ExecuteProgram (e2->progs.sv->touch, "QC function pev->touch is missing\n"); } PRVM_POP_GLOBALS; @@ -381,17 +381,17 @@ bool SV_CheckWater (edict_t *ent) ent->progs.sv->waterlevel = 0; ent->progs.sv->watertype = CONTENTS_NONE; - cont = SV_PointContents(point); + cont = SV_PointContents( point, ent ); if (cont & (MASK_WATER)) { ent->progs.sv->watertype = cont; ent->progs.sv->waterlevel = 1; point[2] = ent->progs.sv->origin[2] + (ent->progs.sv->mins[2] + ent->progs.sv->maxs[2])*0.5; - if (SV_PointContents(point) & (MASK_WATER)) + if (SV_PointContents(point, ent ) & (MASK_WATER)) { ent->progs.sv->waterlevel = 2; point[2] = ent->progs.sv->origin[2] + ent->progs.sv->view_ofs[2]; - if (SV_PointContents(point) & (MASK_WATER)) + if (SV_PointContents(point, ent ) & (MASK_WATER)) ent->progs.sv->waterlevel = 3; } } @@ -640,7 +640,7 @@ bool SV_MoveStep (edict_t *ent, vec3_t move, bool relink) if (trace.fraction == 1) { VectorCopy(trace.endpos, traceendpos); - if (((int)ent->progs.sv->aiflags & AI_SWIM) && !(SV_PointContents(traceendpos) & MASK_WATER)) + if (((int)ent->progs.sv->aiflags & AI_SWIM) && !(SV_PointContents(traceendpos, ent ) & MASK_WATER)) return false; // swim monster left water VectorCopy (traceendpos, ent->progs.sv->origin); @@ -1022,7 +1022,7 @@ SV_CheckWaterTransition */ void SV_CheckWaterTransition (edict_t *ent) { - int cont = SV_PointContents(ent->progs.sv->origin); + int cont = SV_PointContents(ent->progs.sv->origin, ent ); if (!ent->progs.sv->watertype) { diff --git a/engine/server/sv_spawn.c b/engine/server/sv_spawn.c index f0c35c36..190e0959 100644 --- a/engine/server/sv_spawn.c +++ b/engine/server/sv_spawn.c @@ -173,7 +173,7 @@ void SV_TouchTriggers (edict_t *ent) if ((ent->priv.sv->client || ((int)ent->progs.sv->flags & FL_MONSTER)) && (ent->progs.sv->health <= 0)) return; - num = SV_AreaEdicts(ent->progs.sv->absmin, ent->progs.sv->absmax, touch, MAX_EDICTS, AREA_TRIGGERS); + num = SV_AreaEdicts(ent->progs.sv->absmin, ent->progs.sv->absmax, touch, MAX_EDICTS ); PRVM_PUSH_GLOBALS; diff --git a/engine/server/sv_utils.c b/engine/server/sv_utils.c index 55e76ae5..d474499f 100644 --- a/engine/server/sv_utils.c +++ b/engine/server/sv_utils.c @@ -83,14 +83,14 @@ void SV_SetMinMaxSize (edict_t *e, float *min, float *max, bool rotate) PRVM_ERROR("SV_SetMinMaxSize: backwards mins/maxs"); // set derived values - if( rotate && e->progs.sv->solid == SOLID_BBOX) + if( rotate && e->progs.sv->solid == SOLID_BBOX ) { SV_CalcBBox( e, min, max ); } else { - VectorCopy (min, e->progs.sv->mins); - VectorCopy (max, e->progs.sv->maxs); + VectorCopy( min, e->progs.sv->mins); + VectorCopy( max, e->progs.sv->maxs); } VectorSubtract (max, min, e->progs.sv->size ); @@ -684,7 +684,7 @@ PF_pointcontents */ void PF_pointcontents (void) { - PRVM_G_FLOAT(OFS_RETURN) = SV_PointContents(PRVM_G_VECTOR(OFS_PARM0)); + PRVM_G_FLOAT(OFS_RETURN) = SV_PointContents(PRVM_G_VECTOR(OFS_PARM0), NULL ); } /* diff --git a/engine/server/sv_world.c b/engine/server/sv_world.c index a9ab85ff..738ab60a 100644 --- a/engine/server/sv_world.c +++ b/engine/server/sv_world.c @@ -25,94 +25,86 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. /* =============================================================================== -ENTITY AREA CHECKING +ENTITY CHECKING -FIXME: this use of "area" is different from the bsp file use +To avoid linearly searching through lists of entities during environment testing, +the world is carved up with an evenly spaced, axially aligned bsp tree. Entities +are kept in chains either at the final leafs, or at the first node that splits +them, which prevents having to deal with multiple fragments of a single entity. =============================================================================== */ -#define EDICT_FROM_AREA(l) PRVM_EDICT_NUM(l->entnum) - -typedef struct areanode_s -{ - int axis; // -1 = leaf node - float dist; - struct areanode_s *children[2]; - link_t trigger_edicts; - link_t solid_edicts; -} areanode_t; - #define AREA_DEPTH 4 -#define AREA_NODES 32 +#define AREA_NODES 64 +#define MAX_TOTAL_ENT_LEAFS 128 -areanode_t sv_areanodes[AREA_NODES]; -int sv_numareanodes; - -float *area_mins, *area_maxs; -edict_t **area_list; -int area_count, area_maxcount; -int area_type; - -// ClearLink is used for new headnodes -void ClearLink (link_t *l) +typedef struct area_s { - l->prev = l->next = l; -} + const float *mins; + const float *maxs; + edict_t **list; + int count; + int maxcount; + int type; +} area_t; -void RemoveLink (link_t *l) -{ - l->next->prev = l->prev; - l->prev->next = l->next; -} +worldsector_t sv_worldsectors[AREA_NODES]; +int sv_numworldsectors; -void InsertLinkBefore (link_t *l, link_t *before, edict_t *ent) +/* +=============== +SV_SectorList_f +=============== +*/ +void SV_SectorList_f( void ) { - l->next = before; - l->prev = before->prev; - l->prev->next = l; - l->next->prev = l; - l->entnum = PRVM_NUM_FOR_EDICT(ent); + int i, c; + worldsector_t *sec; + sv_edict_t *ent; + + for ( i = 0; i < sv_numworldsectors; i++ ) + { + sec = &sv_worldsectors[i], c = 0; + for( ent = sec->entities; ent; ent = ent->nextedict ) c++; + if(c) Msg( "sector %i: %i entities\n", i, c ); + } } /* =============== -SV_CreateAreaNode +SV_CreateworldSector Builds a uniformly subdivided tree for the given world size =============== */ -areanode_t *SV_CreateAreaNode (int depth, vec3_t mins, vec3_t maxs) +worldsector_t *SV_CreateWorldSector( int depth, vec3_t mins, vec3_t maxs ) { - areanode_t *anode; + worldsector_t *anode; vec3_t size; vec3_t mins1, maxs1, mins2, maxs2; - anode = &sv_areanodes[sv_numareanodes]; - sv_numareanodes++; + anode = &sv_worldsectors[sv_numworldsectors]; + sv_numworldsectors++; - ClearLink (&anode->trigger_edicts); - ClearLink (&anode->solid_edicts); - - if (depth == AREA_DEPTH) + if( depth == AREA_DEPTH ) { anode->axis = -1; anode->children[0] = anode->children[1] = NULL; return anode; } - VectorSubtract (maxs, mins, size); - if (size[0] > size[1]) anode->axis = 0; + VectorSubtract( maxs, mins, size ); + if( size[0] > size[1] ) anode->axis = 0; else anode->axis = 1; - - anode->dist = 0.5 * (maxs[anode->axis] + mins[anode->axis]); - VectorCopy (mins, mins1); - VectorCopy (mins, mins2); - VectorCopy (maxs, maxs1); - VectorCopy (maxs, maxs2); + + anode->dist = 0.5f * (maxs[anode->axis] + mins[anode->axis]); + VectorCopy(mins, mins1); + VectorCopy(mins, mins2); + VectorCopy(maxs, maxs1); + VectorCopy(maxs, maxs2); maxs1[anode->axis] = mins2[anode->axis] = anode->dist; - - anode->children[0] = SV_CreateAreaNode (depth+1, mins2, maxs2); - anode->children[1] = SV_CreateAreaNode (depth+1, mins1, maxs1); + anode->children[0] = SV_CreateWorldSector( depth+1, mins2, maxs2); + anode->children[1] = SV_CreateWorldSector( depth+1, mins1, maxs1); return anode; } @@ -125,90 +117,103 @@ SV_ClearWorld */ void SV_ClearWorld (void) { - memset (sv_areanodes, 0, sizeof(sv_areanodes)); - sv_numareanodes = 0; - SV_CreateAreaNode (0, sv.models[1]->mins, sv.models[1]->maxs); + cmodel_t *world = sv.models[1]; + memset( sv_worldsectors, 0, sizeof(sv_worldsectors)); + sv_numworldsectors = 0; + SV_CreateWorldSector( 0, world->mins, world->maxs ); } - /* =============== SV_UnlinkEdict - =============== */ -void SV_UnlinkEdict (edict_t *ent) +void SV_UnlinkEdict( edict_t *ent ) { - if (!ent->priv.sv->area.prev) return; // not linked in anywhere - RemoveLink (&ent->priv.sv->area); - ent->priv.sv->area.prev = ent->priv.sv->area.next = NULL; -} + sv_edict_t *sv_ent, *scan; + worldsector_t *ws; + sv_ent = ent->priv.sv; + ws = sv_ent->worldsector; + if( !ws ) return; // not linked in anywhere + sv_ent->worldsector = NULL; +//sv_ent->linked = false; + + if( ws->entities == sv_ent ) + { + ws->entities = sv_ent->nextedict; + return; + } + + for( scan = ws->entities; scan; scan = scan->nextedict ) + { + if( scan->nextedict == sv_ent ) + { + scan->nextedict = sv_ent->nextedict; + return; + } + } + MsgWarn("SV_UnlinkEdict: not found in worldSector\n" ); +} /* =============== -SV_LinkEdict - +SV_LinkEntity =============== */ -#define MAX_TOTAL_ENT_LEAFS 128 -void SV_LinkEdict (edict_t *ent) +void SV_LinkEdict( edict_t *ent ) { - areanode_t *node; + worldsector_t *node; int leafs[MAX_TOTAL_ENT_LEAFS]; - int clusters[MAX_TOTAL_ENT_LEAFS]; + int cluster; int num_leafs; int i, j, k; int area; - int topnode; + int lastleaf; + sv_edict_t *sv_ent; - if (ent->priv.sv->area.prev) SV_UnlinkEdict (ent); // unlink from old position + sv_ent = ent->priv.sv; + + if( sv_ent->worldsector ) SV_UnlinkEdict( ent ); // unlink from old position if (ent == prog->edicts) return; // don't add the world if (ent->priv.sv->free) return; // set the size - VectorSubtract (ent->progs.sv->maxs, ent->progs.sv->mins, ent->progs.sv->size); - + VectorSubtract( ent->progs.sv->maxs, ent->progs.sv->mins, ent->progs.sv->size ); + // encode the size into the entity_state for client prediction if (ent->progs.sv->solid == SOLID_BBOX && !((int)ent->progs.sv->flags & FL_DEADMONSTER)) { // assume that x/y are equal and symetric i = ent->progs.sv->maxs[0]/SV_COORD_FRAC; - if (i<1) i = 1; - if (i>31) i = 31; + if( i < 1 ) i = 1; + if( i > 31) i = 31; // z is not symetric j = (-ent->progs.sv->mins[2])/SV_COORD_FRAC; - if (j < 1) j = 1; - if (j > 31) j = 31; + if( j < 1 ) j = 1; + if( j > 31) j = 31; // and z maxs can be negative... k = (ent->progs.sv->maxs[2]+32)/SV_COORD_FRAC; - if (k<1) k = 1; - if (k>63) k = 63; - ent->priv.sv->solid = (k<<10) | (j<<5) | i; + if( k < 1 ) k = 1; + if( k > 63) k = 63; + sv_ent->solid = (k<<10) | (j<<5) | i; } else if (ent->progs.sv->solid == SOLID_BSP) { - ent->priv.sv->solid = 31; // a solid_bbox will never create this value + sv_ent->solid = 31; // a solid_bbox will never create this value } - else ent->priv.sv->solid = 0; + else sv_ent->solid = 0; // set the abs box if (ent->progs.sv->solid == SOLID_BSP && !VectorIsNull(ent->progs.sv->angles)) { // expand for rotation - float max = 0, v; int i; + float max = RadiusFromBounds( ent->progs.sv->mins, ent->progs.sv->maxs ); - for (i = 0; i<3 ; i++) - { - v =fabs( ent->progs.sv->mins[i]); - if (v > max) max = v; - v =fabs( ent->progs.sv->maxs[i]); - if (v > max) max = v; - } - for (i=0 ; i<3 ; i++) + for (i = 0; i < 3; i++) { ent->progs.sv->absmin[i] = ent->progs.sv->origin[i] - max; ent->progs.sv->absmax[i] = ent->progs.sv->origin[i] + max; @@ -230,74 +235,69 @@ void SV_LinkEdict (edict_t *ent) ent->progs.sv->absmax[2] += 1; // link to PVS leafs - ent->priv.sv->num_clusters = 0; - ent->priv.sv->areanum = 0; - ent->priv.sv->areanum2 = 0; + sv_ent->num_clusters = 0; + sv_ent->lastcluster = 0; + sv_ent->areanum = 0; + sv_ent->areanum2 = 0; - //get all leafs, including solids - num_leafs = pe->BoxLeafnums (ent->progs.sv->absmin, ent->progs.sv->absmax, leafs, MAX_TOTAL_ENT_LEAFS, &topnode); + // get all leafs, including solids + num_leafs = pe->BoxLeafnums( ent->progs.sv->absmin, ent->progs.sv->absmax, leafs, MAX_TOTAL_ENT_LEAFS, &lastleaf ); - // set areas - for (i = 0; i < num_leafs; i++) + // if none of the leafs were inside the map, the + // entity is outside the world and can be considered unlinked + if( !num_leafs ) return; + + // set areas, even from clusters that don't fit in the entity array + for( i = 0; i < num_leafs; i++ ) { - clusters[i] = pe->LeafCluster (leafs[i]); - area = pe->LeafArea (leafs[i]); - if (area) - { // doors may legally straggle two areas, + area = pe->LeafArea( leafs[i] ); + if( area ) + { + // doors may legally straggle two areas, // but nothing should evern need more than that if (ent->priv.sv->areanum && ent->priv.sv->areanum != area) { - if (ent->priv.sv->areanum2 && ent->priv.sv->areanum2 != area && sv.state == ss_loading) - MsgWarn("SV_LinkEdict: object touching 3 areas at %f %f %f\n", ent->progs.sv->absmin[0], ent->progs.sv->absmin[1], ent->progs.sv->absmin[2]); + if (ent->priv.sv->areanum2 && ent->priv.sv->areanum2 != area && sv.state == ss_loading ) + { + float *v = ent->progs.sv->absmin; + MsgWarn("SV_LinkEdict: object touching 3 areas at %f %f %f\n", v[0], v[1], v[2]); + } ent->priv.sv->areanum2 = area; } else ent->priv.sv->areanum = area; } } - if (num_leafs >= MAX_TOTAL_ENT_LEAFS) + // store as many explicit clusters as we can + sv_ent->num_clusters = 0; + for (i = 0; i < num_leafs; i++) { - // assume we missed some leafs, and mark by headnode - ent->priv.sv->num_clusters = -1; - ent->priv.sv->headnode = topnode; - } - else - { - ent->priv.sv->num_clusters = 0; - for (i = 0; i < num_leafs; i++) + cluster = pe->LeafCluster( leafs[i] ); + if( cluster ) { - if (clusters[i] == -1) continue; // not a visible leaf - for (j = 0; j < i; j++) - { - if (clusters[j] == clusters[i]) break; - } - if (j == i) - { - if (ent->priv.sv->num_clusters == MAX_ENT_CLUSTERS) - { - // assume we missed some leafs, and mark by headnode - ent->priv.sv->num_clusters = -1; - ent->priv.sv->headnode = topnode; - break; - } - ent->priv.sv->clusternums[ent->priv.sv->num_clusters++] = clusters[i]; - } + sv_ent->clusternums[sv_ent->num_clusters++] = cluster; + if( sv_ent->num_clusters == MAX_ENT_CLUSTERS ) + break; // list is full } } + // store off a last cluster if we need to + if( i != num_leafs ) sv_ent->lastcluster = pe->LeafCluster( lastleaf ); + // if first time, make sure old_origin is valid - if (!ent->priv.sv->linkcount) + if(!ent->priv.sv->linkcount) { VectorCopy (ent->progs.sv->origin, ent->progs.sv->old_origin); } ent->priv.sv->linkcount++; + // don't link not solid or rigid bodies if (ent->progs.sv->solid == SOLID_NOT || ent->progs.sv->solid >= SOLID_BOX) return; - // find the first node that the ent's box crosses - node = sv_areanodes; - while (1) + // find the first world sector node that the ent's box crosses + node = sv_worldsectors; + while( 1 ) { if (node->axis == -1) break; if (ent->progs.sv->absmin[node->axis] > node->dist) @@ -307,57 +307,57 @@ void SV_LinkEdict (edict_t *ent) else break; // crosses the node } - // link it in - if (ent->progs.sv->solid == SOLID_TRIGGER) InsertLinkBefore (&ent->priv.sv->area, &node->trigger_edicts, ent ); - else InsertLinkBefore (&ent->priv.sv->area, &node->solid_edicts, ent ); + // link it in + sv_ent->worldsector = node; + sv_ent->nextedict = node->entities; + node->entities = sv_ent; +//sv_ent->linked = true; } +/* +============================================================================ +AREA QUERY + +Fills in a list of all entities who's absmin / absmax intersects the given +bounds. This does NOT mean that they actually touch in the case of bmodels. +============================================================================ +*/ /* ==================== SV_AreaEdicts_r - ==================== */ -void SV_AreaEdicts_r (areanode_t *node) +void SV_AreaEdicts_r( worldsector_t *node, area_t *ap ) { - link_t *l, *next, *start; - edict_t *check; + sv_edict_t *check, *next; + edict_t *gcheck; int count = 0; - // touch linked edicts - if (area_type == AREA_SOLID) - start = &node->solid_edicts; - else start = &node->trigger_edicts; - - for (l = start->next; l != start; l = next) + for( check = node->entities; check; check = next ) { - next = l->next; - check = EDICT_FROM_AREA(l); + next = check->nextedict; + gcheck = PRVM_EDICT_NUM( check->serialnumber ); - if (check->progs.sv->solid == SOLID_NOT) continue; // deactivated - if (check->progs.sv->absmin[0] > area_maxs[0] || check->progs.sv->absmin[1] > area_maxs[1] || check->progs.sv->absmin[2] > area_maxs[2] - || check->progs.sv->absmax[0] < area_mins[0] || check->progs.sv->absmax[1] < area_mins[1] || check->progs.sv->absmax[2] < area_mins[2]) + if (gcheck->progs.sv->absmin[0] > ap->maxs[0] || gcheck->progs.sv->absmin[1] > ap->maxs[1] || gcheck->progs.sv->absmin[2] > ap->maxs[2] + || gcheck->progs.sv->absmax[0] < ap->mins[0] || gcheck->progs.sv->absmax[1] < ap->mins[1] || gcheck->progs.sv->absmax[2] < ap->mins[2]) continue; // not touching - if (area_count == area_maxcount) + if( ap->count == ap->maxcount ) { - MsgWarn("SV_AreaEdicts: maxcount\n"); + MsgDev(D_NOTE, "SV_AreaEdicts_r: maxcount!\n"); return; } - - area_list[area_count] = check; - area_count++; + ap->list[ap->count] = PRVM_EDICT_NUM( check->serialnumber ); + ap->count++; } - if (node->axis == -1) return; // terminal node + if( node->axis == -1 ) return; // terminal node // recurse down both sides - if ( area_maxs[node->axis] > node->dist ) - SV_AreaEdicts_r ( node->children[0] ); - if ( area_mins[node->axis] < node->dist ) - SV_AreaEdicts_r ( node->children[1] ); + if( ap->maxs[node->axis] > node->dist ) SV_AreaEdicts_r ( node->children[0], ap ); + if( ap->mins[node->axis] < node->dist ) SV_AreaEdicts_r ( node->children[1], ap ); } /* @@ -365,92 +365,56 @@ void SV_AreaEdicts_r (areanode_t *node) SV_AreaEdicts ================ */ -int SV_AreaEdicts (vec3_t mins, vec3_t maxs, edict_t **list, int maxcount, int areatype) +int SV_AreaEdicts( const vec3_t mins, const vec3_t maxs, edict_t **list, int maxcount ) { - area_mins = mins; - area_maxs = maxs; - area_list = list; - area_count = 0; - area_maxcount = maxcount; - area_type = areatype; + area_t ap; - SV_AreaEdicts_r (sv_areanodes); + ap.mins = mins; + ap.maxs = maxs; + ap.list = list; + ap.count = 0; + ap.maxcount = maxcount; - return area_count; + SV_AreaEdicts_r( sv_worldsectors, &ap ); + + return ap.count; } - //=========================================================================== - -/* -============= -SV_PointContents -============= -*/ -int SV_PointContents( vec3_t p ) -{ - edict_t *touch[MAX_EDICTS], *hit; - int i, num; - int contents, c2; - float *angles; - - // get base contents from world - contents = pe->PointContents( p ); - - // or in contents from all the other entities - num = SV_AreaEdicts (p, p, touch, MAX_EDICTS, AREA_SOLID); - - for (i = 0; i < num; i++) - { - hit = touch[i]; - - // might intersect, so do an exact clip - angles = hit->progs.sv->angles; - if (hit->progs.sv->solid != SOLID_BSP) angles = vec3_origin; // boxes don't rotate - c2 = pe->TransformedPointContents( p, hit->progs.sv->origin, hit->progs.sv->angles ); - contents |= c2; - } - return contents; -} - - - typedef struct { vec3_t boxmins, boxmaxs;// enclose the test object along entire move - float *mins, *maxs; // size of the moving object - vec3_t mins2, maxs2; // size when clipping against mosnters - float *start, *end; + const float *mins, *maxs; + const float *start; + vec3_t end; trace_t trace; edict_t *passedict; int contentmask; - } moveclip_t; /* ==================== SV_ClipMoveToEntities - ==================== */ -void SV_ClipMoveToEntities ( moveclip_t *clip ) +void SV_ClipMoveToEntities( moveclip_t *clip ) { int i, num; edict_t *touchlist[MAX_EDICTS], *touch; trace_t trace; - float *angles; + cmodel_t *cmodel; + float *origin, *angles; - num = SV_AreaEdicts (clip->boxmins, clip->boxmaxs, touchlist, MAX_EDICTS, AREA_SOLID); + num = SV_AreaEdicts( clip->boxmins, clip->boxmaxs, touchlist, MAX_EDICTS ); - // be careful, it is possible to have an entity in this - // list removed before we get to it (killtriggered) - for (i = 0; i < num; i++) + for( i = 0; i < num; i++ ) { + if( clip->trace.allsolid ) return; + touch = touchlist[i]; - if (touch->progs.sv->solid == SOLID_NOT) continue; - if (touch == clip->passedict) continue; - if (clip->trace.allsolid) return; - if (clip->passedict) + if( touch == clip->passedict ) continue; + if( touch->progs.sv->solid == SOLID_NOT ) continue; + if( clip->passedict ) { if (PRVM_PROG_TO_EDICT(touch->progs.sv->owner) == clip->passedict) continue; // don't clip against own missiles @@ -458,56 +422,37 @@ void SV_ClipMoveToEntities ( moveclip_t *clip ) continue; // don't clip against owner } - if ( !(clip->contentmask & CONTENTS_DEADMONSTER) && ((int)touch->progs.sv->flags & FL_DEADMONSTER)) + if(!(clip->contentmask & CONTENTS_DEADMONSTER) && ((int)touch->progs.sv->flags & FL_DEADMONSTER)) continue; - // might intersect, so do an exact clip + cmodel = SV_GetModelPtr( touch ); + + origin = touch->progs.sv->origin; angles = touch->progs.sv->angles; - if (touch->progs.sv->solid != SOLID_BSP) angles = vec3_origin; // boxes don't rotate - if ((int)touch->progs.sv->flags & FL_MONSTER) - { - trace = pe->TransformedBoxTrace (clip->start, clip->end, clip->mins2, clip->maxs2, clip->contentmask, touch->progs.sv->origin, angles); - } - else - { - trace = pe->TransformedBoxTrace (clip->start, clip->end, clip->mins, clip->maxs, clip->contentmask, touch->progs.sv->origin, angles); - } - if (trace.allsolid || trace.startsolid || trace.fraction < clip->trace.fraction) + if( !touch->progs.sv->solid == SOLID_BSP ) angles = vec3_origin; // boxes don't rotate + + trace = pe->TransformedBoxTrace((float *)clip->start, (float *)clip->end, (float *)clip->mins, (float *)clip->maxs, cmodel, clip->contentmask, origin, angles ); + + if( trace.allsolid ) { + clip->trace.allsolid = true; trace.ent = touch; - if (clip->trace.startsolid) - { - clip->trace = trace; - clip->trace.startsolid = true; - } - else clip->trace = trace; - } - else if (trace.startsolid) clip->trace.startsolid = true; - } -} - - -/* -================== -SV_TraceBounds -================== -*/ -void SV_TraceBounds (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, vec3_t boxmins, vec3_t boxmaxs) -{ - int i; - - for (i = 0; i < 3; i++) - { - if (end[i] > start[i]) + } + else if( trace.startsolid ) { - boxmins[i] = start[i] + mins[i] - 1; - boxmaxs[i] = end[i] + maxs[i] + 1; + clip->trace.startsolid = true; + trace.ent = touch; } - else + if( trace.fraction < clip->trace.fraction ) { - boxmins[i] = end[i] + mins[i] - 1; - boxmaxs[i] = start[i] + maxs[i] + 1; + bool oldStart; + + // make sure we keep a startsolid from a previous trace + oldStart = clip->trace.startsolid; + trace.ent = touch; + clip->trace = trace; + clip->trace.startsolid |= oldStart; } } } @@ -517,40 +462,50 @@ void SV_TraceBounds (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, vec3_t SV_Trace Moves the given mins/maxs volume through the world from start to end. - -Passedict and edicts owned by passedict are explicitly not checked. - +passEntityNum and entities owned by passEntityNum are explicitly not checked. ================== */ -trace_t SV_Trace (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, edict_t *passedict, int contentmask) +trace_t SV_Trace( const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, edict_t *passedict, int contentmask ) { moveclip_t clip; + int i; - if (!mins) mins = vec3_origin; - if (!maxs) maxs = vec3_origin; - - memset ( &clip, 0, sizeof ( moveclip_t ) ); + if( !mins ) mins = vec3_origin; + if( !maxs ) maxs = vec3_origin; + memset( &clip, 0, sizeof( moveclip_t )); // clip to world - clip.trace = pe->BoxTrace( start, end, mins, maxs, contentmask ); - clip.trace.ent = prog->edicts; - if (clip.trace.fraction == 0) return clip.trace; // blocked by the world + clip.trace = pe->BoxTrace( start, end, mins, maxs, NULL, contentmask ); + clip.trace.ent = clip.trace.fraction != 1.0 ? prog->edicts : NULL; + if( clip.trace.fraction == 0 ) return clip.trace; // blocked immediately by the world clip.contentmask = contentmask; clip.start = start; - clip.end = end; + VectorCopy( end, clip.end ); clip.mins = mins; clip.maxs = maxs; clip.passedict = passedict; - VectorCopy (mins, clip.mins2); - VectorCopy (maxs, clip.maxs2); - // create the bounding box of the entire move - SV_TraceBounds ( start, clip.mins2, clip.maxs2, end, clip.boxmins, clip.boxmaxs ); + // we can limit it to the part of the move not + // already clipped off by the world, which can be + // a significant savings for line of sight and shot traces + for( i = 0; i < 3; i++ ) + { + if( end[i] > start[i] ) + { + clip.boxmins[i] = clip.start[i] + clip.mins[i] - 1; + clip.boxmaxs[i] = clip.end[i] + clip.maxs[i] + 1; + } + else + { + clip.boxmins[i] = clip.end[i] + clip.mins[i] - 1; + clip.boxmaxs[i] = clip.start[i] + clip.maxs[i] + 1; + } + } // clip to other solid entities - SV_ClipMoveToEntities ( &clip ); + SV_ClipMoveToEntities( &clip ); return clip.trace; } @@ -595,5 +550,63 @@ trace_t SV_TraceToss (edict_t *tossent, edict_t *ignore) trace_t SV_ClipMoveToEntity(edict_t *ent, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int contentsmask) { - return pe->BoxTrace(start, end, mins, maxs, contentsmask); + edict_t *touch; + cmodel_t *cmodel; + float *origin, *angles; + trace_t trace; + + touch = ent; + + memset( &trace, 0, sizeof(trace_t)); + // if it doesn't have any brushes of a type we + // are looking for, ignore it + if(!(contentsmask & CONTENTS_DEADMONSTER) && ((int)touch->progs.sv->flags & FL_DEADMONSTER)) + { + trace.fraction = 1.0; + return trace; + } + // might intersect, so do an exact clip + cmodel = SV_GetModelPtr( touch ); + origin = touch->progs.sv->origin; + angles = touch->progs.sv->angles; + if( !touch->progs.sv->solid == SOLID_BSP ) angles = vec3_origin; // boxes don't rotate + + trace = pe->TransformedBoxTrace( start, end, mins, maxs, cmodel, contentsmask, origin, angles ); + if( trace.fraction < 1 ) trace.ent = touch; + + return trace; +} + +/* +============= +SV_PointContents +============= +*/ +int SV_PointContents( const vec3_t p, edict_t *passedict ) +{ + edict_t *touch[MAX_EDICTS], *hit; + int i, num; + int contents, c2; + cmodel_t *cmodel; + float *angles; + + // get base contents from world + contents = pe->PointContents( p, NULL ); + + // or in contents from all the other entities + num = SV_AreaEdicts( p, p, touch, MAX_EDICTS ); + + for( i = 0; i < num; i++ ) + { + if ( touch[i] == passedict ) continue; + hit = touch[i]; + + // might intersect, so do an exact clip + cmodel = SV_GetModelPtr( hit ); + angles = hit->progs.sv->angles; + if( !hit->progs.sv->solid == SOLID_BSP ) angles = vec3_origin; // boxes don't rotate + c2 = pe->TransformedPointContents( p, cmodel, hit->progs.sv->origin, angles ); + contents |= c2; + } + return contents; } \ No newline at end of file diff --git a/physic/cm_local.h b/physic/cm_local.h index da658171..4cde7f5c 100644 --- a/physic/cm_local.h +++ b/physic/cm_local.h @@ -7,6 +7,8 @@ #include "physic.h" +#define BOX_MODEL_HANDLE MAX_MODELS - 1 + typedef struct { cplane_t *plane; @@ -19,15 +21,6 @@ typedef struct csurface_t *surface; } cbrushside_t; -typedef struct -{ - int contents; - int cluster; - int area; - int firstleafbrush; - int numleafbrushes; -} cleaf_t; - typedef struct { int contents; @@ -138,6 +131,7 @@ typedef struct box_s { cplane_t *planes; cbrush_t *brush; + cmodel_t model; } box_t; typedef struct mapleaf_s @@ -171,6 +165,7 @@ typedef struct tracework_s float maxOffset; // longest corner length from origin vec3_t bounds[2]; // enclosing box of start and end surrounding by size vec3_t extents; // greatest of abs(size[0]) and abs(size[1]) + vec3_t origin; int contents; bool ispoint; // optimized case trace_t result; // returned from trace call diff --git a/physic/cm_model.c b/physic/cm_model.c index 239d1f13..7c01250a 100644 --- a/physic/cm_model.c +++ b/physic/cm_model.c @@ -59,6 +59,25 @@ void CM_GetPoint2( int index, vec3_t out ) CM_ConvertDimensionToMeters( out, cm.vertices[vert_index].point ); } +/* +================= +CM_BoundBrush +================= +*/ +void CM_BoundBrush( cbrush_t *b ) +{ + cbrushside_t *sides; + sides = &cm.brushsides[b->firstbrushside]; + + b->bounds[0][0] = -sides[0].plane->dist; + b->bounds[1][0] = sides[1].plane->dist; + + b->bounds[0][1] = -sides[2].plane->dist; + b->bounds[1][1] = sides[3].plane->dist; + + b->bounds[0][2] = -sides[4].plane->dist; + b->bounds[1][2] = sides[5].plane->dist; +} int CM_NumTexinfo( void ) { return cm.numtexinfo; } int CM_NumClusters( void ) { return cm.numclusters; } @@ -231,6 +250,7 @@ void BSP_LoadBrushes( lump_t *l ) out->firstbrushside = LittleLong(in->firstside); out->numsides = LittleLong(in->numsides); out->contents = LittleLong(in->contents); + CM_BoundBrush( out ); } } @@ -563,6 +583,19 @@ void BSP_LoadStringData( lump_t *l ) Mem_Copy( cm.stringdata, cm.mod_base + l->fileofs, l->filelen ); } +/* +================= +BSP_LoadStringData +================= +*/ +void BSP_LoadBuiltinProgs( lump_t *l ) +{ + if(!l->filelen) + { + return; + } +} + /* ================= BSP_LoadStringTable @@ -660,8 +693,8 @@ void CM_LoadBSP( const void *buffer ) BSP_LoadSurfedges(&header.lumps[LUMP_SURFEDGES]); BSP_LoadFaces(&header.lumps[LUMP_FACES]); BSP_LoadSurfDesc(&header.lumps[LUMP_SURFDESC]); - BSP_LoadCollision(&header.lumps[LUMP_COLLISION]); BSP_LoadModels(&header.lumps[LUMP_MODELS]); + BSP_LoadCollision(&header.lumps[LUMP_COLLISION]); cm.loaded = true; cm.use_thread = true; @@ -802,8 +835,8 @@ cmodel_t *CM_BeginRegistration( const char *name, bool clientload, uint *checksu BSP_LoadLeafs(&hdr->lumps[LUMP_LEAFS]); BSP_LoadLeafBrushes(&hdr->lumps[LUMP_LEAFBRUSHES]); BSP_LoadPlanes(&hdr->lumps[LUMP_PLANES]); - BSP_LoadBrushes(&hdr->lumps[LUMP_BRUSHES]); BSP_LoadBrushSides(&hdr->lumps[LUMP_BRUSHSIDES]); + BSP_LoadBrushes(&hdr->lumps[LUMP_BRUSHES]); BSP_LoadNodes(&hdr->lumps[LUMP_NODES]); BSP_LoadAreas(&hdr->lumps[LUMP_AREAS]); BSP_LoadAreaPortals(&hdr->lumps[LUMP_AREAPORTALS]); @@ -893,7 +926,7 @@ 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) +void CM_InitBoxHull( void ) { cplane_t *p; cbrushside_t *s; @@ -903,7 +936,9 @@ void CM_InitBoxHull (void) box.brush = &cm.brushes[cm.numbrushes]; box.brush->numsides = 6; box.brush->firstbrushside = cm.numbrushsides; - box.brush->contents = CONTENTS_MONSTER; + box.brush->contents = CONTENTS_MONSTER;//FIXME + box.model.leaf.numleafbrushes = 1; + box.model.leaf.firstleafbrush = cm.numleafbrushes; cm.leafbrushes[cm.numleafbrushes] = cm.numbrushes; for (i = 0; i < 6; i++) @@ -931,6 +966,60 @@ void CM_InitBoxHull (void) } } +/* +=================== +CM_TempBoxModel + +To keep everything totally uniform, bounding boxes are turned into small +BSP trees instead of being compared directly. +Capsules are handled differently though. +=================== +*/ +int CM_TempBoxModel( const vec3_t mins, const vec3_t maxs ) +{ + VectorCopy( mins, box.model.mins ); + VectorCopy( maxs, box.model.maxs ); + + box.planes[0].dist = maxs[0]; + box.planes[1].dist = -maxs[0]; + box.planes[2].dist = mins[0]; + box.planes[3].dist = -mins[0]; + box.planes[4].dist = maxs[1]; + box.planes[5].dist = -maxs[1]; + box.planes[6].dist = mins[1]; + box.planes[7].dist = -mins[1]; + box.planes[8].dist = maxs[2]; + box.planes[9].dist = -maxs[2]; + box.planes[10].dist = mins[2]; + box.planes[11].dist = -mins[2]; + + VectorCopy( mins, box.brush->bounds[0] ); + VectorCopy( maxs, box.brush->bounds[1] ); + + return BOX_MODEL_HANDLE; +} + +/* +=================== +CM_ModelBounds +=================== +*/ +void CM_ModelBounds( cmodel_t *cmod, vec3_t mins, vec3_t maxs ) +{ + if( cmod ) + { + VectorCopy( cmod->mins, mins ); + VectorCopy( cmod->maxs, maxs ); + } + else + { + VectorSet( mins, -32, -32, -32 ); + VectorSet( maxs, 32, 32, 32 ); + MsgWarn("can't compute bounding box, use default size\n"); + } +} + + /* =============================================================================== diff --git a/physic/cm_test.c b/physic/cm_test.c index 8439c416..821bf0c9 100644 --- a/physic/cm_test.c +++ b/physic/cm_test.c @@ -160,7 +160,7 @@ int CM_BoxLeafnums( const vec3_t mins, const vec3_t maxs, int *list, int listsiz CM_BoxLeafnums_r( &ll, 0 ); - //if( lastleaf ) *lastleaf = ll.lastleaf;//FIXME + if( lastleaf ) *lastleaf = ll.lastleaf; return ll.count; } @@ -170,7 +170,7 @@ CM_PointContents ================== */ -int CM_PointContents( const vec3_t p ) +int CM_PointContents( const vec3_t p, cmodel_t *model ) { int leafnum; int i, k; @@ -182,9 +182,16 @@ int CM_PointContents( const vec3_t p ) float d; if(!cm.numnodes) return 0; // map not loaded - - leafnum = CM_PointLeafnum_r (p, 0); - leaf = &cm.leafs[leafnum]; + if( model && model->type == mod_brush ) + { + // ignore studio models + leaf = &model->leaf; + } + else + { + leafnum = CM_PointLeafnum_r (p, 0); + leaf = &cm.leafs[leafnum]; + } contents = 0; for( k = 0; k < leaf->numleafbrushes; k++) @@ -212,7 +219,7 @@ Handles offseting and rotation of the end points for moving and rotating entities ================== */ -int CM_TransformedPointContents( const vec3_t p, const vec3_t origin, const vec3_t angles ) +int CM_TransformedPointContents( const vec3_t p, cmodel_t *model, const vec3_t origin, const vec3_t angles ) { vec3_t p_l; vec3_t temp; @@ -230,5 +237,5 @@ int CM_TransformedPointContents( const vec3_t p, const vec3_t origin, const vec3 p_l[1] = -DotProduct( temp, right ); p_l[2] = DotProduct( temp, up ); } - return CM_PointContents( p_l ); + return CM_PointContents( p_l, model ); } \ No newline at end of file diff --git a/physic/cm_trace.c b/physic/cm_trace.c index 4146b77b..ddda9ac8 100644 --- a/physic/cm_trace.c +++ b/physic/cm_trace.c @@ -4,7 +4,7 @@ //======================================================================= #include "cm_local.h" -#include "basefiles.h" +#include "cm_utils.h" #define DIST_EPSILON (0.03125) // 1/32 epsilon to keep floating point happy #define MAX_POSITION_LEAFS 1024 @@ -111,16 +111,13 @@ void CM_TestBoxInBrush( tracework_t *tw, cbrush_t *brush ) CM_TestInLeaf ================ */ -void CM_TestInLeaf( tracework_t *tw, int leafnum ) +void CM_TestInLeaf( tracework_t *tw, cleaf_t *leaf ) { int k; int brushnum; - cleaf_t *leaf; cbrush_t *b; - leaf = &cm.leafs[leafnum]; if(!(leaf->contents & maptrace.contents)) return; - // test box position against all brushes in the leaf for (k = 0; k < leaf->numleafbrushes; k++) { @@ -300,7 +297,7 @@ void CM_PositionTest( tracework_t *tw ) // test the contents of the leafs for( i = 0; i < ll.count; i++) { - CM_TestInLeaf( tw, leafs[i] ); + CM_TestInLeaf( tw, &cm.leafs[leafs[i]] ); if( tw->result.allsolid ) break; } @@ -420,22 +417,23 @@ void CM_TraceThroughTree( tracework_t *tw, int num, float p1f, float p2f, vec3_t CM_Trace ================== */ -void CM_Trace( trace_t *results, const vec3_t start, const vec3_t end, vec3_t mins, vec3_t maxs, int brushmask ) +void CM_Trace( trace_t *results, const vec3_t start, const vec3_t end, vec3_t mins, vec3_t maxs, cmodel_t *mod, const vec3_t origin, int brushmask ) { int i; tracework_t tw; vec3_t offset; - + cm.checkcount++; // for multi-check avoidance // fill in a default trace memset( &tw, 0, sizeof(tw) ); - tw.result.fraction = 1; // assume it goes the entire distance until shown otherwise + tw.result.fraction = 1; // assume it goes the entire distance until shown otherwise + VectorCopy( origin, tw.origin ); if(!cm.numnodes) { *results = tw.result; - return; // map not loaded, shouldn't happen + return; // map not loaded, shouldn't happen } // allow NULL to be passed in for 0,0,0 @@ -510,7 +508,8 @@ void CM_Trace( trace_t *results, const vec3_t start, const vec3_t end, vec3_t mi // check for position test special case if( VectorCompare( start, end )) { - CM_PositionTest( &tw ); + if( mod && mod->type == mod_brush ) CM_TestInLeaf( &tw, &mod->leaf ); + else CM_PositionTest( &tw ); } else { @@ -527,8 +526,10 @@ void CM_Trace( trace_t *results, const vec3_t start, const vec3_t end, vec3_t mi tw.extents[1] = tw.maxs[1]; tw.extents[2] = tw.maxs[2]; } + // general sweeping through world - CM_TraceThroughTree( &tw, 0, 0, 1, tw.start, tw.end ); + if ( mod && mod->type == mod_brush ) CM_TraceThroughLeaf( &tw, &mod->leaf ); + else CM_TraceThroughTree( &tw, 0, 0, 1, tw.start, tw.end ); } // generate endpos from the original, unmodified start/end @@ -557,15 +558,14 @@ void CM_Trace( trace_t *results, const vec3_t start, const vec3_t end, vec3_t mi =============================================================================== */ - /* ================== CM_BoxTrace ================== */ -trace_t CM_BoxTrace( vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, int brushmask ) +trace_t CM_BoxTrace( const vec3_t start, const vec3_t end, vec3_t mins, vec3_t maxs, cmodel_t *model, int brushmask ) { - CM_Trace( &cm.trace, start, end, mins, maxs, brushmask ); + CM_Trace( &cm.trace, start, end, mins, maxs, model, vec3_origin, brushmask ); return cm.trace; } @@ -577,7 +577,7 @@ Handles offseting and rotation of the end points for moving and rotating entities ================== */ -trace_t CM_TransformedBoxTrace( const vec3_t start, const vec3_t end, vec3_t mins, vec3_t maxs, int brushmask, vec3_t origin, vec3_t angles ) +trace_t CM_TransformedBoxTrace( const vec3_t start, const vec3_t end, vec3_t mins, vec3_t maxs, cmodel_t *model, int brushmask, vec3_t origin, vec3_t angles ) { trace_t trace; vec3_t start_l, end_l; @@ -608,7 +608,7 @@ trace_t CM_TransformedBoxTrace( const vec3_t start, const vec3_t end, vec3_t min VectorSubtract( end_l, origin, end_l ); // rotate start and end into the models frame of reference - if (!VectorIsNull( angles )) rotated = true; + if(!VectorIsNull( angles )) rotated = true; else rotated = false; if( rotated ) @@ -625,7 +625,7 @@ trace_t CM_TransformedBoxTrace( const vec3_t start, const vec3_t end, vec3_t min } // sweep the box through the model - CM_Trace( &trace, start_l, end_l, symetricSize[0], symetricSize[1], brushmask ); + CM_Trace( &trace, start_l, end_l, symetricSize[0], symetricSize[1], model, origin, brushmask ); // if the bmodel was rotated and there was a collision if( rotated && trace.fraction != 1.0 ) diff --git a/physic/cm_utils.h b/physic/cm_utils.h index e0e8ba62..1af05bf2 100644 --- a/physic/cm_utils.h +++ b/physic/cm_utils.h @@ -44,10 +44,10 @@ int CM_NumTexinfo( void ); int CM_NumInlineModels( void ); const char *CM_EntityString( void ); const char *CM_TexName( int index ); -int CM_PointContents( const vec3_t p ); -int CM_TransformedPointContents( const vec3_t p, const vec3_t origin, const vec3_t angles ); -trace_t CM_BoxTrace( vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, int brushmask ); -trace_t CM_TransformedBoxTrace( const vec3_t start, const vec3_t end, vec3_t mins, vec3_t maxs, int brushmask, vec3_t origin, vec3_t angles ); +int CM_PointContents( const vec3_t p, cmodel_t *model ); +int CM_TransformedPointContents( const vec3_t p, cmodel_t *model, const vec3_t origin, const vec3_t angles ); +trace_t CM_BoxTrace( const vec3_t start, const vec3_t end, vec3_t mins, vec3_t maxs, cmodel_t *model, int brushmask ); +trace_t CM_TransformedBoxTrace( const vec3_t start, const vec3_t end, vec3_t mins, vec3_t maxs, cmodel_t *model, int brushmask, vec3_t origin, vec3_t angles ); byte *CM_ClusterPVS( int cluster ); byte *CM_ClusterPHS( int cluster ); int CM_PointLeafnum( const vec3_t p ); @@ -56,5 +56,6 @@ int CM_LeafCluster( int leafnum ); int CM_LeafArea( int leafnum ); bool CM_AreasConnected( int area1, int area2 ); int CM_WriteAreaBits( byte *buffer, int area ); +void CM_ModelBounds( cmodel_t *model, vec3_t mins, vec3_t maxs ); #endif//CM_UTILS_H \ No newline at end of file diff --git a/pr_server/client.c b/pr_server/client.c index 18d939a3..b874b1ff 100644 --- a/pr_server/client.c +++ b/pr_server/client.c @@ -289,6 +289,7 @@ void() PutClientInServer = pev->mass = 90; pev->th_pain = PlayerPain; pev->th_die = PlayerDie; + pev->touch = PlayerTouch; setstats( pev, STAT_HEALTH_ICON, "hud/i_health"); setstats( pev, STAT_HEALTH, ftoa(pev->health)); diff --git a/pr_server/func_mover.c b/pr_server/func_mover.c index d02a265f..173a005b 100644 --- a/pr_server/func_mover.c +++ b/pr_server/func_mover.c @@ -186,6 +186,11 @@ void() func_mover_touch = } }; +void func_mover_null ( void ) +{ + // null touching function +} + void() func_mover_use = { if(pev->message) @@ -221,6 +226,7 @@ void() func_mover = pev->th_die = func_mover_die; if(!pev->targetname) pev->touch = func_mover_touch; + else pev->touch = func_mover_null; //func_mover; DEFAULTS; if (!pev->speed) diff --git a/pr_server/funcs.c b/pr_server/funcs.c index f7bc0819..f192070b 100644 --- a/pr_server/funcs.c +++ b/pr_server/funcs.c @@ -51,6 +51,11 @@ void() func_illusionary = pev->solid = SOLID_TRIGGER; }; +void func_wall_touch ( void ) +{ + // null touching function +} + void animate_wall( void ) { pev->frame++; @@ -66,6 +71,7 @@ void() func_wall = pev->nextthink = time + 1.0; pev->think = animate_wall; + pev->touch = func_wall_touch; }; /* diff --git a/pr_server/player.c b/pr_server/player.c index 08194889..26142bbe 100644 --- a/pr_server/player.c +++ b/pr_server/player.c @@ -204,6 +204,10 @@ void() DeathSound = sound (pev, CHAN_VOICE, pev->noise, 1, ATTN_NONE); }; +void PlayerTouch( void ) +{ +} + void () PlayerDie = { pev->view_ofs = '0 0 -8'; diff --git a/public/dllapi.h b/public/dllapi.h index 539ad0ae..0a80b638 100644 --- a/public/dllapi.h +++ b/public/dllapi.h @@ -245,10 +245,10 @@ typedef struct physic_exp_s int (*NumBmodels )( void ); const char *(*GetEntityString)( void ); const char *(*GetTextureName)( int index ); - int (*PointContents)( const vec3_t p ); - int (*TransformedPointContents)( const vec3_t p, const vec3_t origin, const vec3_t angles ); - trace_t (*BoxTrace)( vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, int brushmask); - trace_t (*TransformedBoxTrace)( const vec3_t start, const vec3_t end, vec3_t mins, vec3_t maxs, int brushmask, vec3_t origin, vec3_t angles ); + int (*PointContents)( const vec3_t p, cmodel_t *model ); + int (*TransformedPointContents)( const vec3_t p, cmodel_t *model, const vec3_t origin, const vec3_t angles ); + trace_t (*BoxTrace)( const vec3_t start, const vec3_t end, vec3_t mins, vec3_t maxs, cmodel_t *model, int brushmask); + trace_t (*TransformedBoxTrace)( const vec3_t start, const vec3_t end, vec3_t mins, vec3_t maxs, cmodel_t *model, int brushmask, vec3_t origin, vec3_t angles ); byte *(*ClusterPVS)( int cluster ); byte *(*ClusterPHS)( int cluster ); int (*PointLeafnum)( vec3_t p ); diff --git a/public/mathlib.h b/public/mathlib.h index e0c08cf2..16dfdc51 100644 --- a/public/mathlib.h +++ b/public/mathlib.h @@ -960,6 +960,23 @@ _inline void CM_RoundUpHullSize( vec3_t size ) } } +/* +================= +RadiusFromBounds +================= +*/ +_inline float RadiusFromBounds( vec3_t mins, vec3_t maxs ) +{ + int i; + vec3_t corner; + + for (i = 0; i < 3; i++) + { + corner[i] = fabs(mins[i]) > fabs(maxs[i]) ? fabs(mins[i]) : fabs(maxs[i]); + } + return VectorLength( corner ); +} + static vec3_t vec3_origin = { 0, 0, 0 }; static vec3_t vec3_angles = { 0, 0, 0 }; diff --git a/public/stdref.h b/public/stdref.h index fc7fec6a..005a6abf 100644 --- a/public/stdref.h +++ b/public/stdref.h @@ -1364,6 +1364,15 @@ typedef struct cplane_s byte pad[2]; } cplane_t; +typedef struct +{ + int contents; + int cluster; + int area; + int firstleafbrush; + int numleafbrushes; +} cleaf_t; + typedef struct cmesh_s { vec3_t *verts; @@ -1376,8 +1385,8 @@ typedef struct cmodel_s byte *mempool; // personal mempool int registration_sequence; - vec3_t mins, maxs; // boundbox - int headnode; // bsp info + vec3_t mins, maxs; // model boundbox + cleaf_t leaf; int type; // model type int firstface; // used to create collision tree int numfaces; diff --git a/render/gl_model.c b/render/gl_model.c index e4140686..12487a11 100644 --- a/render/gl_model.c +++ b/render/gl_model.c @@ -372,25 +372,6 @@ void Mod_LoadVertexes (lump_t *l) } } -/* -================= -RadiusFromBounds -================= -*/ -float RadiusFromBounds (vec3_t mins, vec3_t maxs) -{ - int i; - vec3_t corner; - - for (i=0 ; i<3 ; i++) - { - corner[i] = fabs(mins[i]) > fabs(maxs[i]) ? fabs(mins[i]) : fabs(maxs[i]); - } - - return VectorLength (corner); -} - - /* ================= Mod_LoadSubmodels