26 Aug 2010
This commit is contained in:
parent
9e797d351d
commit
08114a7f78
|
@ -1055,6 +1055,13 @@ int AddToFullPack( struct entity_state_s *state, int e, edict_t *ent, edict_t *h
|
|||
// Copy state data
|
||||
//
|
||||
|
||||
#ifdef DEBUG
|
||||
// NOTE: edit delta.lst if you want to get it work: add new field
|
||||
// DEFINE_DELTA( classname, DT_STRING, 1, 1.0 ),
|
||||
// into Entity_Encode, Player_Encode and Custom_Encode structures
|
||||
strncpy( state->classname, STRING( ent->v.classname ), sizeof( state->classname ));
|
||||
#endif
|
||||
|
||||
// Round animtime to nearest millisecond
|
||||
state->animtime = (int)(1000.0 * ent->v.animtime ) / 1000.0;
|
||||
|
||||
|
|
|
@ -114,6 +114,7 @@ void CL_DeltaEntity( sizebuf_t *msg, frame_t *frame, int newnum, entity_state_t
|
|||
cl_entity_t *ent;
|
||||
entity_state_t *state;
|
||||
bool newent = (old) ? false : true;
|
||||
int result = 1;
|
||||
|
||||
ent = EDICT_NUM( newnum );
|
||||
state = &cl.entity_curstates[cl.parse_entities & (MAX_PARSE_ENTITIES-1)];
|
||||
|
@ -121,13 +122,25 @@ void CL_DeltaEntity( sizebuf_t *msg, frame_t *frame, int newnum, entity_state_t
|
|||
if( newent ) old = &ent->baseline;
|
||||
|
||||
if( unchanged ) *state = *old;
|
||||
else MSG_ReadDeltaEntity( msg, old, state, newnum, cl.frame.servertime );
|
||||
else result = MSG_ReadDeltaEntity( msg, old, state, newnum, cl.frame.servertime );
|
||||
|
||||
if( state->number == -1 )
|
||||
if( !result )
|
||||
{
|
||||
if( newent ) Host_Error( "Cl_DeltaEntity: tried to release new entity\n" );
|
||||
CL_FreeEntity( ent );
|
||||
return; // entity was delta removed
|
||||
|
||||
if( state->number == -1 )
|
||||
{
|
||||
// Msg( "Entity %s was removed from server\n", ent->curstate.classname );
|
||||
CL_FreeEntity( ent );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Msg( "Entity %s was removed from delta-message\n", ent->curstate.classname );
|
||||
ent->curstate.effects |= EF_NODRAW; // don't rendering
|
||||
}
|
||||
|
||||
// entity was delta removed
|
||||
return;
|
||||
}
|
||||
|
||||
cl.parse_entities++;
|
||||
|
@ -442,6 +455,10 @@ void CL_AddPacketEntities( frame_t *frame )
|
|||
ent = CL_GetEntityByIndex( e );
|
||||
if( !ent ) continue;
|
||||
|
||||
// entity not visible for this client
|
||||
if( ent->curstate.effects & EF_NODRAW )
|
||||
continue;
|
||||
|
||||
entityType = ent->curstate.entityType;
|
||||
CL_UpdateEntityFields( ent );
|
||||
|
||||
|
|
|
@ -90,7 +90,6 @@ byte *CM_LeafPVS( int leafnum );
|
|||
byte *CM_LeafPHS( int leafnum );
|
||||
int CM_PointLeafnum( const vec3_t p );
|
||||
mleaf_t *CM_PointInLeaf( const vec3_t p, mnode_t *node );
|
||||
bool CM_HeadnodeVisible( int nodenum, byte *visbits );
|
||||
int CM_BoxLeafnums( const vec3_t mins, const vec3_t maxs, short *list, int listsize, int *lastleaf );
|
||||
int CM_TempBoxModel( const vec3_t mins, const vec3_t maxs, bool capsule );
|
||||
bool CM_BoxVisible( const vec3_t mins, const vec3_t maxs, byte *visbits );
|
||||
|
@ -126,8 +125,6 @@ void CM_EndRegistration( void );
|
|||
//
|
||||
// cm_studio.c
|
||||
//
|
||||
void CM_SpriteModel( model_t *mod, byte *buffer );
|
||||
void CM_StudioModel( model_t *mod, byte *buffer );
|
||||
void CM_StudioInitBoxHull( void );
|
||||
int CM_StudioBodyVariations( int handle );
|
||||
void CM_StudioGetAttachment( edict_t *e, int iAttachment, float *org, float *ang );
|
||||
|
|
|
@ -855,6 +855,55 @@ static void CM_BrushModel( model_t *mod, byte *buffer )
|
|||
}
|
||||
}
|
||||
|
||||
static void CM_StudioModel( model_t *mod, byte *buffer )
|
||||
{
|
||||
studiohdr_t *phdr;
|
||||
mstudioseqdesc_t *pseqdesc;
|
||||
|
||||
phdr = (studiohdr_t *)buffer;
|
||||
if( phdr->version != STUDIO_VERSION )
|
||||
{
|
||||
MsgDev( D_ERROR, "CM_StudioModel: %s has wrong version number (%i should be %i)\n", loadmodel->name, phdr->version, STUDIO_VERSION );
|
||||
return;
|
||||
}
|
||||
|
||||
loadmodel->type = mod_studio;
|
||||
pseqdesc = (mstudioseqdesc_t *)((byte *)phdr + phdr->seqindex);
|
||||
loadmodel->numframes = pseqdesc[0].numframes;
|
||||
loadmodel->registration_sequence = cm.registration_sequence;
|
||||
|
||||
loadmodel->mempool = Mem_AllocPool( va("^2%s^7", loadmodel->name ));
|
||||
loadmodel->extradata = Mem_Alloc( loadmodel->mempool, LittleLong( phdr->length ));
|
||||
Mem_Copy( loadmodel->extradata, buffer, LittleLong( phdr->length ));
|
||||
|
||||
// setup bounding box
|
||||
VectorCopy( phdr->bbmin, loadmodel->mins );
|
||||
VectorCopy( phdr->bbmax, loadmodel->maxs );
|
||||
}
|
||||
|
||||
static void CM_SpriteModel( model_t *mod, byte *buffer )
|
||||
{
|
||||
dsprite_t *phdr;
|
||||
|
||||
phdr = (dsprite_t *)buffer;
|
||||
|
||||
if( phdr->version != SPRITE_VERSION )
|
||||
{
|
||||
MsgDev( D_ERROR, "CM_SpriteModel: %s has wrong version number (%i should be %i)\n", loadmodel->name, phdr->version, SPRITE_VERSION );
|
||||
return;
|
||||
}
|
||||
|
||||
loadmodel->type = mod_sprite;
|
||||
loadmodel->numframes = phdr->numframes;
|
||||
loadmodel->registration_sequence = cm.registration_sequence;
|
||||
|
||||
// setup bounding box
|
||||
loadmodel->mins[0] = loadmodel->mins[1] = -phdr->bounds[0] / 2;
|
||||
loadmodel->maxs[0] = loadmodel->maxs[1] = phdr->bounds[0] / 2;
|
||||
loadmodel->mins[2] = -phdr->bounds[1] / 2;
|
||||
loadmodel->maxs[2] = phdr->bounds[1] / 2;
|
||||
}
|
||||
|
||||
void CM_FreeWorld( void )
|
||||
{
|
||||
if( worldmodel )
|
||||
|
|
|
@ -800,52 +800,4 @@ void CM_GetBonePosition( edict_t* e, int iBone, float *org, float *ang )
|
|||
if( org ) Matrix4x4_OriginFromMatrix( studio.bones[iBone], org );
|
||||
if( ang ) Matrix3x3_ToAngles( axis, ang, true );
|
||||
|
||||
}
|
||||
|
||||
void CM_StudioModel( model_t *mod, byte *buffer )
|
||||
{
|
||||
studiohdr_t *phdr;
|
||||
mstudioseqdesc_t *pseqdesc;
|
||||
|
||||
phdr = (studiohdr_t *)buffer;
|
||||
if( phdr->version != STUDIO_VERSION )
|
||||
{
|
||||
MsgDev( D_ERROR, "CM_StudioModel: %s has wrong version number (%i should be %i)\n", loadmodel->name, phdr->version, STUDIO_VERSION );
|
||||
return;
|
||||
}
|
||||
|
||||
loadmodel->type = mod_studio;
|
||||
pseqdesc = (mstudioseqdesc_t *)((byte *)phdr + phdr->seqindex);
|
||||
loadmodel->numframes = pseqdesc[0].numframes;
|
||||
loadmodel->registration_sequence = cm.registration_sequence;
|
||||
|
||||
loadmodel->mempool = Mem_AllocPool( va("^2%s^7", loadmodel->name ));
|
||||
loadmodel->extradata = Mem_Alloc( loadmodel->mempool, LittleLong( phdr->length ));
|
||||
Mem_Copy( loadmodel->extradata, buffer, LittleLong( phdr->length ));
|
||||
|
||||
// setup bounding box
|
||||
CM_StudioExtractBbox( phdr, 0, loadmodel->mins, loadmodel->maxs );
|
||||
}
|
||||
|
||||
void CM_SpriteModel( model_t *mod, byte *buffer )
|
||||
{
|
||||
dsprite_t *phdr;
|
||||
|
||||
phdr = (dsprite_t *)buffer;
|
||||
|
||||
if( phdr->version != SPRITE_VERSION )
|
||||
{
|
||||
MsgDev( D_ERROR, "CM_SpriteModel: %s has wrong version number (%i should be %i)\n", loadmodel->name, phdr->version, SPRITE_VERSION );
|
||||
return;
|
||||
}
|
||||
|
||||
loadmodel->type = mod_sprite;
|
||||
loadmodel->numframes = phdr->numframes;
|
||||
loadmodel->registration_sequence = cm.registration_sequence;
|
||||
|
||||
// setup bounding box
|
||||
loadmodel->mins[0] = loadmodel->mins[1] = -phdr->bounds[0] / 2;
|
||||
loadmodel->maxs[0] = loadmodel->maxs[1] = phdr->bounds[0] / 2;
|
||||
loadmodel->mins[2] = -phdr->bounds[1] / 2;
|
||||
loadmodel->maxs[2] = phdr->bounds[1] / 2;
|
||||
}
|
|
@ -5,30 +5,7 @@
|
|||
|
||||
#include "cm_local.h"
|
||||
#include "mathlib.h"
|
||||
|
||||
/*
|
||||
==============
|
||||
BoxOnPlaneSide (engine fast version)
|
||||
|
||||
Returns SIDE_FRONT, SIDE_BACK, or SIDE_ON
|
||||
==============
|
||||
*/
|
||||
int CM_BoxOnPlaneSide( const vec3_t emins, const vec3_t emaxs, const mplane_t *p )
|
||||
{
|
||||
if( p->type < 3 ) return ((emaxs[p->type] >= p->dist) | ((emins[p->type] < p->dist) << 1));
|
||||
switch( p->signbits )
|
||||
{
|
||||
default:
|
||||
case 0: return (((p->normal[0] * emaxs[0] + p->normal[1] * emaxs[1] + p->normal[2] * emaxs[2]) >= p->dist) | (((p->normal[0] * emins[0] + p->normal[1] * emins[1] + p->normal[2] * emins[2]) < p->dist) << 1));
|
||||
case 1: return (((p->normal[0] * emins[0] + p->normal[1] * emaxs[1] + p->normal[2] * emaxs[2]) >= p->dist) | (((p->normal[0] * emaxs[0] + p->normal[1] * emins[1] + p->normal[2] * emins[2]) < p->dist) << 1));
|
||||
case 2: return (((p->normal[0] * emaxs[0] + p->normal[1] * emins[1] + p->normal[2] * emaxs[2]) >= p->dist) | (((p->normal[0] * emins[0] + p->normal[1] * emaxs[1] + p->normal[2] * emins[2]) < p->dist) << 1));
|
||||
case 3: return (((p->normal[0] * emins[0] + p->normal[1] * emins[1] + p->normal[2] * emaxs[2]) >= p->dist) | (((p->normal[0] * emaxs[0] + p->normal[1] * emaxs[1] + p->normal[2] * emins[2]) < p->dist) << 1));
|
||||
case 4: return (((p->normal[0] * emaxs[0] + p->normal[1] * emaxs[1] + p->normal[2] * emins[2]) >= p->dist) | (((p->normal[0] * emins[0] + p->normal[1] * emins[1] + p->normal[2] * emaxs[2]) < p->dist) << 1));
|
||||
case 5: return (((p->normal[0] * emins[0] + p->normal[1] * emaxs[1] + p->normal[2] * emins[2]) >= p->dist) | (((p->normal[0] * emaxs[0] + p->normal[1] * emins[1] + p->normal[2] * emaxs[2]) < p->dist) << 1));
|
||||
case 6: return (((p->normal[0] * emaxs[0] + p->normal[1] * emins[1] + p->normal[2] * emins[2]) >= p->dist) | (((p->normal[0] * emins[0] + p->normal[1] * emaxs[1] + p->normal[2] * emaxs[2]) < p->dist) << 1));
|
||||
case 7: return (((p->normal[0] * emins[0] + p->normal[1] * emins[1] + p->normal[2] * emins[2]) >= p->dist) | (((p->normal[0] * emaxs[0] + p->normal[1] * emaxs[1] + p->normal[2] * emaxs[2]) < p->dist) << 1));
|
||||
}
|
||||
}
|
||||
#include "world.h"
|
||||
|
||||
/*
|
||||
==================
|
||||
|
@ -89,7 +66,7 @@ void CM_BoxLeafnums_r( leaflist_t *ll, mnode_t *node )
|
|||
}
|
||||
|
||||
plane = node->plane;
|
||||
s = CM_BoxOnPlaneSide( ll->mins, ll->maxs, plane );
|
||||
s = BOX_ON_PLANE_SIDE( ll->mins, ll->maxs, plane );
|
||||
|
||||
if( s == 1 )
|
||||
{
|
||||
|
@ -136,54 +113,6 @@ int CM_BoxLeafnums( const vec3_t mins, const vec3_t maxs, short *list, int lists
|
|||
return ll.count;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
CM_HeadnodeVisible_r
|
||||
=============
|
||||
*/
|
||||
bool CM_HeadnodeVisible_r( mnode_t *node, byte *visbits )
|
||||
{
|
||||
mleaf_t *leaf;
|
||||
int leafnum;
|
||||
|
||||
if( node->contents < 0 )
|
||||
{
|
||||
if( node->contents != CONTENTS_SOLID )
|
||||
{
|
||||
leaf = (mleaf_t *)node;
|
||||
leafnum = (leaf - worldmodel->leafs - 1);
|
||||
|
||||
if( visbits[leafnum>>3] & (1<<( leafnum & 7 )))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if( CM_HeadnodeVisible_r( node->children[0], visbits ))
|
||||
return true;
|
||||
return CM_HeadnodeVisible_r( node->children[1], visbits );
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
CM_HeadnodeVisible
|
||||
|
||||
returns true if any leaf under headnode
|
||||
is potentially visible
|
||||
=============
|
||||
*/
|
||||
bool CM_HeadnodeVisible( int nodenum, byte *visbits )
|
||||
{
|
||||
mnode_t *node;
|
||||
|
||||
if( !worldmodel ) return false;
|
||||
if( nodenum == -1 ) return false;
|
||||
|
||||
node = (mnode_t *)worldmodel->nodes + nodenum;
|
||||
|
||||
return CM_HeadnodeVisible_r( node, visbits );
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
CM_BoxVisible
|
||||
|
|
|
@ -112,7 +112,7 @@ void BF_WriteOneBit( sizebuf_t *bf, int nValue )
|
|||
|
||||
void BF_WriteUBitLongExt( sizebuf_t *bf, uint curData, int numbits, bool bCheckRange )
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
#ifdef PARANOID
|
||||
// make sure it doesn't overflow.
|
||||
if( bCheckRange && numbits < 32 )
|
||||
{
|
||||
|
|
|
@ -1382,11 +1382,21 @@ void MSG_WriteDeltaEntity( entity_state_t *from, entity_state_t *to, sizebuf_t *
|
|||
|
||||
if( to == NULL )
|
||||
{
|
||||
int fRemoveType;
|
||||
|
||||
if( from == NULL ) return;
|
||||
|
||||
// a NULL to is a delta remove message
|
||||
BF_WriteWord( msg, from->number );
|
||||
BF_WriteOneBit( msg, 1 ); // entity killed
|
||||
|
||||
// fRemoveType:
|
||||
// 0 - keep alive, has delta-update
|
||||
// 1 - remove from delta message (but keep states)
|
||||
// 2 - completely remove from server
|
||||
if( force ) fRemoveType = 2;
|
||||
else fRemoveType = 1;
|
||||
|
||||
BF_WriteUBitLong( msg, fRemoveType, 2 );
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1396,7 +1406,7 @@ void MSG_WriteDeltaEntity( entity_state_t *from, entity_state_t *to, sizebuf_t *
|
|||
Host_Error( "MSG_WriteDeltaEntity: Bad entity number: %i\n", to->number );
|
||||
|
||||
BF_WriteWord( msg, to->number );
|
||||
BF_WriteOneBit( msg, 0 ); // alive
|
||||
BF_WriteUBitLong( msg, 0, 2 ); // alive
|
||||
|
||||
if( to->entityType != from->entityType )
|
||||
{
|
||||
|
@ -1448,25 +1458,39 @@ If the delta removes the entity, entity_state_t->number will be set to MAX_EDICT
|
|||
Can go from either a baseline or a previous packet_entity
|
||||
==================
|
||||
*/
|
||||
void MSG_ReadDeltaEntity( sizebuf_t *msg, entity_state_t *from, entity_state_t *to, int number, int timebase )
|
||||
bool MSG_ReadDeltaEntity( sizebuf_t *msg, entity_state_t *from, entity_state_t *to, int number, int timebase )
|
||||
{
|
||||
delta_info_t *dt;
|
||||
delta_t *pField;
|
||||
float flTime = timebase * 0.001f;
|
||||
int i;
|
||||
int i, fRemoveType;
|
||||
|
||||
if( number < 0 || number >= GI->max_edicts )
|
||||
Host_Error( "MSG_ReadDeltaEntity: bad delta entity number: %i\n", number );
|
||||
|
||||
*to = *from;
|
||||
to->number = number;
|
||||
fRemoveType = BF_ReadUBitLong( msg, 2 );
|
||||
|
||||
if( BF_ReadOneBit( msg ))
|
||||
if( fRemoveType )
|
||||
{
|
||||
// check for a remove
|
||||
Mem_Set( to, 0, sizeof( *to ));
|
||||
to->number = -1; // entity was removed
|
||||
return;
|
||||
Mem_Set( to, 0, sizeof( *to ));
|
||||
|
||||
if( fRemoveType & 1 )
|
||||
{
|
||||
// removed from delta-message
|
||||
return false;
|
||||
}
|
||||
|
||||
if( fRemoveType & 2 )
|
||||
{
|
||||
// entity was removed from server
|
||||
to->number = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
Host_Error( "MSG_ReadDeltaEntity: unknown update type %i\n", fRemoveType );
|
||||
}
|
||||
|
||||
if( BF_ReadOneBit( msg ))
|
||||
|
@ -1495,6 +1519,9 @@ void MSG_ReadDeltaEntity( sizebuf_t *msg, entity_state_t *from, entity_state_t *
|
|||
{
|
||||
Delta_ReadField( msg, pField, from, to, flTime );
|
||||
}
|
||||
|
||||
// message parsed
|
||||
return true;
|
||||
}
|
||||
|
||||
void Delta_AddEncoder( char *name, pfnDeltaEncode encodeFunc )
|
||||
|
|
|
@ -101,6 +101,6 @@ void MSG_ReadDeltaMovevars( sizebuf_t *msg, movevars_t *from, movevars_t *to );
|
|||
void MSG_WriteClientData( sizebuf_t *msg, clientdata_t *from, clientdata_t *to, int timebase );
|
||||
void MSG_ReadClientData( sizebuf_t *msg, clientdata_t *from, clientdata_t *to, int timebase );
|
||||
void MSG_WriteDeltaEntity( entity_state_t *from, entity_state_t *to, sizebuf_t *msg, bool force, int timebase );
|
||||
void MSG_ReadDeltaEntity( sizebuf_t *msg, entity_state_t *from, entity_state_t *to, int number, int timebase );
|
||||
bool MSG_ReadDeltaEntity( sizebuf_t *msg, entity_state_t *from, entity_state_t *to, int number, int timebase );
|
||||
|
||||
#endif//NET_ENCODE_H
|
|
@ -110,4 +110,93 @@ trace_t World_CombineTraces( trace_t *cliptrace, trace_t *trace, edict_t *touch
|
|||
cliptrace->fStartSolid = true;
|
||||
|
||||
return *cliptrace;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
RankForContents
|
||||
|
||||
Used for determine contents priority
|
||||
==================
|
||||
*/
|
||||
int RankForContents( int contents )
|
||||
{
|
||||
switch( contents )
|
||||
{
|
||||
case CONTENTS_EMPTY: return 0;
|
||||
case CONTENTS_WATER: return 1;
|
||||
case CONTENTS_TRANSLUCENT: return 2;
|
||||
case CONTENTS_CURRENT_0: return 3;
|
||||
case CONTENTS_CURRENT_90: return 4;
|
||||
case CONTENTS_CURRENT_180: return 5;
|
||||
case CONTENTS_CURRENT_270: return 6;
|
||||
case CONTENTS_CURRENT_UP: return 7;
|
||||
case CONTENTS_CURRENT_DOWN: return 8;
|
||||
case CONTENTS_SLIME: return 9;
|
||||
case CONTENTS_LAVA: return 10;
|
||||
case CONTENTS_SKY: return 11;
|
||||
case CONTENTS_SOLID: return 12;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
BoxOnPlaneSide
|
||||
|
||||
Returns 1, 2, or 1 + 2
|
||||
==================
|
||||
*/
|
||||
int BoxOnPlaneSide( const vec3_t emins, const vec3_t emaxs, const mplane_t *p )
|
||||
{
|
||||
float dist1, dist2;
|
||||
int sides = 0;
|
||||
|
||||
// general case
|
||||
switch( p->signbits )
|
||||
{
|
||||
case 0:
|
||||
dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
|
||||
dist2 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
|
||||
break;
|
||||
case 1:
|
||||
dist1 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
|
||||
dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
|
||||
break;
|
||||
case 2:
|
||||
dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
|
||||
dist2 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
|
||||
break;
|
||||
case 3:
|
||||
dist1 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
|
||||
dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
|
||||
break;
|
||||
case 4:
|
||||
dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
|
||||
dist2 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
|
||||
break;
|
||||
case 5:
|
||||
dist1 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
|
||||
dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
|
||||
break;
|
||||
case 6:
|
||||
dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
|
||||
dist2 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
|
||||
break;
|
||||
case 7:
|
||||
dist1 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
|
||||
dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
|
||||
break;
|
||||
default:
|
||||
// shut up compiler
|
||||
dist1 = dist2 = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if( dist1 >= p->dist )
|
||||
sides = 1;
|
||||
if( dist2 < p->dist )
|
||||
sides |= 2;
|
||||
|
||||
return sides;
|
||||
}
|
|
@ -21,8 +21,8 @@ ENTITY AREA CHECKING
|
|||
*/
|
||||
#define EDICT_FROM_AREA( l ) EDICT_NUM( l->entnum )
|
||||
#define MAX_TOTAL_ENT_LEAFS 128
|
||||
#define AREA_NODES 64
|
||||
#define AREA_DEPTH 5
|
||||
#define AREA_NODES 32
|
||||
#define AREA_DEPTH 4
|
||||
|
||||
typedef struct areanode_s
|
||||
{
|
||||
|
@ -44,30 +44,6 @@ typedef struct area_s
|
|||
int type;
|
||||
} area_t;
|
||||
|
||||
typedef struct moveclip_s
|
||||
{
|
||||
vec3_t boxmins; // enclose the test object along entire move
|
||||
vec3_t boxmaxs;
|
||||
float *mins;
|
||||
float *maxs; // size of the moving object
|
||||
vec3_t mins2;
|
||||
vec3_t maxs2;
|
||||
const float *start;
|
||||
const float *end;
|
||||
trace_t trace;
|
||||
|
||||
union
|
||||
{
|
||||
|
||||
struct edict_s *passedict;
|
||||
struct cl_entity_s *passentity;
|
||||
|
||||
};
|
||||
|
||||
int type; // move type
|
||||
int flags; // trace flags
|
||||
} moveclip_t;
|
||||
|
||||
extern const char *et_name[];
|
||||
|
||||
// linked list
|
||||
|
@ -78,6 +54,25 @@ void ClearLink( link_t *l );
|
|||
// trace common
|
||||
void World_MoveBounds( const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, vec3_t boxmins, vec3_t boxmaxs );
|
||||
trace_t World_CombineTraces( trace_t *cliptrace, trace_t *trace, edict_t *touch );
|
||||
int BoxOnPlaneSide( const vec3_t emins, const vec3_t emaxs, const mplane_t *p );
|
||||
int RankForContents( int contents );
|
||||
|
||||
#define BOX_ON_PLANE_SIDE( emins, emaxs, p ) \
|
||||
((( p )->type < 3 ) ? \
|
||||
( \
|
||||
((p)->dist <= (emins)[(p)->type]) ? \
|
||||
1 \
|
||||
: \
|
||||
( \
|
||||
((p)->dist >= (emaxs)[(p)->type]) ? \
|
||||
2 \
|
||||
: \
|
||||
3 \
|
||||
) \
|
||||
) \
|
||||
: \
|
||||
BoxOnPlaneSide(( emins ), ( emaxs ), ( p )))
|
||||
|
||||
|
||||
#include "bspfile.h"
|
||||
#include "pm_shared.h"
|
||||
|
|
|
@ -314,6 +314,10 @@ SOURCE=.\server\sv_save.c
|
|||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\server\sv_studio.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\server\sv_world.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
|
|
@ -43,6 +43,7 @@ extern int SV_UPDATE_BACKUP;
|
|||
// convert msecs to float time properly
|
||||
#define sv_time() ( sv.time * 0.001f )
|
||||
#define sv_frametime() ( sv.frametime * 0.001f )
|
||||
#define SV_IsValidEdict( e ) ( e && !e->free )
|
||||
|
||||
typedef enum
|
||||
{
|
||||
|
@ -85,6 +86,8 @@ typedef struct server_s
|
|||
sizebuf_t signon;
|
||||
byte signon_buf[MAX_MSGLEN];
|
||||
|
||||
model_t *worldmodel; // pointer to world
|
||||
|
||||
bool write_bad_message; // just for debug
|
||||
bool paused;
|
||||
} server_t;
|
||||
|
@ -422,7 +425,6 @@ void SV_StartSound( edict_t *ent, int chan, const char *sample, float vol, float
|
|||
edict_t* pfnPEntityOfEntIndex( int iEntIndex );
|
||||
int pfnIndexOfEdict( const edict_t *pEdict );
|
||||
void SV_UpdateBaseVelocity( edict_t *ent );
|
||||
bool SV_IsValidEdict( const edict_t *e );
|
||||
script_t *CM_GetEntityScript( void );
|
||||
|
||||
_inline edict_t *SV_EDICT_NUM( int n, const char * file, const int line )
|
||||
|
@ -443,6 +445,16 @@ void SV_ChangeLevel( bool loadfromsavedgame, const char *mapname, const char *st
|
|||
const char *SV_GetLatestSave( void );
|
||||
int SV_LoadGameState( char const *level, bool createPlayers );
|
||||
void SV_LoadAdjacentEnts( const char *pOldLevel, const char *pLandmarkName );
|
||||
|
||||
//
|
||||
// sv_studio.c
|
||||
//
|
||||
void SV_InitStudioHull( void );
|
||||
bool SV_StudioExtractBbox( model_t *mod, int sequence, float *mins, float *maxs );
|
||||
void SV_StudioGetAttachment( edict_t *e, int iAttachment, float *org, float *ang );
|
||||
bool SV_StudioTrace( edict_t *ent, const vec3_t p1, vec3_t mins, vec3_t maxs, const vec3_t p2, trace_t *ptr );
|
||||
void SV_GetBonePosition( edict_t *e, int iBone, float *org, float *ang );
|
||||
|
||||
//============================================================
|
||||
|
||||
// high level object sorting to reduce interaction tests
|
||||
|
@ -480,6 +492,8 @@ bool SV_CopyEdictToPhysEnt( physent_t *pe, edict_t *ed, bool player_trace );
|
|||
extern areanode_t sv_areanodes[];
|
||||
|
||||
void SV_ClearWorld( void );
|
||||
bool SV_HeadnodeVisible( mnode_t *node, byte *visbits );
|
||||
int SV_HullPointContents( hull_t *hull, int num, const vec3_t p );
|
||||
trace_t SV_Move( const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, int type, edict_t *e );
|
||||
trace_t SV_ClipMove( edict_t *ent, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, int flags );
|
||||
trace_t SV_MoveToss( edict_t *tossent, edict_t *ignore );
|
||||
|
|
|
@ -187,7 +187,7 @@ gotnewcl:
|
|||
newcl->userid = g_userid++; // create unique userid
|
||||
|
||||
// get the game a chance to reject this connection or modify the userinfo
|
||||
if(!(SV_ClientConnect( ent, userinfo )))
|
||||
if( !( SV_ClientConnect( ent, userinfo )))
|
||||
{
|
||||
if(*Info_ValueForKey( userinfo, "rejmsg" ))
|
||||
Netchan_OutOfBandPrint( NS_SERVER, from, "print\n%s\nConnection refused.\n", Info_ValueForKey( userinfo, "rejmsg" ));
|
||||
|
|
|
@ -117,8 +117,14 @@ void SV_EmitPacketEntities( client_frame_t *from, client_frame_t *to, sizebuf_t
|
|||
|
||||
if( newnum > oldnum )
|
||||
{
|
||||
bool force;
|
||||
|
||||
if( EDICT_NUM( oldent->number )->free )
|
||||
force = true; // entity completely removed from server
|
||||
else force = false; // just removed from delta-message
|
||||
|
||||
// remove from message
|
||||
MSG_WriteDeltaEntity( oldent, NULL, msg, false, sv.time );
|
||||
MSG_WriteDeltaEntity( oldent, NULL, msg, force, sv.time );
|
||||
oldindex++;
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -65,6 +65,7 @@ void SV_SysError( const char *error_string )
|
|||
|
||||
void SV_SetMinMaxSize( edict_t *e, const float *min, const float *max )
|
||||
{
|
||||
float scale = 1.0f;
|
||||
int i;
|
||||
|
||||
if( !SV_IsValidEdict( e ) || !min || !max )
|
||||
|
@ -79,9 +80,21 @@ void SV_SetMinMaxSize( edict_t *e, const float *min, const float *max )
|
|||
return;
|
||||
}
|
||||
}
|
||||
|
||||
VectorCopy( min, e->v.mins );
|
||||
VectorCopy( max, e->v.maxs );
|
||||
#if 0
|
||||
// FIXME: enable this when other server parts will be done and tested
|
||||
if( e->v.scale > 0.0f && e->v.scale != 1.0f )
|
||||
{
|
||||
switch( CM_GetModelType( e->v.modelindex ))
|
||||
{
|
||||
case mod_sprite:
|
||||
case mod_studio:
|
||||
scale = e->v.scale;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
VectorScale( min, scale, e->v.mins );
|
||||
VectorScale( max, scale, e->v.maxs );
|
||||
VectorSubtract( max, min, e->v.size );
|
||||
|
||||
SV_LinkEdict( e, false );
|
||||
|
@ -106,7 +119,7 @@ void SV_SetModel( edict_t *ent, const char *name )
|
|||
{
|
||||
vec3_t mins = { 0.0f, 0.0f, 0.0f };
|
||||
vec3_t maxs = { 0.0f, 0.0f, 0.0f };
|
||||
int i;
|
||||
int i, mod_type;
|
||||
|
||||
i = SV_ModelIndex( name );
|
||||
if( i == 0 ) return;
|
||||
|
@ -114,9 +127,16 @@ void SV_SetModel( edict_t *ent, const char *name )
|
|||
ent->v.model = MAKE_STRING( sv.configstrings[CS_MODELS+i] );
|
||||
ent->v.modelindex = i;
|
||||
|
||||
// set sizes only for brush models
|
||||
if( CM_GetModelType( ent->v.modelindex ) == mod_brush )
|
||||
mod_type = CM_GetModelType( ent->v.modelindex );
|
||||
|
||||
// studio models set to zero sizes as default
|
||||
switch( mod_type )
|
||||
{
|
||||
case mod_brush:
|
||||
case mod_sprite:
|
||||
Mod_GetBounds( ent->v.modelindex, mins, maxs );
|
||||
break;
|
||||
}
|
||||
|
||||
SV_SetMinMaxSize( ent, mins, maxs );
|
||||
}
|
||||
|
@ -528,16 +548,6 @@ void SV_PlaybackEvent( sizebuf_t *msg, event_info_t *info )
|
|||
MSG_WriteDeltaEvent( msg, &nullargs, &info->args ); // FIXME: zero-compressing
|
||||
}
|
||||
|
||||
bool SV_IsValidEdict( const edict_t *e )
|
||||
{
|
||||
if( !e ) return false;
|
||||
if( e->free ) return false;
|
||||
|
||||
// edict without pvPrivateData is valid edict
|
||||
// server.dll know how allocate it
|
||||
return true;
|
||||
}
|
||||
|
||||
const char *SV_ClassName( const edict_t *e )
|
||||
{
|
||||
if( !e ) return "(null)";
|
||||
|
@ -1346,7 +1356,7 @@ void SV_StartSound( edict_t *ent, int chan, const char *sample, float vol, float
|
|||
|
||||
// can't track this entity on the client.
|
||||
// write static sound
|
||||
if( !ent->num_leafs ) flags |= SND_FIXED_ORIGIN;
|
||||
if( !ent->headnode ) flags |= SND_FIXED_ORIGIN;
|
||||
|
||||
// ultimate method for detect bsp models with invalid solidity (e.g. func_pushable)
|
||||
if( CM_GetModelType( ent->v.modelindex ) == mod_brush )
|
||||
|
@ -1389,7 +1399,7 @@ void SV_StartSound( edict_t *ent, int chan, const char *sample, float vol, float
|
|||
sound_idx = SV_SoundIndex( sample );
|
||||
}
|
||||
|
||||
if( !ent->num_leafs )
|
||||
if( !ent->headnode )
|
||||
entityIndex = 0;
|
||||
else if( SV_IsValidEdict( ent->v.aiment ))
|
||||
entityIndex = ent->v.aiment->serialnumber;
|
||||
|
@ -2334,6 +2344,9 @@ edict_t* pfnPEntityOfEntIndex( int iEntIndex )
|
|||
{
|
||||
if( iEntIndex < 0 || iEntIndex >= svgame.numEntities )
|
||||
return NULL; // out of range
|
||||
|
||||
if( EDICT_NUM( iEntIndex )->free )
|
||||
return NULL;
|
||||
return EDICT_NUM( iEntIndex );
|
||||
}
|
||||
|
||||
|
@ -2467,7 +2480,7 @@ static void pfnGetBonePosition( const edict_t* pEdict, int iBone, float *rgflOri
|
|||
return;
|
||||
}
|
||||
|
||||
CM_GetBonePosition( (edict_t *)pEdict, iBone, rgflOrigin, rgflAngles );
|
||||
SV_GetBonePosition( (edict_t *)pEdict, iBone, rgflOrigin, rgflAngles );
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -2564,7 +2577,7 @@ static void pfnGetAttachment( const edict_t *pEdict, int iAttachment, float *rgf
|
|||
MsgDev( D_WARN, "SV_GetAttachment: invalid entity %s\n", SV_ClassName( pEdict ));
|
||||
return;
|
||||
}
|
||||
CM_StudioGetAttachment(( edict_t *)pEdict, iAttachment, rgflOrigin, rgflAngles );
|
||||
SV_StudioGetAttachment(( edict_t *)pEdict, iAttachment, rgflOrigin, rgflAngles );
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -3253,50 +3266,51 @@ pfnCheckVisibility
|
|||
|
||||
=============
|
||||
*/
|
||||
int pfnCheckVisibility( const edict_t *entity, byte *pset )
|
||||
int pfnCheckVisibility( const edict_t *ent, byte *pset )
|
||||
{
|
||||
int i, l;
|
||||
|
||||
if( !SV_IsValidEdict( entity ))
|
||||
if( !SV_IsValidEdict( ent ))
|
||||
{
|
||||
MsgDev( D_WARN, "SV_CheckVisibility: invalid entity %s\n", SV_ClassName( entity ));
|
||||
MsgDev( D_WARN, "SV_CheckVisibility: invalid entity %s\n", SV_ClassName( ent ));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if( !pset ) return 1; // vis not set - fullvis enabled
|
||||
// vis not set - fullvis enabled
|
||||
if( !pset ) return 1;
|
||||
|
||||
// check individual leafs
|
||||
if( !entity->num_leafs )
|
||||
return 0; // not a linked in
|
||||
if( !ent->headnode )
|
||||
return 0; // not a linked in ?
|
||||
|
||||
if( entity->num_leafs == -1 )
|
||||
{
|
||||
// too many leafs for individual check, go by headnode
|
||||
if( !CM_HeadnodeVisible( entity->headnode, pset ))
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
if( ent->headnode == -1 )
|
||||
{
|
||||
int i;
|
||||
|
||||
// check individual leafs
|
||||
for( i = 0; i < entity->num_leafs; i++ )
|
||||
for( i = 0; i < ent->num_leafs; i++ )
|
||||
{
|
||||
l = entity->leafnums[i];
|
||||
|
||||
if( pset[l>>3] & (1<<( l & 7 )))
|
||||
if( pset[ent->leafnums[i] >> 3] & (1 << (ent->leafnums[i] & 7 )))
|
||||
break;
|
||||
}
|
||||
|
||||
if( i == entity->num_leafs )
|
||||
if( i == ent->num_leafs )
|
||||
return 0; // not visible
|
||||
}
|
||||
|
||||
// run additional check for BoxVisible
|
||||
if( CM_GetModelType( entity->v.modelindex ) == mod_brush )
|
||||
else
|
||||
{
|
||||
if( !CM_BoxVisible( entity->v.absmin, entity->v.absmax, pset ))
|
||||
mnode_t *node;
|
||||
|
||||
// too many leafs for individual check, go by headnode
|
||||
node = sv.worldmodel->nodes + ent->headnode;
|
||||
if( !SV_HeadnodeVisible( node, pset ))
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
// NOTE: uncommenat this if you want to get more accuracy culling on large brushes
|
||||
if( CM_GetModelType( ent->v.modelindex ) == mod_brush )
|
||||
{
|
||||
if( !CM_BoxVisible( ent->v.absmin, ent->v.absmax, pset ))
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -342,6 +342,7 @@ bool SV_SpawnServer( const char *mapname, const char *startspot )
|
|||
com.sprintf( sv.configstrings[CS_MODELS+1], "maps/%s.bsp", sv.name );
|
||||
CM_BeginRegistration( sv.configstrings[CS_MODELS+1], false, &checksum );
|
||||
com.sprintf( sv.configstrings[CS_MAPCHECKSUM], "%i", checksum );
|
||||
sv.worldmodel = CM_ClipHandleToModel( 1 ); // get world pointer
|
||||
|
||||
for( i = 1; i < CM_NumBmodels(); i++ )
|
||||
{
|
||||
|
|
|
@ -34,22 +34,6 @@ Utility functions
|
|||
|
||||
===============================================================================
|
||||
*/
|
||||
/*
|
||||
============
|
||||
SV_TestEntityPosition
|
||||
|
||||
returns true if the entity is in solid currently
|
||||
============
|
||||
*/
|
||||
bool SV_TestEntityPosition( edict_t *ent )
|
||||
{
|
||||
trace_t trace;
|
||||
|
||||
trace = SV_Move( ent->v.origin, ent->v.mins, ent->v.maxs, ent->v.origin, MOVE_NORMAL|FMOVE_SIMPLEBOX, ent );
|
||||
|
||||
return trace.fStartSolid;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
SV_CheckAllEnts
|
||||
|
|
|
@ -0,0 +1,967 @@
|
|||
//=======================================================================
|
||||
// Copyright XashXT Group 2010 ©
|
||||
// sv_studio.c - server studio utilities
|
||||
//=======================================================================
|
||||
|
||||
// FIXME: these code needs be some cleanup from lerping code
|
||||
|
||||
#include "common.h"
|
||||
#include "server.h"
|
||||
#include "matrix_lib.h"
|
||||
|
||||
static studiohdr_t *sv_studiohdr;
|
||||
static mplane_t sv_hitboxplanes[6]; // there a temp hitbox
|
||||
static matrix4x4 sv_studiomatrix;
|
||||
static matrix4x4 sv_studiobones[MAXSTUDIOBONES];
|
||||
typedef bool (*pfnHitboxTrace)( trace_t *trace );
|
||||
static float trace_realfraction;
|
||||
static vec3_t trace_startmins, trace_endmins;
|
||||
static vec3_t trace_startmaxs, trace_endmaxs;
|
||||
static vec3_t trace_absmins, trace_absmaxs;
|
||||
|
||||
/*
|
||||
====================
|
||||
SV_InitStudioHull
|
||||
====================
|
||||
*/
|
||||
void SV_InitStudioHull( void )
|
||||
{
|
||||
int i, side;
|
||||
mplane_t *p;
|
||||
|
||||
for( i = 0; i < 6; i++ )
|
||||
{
|
||||
side = i & 1;
|
||||
|
||||
// planes
|
||||
p = &sv_hitboxplanes[i];
|
||||
VectorClear( p->normal );
|
||||
|
||||
if( side )
|
||||
{
|
||||
p->type = PLANE_NONAXIAL;
|
||||
p->normal[i>>1] = -1.0f;
|
||||
p->signbits = (1<<(i>>1));
|
||||
}
|
||||
else
|
||||
{
|
||||
p->type = i>>1;
|
||||
p->normal[i>>1] = 1.0f;
|
||||
p->signbits = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
SV_HullForHitbox
|
||||
====================
|
||||
*/
|
||||
static void SV_HullForHitbox( const vec3_t mins, const vec3_t maxs )
|
||||
{
|
||||
sv_hitboxplanes[0].dist = maxs[0];
|
||||
sv_hitboxplanes[1].dist = -mins[0];
|
||||
sv_hitboxplanes[2].dist = maxs[1];
|
||||
sv_hitboxplanes[3].dist = -mins[1];
|
||||
sv_hitboxplanes[4].dist = maxs[2];
|
||||
sv_hitboxplanes[5].dist = -mins[2];
|
||||
}
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
STUDIO MODELS TRACING
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
/*
|
||||
====================
|
||||
StudioSetUpTransform
|
||||
====================
|
||||
*/
|
||||
static void SV_StudioSetUpTransform( edict_t *ent )
|
||||
{
|
||||
float *ang, *org;
|
||||
float scale = 1.0f;
|
||||
|
||||
org = ent->v.origin;
|
||||
ang = ent->v.angles;
|
||||
|
||||
if( ent->v.scale != 0.0f ) scale = ent->v.scale;
|
||||
Matrix4x4_CreateFromEntity( sv_studiomatrix, org[0], org[1], org[2], -ang[PITCH], ang[YAW], ang[ROLL], scale );
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
StudioCalcBoneAdj
|
||||
|
||||
====================
|
||||
*/
|
||||
static void SV_StudioCalcBoneAdj( float dadt, float *adj, const byte *pcontroller1, const byte *pcontroller2 )
|
||||
{
|
||||
int i, j;
|
||||
float value;
|
||||
mstudiobonecontroller_t *pbonecontroller;
|
||||
|
||||
pbonecontroller = (mstudiobonecontroller_t *)((byte *)sv_studiohdr + sv_studiohdr->bonecontrollerindex);
|
||||
|
||||
for( j = 0; j < sv_studiohdr->numbonecontrollers; j++ )
|
||||
{
|
||||
i = pbonecontroller[j].index;
|
||||
|
||||
if( i == 4 ) continue; // ignore mouth
|
||||
if( i <= MAXSTUDIOCONTROLLERS )
|
||||
{
|
||||
// check for 360% wrapping
|
||||
if( pbonecontroller[j].type & STUDIO_RLOOP )
|
||||
{
|
||||
if( abs( pcontroller1[i] - pcontroller2[i] ) > 128 )
|
||||
{
|
||||
int a, b;
|
||||
|
||||
a = (pcontroller1[j] + 128) % 256;
|
||||
b = (pcontroller2[j] + 128) % 256;
|
||||
value = ((a * dadt) + (b * (1.0f - dadt)) - 128) * (360.0f / 256.0f) + pbonecontroller[j].start;
|
||||
}
|
||||
else
|
||||
{
|
||||
value = ((pcontroller1[i] * dadt + (pcontroller2[i]) * (1.0 - dadt))) * (360.0/256.0) + pbonecontroller[j].start;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
value = (pcontroller1[i] * dadt + pcontroller2[i] * (1.0f - dadt)) / 255.0f;
|
||||
if( value < 0.0f ) value = 0.0f;
|
||||
if( value > 1.0f ) value = 1.0f;
|
||||
value = (1.0f - value) * pbonecontroller[j].start + value * pbonecontroller[j].end;
|
||||
}
|
||||
}
|
||||
|
||||
switch( pbonecontroller[j].type & STUDIO_TYPES )
|
||||
{
|
||||
case STUDIO_XR:
|
||||
case STUDIO_YR:
|
||||
case STUDIO_ZR:
|
||||
adj[j] = value * (M_PI / 180.0f);
|
||||
break;
|
||||
case STUDIO_X:
|
||||
case STUDIO_Y:
|
||||
case STUDIO_Z:
|
||||
adj[j] = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
StudioCalcBoneQuaterion
|
||||
|
||||
====================
|
||||
*/
|
||||
static void SV_StudioCalcBoneQuaterion( int frame, float s, mstudiobone_t *pbone, mstudioanim_t *panim, float *adj, float *q )
|
||||
{
|
||||
int j, k;
|
||||
vec4_t q1, q2;
|
||||
vec3_t angle1, angle2;
|
||||
mstudioanimvalue_t *panimvalue;
|
||||
|
||||
for( j = 0; j < 3; j++ )
|
||||
{
|
||||
if( panim->offset[j+3] == 0 )
|
||||
{
|
||||
angle2[j] = angle1[j] = pbone->value[j+3]; // default;
|
||||
}
|
||||
else
|
||||
{
|
||||
panimvalue = (mstudioanimvalue_t *)((byte *)panim + panim->offset[j+3]);
|
||||
k = frame;
|
||||
|
||||
// debug
|
||||
if( panimvalue->num.total < panimvalue->num.valid )
|
||||
k = 0;
|
||||
|
||||
while( panimvalue->num.total <= k )
|
||||
{
|
||||
k -= panimvalue->num.total;
|
||||
panimvalue += panimvalue->num.valid + 1;
|
||||
// DEBUG
|
||||
if( panimvalue->num.total < panimvalue->num.valid )
|
||||
k = 0;
|
||||
}
|
||||
// Bah, missing blend!
|
||||
if( panimvalue->num.valid > k )
|
||||
{
|
||||
angle1[j] = panimvalue[k+1].value;
|
||||
|
||||
if( panimvalue->num.valid > k + 1 )
|
||||
{
|
||||
angle2[j] = panimvalue[k+2].value;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( panimvalue->num.total > k + 1 )
|
||||
angle2[j] = angle1[j];
|
||||
else angle2[j] = panimvalue[panimvalue->num.valid+2].value;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
angle1[j] = panimvalue[panimvalue->num.valid].value;
|
||||
if( panimvalue->num.total > k + 1 )
|
||||
{
|
||||
angle2[j] = angle1[j];
|
||||
}
|
||||
else
|
||||
{
|
||||
angle2[j] = panimvalue[panimvalue->num.valid + 2].value;
|
||||
}
|
||||
}
|
||||
angle1[j] = pbone->value[j+3] + angle1[j] * pbone->scale[j+3];
|
||||
angle2[j] = pbone->value[j+3] + angle2[j] * pbone->scale[j+3];
|
||||
}
|
||||
|
||||
if( pbone->bonecontroller[j+3] != -1 )
|
||||
{
|
||||
angle1[j] += adj[pbone->bonecontroller[j+3]];
|
||||
angle2[j] += adj[pbone->bonecontroller[j+3]];
|
||||
}
|
||||
}
|
||||
|
||||
if( !VectorCompare( angle1, angle2 ))
|
||||
{
|
||||
AngleQuaternion( angle1, q1 );
|
||||
AngleQuaternion( angle2, q2 );
|
||||
QuaternionSlerp( q1, q2, s, q );
|
||||
}
|
||||
else
|
||||
{
|
||||
AngleQuaternion( angle1, q );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
StudioCalcBonePosition
|
||||
|
||||
====================
|
||||
*/
|
||||
static void SV_StudioCalcBonePosition( int frame, float s, mstudiobone_t *pbone, mstudioanim_t *panim, float *adj, float *pos )
|
||||
{
|
||||
int j, k;
|
||||
mstudioanimvalue_t *panimvalue;
|
||||
|
||||
for( j = 0; j < 3; j++ )
|
||||
{
|
||||
pos[j] = pbone->value[j]; // default;
|
||||
if( panim->offset[j] != 0.0f )
|
||||
{
|
||||
panimvalue = (mstudioanimvalue_t *)((byte *)panim + panim->offset[j]);
|
||||
|
||||
k = frame;
|
||||
|
||||
// debug
|
||||
if( panimvalue->num.total < panimvalue->num.valid )
|
||||
k = 0;
|
||||
|
||||
// find span of values that includes the frame we want
|
||||
while( panimvalue->num.total <= k )
|
||||
{
|
||||
k -= panimvalue->num.total;
|
||||
panimvalue += panimvalue->num.valid + 1;
|
||||
|
||||
// DEBUG
|
||||
if( panimvalue->num.total < panimvalue->num.valid )
|
||||
k = 0;
|
||||
}
|
||||
|
||||
// if we're inside the span
|
||||
if( panimvalue->num.valid > k )
|
||||
{
|
||||
// and there's more data in the span
|
||||
if( panimvalue->num.valid > k + 1 )
|
||||
{
|
||||
pos[j] += (panimvalue[k+1].value * (1.0f - s) + s * panimvalue[k+2].value) * pbone->scale[j];
|
||||
}
|
||||
else
|
||||
{
|
||||
pos[j] += panimvalue[k+1].value * pbone->scale[j];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// are we at the end of the repeating values section and there's another section with data?
|
||||
if( panimvalue->num.total <= k + 1 )
|
||||
{
|
||||
pos[j] += (panimvalue[panimvalue->num.valid].value * (1.0f - s) + s * panimvalue[panimvalue->num.valid + 2].value) * pbone->scale[j];
|
||||
}
|
||||
else
|
||||
{
|
||||
pos[j] += panimvalue[panimvalue->num.valid].value * pbone->scale[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( pbone->bonecontroller[j] != -1 && adj )
|
||||
{
|
||||
pos[j] += adj[pbone->bonecontroller[j]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
StudioCalcRotations
|
||||
|
||||
====================
|
||||
*/
|
||||
static void SV_StudioCalcRotations( edict_t *ent, float pos[][3], vec4_t *q, mstudioseqdesc_t *pseqdesc, mstudioanim_t *panim, float f )
|
||||
{
|
||||
int i, frame;
|
||||
mstudiobone_t *pbone;
|
||||
float adj[MAXSTUDIOCONTROLLERS];
|
||||
float s, dadt = 1.0f; // noInterp
|
||||
|
||||
if( f > pseqdesc->numframes - 1 )
|
||||
f = 0;
|
||||
else if( f < -0.01f )
|
||||
f = -0.01f;
|
||||
|
||||
frame = (int)f;
|
||||
s = (f - frame);
|
||||
|
||||
// add in programtic controllers
|
||||
pbone = (mstudiobone_t *)((byte *)sv_studiohdr + sv_studiohdr->boneindex);
|
||||
|
||||
SV_StudioCalcBoneAdj( dadt, adj, ent->v.controller, ent->v.controller );
|
||||
|
||||
for( i = 0; i < sv_studiohdr->numbones; i++, pbone++, panim++ )
|
||||
{
|
||||
SV_StudioCalcBoneQuaterion( frame, s, pbone, panim, adj, q[i] );
|
||||
SV_StudioCalcBonePosition( frame, s, pbone, panim, adj, pos[i] );
|
||||
}
|
||||
|
||||
if( pseqdesc->motiontype & STUDIO_X ) pos[pseqdesc->motionbone][0] = 0.0f;
|
||||
if( pseqdesc->motiontype & STUDIO_Y ) pos[pseqdesc->motionbone][1] = 0.0f;
|
||||
if( pseqdesc->motiontype & STUDIO_Z ) pos[pseqdesc->motionbone][2] = 0.0f;
|
||||
|
||||
s = 0 * ((1.0f - (f - (int)(f))) / (pseqdesc->numframes)) * ent->v.framerate;
|
||||
|
||||
if( pseqdesc->motiontype & STUDIO_LX ) pos[pseqdesc->motionbone][0] += s * pseqdesc->linearmovement[0];
|
||||
if( pseqdesc->motiontype & STUDIO_LY ) pos[pseqdesc->motionbone][1] += s * pseqdesc->linearmovement[1];
|
||||
if( pseqdesc->motiontype & STUDIO_LZ ) pos[pseqdesc->motionbone][2] += s * pseqdesc->linearmovement[2];
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
StudioEstimateFrame
|
||||
|
||||
====================
|
||||
*/
|
||||
static float SV_StudioEstimateFrame( edict_t *ent, mstudioseqdesc_t *pseqdesc )
|
||||
{
|
||||
double f;
|
||||
|
||||
if( pseqdesc->numframes <= 1 )
|
||||
f = 0;
|
||||
else f = (ent->v.frame * ( pseqdesc->numframes - 1 )) / 256.0;
|
||||
|
||||
if( pseqdesc->flags & STUDIO_LOOPING )
|
||||
{
|
||||
if( pseqdesc->numframes > 1 )
|
||||
f -= (int)(f / (pseqdesc->numframes - 1)) * (pseqdesc->numframes - 1);
|
||||
if( f < 0 ) f += (pseqdesc->numframes - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
if( f >= pseqdesc->numframes - 1.001 )
|
||||
f = pseqdesc->numframes - 1.001;
|
||||
if( f < 0.0 ) f = 0.0;
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
StudioSlerpBones
|
||||
|
||||
====================
|
||||
*/
|
||||
static void SV_StudioSlerpBones( vec4_t q1[], float pos1[][3], vec4_t q2[], float pos2[][3], float s )
|
||||
{
|
||||
int i;
|
||||
vec4_t q3;
|
||||
float s1;
|
||||
|
||||
s = bound( 0.0f, s, 1.0f );
|
||||
s1 = 1.0f - s;
|
||||
|
||||
for( i = 0; i < sv_studiohdr->numbones; i++ )
|
||||
{
|
||||
QuaternionSlerp( q1[i], q2[i], s, q3 );
|
||||
q1[i][0] = q3[0];
|
||||
q1[i][1] = q3[1];
|
||||
q1[i][2] = q3[2];
|
||||
q1[i][3] = q3[3];
|
||||
pos1[i][0] = pos1[i][0] * s1 + pos2[i][0] * s;
|
||||
pos1[i][1] = pos1[i][1] * s1 + pos2[i][1] * s;
|
||||
pos1[i][2] = pos1[i][2] * s1 + pos2[i][2] * s;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
StudioGetAnim
|
||||
|
||||
====================
|
||||
*/
|
||||
static mstudioanim_t *SV_StudioGetAnim( model_t *m_pSubModel, mstudioseqdesc_t *pseqdesc )
|
||||
{
|
||||
mstudioseqgroup_t *pseqgroup;
|
||||
cache_user_t *paSequences;
|
||||
size_t filesize;
|
||||
byte *buf;
|
||||
|
||||
pseqgroup = (mstudioseqgroup_t *)((byte *)sv_studiohdr + sv_studiohdr->seqgroupindex) + pseqdesc->seqgroup;
|
||||
if( pseqdesc->seqgroup == 0 )
|
||||
return (mstudioanim_t *)((byte *)sv_studiohdr + pseqgroup->data + pseqdesc->animindex);
|
||||
|
||||
paSequences = (cache_user_t *)m_pSubModel->submodels;
|
||||
|
||||
if( paSequences == NULL )
|
||||
{
|
||||
paSequences = (cache_user_t *)Mem_Alloc( m_pSubModel->mempool, MAXSTUDIOGROUPS * sizeof( cache_user_t ));
|
||||
m_pSubModel->submodels = (void *)paSequences;
|
||||
}
|
||||
|
||||
// check for already loaded
|
||||
if( !Cache_Check( m_pSubModel->mempool, ( cache_user_t *)&( paSequences[pseqdesc->seqgroup] )))
|
||||
{
|
||||
string filepath, modelname, modelpath;
|
||||
|
||||
FS_FileBase( m_pSubModel->name, modelname );
|
||||
FS_ExtractFilePath( m_pSubModel->name, modelpath );
|
||||
com.snprintf( filepath, sizeof( filepath ), "%s/%s%i%i.mdl", modelpath, modelname, pseqdesc->seqgroup / 10, pseqdesc->seqgroup % 10 );
|
||||
|
||||
buf = FS_LoadFile( filepath, &filesize );
|
||||
if( !buf || !filesize ) Host_Error( "CM_StudioGetAnim: can't load %s\n", modelpath );
|
||||
if( IDSEQGRPHEADER != *(uint *)buf )
|
||||
Host_Error( "SV_StudioGetAnim: %s is corrupted\n", modelpath );
|
||||
|
||||
paSequences[pseqdesc->seqgroup].data = Mem_Alloc( m_pSubModel->mempool, filesize );
|
||||
Mem_Copy( paSequences[pseqdesc->seqgroup].data, buf, filesize );
|
||||
Mem_Free( buf );
|
||||
}
|
||||
return (mstudioanim_t *)((byte *)paSequences[pseqdesc->seqgroup].data + pseqdesc->animindex);
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
StudioSetupBones
|
||||
====================
|
||||
*/
|
||||
static void SV_StudioSetupBones( edict_t *ent )
|
||||
{
|
||||
int i;
|
||||
double f;
|
||||
|
||||
mstudiobone_t *pbones;
|
||||
mstudioseqdesc_t *pseqdesc;
|
||||
mstudioanim_t *panim;
|
||||
model_t *m_pModel;
|
||||
|
||||
static float pos[MAXSTUDIOBONES][3];
|
||||
static vec4_t q[MAXSTUDIOBONES];
|
||||
matrix4x4 bonematrix;
|
||||
|
||||
static float pos2[MAXSTUDIOBONES][3];
|
||||
static vec4_t q2[MAXSTUDIOBONES];
|
||||
static float pos3[MAXSTUDIOBONES][3];
|
||||
static vec4_t q3[MAXSTUDIOBONES];
|
||||
static float pos4[MAXSTUDIOBONES][3];
|
||||
static vec4_t q4[MAXSTUDIOBONES];
|
||||
|
||||
m_pModel = CM_ClipHandleToModel( ent->v.modelindex );
|
||||
|
||||
if( ent->v.sequence >= sv_studiohdr->numseq ) ent->v.sequence = 0;
|
||||
pseqdesc = (mstudioseqdesc_t *)((byte *)sv_studiohdr + sv_studiohdr->seqindex) + ent->v.sequence;
|
||||
|
||||
f = SV_StudioEstimateFrame( ent, pseqdesc );
|
||||
|
||||
panim = SV_StudioGetAnim( m_pModel, pseqdesc );
|
||||
SV_StudioCalcRotations( ent, pos, q, pseqdesc, panim, f );
|
||||
|
||||
if( pseqdesc->numblends > 1 )
|
||||
{
|
||||
float s;
|
||||
float dadt = 1.0f;
|
||||
|
||||
panim += sv_studiohdr->numbones;
|
||||
SV_StudioCalcRotations( ent, pos2, q2, pseqdesc, panim, f );
|
||||
|
||||
s = (ent->v.blending[0] * dadt + ent->v.blending[0] * ( 1.0f - dadt )) / 255.0f;
|
||||
|
||||
SV_StudioSlerpBones( q, pos, q2, pos2, s );
|
||||
|
||||
if( pseqdesc->numblends == 4 )
|
||||
{
|
||||
panim += sv_studiohdr->numbones;
|
||||
SV_StudioCalcRotations( ent, pos3, q3, pseqdesc, panim, f );
|
||||
|
||||
panim += sv_studiohdr->numbones;
|
||||
SV_StudioCalcRotations( ent, pos4, q4, pseqdesc, panim, f );
|
||||
|
||||
s = ( ent->v.blending[0] * dadt + ent->v.blending[0] * ( 1.0f - dadt )) / 255.0f;
|
||||
SV_StudioSlerpBones( q3, pos3, q4, pos4, s );
|
||||
|
||||
s = ( ent->v.blending[1] * dadt + ent->v.blending[1] * ( 1.0f - dadt )) / 255.0f;
|
||||
SV_StudioSlerpBones( q, pos, q3, pos3, s );
|
||||
}
|
||||
}
|
||||
|
||||
pbones = (mstudiobone_t *)((byte *)sv_studiohdr + sv_studiohdr->boneindex);
|
||||
|
||||
for( i = 0; i < sv_studiohdr->numbones; i++ )
|
||||
{
|
||||
Matrix4x4_FromOriginQuat( bonematrix, pos[i][0], pos[i][1], pos[i][2], q[i][0], q[i][1], q[i][2], q[i][3] );
|
||||
if( pbones[i].parent == -1 )
|
||||
Matrix4x4_ConcatTransforms( sv_studiobones[i], sv_studiomatrix, bonematrix );
|
||||
else Matrix4x4_ConcatTransforms( sv_studiobones[i], sv_studiobones[pbones[i].parent], bonematrix );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
StudioCalcAttachments
|
||||
|
||||
====================
|
||||
*/
|
||||
static bool SV_StudioCalcAttachments( edict_t *e, int iAttachment, float *org, float *ang )
|
||||
{
|
||||
int i;
|
||||
mstudioattachment_t *pAtt;
|
||||
vec3_t axis[3];
|
||||
vec3_t localOrg, localAng;
|
||||
void *hdr = Mod_Extradata( e->v.modelindex );
|
||||
|
||||
if( !hdr ) return false;
|
||||
|
||||
sv_studiohdr = (studiohdr_t *)hdr;
|
||||
if( sv_studiohdr->numattachments <= 0 )
|
||||
return false;
|
||||
|
||||
SV_StudioSetUpTransform( e );
|
||||
SV_StudioSetupBones( e );
|
||||
|
||||
if( sv_studiohdr->numattachments > MAXSTUDIOATTACHMENTS )
|
||||
{
|
||||
sv_studiohdr->numattachments = MAXSTUDIOATTACHMENTS; // reduce it
|
||||
MsgDev( D_WARN, "SV_StudioCalcAttahments: too many attachments on %s\n", sv_studiohdr->name );
|
||||
}
|
||||
|
||||
iAttachment = bound( 0, iAttachment, sv_studiohdr->numattachments );
|
||||
|
||||
// calculate attachment points
|
||||
pAtt = (mstudioattachment_t *)((byte *)sv_studiohdr + sv_studiohdr->attachmentindex);
|
||||
|
||||
for( i = 0; i < sv_studiohdr->numattachments; i++ )
|
||||
{
|
||||
if( i == iAttachment )
|
||||
{
|
||||
// compute pos and angles
|
||||
Matrix4x4_VectorTransform( sv_studiobones[pAtt[i].bone], pAtt[i].org, localOrg );
|
||||
Matrix4x4_VectorTransform( sv_studiobones[pAtt[i].bone], pAtt[i].vectors[0], axis[0] );
|
||||
Matrix4x4_VectorTransform( sv_studiobones[pAtt[i].bone], pAtt[i].vectors[1], axis[1] );
|
||||
Matrix4x4_VectorTransform( sv_studiobones[pAtt[i].bone], pAtt[i].vectors[2], axis[2] );
|
||||
Matrix3x3_ToAngles( axis, localAng, true ); // FIXME: dll's uses FLU ?
|
||||
if( org ) VectorCopy( localOrg, org );
|
||||
if( ang ) VectorCopy( localAng, ang );
|
||||
break; // done
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool SV_StudioSetupModel( edict_t *ent )
|
||||
{
|
||||
void *hdr = Mod_Extradata( ent->v.modelindex );
|
||||
|
||||
if( !hdr ) return false;
|
||||
|
||||
sv_studiohdr = (studiohdr_t *)hdr;
|
||||
SV_StudioSetUpTransform( ent );
|
||||
SV_StudioSetupBones( ent );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SV_StudioExtractBbox( model_t *mod, int sequence, float *mins, float *maxs )
|
||||
{
|
||||
mstudioseqdesc_t *pseqdesc;
|
||||
studiohdr_t *phdr;
|
||||
|
||||
ASSERT( mod != NULL );
|
||||
|
||||
if( mod->type != mod_studio || !mod->extradata )
|
||||
return false;
|
||||
|
||||
phdr = (studiohdr_t *)mod->extradata;
|
||||
if( !phdr->numhitboxes ) return false;
|
||||
|
||||
pseqdesc = (mstudioseqdesc_t *)((byte *)phdr + phdr->seqindex);
|
||||
|
||||
if( sequence < 0 || sequence >= phdr->numseq )
|
||||
return false;
|
||||
|
||||
VectorCopy( pseqdesc[sequence].bbmin, mins );
|
||||
VectorCopy( pseqdesc[sequence].bbmax, maxs );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
StudioTestToHitbox
|
||||
|
||||
test point trace in hitbox
|
||||
================
|
||||
*/
|
||||
static bool SV_StudioTestToHitbox( trace_t *trace )
|
||||
{
|
||||
int i;
|
||||
mplane_t *p;
|
||||
|
||||
for( i = 0; i < 6; i++ )
|
||||
{
|
||||
p = &sv_hitboxplanes[i];
|
||||
|
||||
// push the plane out apropriately for mins/maxs
|
||||
// if completely in front of face, no intersection
|
||||
if( p->type < 3 )
|
||||
{
|
||||
if( trace_startmins[p->type] > p->dist )
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch( p->signbits )
|
||||
{
|
||||
case 0:
|
||||
if( p->normal[0]*trace_startmins[0] + p->normal[1]*trace_startmins[1] + p->normal[2]*trace_startmins[2] > p->dist )
|
||||
return false;
|
||||
break;
|
||||
case 1:
|
||||
if( p->normal[0]*trace_startmaxs[0] + p->normal[1]*trace_startmins[1] + p->normal[2]*trace_startmins[2] > p->dist )
|
||||
return false;
|
||||
break;
|
||||
case 2:
|
||||
if( p->normal[0]*trace_startmins[0] + p->normal[1]*trace_startmaxs[1] + p->normal[2]*trace_startmins[2] > p->dist )
|
||||
return false;
|
||||
break;
|
||||
case 3:
|
||||
if( p->normal[0]*trace_startmaxs[0] + p->normal[1]*trace_startmaxs[1] + p->normal[2]*trace_startmins[2] > p->dist )
|
||||
return false;
|
||||
break;
|
||||
case 4:
|
||||
if( p->normal[0]*trace_startmins[0] + p->normal[1]*trace_startmins[1] + p->normal[2]*trace_startmaxs[2] > p->dist )
|
||||
return false;
|
||||
break;
|
||||
case 5:
|
||||
if( p->normal[0]*trace_startmaxs[0] + p->normal[1]*trace_startmins[1] + p->normal[2]*trace_startmaxs[2] > p->dist )
|
||||
return false;
|
||||
break;
|
||||
case 6:
|
||||
if( p->normal[0]*trace_startmins[0] + p->normal[1]*trace_startmaxs[1] + p->normal[2]*trace_startmaxs[2] > p->dist )
|
||||
return false;
|
||||
break;
|
||||
case 7:
|
||||
if( p->normal[0]*trace_startmaxs[0] + p->normal[1]*trace_startmaxs[1] + p->normal[2]*trace_startmaxs[2] > p->dist )
|
||||
return false;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// inside this hitbox
|
||||
trace->flFraction = trace_realfraction = 0;
|
||||
trace->fStartSolid = trace->fAllSolid = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
StudioClipToHitbox
|
||||
|
||||
trace hitbox
|
||||
================
|
||||
*/
|
||||
static bool SV_StudioClipToHitbox( trace_t *trace )
|
||||
{
|
||||
int i;
|
||||
mplane_t *p, *clipplane;
|
||||
float enterfrac, leavefrac, distfrac;
|
||||
float d, d1, d2;
|
||||
bool getout, startout;
|
||||
float f;
|
||||
|
||||
enterfrac = -1.0f;
|
||||
leavefrac = 1.0f;
|
||||
clipplane = NULL;
|
||||
|
||||
getout = false;
|
||||
startout = false;
|
||||
|
||||
for( i = 0; i < 6; i++ )
|
||||
{
|
||||
p = &sv_hitboxplanes[i];
|
||||
|
||||
// push the plane out apropriately for mins/maxs
|
||||
if( p->type < 3 )
|
||||
{
|
||||
d1 = trace_startmins[p->type] - p->dist;
|
||||
d2 = trace_endmins[p->type] - p->dist;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch( p->signbits )
|
||||
{
|
||||
case 0:
|
||||
d1 = p->normal[0]*trace_startmins[0] + p->normal[1]*trace_startmins[1] + p->normal[2]*trace_startmins[2] - p->dist;
|
||||
d2 = p->normal[0]*trace_endmins[0] + p->normal[1]*trace_endmins[1] + p->normal[2]*trace_endmins[2] - p->dist;
|
||||
break;
|
||||
case 1:
|
||||
d1 = p->normal[0]*trace_startmaxs[0] + p->normal[1]*trace_startmins[1] + p->normal[2]*trace_startmins[2] - p->dist;
|
||||
d2 = p->normal[0]*trace_endmaxs[0] + p->normal[1]*trace_endmins[1] + p->normal[2]*trace_endmins[2] - p->dist;
|
||||
break;
|
||||
case 2:
|
||||
d1 = p->normal[0]*trace_startmins[0] + p->normal[1]*trace_startmaxs[1] + p->normal[2]*trace_startmins[2] - p->dist;
|
||||
d2 = p->normal[0]*trace_endmins[0] + p->normal[1]*trace_endmaxs[1] + p->normal[2]*trace_endmins[2] - p->dist;
|
||||
break;
|
||||
case 3:
|
||||
d1 = p->normal[0]*trace_startmaxs[0] + p->normal[1]*trace_startmaxs[1] + p->normal[2]*trace_startmins[2] - p->dist;
|
||||
d2 = p->normal[0]*trace_endmaxs[0] + p->normal[1]*trace_endmaxs[1] + p->normal[2]*trace_endmins[2] - p->dist;
|
||||
break;
|
||||
case 4:
|
||||
d1 = p->normal[0]*trace_startmins[0] + p->normal[1]*trace_startmins[1] + p->normal[2]*trace_startmaxs[2] - p->dist;
|
||||
d2 = p->normal[0]*trace_endmins[0] + p->normal[1]*trace_endmins[1] + p->normal[2]*trace_endmaxs[2] - p->dist;
|
||||
break;
|
||||
case 5:
|
||||
d1 = p->normal[0]*trace_startmaxs[0] + p->normal[1]*trace_startmins[1] + p->normal[2]*trace_startmaxs[2] - p->dist;
|
||||
d2 = p->normal[0]*trace_endmaxs[0] + p->normal[1]*trace_endmins[1] + p->normal[2]*trace_endmaxs[2] - p->dist;
|
||||
break;
|
||||
case 6:
|
||||
d1 = p->normal[0]*trace_startmins[0] + p->normal[1]*trace_startmaxs[1] + p->normal[2]*trace_startmaxs[2] - p->dist;
|
||||
d2 = p->normal[0]*trace_endmins[0] + p->normal[1]*trace_endmaxs[1] + p->normal[2]*trace_endmaxs[2] - p->dist;
|
||||
break;
|
||||
case 7:
|
||||
d1 = p->normal[0]*trace_startmaxs[0] + p->normal[1]*trace_startmaxs[1] + p->normal[2]*trace_startmaxs[2] - p->dist;
|
||||
d2 = p->normal[0]*trace_endmaxs[0] + p->normal[1]*trace_endmaxs[1] + p->normal[2]*trace_endmaxs[2] - p->dist;
|
||||
break;
|
||||
default:
|
||||
d1 = d2 = 0; // shut up compiler
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( d2 > 0 ) getout = true; // endpoint is not in solid
|
||||
if( d1 > 0 ) startout = true;
|
||||
|
||||
// if completely in front of face, no intersection
|
||||
if( d1 > 0 && d2 >= d1 )
|
||||
return false;
|
||||
|
||||
if( d1 <= 0 && d2 <= 0 )
|
||||
continue;
|
||||
|
||||
// crosses face
|
||||
d = 1.0f / ( d1 - d2 );
|
||||
f = d1 * d;
|
||||
|
||||
if( d > 0 )
|
||||
{
|
||||
// enter
|
||||
if( f > enterfrac )
|
||||
{
|
||||
distfrac = d;
|
||||
enterfrac = f;
|
||||
clipplane = p;
|
||||
}
|
||||
}
|
||||
else if( d < 0 )
|
||||
{
|
||||
// leave
|
||||
if( f < leavefrac )
|
||||
leavefrac = f;
|
||||
}
|
||||
}
|
||||
|
||||
if( !startout )
|
||||
{
|
||||
// original point was inside hitbox
|
||||
trace->fStartSolid = true;
|
||||
if( !getout ) trace->fAllSolid = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
if( enterfrac - FRAC_EPSILON <= leavefrac )
|
||||
{
|
||||
if( enterfrac > -1.0f && enterfrac < trace_realfraction )
|
||||
{
|
||||
if( enterfrac < 0 )
|
||||
enterfrac = 0;
|
||||
trace_realfraction = enterfrac;
|
||||
trace->flFraction = enterfrac - DIST_EPSILON * distfrac;
|
||||
VectorCopy( clipplane->normal, trace->vecPlaneNormal );
|
||||
trace->flPlaneDist = clipplane->dist;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
SV_StudioIntersect
|
||||
|
||||
testing for potentially intersection of trace and animation bboxes
|
||||
================
|
||||
*/
|
||||
static bool SV_StudioIntersect( edict_t *ent, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end )
|
||||
{
|
||||
vec3_t trace_mins, trace_maxs;
|
||||
vec3_t anim_mins, anim_maxs;
|
||||
model_t *mod = CM_ClipHandleToModel( ent->v.modelindex );
|
||||
|
||||
// create the bounding box of the entire move
|
||||
World_MoveBounds( start, mins, maxs, end, trace_mins, trace_maxs );
|
||||
|
||||
if( !SV_StudioExtractBbox( mod, ent->v.sequence, anim_mins, anim_maxs ))
|
||||
return false; // invalid sequence
|
||||
|
||||
if( !VectorIsNull( ent->v.angles ))
|
||||
{
|
||||
// expand for rotation
|
||||
float max, v;
|
||||
int i;
|
||||
|
||||
for( i = 0, max = 0.0f; i < 3; i++ )
|
||||
{
|
||||
v = fabs( anim_mins[i] );
|
||||
if( v > max ) max = v;
|
||||
v = fabs( anim_maxs[i] );
|
||||
if( v > max ) max = v;
|
||||
}
|
||||
|
||||
for( i = 0; i < 3; i++ )
|
||||
{
|
||||
anim_mins[i] = ent->v.origin[i] - max;
|
||||
anim_maxs[i] = ent->v.origin[i] + max;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
VectorAdd( anim_mins, ent->v.origin, anim_mins );
|
||||
VectorAdd( anim_maxs, ent->v.origin, anim_maxs );
|
||||
}
|
||||
|
||||
// check intersection with trace entire move and animation bbox
|
||||
return BoundsIntersect( trace_mins, trace_maxs, anim_mins, anim_maxs );
|
||||
}
|
||||
|
||||
bool SV_StudioTrace( edict_t *ent, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, trace_t *ptr )
|
||||
{
|
||||
vec3_t start_l, end_l;
|
||||
int i, outBone = -1;
|
||||
pfnHitboxTrace TraceHitbox = NULL;
|
||||
|
||||
// assume we didn't hit anything
|
||||
Mem_Set( ptr, 0, sizeof( pmtrace_t ));
|
||||
VectorCopy( end, ptr->vecEndPos );
|
||||
ptr->flFraction = trace_realfraction = 1.0f;
|
||||
ptr->iHitgroup = -1;
|
||||
|
||||
if( !SV_StudioIntersect( ent, start, mins, maxs, end ))
|
||||
return false;
|
||||
|
||||
if( !SV_StudioSetupModel( ent ))
|
||||
return false;
|
||||
|
||||
if( VectorCompare( start, end ))
|
||||
TraceHitbox = SV_StudioTestToHitbox; // special case for test position
|
||||
else TraceHitbox = SV_StudioClipToHitbox;
|
||||
|
||||
// go to check individual hitboxes
|
||||
for( i = 0; i < sv_studiohdr->numhitboxes; i++ )
|
||||
{
|
||||
mstudiobbox_t *phitbox = (mstudiobbox_t *)((byte*)sv_studiohdr + sv_studiohdr->hitboxindex) + i;
|
||||
matrix4x4 bonemat;
|
||||
|
||||
// transform traceline into local bone space
|
||||
Matrix4x4_Invert_Simple( bonemat, sv_studiobones[phitbox->bone] );
|
||||
Matrix4x4_VectorTransform( bonemat, start, start_l );
|
||||
Matrix4x4_VectorTransform( bonemat, end, end_l );
|
||||
|
||||
SV_HullForHitbox( phitbox->bbmin, phitbox->bbmax );
|
||||
|
||||
VectorAdd( start_l, mins, trace_startmins );
|
||||
VectorAdd( start_l, maxs, trace_startmaxs );
|
||||
VectorAdd( end_l, mins, trace_endmins );
|
||||
VectorAdd( end_l, maxs, trace_endmaxs );
|
||||
|
||||
if( TraceHitbox( ptr ))
|
||||
{
|
||||
outBone = phitbox->bone;
|
||||
ptr->iHitgroup = phitbox->group;
|
||||
}
|
||||
|
||||
if( ptr->fAllSolid )
|
||||
break;
|
||||
}
|
||||
|
||||
// all hitboxes were swept, get trace result
|
||||
if( outBone >= 0 )
|
||||
{
|
||||
vec3_t temp;
|
||||
|
||||
ptr->pHit = ent;
|
||||
VectorCopy( ptr->vecPlaneNormal, temp );
|
||||
ptr->flFraction = bound( 0, ptr->flFraction, 1.0f );
|
||||
VectorLerp( start, ptr->flFraction, end, ptr->vecEndPos );
|
||||
Matrix4x4_TransformPositivePlane( sv_studiobones[outBone], temp, ptr->flPlaneDist, ptr->vecPlaneNormal, &ptr->flPlaneDist );
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void SV_StudioGetAttachment( edict_t *e, int iAttachment, float *org, float *ang )
|
||||
{
|
||||
if( !SV_StudioCalcAttachments( e, iAttachment, org, ang ))
|
||||
{
|
||||
// reset attachments
|
||||
if( org ) VectorCopy( e->v.origin, org );
|
||||
if( ang ) VectorCopy( e->v.angles, ang );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void SV_GetBonePosition( edict_t *e, int iBone, float *org, float *ang )
|
||||
{
|
||||
matrix3x3 axis;
|
||||
|
||||
if( !SV_StudioSetupModel( e ) || sv_studiohdr->numbones <= 0 )
|
||||
{
|
||||
// reset bones
|
||||
if( org ) VectorCopy( e->v.origin, org );
|
||||
if( ang ) VectorCopy( e->v.angles, ang );
|
||||
return;
|
||||
}
|
||||
|
||||
iBone = bound( 0, iBone, sv_studiohdr->numbones );
|
||||
Matrix3x3_FromMatrix4x4( axis, sv_studiobones[iBone] );
|
||||
if( org ) Matrix4x4_OriginFromMatrix( sv_studiobones[iBone], org );
|
||||
if( ang ) Matrix3x3_ToAngles( axis, ang, true );
|
||||
|
||||
}
|
|
@ -8,6 +8,159 @@
|
|||
#include "const.h"
|
||||
#include "pm_local.h"
|
||||
|
||||
typedef struct moveclip_s
|
||||
{
|
||||
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
|
||||
const float *start, *end;
|
||||
trace_t trace;
|
||||
edict_t *passedict;
|
||||
int type; // move type
|
||||
int flags; // trace flags
|
||||
int trace_hull; // -1 to let entity select hull
|
||||
} moveclip_t;
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
HULL BOXES
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
static hull_t box_hull;
|
||||
static dclipnode_t box_clipnodes[6];
|
||||
static mplane_t box_planes[6];
|
||||
|
||||
/*
|
||||
===================
|
||||
SV_InitBoxHull
|
||||
|
||||
Set up the planes and clipnodes so that the six floats of a bounding box
|
||||
can just be stored out and get a proper hull_t structure.
|
||||
===================
|
||||
*/
|
||||
void SV_InitBoxHull( void )
|
||||
{
|
||||
int i, side;
|
||||
|
||||
box_hull.clipnodes = box_clipnodes;
|
||||
box_hull.planes = box_planes;
|
||||
box_hull.firstclipnode = 0;
|
||||
box_hull.lastclipnode = 5;
|
||||
|
||||
for( i = 0; i < 6; i++ )
|
||||
{
|
||||
box_clipnodes[i].planenum = i;
|
||||
|
||||
side = i & 1;
|
||||
|
||||
box_clipnodes[i].children[side] = CONTENTS_EMPTY;
|
||||
if( i != 5 ) box_clipnodes[i].children[side^1] = i + 1;
|
||||
else box_clipnodes[i].children[side^1] = CONTENTS_SOLID;
|
||||
|
||||
box_planes[i].type = i>>1;
|
||||
box_planes[i].normal[i>>1] = 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
===================
|
||||
SV_HullForBox
|
||||
|
||||
To keep everything totally uniform, bounding boxes are turned into small
|
||||
BSP trees instead of being compared directly.
|
||||
===================
|
||||
*/
|
||||
hull_t *SV_HullForBox( const vec3_t mins, const vec3_t maxs )
|
||||
{
|
||||
box_planes[0].dist = maxs[0];
|
||||
box_planes[1].dist = mins[0];
|
||||
box_planes[2].dist = maxs[1];
|
||||
box_planes[3].dist = mins[1];
|
||||
box_planes[4].dist = maxs[2];
|
||||
box_planes[5].dist = mins[2];
|
||||
|
||||
return &box_hull;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
SV_HullForEntity
|
||||
|
||||
Returns a hull that can be used for testing or clipping an object of mins/maxs
|
||||
size.
|
||||
Offset is filled in to contain the adjustment that must be added to the
|
||||
testing object's origin to get a point to use with the returned hull.
|
||||
================
|
||||
*/
|
||||
hull_t *SV_HullForEntity( edict_t *ent, int hullNumber, vec3_t mins, vec3_t maxs, vec3_t offset )
|
||||
{
|
||||
hull_t *hull;
|
||||
model_t *model;
|
||||
vec3_t hullmins, hullmaxs;
|
||||
vec3_t size;
|
||||
|
||||
// decide which clipping hull to use, based on the size
|
||||
if( ent->v.solid == SOLID_BSP )
|
||||
{
|
||||
// explicit hulls in the BSP model
|
||||
if( ent->v.movetype != MOVETYPE_PUSH )
|
||||
Host_Error( "SOLID_BSP without MOVETYPE_PUSH\n" );
|
||||
|
||||
model = CM_ClipHandleToModel( ent->v.modelindex );
|
||||
|
||||
if( !model || model->type != mod_brush && model->type != mod_world )
|
||||
Host_Error( "MOVETYPE_PUSH with a non bsp model\n" );
|
||||
|
||||
VectorSubtract( maxs, mins, size );
|
||||
|
||||
if( hullNumber == -1 )
|
||||
{
|
||||
// FIXME: these constanst doesn't works with user-defined hulls
|
||||
// revisit this
|
||||
if( size[0] < 3 )
|
||||
hull = &model->hulls[0]; // point hull
|
||||
else if( size[0] <= 36 )
|
||||
{
|
||||
if( size[2] <= 36 )
|
||||
hull = &model->hulls[3]; // head hull (ducked)
|
||||
else hull = &model->hulls[1]; // human hull
|
||||
}
|
||||
else hull = &model->hulls[2]; // large hull
|
||||
}
|
||||
else
|
||||
{
|
||||
// TraceHull stuff
|
||||
hull = &model->hulls[hullNumber];
|
||||
}
|
||||
|
||||
// calculate an offset value to center the origin
|
||||
VectorSubtract( hull->clip_mins, mins, offset );
|
||||
VectorAdd( offset, ent->v.origin, offset );
|
||||
}
|
||||
else
|
||||
{
|
||||
// create a temp hull from bounding box sizes
|
||||
VectorSubtract( ent->v.mins, maxs, hullmins );
|
||||
VectorSubtract( ent->v.maxs, mins, hullmaxs );
|
||||
hull = SV_HullForBox( hullmins, hullmaxs );
|
||||
|
||||
VectorCopy( ent->v.origin, offset );
|
||||
}
|
||||
return hull;
|
||||
}
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
ENTITY AREA CHECKING
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
areanode_t sv_areanodes[AREA_NODES];
|
||||
int sv_numareanodes;
|
||||
|
||||
|
@ -43,7 +196,7 @@ areanode_t *SV_CreateAreaNode( int depth, vec3_t mins, vec3_t maxs )
|
|||
anode->axis = 0;
|
||||
else anode->axis = 1;
|
||||
|
||||
anode->dist = 0.5f * (maxs[anode->axis] + mins[anode->axis]);
|
||||
anode->dist = 0.5f * ( maxs[anode->axis] + mins[anode->axis] );
|
||||
VectorCopy( mins, mins1 );
|
||||
VectorCopy( mins, mins2 );
|
||||
VectorCopy( maxs, maxs1 );
|
||||
|
@ -64,13 +217,28 @@ SV_ClearWorld
|
|||
*/
|
||||
void SV_ClearWorld( void )
|
||||
{
|
||||
vec3_t mins, maxs;
|
||||
int worldIndex = 1;
|
||||
SV_InitBoxHull(); // for box testing
|
||||
SV_InitStudioHull();// for hitbox testing
|
||||
|
||||
sv_numareanodes = 0;
|
||||
Mod_GetBounds( worldIndex, mins, maxs );
|
||||
Mem_Set( sv_areanodes, 0, sizeof( sv_areanodes ));
|
||||
SV_CreateAreaNode( 0, mins, maxs );
|
||||
sv_numareanodes = 0;
|
||||
|
||||
SV_CreateAreaNode( 0, sv.worldmodel->mins, sv.worldmodel->maxs );
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
SV_UnlinkEdict
|
||||
===============
|
||||
*/
|
||||
void SV_UnlinkEdict( edict_t *ent )
|
||||
{
|
||||
// not linked in anywhere
|
||||
if( !ent->area.prev ) return;
|
||||
|
||||
RemoveLink( &ent->area );
|
||||
ent->area.prev = NULL;
|
||||
ent->area.next = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -90,27 +258,27 @@ void SV_TouchLinks( edict_t *ent, areanode_t *node )
|
|||
{
|
||||
next = l->next;
|
||||
touch = EDICT_FROM_AREA( l );
|
||||
if( touch == ent ) continue;
|
||||
if( touch->free || touch->v.solid != SOLID_TRIGGER ) // disabled ?
|
||||
|
||||
if( touch == ent || touch->v.solid != SOLID_TRIGGER ) // disabled ?
|
||||
continue;
|
||||
|
||||
if( !BoundsIntersect( ent->v.absmin, ent->v.absmax, touch->v.absmin, touch->v.absmax ))
|
||||
continue;
|
||||
|
||||
// check triggers accuracy
|
||||
if( CM_GetModelType( touch->v.modelindex ) == mod_brush )
|
||||
{
|
||||
hull = CM_HullForBsp( touch, ent->v.mins, ent->v.maxs, test );
|
||||
hull = SV_HullForEntity( touch, -1, ent->v.mins, ent->v.maxs, test );
|
||||
|
||||
// offset the test point appropriately for this hull.
|
||||
VectorSubtract( ent->v.origin, test, test );
|
||||
|
||||
// test hull for intersection with this model
|
||||
if( CM_HullPointContents( hull, hull->firstclipnode, test ) == CONTENTS_EMPTY )
|
||||
if( SV_HullPointContents( hull, hull->firstclipnode, test ) == CONTENTS_EMPTY )
|
||||
continue;
|
||||
}
|
||||
|
||||
svgame.dllFuncs.pfnTouch( touch, ent );
|
||||
if( ent->free ) break; // killtarget issues
|
||||
}
|
||||
|
||||
// recurse down both sides
|
||||
|
@ -122,30 +290,17 @@ void SV_TouchLinks( edict_t *ent, areanode_t *node )
|
|||
SV_TouchLinks( ent, node->children[1] );
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
SV_UnlinkEdict
|
||||
===============
|
||||
*/
|
||||
void SV_UnlinkEdict( edict_t *ent )
|
||||
{
|
||||
// not linked in anywhere
|
||||
if( !ent->area.prev ) return;
|
||||
|
||||
RemoveLink( &ent->area );
|
||||
ent->area.prev = NULL;
|
||||
ent->area.next = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
SV_CheckForOutside
|
||||
|
||||
Remove entity out of level
|
||||
Remove entity out of the level
|
||||
===============
|
||||
*/
|
||||
void SV_CheckForOutside( edict_t *ent )
|
||||
{
|
||||
const float *org;
|
||||
|
||||
// not solid edicts can be fly through walls
|
||||
if( ent->v.solid == SOLID_NOT ) return;
|
||||
|
||||
|
@ -159,29 +314,105 @@ void SV_CheckForOutside( edict_t *ent )
|
|||
if( CM_GetModelType( ent->v.modelindex ) != mod_studio )
|
||||
return;
|
||||
|
||||
if( SV_PointContents( ent->v.origin ) == CONTENTS_SOLID )
|
||||
{
|
||||
const float *org = ent->v.origin;
|
||||
org = ent->v.origin;
|
||||
|
||||
MsgDev( D_ERROR, "%s outside of the world at %g %g %g\n", SV_ClassName( ent ), org[0], org[1], org[2] );
|
||||
ent->v.flags |= FL_KILLME;
|
||||
}
|
||||
if( SV_PointContents( org ) != CONTENTS_SOLID )
|
||||
return;
|
||||
|
||||
MsgDev( D_ERROR, "%s outside of the world at %g %g %g\n", SV_ClassName( ent ), org[0], org[1], org[2] );
|
||||
|
||||
ent->v.flags |= FL_KILLME;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
SV_LinkEntity
|
||||
SV_FindTouchedLeafs
|
||||
|
||||
===============
|
||||
*/
|
||||
void SV_FindTouchedLeafs( edict_t *ent, mnode_t *node )
|
||||
{
|
||||
mplane_t *splitplane;
|
||||
int sides, leafnum;
|
||||
mleaf_t *leaf;
|
||||
|
||||
if( node->contents == CONTENTS_SOLID )
|
||||
return;
|
||||
|
||||
// add an efrag if the node is a leaf
|
||||
if( node->contents < 0 )
|
||||
{
|
||||
// get headnode
|
||||
if( ent->headnode == -1 )
|
||||
ent->headnode = node - worldmodel->nodes;
|
||||
|
||||
if( ent->num_leafs == MAX_ENT_LEAFS )
|
||||
return;
|
||||
|
||||
leaf = (mleaf_t *)node;
|
||||
leafnum = leaf - sv.worldmodel->leafs - 1;
|
||||
|
||||
ent->leafnums[ent->num_leafs] = leafnum;
|
||||
ent->num_leafs++;
|
||||
return;
|
||||
}
|
||||
|
||||
// NODE_MIXED
|
||||
splitplane = node->plane;
|
||||
sides = BOX_ON_PLANE_SIDE( ent->v.absmin, ent->v.absmax, splitplane );
|
||||
|
||||
if( sides == 3 )
|
||||
{
|
||||
// get headnode
|
||||
if( ent->headnode == -1 )
|
||||
ent->headnode = node - worldmodel->nodes;
|
||||
}
|
||||
|
||||
// recurse down the contacted sides
|
||||
if( sides & 1 ) SV_FindTouchedLeafs( ent, node->children[0] );
|
||||
if( sides & 2 ) SV_FindTouchedLeafs( ent, node->children[1] );
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
SV_HeadnodeVisible
|
||||
=============
|
||||
*/
|
||||
bool SV_HeadnodeVisible( mnode_t *node, byte *visbits )
|
||||
{
|
||||
mleaf_t *leaf;
|
||||
int leafnum;
|
||||
|
||||
if( node->contents < 0 )
|
||||
{
|
||||
if( node->contents != CONTENTS_SOLID )
|
||||
{
|
||||
leaf = (mleaf_t *)node;
|
||||
leafnum = (leaf - worldmodel->leafs - 1);
|
||||
|
||||
if( visbits[leafnum >> 3] & (1<<( leafnum & 7 )))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if( SV_HeadnodeVisible( node->children[0], visbits ))
|
||||
return true;
|
||||
return SV_HeadnodeVisible( node->children[1], visbits );
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
SV_LinkEdict
|
||||
===============
|
||||
*/
|
||||
void SV_LinkEdict( edict_t *ent, bool touch_triggers )
|
||||
{
|
||||
areanode_t *node;
|
||||
short leafs[MAX_TOTAL_ENT_LEAFS];
|
||||
int i, j, num_leafs, topNode;
|
||||
|
||||
if( ent->area.prev ) SV_UnlinkEdict( ent ); // unlink from old position
|
||||
if( ent == EDICT_NUM( 0 )) return; // don't add the world
|
||||
if( ent->free ) return;
|
||||
if( ent->area.prev ) SV_UnlinkEdict( ent ); // unlink from old position
|
||||
if( ent == svgame.edicts ) return; // don't add the world
|
||||
if( !SV_IsValidEdict( ent )) return; // never add freed ents
|
||||
|
||||
// set the abs box
|
||||
svgame.dllFuncs.pfnSetAbsBox( ent );
|
||||
|
@ -189,50 +420,23 @@ void SV_LinkEdict( edict_t *ent, bool touch_triggers )
|
|||
// link to PVS leafs
|
||||
ent->num_leafs = 0;
|
||||
|
||||
// get all leafs, including solids
|
||||
num_leafs = CM_BoxLeafnums( ent->v.absmin, ent->v.absmax, leafs, MAX_TOTAL_ENT_LEAFS, &topNode );
|
||||
|
||||
// if none of the leafs were inside the map, the
|
||||
// entity is outside the world and can be considered unlinked
|
||||
if( !num_leafs )
|
||||
if( ent->v.modelindex )
|
||||
{
|
||||
SV_CheckForOutside( ent );
|
||||
return;
|
||||
}
|
||||
ent->headnode = -1;
|
||||
SV_FindTouchedLeafs( ent, sv.worldmodel->nodes );
|
||||
|
||||
if( num_leafs >= MAX_ENT_LEAFS )
|
||||
{
|
||||
// assume we missed some leafs, and mark by headnode
|
||||
ent->num_leafs = -1;
|
||||
ent->headnode = topNode;
|
||||
}
|
||||
else
|
||||
{
|
||||
ent->num_leafs = 0;
|
||||
|
||||
for( i = 0; i < num_leafs; i++ )
|
||||
// if none of the leafs were inside the map, the
|
||||
// entity is outside the world and can be considered unlinked
|
||||
if( !ent->num_leafs )
|
||||
{
|
||||
if( leafs[i] == -1 )
|
||||
continue; // not a visible leaf
|
||||
|
||||
for( j = 0; j < i; j++ )
|
||||
{
|
||||
if( leafs[j] == leafs[i] )
|
||||
break;
|
||||
}
|
||||
|
||||
if( j == i )
|
||||
{
|
||||
if( ent->num_leafs == MAX_ENT_LEAFS )
|
||||
{
|
||||
// assume we missed some leafs, and mark by headNode
|
||||
ent->num_leafs = -1;
|
||||
ent->headnode = topNode;
|
||||
break;
|
||||
}
|
||||
ent->leafnums[ent->num_leafs++] = leafs[i];
|
||||
}
|
||||
SV_CheckForOutside( ent );
|
||||
ent->headnode = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
if( ent->num_leafs == MAX_ENT_LEAFS )
|
||||
ent->num_leafs = 0; // so we use headnode instead
|
||||
else ent->headnode = -1; // use normal leafs check
|
||||
}
|
||||
|
||||
// ignore not solid bodies
|
||||
|
@ -263,79 +467,256 @@ void SV_LinkEdict( edict_t *ent, bool touch_triggers )
|
|||
}
|
||||
|
||||
/*
|
||||
============================================================================
|
||||
===============================================================================
|
||||
|
||||
AREA QUERY
|
||||
POINT TESTING IN HULLS
|
||||
|
||||
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
|
||||
====================
|
||||
==================
|
||||
SV_HullPointContents
|
||||
|
||||
==================
|
||||
*/
|
||||
void SV_AreaEdicts_r( areanode_t *node, area_t *ap )
|
||||
int SV_HullPointContents( hull_t *hull, int num, const vec3_t p )
|
||||
{
|
||||
link_t *l, *next, *start;
|
||||
edict_t *check;
|
||||
int count = 0;
|
||||
float d;
|
||||
dclipnode_t *node;
|
||||
mplane_t *plane;
|
||||
|
||||
// touch linked edicts
|
||||
if( ap->type == AREA_SOLID )
|
||||
start = &node->solid_edicts;
|
||||
else if( ap->type == AREA_TRIGGERS )
|
||||
start = &node->trigger_edicts;
|
||||
else start = &node->water_edicts;
|
||||
|
||||
for( l = start->next; l != start; l = next )
|
||||
while( num >= 0 )
|
||||
{
|
||||
next = l->next;
|
||||
check = EDICT_FROM_AREA( l );
|
||||
|
||||
if( check->v.solid == SOLID_NOT && check->v.skin == CONTENTS_NONE )
|
||||
continue; // deactivated
|
||||
|
||||
if( !BoundsIntersect( check->v.absmin, check->v.absmax, ap->mins, ap->maxs ))
|
||||
continue; // not touching
|
||||
|
||||
if( ap->count == ap->maxcount )
|
||||
{
|
||||
MsgDev( D_WARN, "SV_AreaEdicts: maxcount hit\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
ap->list[ap->count] = check;
|
||||
ap->count++;
|
||||
}
|
||||
if( num < hull->firstclipnode || num > hull->lastclipnode )
|
||||
Host_Error( "SV_HullPointContents: bad node number %i\n", num );
|
||||
|
||||
if( node->axis == -1 ) return; // terminal node
|
||||
node = hull->clipnodes + num;
|
||||
plane = hull->planes + node->planenum;
|
||||
|
||||
if( plane->type < 3 )
|
||||
d = p[plane->type] - plane->dist;
|
||||
else d = DotProduct( plane->normal, p ) - plane->dist;
|
||||
|
||||
// recurse down both sides
|
||||
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 );
|
||||
if( d < 0 ) num = node->children[1];
|
||||
else num = node->children[0];
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
SV_AreaEdicts
|
||||
================
|
||||
====================
|
||||
SV_WaterLinks
|
||||
====================
|
||||
*/
|
||||
int SV_AreaEdicts( const vec3_t mins, const vec3_t maxs, edict_t **list, int maxcount, int areatype )
|
||||
void SV_WaterLinks( const vec3_t mins, const vec3_t maxs, int *pCont, areanode_t *node )
|
||||
{
|
||||
area_t ap;
|
||||
link_t *l, *next;
|
||||
edict_t *touch;
|
||||
|
||||
ap.mins = mins;
|
||||
ap.maxs = maxs;
|
||||
ap.list = list;
|
||||
ap.count = 0;
|
||||
ap.maxcount = maxcount;
|
||||
ap.type = areatype;
|
||||
// get water edicts
|
||||
for( l = node->water_edicts.next; l != &node->water_edicts; l = next )
|
||||
{
|
||||
next = l->next;
|
||||
touch = EDICT_FROM_AREA( l );
|
||||
|
||||
SV_AreaEdicts_r( sv_areanodes, &ap );
|
||||
if( touch->v.solid != SOLID_NOT ) // disabled ?
|
||||
continue;
|
||||
|
||||
return ap.count;
|
||||
// only brushes can have special contents
|
||||
if( CM_GetModelType( touch->v.modelindex ) != mod_brush )
|
||||
continue;
|
||||
|
||||
if( !BoundsIntersect( mins, maxs, touch->v.absmin, touch->v.absmax ))
|
||||
continue;
|
||||
|
||||
// compare contents ranking
|
||||
if( RankForContents( touch->v.skin ) > RankForContents( *pCont ))
|
||||
*pCont = touch->v.skin; // new content has more priority
|
||||
}
|
||||
|
||||
// recurse down both sides
|
||||
if( node->axis == -1 ) return;
|
||||
|
||||
if( maxs[node->axis] > node->dist )
|
||||
SV_WaterLinks( mins, maxs, pCont, node->children[0] );
|
||||
if( mins[node->axis] < node->dist )
|
||||
SV_WaterLinks( mins, maxs, pCont, node->children[1] );
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
SV_TruePointContents
|
||||
|
||||
=============
|
||||
*/
|
||||
int SV_TruePointContents( const vec3_t p )
|
||||
{
|
||||
int cont;
|
||||
|
||||
// sanity check
|
||||
if( !p ) return CONTENTS_NONE;
|
||||
|
||||
// get base contents from world
|
||||
cont = SV_HullPointContents( &sv.worldmodel->hulls[0], 0, p );
|
||||
|
||||
// check all water entities
|
||||
SV_WaterLinks( p, p, &cont, sv_areanodes );
|
||||
|
||||
return cont;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
SV_PointContents
|
||||
|
||||
=============
|
||||
*/
|
||||
int SV_PointContents( const vec3_t p )
|
||||
{
|
||||
int cont = SV_TruePointContents( p );
|
||||
|
||||
if( cont <= CONTENTS_CURRENT_0 && cont >= CONTENTS_CURRENT_DOWN )
|
||||
cont = CONTENTS_WATER;
|
||||
return cont;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
|
||||
/*
|
||||
============
|
||||
SV_TestEntityPosition
|
||||
|
||||
returns true if the entity is in solid currently
|
||||
============
|
||||
*/
|
||||
bool SV_TestEntityPosition( edict_t *ent )
|
||||
{
|
||||
trace_t trace;
|
||||
|
||||
trace = SV_Move( ent->v.origin, ent->v.mins, ent->v.maxs, ent->v.origin, MOVE_NORMAL, ent );
|
||||
|
||||
return trace.fStartSolid;
|
||||
}
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
LINE TESTING IN HULLS
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
/*
|
||||
==================
|
||||
SV_RecursiveHullCheck
|
||||
|
||||
==================
|
||||
*/
|
||||
bool SV_RecursiveHullCheck( hull_t *hull, int num, float p1f, float p2f, vec3_t p1, vec3_t p2, trace_t *trace )
|
||||
{
|
||||
dclipnode_t *node;
|
||||
mplane_t *plane;
|
||||
float t1, t2;
|
||||
float frac, midf;
|
||||
int side;
|
||||
vec3_t mid;
|
||||
|
||||
// check for empty
|
||||
if( num < 0 )
|
||||
{
|
||||
if( num != CONTENTS_SOLID )
|
||||
{
|
||||
trace->fAllSolid = false;
|
||||
if( num == CONTENTS_EMPTY )
|
||||
trace->fInOpen = true;
|
||||
else trace->fInWater = true;
|
||||
}
|
||||
else trace->fStartSolid = true;
|
||||
return true; // empty
|
||||
}
|
||||
|
||||
if( num < hull->firstclipnode || num > hull->lastclipnode )
|
||||
Host_Error( "SV_RecursiveHullCheck: bad node number %i\n", num );
|
||||
|
||||
// find the point distances
|
||||
node = hull->clipnodes + num;
|
||||
plane = hull->planes + node->planenum;
|
||||
|
||||
if( plane->type < 3 )
|
||||
{
|
||||
t1 = p1[plane->type] - plane->dist;
|
||||
t2 = p2[plane->type] - plane->dist;
|
||||
}
|
||||
else
|
||||
{
|
||||
t1 = DotProduct( plane->normal, p1 ) - plane->dist;
|
||||
t2 = DotProduct( plane->normal, p2 ) - plane->dist;
|
||||
}
|
||||
|
||||
if( t1 >= 0 && t2 >= 0 )
|
||||
return SV_RecursiveHullCheck( hull, node->children[0], p1f, p2f, p1, p2, trace );
|
||||
if( t1 < 0 && t2 < 0 )
|
||||
return SV_RecursiveHullCheck( hull, node->children[1], p1f, p2f, p1, p2, trace );
|
||||
|
||||
// put the crosspoint DIST_EPSILON pixels on the near side
|
||||
if( t1 < 0 ) frac = ( t1 + DIST_EPSILON ) / ( t1 - t2 );
|
||||
else frac = ( t1 - DIST_EPSILON ) / ( t1 - t2 );
|
||||
|
||||
if( frac < 0.0f ) frac = 0.0f;
|
||||
if( frac > 1.0f ) frac = 1.0f;
|
||||
|
||||
midf = p1f + ( p2f - p1f ) * frac;
|
||||
VectorLerp( p1, frac, p2, mid );
|
||||
|
||||
side = (t1 < 0);
|
||||
|
||||
// move up to the node
|
||||
if( !SV_RecursiveHullCheck( hull, node->children[side], p1f, midf, p1, mid, trace ))
|
||||
return false;
|
||||
|
||||
if( SV_HullPointContents( hull, node->children[side^1], mid ) != CONTENTS_SOLID )
|
||||
{
|
||||
// go past the node
|
||||
return SV_RecursiveHullCheck (hull, node->children[side^1], midf, p2f, mid, p2, trace);
|
||||
}
|
||||
|
||||
if( trace->fAllSolid )
|
||||
return false; // never got out of the solid area
|
||||
|
||||
//==================
|
||||
// the other side of the node is solid, this is the impact point
|
||||
//==================
|
||||
if( !side )
|
||||
{
|
||||
VectorCopy( plane->normal, trace->vecPlaneNormal );
|
||||
trace->flPlaneDist = plane->dist;
|
||||
}
|
||||
else
|
||||
{
|
||||
VectorNegate( plane->normal, trace->vecPlaneNormal );
|
||||
trace->flPlaneDist = -plane->dist;
|
||||
}
|
||||
|
||||
while( SV_HullPointContents( hull, hull->firstclipnode, mid ) == CONTENTS_SOLID )
|
||||
{
|
||||
// shouldn't really happen, but does occasionally
|
||||
frac -= 0.1f;
|
||||
|
||||
if( frac < 0.0f )
|
||||
{
|
||||
trace->flFraction = midf;
|
||||
VectorCopy( mid, trace->vecEndPos );
|
||||
MsgDev( D_WARN, "trace backed up 0.0\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
midf = p1f + (p2f - p1f) * frac;
|
||||
VectorLerp( p1, frac, p2, mid );
|
||||
}
|
||||
|
||||
trace->flFraction = midf;
|
||||
VectorCopy( mid, trace->vecEndPos );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -590,62 +971,79 @@ trace_t SV_MoveToss( edict_t *tossent, edict_t *ignore )
|
|||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
SV_PointContents
|
||||
============================================================================
|
||||
|
||||
=============
|
||||
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.
|
||||
============================================================================
|
||||
*/
|
||||
int SV_TruePointContents( const vec3_t p )
|
||||
/*
|
||||
====================
|
||||
SV_AreaEdicts_r
|
||||
====================
|
||||
*/
|
||||
void SV_AreaEdicts_r( areanode_t *node, area_t *ap )
|
||||
{
|
||||
int i, num, contents;
|
||||
edict_t *hit, *touch[MAX_EDICTS];
|
||||
link_t *l, *next, *start;
|
||||
edict_t *check;
|
||||
int count = 0;
|
||||
|
||||
// sanity check
|
||||
if( !p ) return CONTENTS_NONE;
|
||||
// touch linked edicts
|
||||
if( ap->type == AREA_SOLID )
|
||||
start = &node->solid_edicts;
|
||||
else if( ap->type == AREA_TRIGGERS )
|
||||
start = &node->trigger_edicts;
|
||||
else start = &node->water_edicts;
|
||||
|
||||
// get base contents from world
|
||||
contents = CM_PointContents( p );
|
||||
|
||||
if( contents != CONTENTS_EMPTY )
|
||||
return contents; // have some world contents
|
||||
|
||||
// check contents from all the solid entities
|
||||
num = SV_AreaEdicts( p, p, touch, MAX_EDICTS, AREA_SOLID );
|
||||
|
||||
for( i = 0; i < num; i++ )
|
||||
for( l = start->next; l != start; l = next )
|
||||
{
|
||||
hit = touch[i];
|
||||
next = l->next;
|
||||
check = EDICT_FROM_AREA( l );
|
||||
|
||||
if( hit->v.solid != SOLID_BSP )
|
||||
continue; // monsters, players
|
||||
if( check->v.solid == SOLID_NOT && check->v.skin == CONTENTS_NONE )
|
||||
continue; // deactivated
|
||||
|
||||
// solid entity found
|
||||
return CONTENTS_SOLID;
|
||||
if( !BoundsIntersect( check->v.absmin, check->v.absmax, ap->mins, ap->maxs ))
|
||||
continue; // not touching
|
||||
|
||||
if( ap->count == ap->maxcount )
|
||||
{
|
||||
MsgDev( D_WARN, "SV_AreaEdicts: maxcount hit\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
ap->list[ap->count] = check;
|
||||
ap->count++;
|
||||
}
|
||||
|
||||
if( node->axis == -1 ) return; // terminal node
|
||||
|
||||
// check contents from all the custom entities
|
||||
num = SV_AreaEdicts( p, p, touch, MAX_EDICTS, AREA_CUSTOM );
|
||||
|
||||
for( i = 0; i < num; i++ )
|
||||
{
|
||||
hit = touch[i];
|
||||
|
||||
if( hit->v.solid != SOLID_NOT || hit->v.skin == CONTENTS_NONE )
|
||||
continue; // invalid water ?
|
||||
|
||||
// custom contents found
|
||||
return hit->v.skin;
|
||||
}
|
||||
return contents;
|
||||
// recurse down both sides
|
||||
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 );
|
||||
}
|
||||
|
||||
int SV_PointContents( const vec3_t p )
|
||||
/*
|
||||
================
|
||||
SV_AreaEdicts
|
||||
================
|
||||
*/
|
||||
int SV_AreaEdicts( const vec3_t mins, const vec3_t maxs, edict_t **list, int maxcount, int areatype )
|
||||
{
|
||||
int cont = SV_TruePointContents( p );
|
||||
area_t ap;
|
||||
|
||||
if( cont <= CONTENTS_CURRENT_0 && cont >= CONTENTS_CURRENT_DOWN )
|
||||
cont = CONTENTS_WATER;
|
||||
return cont;
|
||||
ap.mins = mins;
|
||||
ap.maxs = maxs;
|
||||
ap.list = list;
|
||||
ap.count = 0;
|
||||
ap.maxcount = maxcount;
|
||||
ap.type = areatype;
|
||||
|
||||
SV_AreaEdicts_r( sv_areanodes, &ap );
|
||||
|
||||
return ap.count;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -151,7 +151,8 @@ bool R_VisCullBox( const vec3_t mins, const vec3_t maxs )
|
|||
if( !node->plane )
|
||||
return false;
|
||||
|
||||
s = BoxOnPlaneSide( extmins, extmaxs, node->plane ) - 1;
|
||||
s = BOX_ON_PLANE_SIDE( extmins, extmaxs, node->plane ) - 1;
|
||||
|
||||
if( s < 2 )
|
||||
{
|
||||
node = node->children[s];
|
||||
|
|
|
@ -113,27 +113,64 @@ void CategorizePlane( mplane_t *plane )
|
|||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
BoxOnPlaneSide (engine fast version)
|
||||
==================
|
||||
BoxOnPlaneSide
|
||||
|
||||
Returns SIDE_FRONT, SIDE_BACK, or SIDE_ON
|
||||
==============
|
||||
Returns 1, 2, or 1 + 2
|
||||
==================
|
||||
*/
|
||||
int BoxOnPlaneSide( const vec3_t emins, const vec3_t emaxs, const mplane_t *p )
|
||||
{
|
||||
if( p->type < 3 ) return ((emaxs[p->type] >= p->dist) | ((emins[p->type] < p->dist) << 1));
|
||||
float dist1, dist2;
|
||||
int sides = 0;
|
||||
|
||||
// general case
|
||||
switch( p->signbits )
|
||||
{
|
||||
case 0:
|
||||
dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
|
||||
dist2 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
|
||||
break;
|
||||
case 1:
|
||||
dist1 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
|
||||
dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
|
||||
break;
|
||||
case 2:
|
||||
dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
|
||||
dist2 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
|
||||
break;
|
||||
case 3:
|
||||
dist1 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
|
||||
dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
|
||||
break;
|
||||
case 4:
|
||||
dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
|
||||
dist2 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
|
||||
break;
|
||||
case 5:
|
||||
dist1 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
|
||||
dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
|
||||
break;
|
||||
case 6:
|
||||
dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
|
||||
dist2 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
|
||||
break;
|
||||
case 7:
|
||||
dist1 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
|
||||
dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
|
||||
break;
|
||||
default:
|
||||
case 0: return (((p->normal[0] * emaxs[0] + p->normal[1] * emaxs[1] + p->normal[2] * emaxs[2]) >= p->dist) | (((p->normal[0] * emins[0] + p->normal[1] * emins[1] + p->normal[2] * emins[2]) < p->dist) << 1));
|
||||
case 1: return (((p->normal[0] * emins[0] + p->normal[1] * emaxs[1] + p->normal[2] * emaxs[2]) >= p->dist) | (((p->normal[0] * emaxs[0] + p->normal[1] * emins[1] + p->normal[2] * emins[2]) < p->dist) << 1));
|
||||
case 2: return (((p->normal[0] * emaxs[0] + p->normal[1] * emins[1] + p->normal[2] * emaxs[2]) >= p->dist) | (((p->normal[0] * emins[0] + p->normal[1] * emaxs[1] + p->normal[2] * emins[2]) < p->dist) << 1));
|
||||
case 3: return (((p->normal[0] * emins[0] + p->normal[1] * emins[1] + p->normal[2] * emaxs[2]) >= p->dist) | (((p->normal[0] * emaxs[0] + p->normal[1] * emaxs[1] + p->normal[2] * emins[2]) < p->dist) << 1));
|
||||
case 4: return (((p->normal[0] * emaxs[0] + p->normal[1] * emaxs[1] + p->normal[2] * emins[2]) >= p->dist) | (((p->normal[0] * emins[0] + p->normal[1] * emins[1] + p->normal[2] * emaxs[2]) < p->dist) << 1));
|
||||
case 5: return (((p->normal[0] * emins[0] + p->normal[1] * emaxs[1] + p->normal[2] * emins[2]) >= p->dist) | (((p->normal[0] * emaxs[0] + p->normal[1] * emins[1] + p->normal[2] * emaxs[2]) < p->dist) << 1));
|
||||
case 6: return (((p->normal[0] * emaxs[0] + p->normal[1] * emins[1] + p->normal[2] * emins[2]) >= p->dist) | (((p->normal[0] * emins[0] + p->normal[1] * emaxs[1] + p->normal[2] * emaxs[2]) < p->dist) << 1));
|
||||
case 7: return (((p->normal[0] * emins[0] + p->normal[1] * emins[1] + p->normal[2] * emins[2]) >= p->dist) | (((p->normal[0] * emaxs[0] + p->normal[1] * emaxs[1] + p->normal[2] * emaxs[2]) < p->dist) << 1));
|
||||
// shut up compiler
|
||||
dist1 = dist2 = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if( dist1 >= p->dist )
|
||||
sides = 1;
|
||||
if( dist2 < p->dist )
|
||||
sides |= 2;
|
||||
|
||||
return sides;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -21,12 +21,29 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
|
||||
// r_math.h
|
||||
float CalcFov( float fov_x, float width, float height );
|
||||
void AdjustFov( float *fov_x, float *fov_y, float width, float height, bool lock_x );
|
||||
int BoxOnPlaneSide( const vec3_t emins, const vec3_t emaxs, const mplane_t *p );
|
||||
void AdjustFov( float *fov_x, float *fov_y, float width, float height, bool lock_x );
|
||||
void RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point, float degrees );
|
||||
void PlaneFromPoints( vec3_t verts[3], mplane_t *plane );
|
||||
void CategorizePlane( mplane_t *plane );
|
||||
|
||||
#define BOX_ON_PLANE_SIDE( emins, emaxs, p ) \
|
||||
((( p )->type < 3 ) ? \
|
||||
( \
|
||||
((p)->dist <= (emins)[(p)->type]) ? \
|
||||
1 \
|
||||
: \
|
||||
( \
|
||||
((p)->dist >= (emaxs)[(p)->type]) ? \
|
||||
2 \
|
||||
: \
|
||||
3 \
|
||||
) \
|
||||
) \
|
||||
: \
|
||||
BoxOnPlaneSide(( emins ), ( emaxs ), ( p )))
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
ColorNormalize
|
||||
|
|
Reference in New Issue