19 Oct 2010

This commit is contained in:
g-cont 2010-10-19 00:00:00 +04:00 committed by Alibek Omarov
parent a2a61486e2
commit 6b87c02012
18 changed files with 526 additions and 1927 deletions

View File

@ -1,12 +0,0 @@
//=======================================================================
// Copyright XashXT Group 2007 ©
// cm_debug.c - draw collision hulls outlines
//=======================================================================
#include "cm_local.h"
#include "mathlib.h"
void CM_DrawCollision( cmdraw_t drawPoly )
{
if( !drawPoly ) return;
}

View File

@ -7,124 +7,107 @@
#include "edict.h"
#include "mathlib.h"
int CM_RecursiveLightPoint( vec3_t color, mnode_t *node, const vec3_t start, const vec3_t end )
{
float front, back, frac;
vec3_t mid;
static vec3_t cm_pointColor;
static float cm_modulate;
loc0:
if( node->contents < 0 )
return false; // didn't hit anything
/*
=================
CM_RecursiveLightPoint
=================
*/
static bool CM_RecursiveLightPoint( mnode_t *node, const vec3_t start, const vec3_t end )
{
int side;
mplane_t *plane;
msurface_t *surf;
mtexinfo_t *tex;
vec3_t mid, scale;
float front, back, frac;
int i, map, size, s, t;
byte *lm;
// didn't hit anything
if( !node->plane ) return false;
// calculate mid point
if( node->plane->type < 3 )
plane = node->plane;
if( plane->type < 3 )
{
front = start[node->plane->type] - node->plane->dist;
back = end[node->plane->type] - node->plane->dist;
front = start[plane->type] - plane->dist;
back = end[plane->type] - plane->dist;
}
else
{
front = DotProduct( start, node->plane->normal ) - node->plane->dist;
back = DotProduct( end, node->plane->normal ) - node->plane->dist;
front = DotProduct( start, plane->normal ) - plane->dist;
back = DotProduct( end, plane->normal ) - plane->dist;
}
// optimized recursion
if(( back < 0 ) == ( front < 0 ))
{
node = node->children[front < 0];
goto loc0;
}
side = front < 0;
if(( back < 0 ) == side )
return CM_RecursiveLightPoint( node->children[side], start, end );
frac = front / ( front - back );
VectorLerp( start, frac, end, mid );
// go down front side
if( CM_RecursiveLightPoint( color, node->children[front < 0], start, mid ))
// co down front side
if( CM_RecursiveLightPoint( node->children[side], start, mid ))
return true; // hit something
if(( back < 0 ) == side )
return false;// didn't hit anything
// check for impact on this node
surf = node->firstface;
for( i = 0; i < node->numfaces; i++, surf++ )
{
// hit something
tex = surf->texinfo;
if( surf->flags & SURF_DRAWTILED )
continue; // no lightmaps
s = DotProduct( mid, tex->vecs[0] ) + tex->vecs[0][3] - surf->texturemins[0];
t = DotProduct( mid, tex->vecs[1] ) + tex->vecs[1][3] - surf->texturemins[1];
if(( s < 0 || s > surf->extents[0] ) || ( t < 0 || t > surf->extents[1] ))
continue;
s >>= 4;
t >>= 4;
if( !surf->samples )
return true;
VectorClear( cm_pointColor );
lm = surf->samples + 3 * (t * ((surf->extents[0] >> 4) + 1) + s);
size = ((surf->extents[0] >> 4) + 1) * ((surf->extents[1] >> 4) + 1) * 3;
for( map = 0; map < surf->numstyles; map++ )
{
VectorScale( cm.lightstyle[surf->styles[map]].rgb, cm_modulate, scale );
cm_pointColor[0] += lm[0] * scale[0];
cm_pointColor[1] += lm[1] * scale[1];
cm_pointColor[2] += lm[2] * scale[2];
lm += size; // skip to next lightmap
}
return true;
}
else
{
int i, ds, dt;
msurface_t *surf;
// check for impact on this node
for( i = 0, surf = node->firstface; i < node->numfaces; i++, surf++ )
{
if( surf->flags & SURF_DRAWTILED )
continue; // no lightmaps
ds = (int)((float)DotProduct( mid, surf->texinfo->vecs[0] ) + surf->texinfo->vecs[0][3] );
dt = (int)((float)DotProduct( mid, surf->texinfo->vecs[1] ) + surf->texinfo->vecs[1][3] );
if( ds < surf->texturemins[0] || dt < surf->texturemins[1] )
continue;
ds -= surf->texturemins[0];
dt -= surf->texturemins[1];
if( ds > surf->extents[0] || dt > surf->extents[1] )
continue;
if( surf->samples )
{
// enhanced to interpolate lighting
byte *lightmap;
int maps, line3, dsfrac = ds & 15, dtfrac = dt & 15;
int r00 = 0, g00 = 0, b00 = 0, r01 = 0, g01 = 0, b01 = 0;
int r10 = 0, g10 = 0, b10 = 0, r11 = 0, g11 = 0, b11 = 0;
float scale;
line3 = ((surf->extents[0] >> 4) + 1) * 3;
lightmap = surf->samples + ((dt >> 4) * ((surf->extents[0] >> 4) + 1) + (ds >> 4)) * 3;
for( maps = 0; maps < LM_STYLES && surf->styles[maps] != 255; maps++ )
{
scale = (float)cm.lightstyle[surf->styles[maps]].value;
r00 += (float)lightmap[0] * scale;
g00 += (float)lightmap[1] * scale;
b00 += (float)lightmap[2] * scale;
r01 += (float)lightmap[3] * scale;
g01 += (float)lightmap[4] * scale;
b01 += (float)lightmap[5] * scale;
r10 += (float)lightmap[line3+0] * scale;
g10 += (float)lightmap[line3+1] * scale;
b10 += (float)lightmap[line3+2] * scale;
r11 += (float)lightmap[line3+3] * scale;
g11 += (float)lightmap[line3+4] * scale;
b11 += (float)lightmap[line3+5] * scale;
lightmap += ((surf->extents[0] >> 4) + 1) * ((surf->extents[1] >> 4) + 1) * 3;
}
color[0] += (float)((int)((((((((r11 - r10) * dsfrac) >> 4) + r10)
- ((((r01 - r00) * dsfrac) >> 4) + r00)) * dtfrac) >> 4)
+ ((((r01 - r00) * dsfrac) >> 4) + r00)));
color[1] += (float)((int)((((((((g11 - g10) * dsfrac) >> 4) + g10)
- ((((g01 - g00) * dsfrac) >> 4) + g00)) * dtfrac) >> 4)
+ ((((g01 - g00) * dsfrac) >> 4) + g00)));
color[2] += (float)((int)((((((((b11 - b10) * dsfrac) >> 4) + b10)
- ((((b01 - b00) * dsfrac) >> 4) + b00)) * dtfrac) >> 4)
+ ((((b01 - b00) * dsfrac) >> 4) + b00)));
}
return true; // success
}
// go down back side
return CM_RecursiveLightPoint( color, node->children[front >= 0], mid, end );
}
// go down back side
return CM_RecursiveLightPoint( node->children[!side], mid, end );
}
void CM_RunLightStyles( float time )
{
int i, ofs;
clightstyle_t *ls;
float l;
if( !sv_models[1] )
return; // no world
if( !worldmodel ) return;
// run lightstyles animation
ofs = (time * 10);
@ -134,9 +117,11 @@ void CM_RunLightStyles( float time )
for( i = 0, ls = cm.lightstyle; i < MAX_LIGHTSTYLES; i++, ls++ )
{
if( ls->length == 0 ) ls->value = 0.0f;
else if( ls->length == 1 ) ls->value = ls->map[0];
else ls->value = ls->map[ofs%ls->length];
if( ls->length == 0 ) l = 0.0f;
else if( ls->length == 1 ) l = ls->map[0];
else l = ls->map[ofs%ls->length];
VectorSet( ls->rgb, l, l, l );
}
}
@ -166,7 +151,7 @@ void CM_ClearLightStyles( void )
Mem_Set( cm.lightstyle, 0, sizeof( cm.lightstyle ));
for( i = 0, ls = cm.lightstyle; i < MAX_LIGHTSTYLES; i++, ls++ )
cm.lightstyle[i].value = 1.0f;
VectorSet( cm.lightstyle[i].rgb, 1.0f, 1.0f, 1.0f );
cm.lastofs = -1;
}
@ -179,7 +164,7 @@ grab the ambient lighting color for current point
*/
int CM_LightEntity( edict_t *pEdict )
{
vec3_t start, end, color;
vec3_t start, end;
if( !pEdict ) return 0;
if( pEdict->v.effects & EF_FULLBRIGHT || !worldmodel->lightdata )
@ -198,11 +183,12 @@ int CM_LightEntity( edict_t *pEdict )
VectorCopy( pEdict->v.origin, end );
if( pEdict->v.effects & EF_INVLIGHT )
end[2] = start[2] + 4096;
else end[2] = start[2] - 4096;
end[2] = start[2] + 8192;
else end[2] = start[2] - 8192;
VectorSet( cm_pointColor, 1.0f, 1.0f, 1.0f );
VectorClear( color );
CM_RecursiveLightPoint( color, worldmodel->nodes, start, end );
cm_modulate = cm_lighting_modulate->value * (1.0 / 255);
CM_RecursiveLightPoint( worldmodel->nodes, start, end );
return VectorAvg( color );
return VectorAvg( cm_pointColor );
}

View File

@ -22,12 +22,13 @@
#define DVIS_PHS 1
extern cvar_t *cm_novis;
extern cvar_t *cm_lighting_modulate;
typedef struct
{
int length;
float map[MAX_STRING];
float value; // current lightvalue
vec3_t rgb; // 0.0 - 2.0
} clightstyle_t;
typedef struct leaflist_s
@ -61,15 +62,9 @@ typedef struct clipmap_s
} clipmap_t;
extern clipmap_t cm;
extern model_t *sv_models[MAX_MODELS]; // replacement client-server table
extern model_t *loadmodel;
extern model_t *worldmodel;
//
// cm_debug.c
//
void CM_DrawCollision( cmdraw_t callback );
//
// cm_light.c
//
@ -78,13 +73,6 @@ void CM_SetLightStyle( int style, const char* val );
int CM_LightEntity( edict_t *pEdict );
void CM_ClearLightStyles( void );
//
// cm_main.c
//
bool CM_InitPhysics( void );
void CM_Frame( float time );
void CM_FreePhysics( void );
//
// cm_test.c
//
@ -93,7 +81,6 @@ byte *CM_LeafPHS( int leafnum );
int CM_PointLeafnum( const vec3_t p );
mleaf_t *CM_PointInLeaf( const vec3_t p, mnode_t *node );
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, const byte *visbits );
int CM_HullPointContents( hull_t *hull, int num, const vec3_t p );
int CM_PointContents( const vec3_t p );
@ -109,35 +96,16 @@ byte *CM_FatPHS( const vec3_t org, bool portal );
//
// cm_model.c
//
void CM_FreeModels( void );
int CM_NumBmodels( void );
bool CM_InitPhysics( void );
void CM_FreePhysics( void );
script_t *CM_GetEntityScript( void );
void Mod_GetBounds( int handle, vec3_t mins, vec3_t maxs );
void Mod_GetFrames( int handle, int *numFrames );
modtype_t CM_GetModelType( int handle );
model_t *CM_ClipHandleToModel( int handle );
hull_t *CM_HullForBox( const vec3_t mins, const vec3_t maxs );
int CM_TempBoxModel( const vec3_t mins, const vec3_t maxs, bool capsule );
void CM_BeginRegistration ( const char *name, bool clientload, uint *checksum );
bool CM_RegisterModel( const char *name, int sv_index );
void *Mod_Extradata( int handle );
model_t *CM_ModForName( const char *name, bool world );
void CM_EndRegistration( void );
//
// cm_studio.c
//
void CM_StudioInitBoxHull( void );
int CM_StudioBodyVariations( int handle );
void CM_StudioGetAttachment( edict_t *e, int iAttachment, float *org, float *ang );
bool CM_StudioTrace( edict_t *e, const vec3_t start, const vec3_t end, trace_t *tr );
void CM_GetBonePosition( edict_t* e, int iBone, float *rgflOrigin, float *rgflAngles );
//
// cm_trace.c
//
trace_t CM_ClipMove( edict_t *ent, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, int flags );
const char *CM_TraceTexture( edict_t *pTextureEntity, const vec3_t v1, const vec3_t v2 );
hull_t *CM_HullForBsp( edict_t *ent, const vec3_t mins, const vec3_t maxs, float *offset );
#endif//CM_LOCAL_H

View File

@ -1,27 +0,0 @@
//=======================================================================
// Copyright XashXT Group 2007 ©
// cm_main.c - collision interface
//=======================================================================
#include "cm_local.h"
// cvars
cvar_t *cm_novis;
bool CM_InitPhysics( void )
{
cm_novis = Cvar_Get( "cm_novis", "0", 0, "force to ignore server visibility" );
Mem_Set( cm.nullrow, 0xFF, MAX_MAP_LEAFS / 8 );
return true;
}
void CM_Frame( float time )
{
CM_RunLightStyles( time );
}
void CM_FreePhysics( void )
{
CM_FreeModels();
}

View File

@ -15,17 +15,18 @@
clipmap_t cm;
byte *mod_base;
model_t *sv_models[MAX_MODELS]; // server replacement modeltable
static model_t *sv_models[MAX_MODELS]; // server replacement modeltable
static model_t cm_inline[MAX_MAP_MODELS]; // inline bsp models
static model_t cm_models[MAX_MODELS];
static int cm_nummodels;
mplane_t box_planes[6];
dclipnode_t box_clipnodes[6];
hull_t box_hull[1];
model_t *loadmodel;
model_t *worldmodel;
// cvars
cvar_t *cm_novis;
cvar_t *cm_lighting_modulate;
/*
===============================================================================
@ -33,88 +34,6 @@ model_t *worldmodel;
===============================================================================
*/
/*
===================
CM_BmodelInitBoxHull
Set up the planes and nodes so that the six floats of a bounding box
can just be stored out and get a proper clipping hull structure.
===================
*/
void CM_BmodelInitBoxHull( void )
{
mplane_t *p;
dclipnode_t *c;
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++ )
{
side = i & 1;
// setup clipnodes
c = &box_clipnodes[i];
c->planenum = i;
c->children[side] = CONTENTS_EMPTY;
if( i != 5 ) c->children[side^1] = i + 1;
else c->children[side^1] = CONTENTS_SOLID;
// setup planes
p = &box_planes[i];
VectorClear( p->normal );
p->type = i>>1;
p->normal[i>>1] = 1.0f;
p->signbits = 0;
}
}
/*
===================
CM_HullForBox
To keep everything totally uniform, bounding boxes are turned into small
BSP trees instead of being compared directly.
===================
*/
hull_t *CM_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;
}
/*
================
CM_FreeModel
================
*/
void CM_FreeModel( model_t *mod )
{
if( !mod || !mod->mempool )
return;
Mem_FreePool( &mod->mempool );
Mem_Set( mod, 0, sizeof( *mod ));
}
int CM_NumBmodels( void )
{
if( worldmodel )
return worldmodel->numsubmodels;
return 0;
}
script_t *CM_GetEntityScript( void )
{
string entfilename;
@ -136,6 +55,71 @@ script_t *CM_GetEntityScript( void )
return cm.entityscript;
}
/*
================
CM_StudioBodyVariations
================
*/
static int CM_StudioBodyVariations( int handle )
{
studiohdr_t *pstudiohdr;
mstudiobodyparts_t *pbodypart;
int i, count;
pstudiohdr = (studiohdr_t *)Mod_Extradata( handle );
if( !pstudiohdr ) return 0;
count = 1;
pbodypart = (mstudiobodyparts_t *)((byte *)pstudiohdr + pstudiohdr->bodypartindex);
// each body part has nummodels variations so there are as many total variations as there
// are in a matrix of each part by each other part
for( i = 0; i < pstudiohdr->numbodyparts; i++ )
{
count = count * pbodypart[i].nummodels;
}
return count;
}
/*
================
CM_FreeModel
================
*/
static void CM_FreeModel( model_t *mod )
{
if( !mod || !mod->mempool )
return;
Mem_FreePool( &mod->mempool );
Mem_Set( mod, 0, sizeof( *mod ));
}
/*
===============================================================================
CM INITALIZE\SHUTDOWN
===============================================================================
*/
bool CM_InitPhysics( void )
{
cm_novis = Cvar_Get( "cm_novis", "0", 0, "force to ignore server visibility" );
cm_lighting_modulate = Cvar_Get( "r_lighting_modulate", "1", CVAR_ARCHIVE|CVAR_LATCH_VIDEO, "lightstyles modulate scale" );
Mem_Set( cm.nullrow, 0xFF, MAX_MAP_LEAFS / 8 );
return true;
}
void CM_FreePhysics( void )
{
int i;
for( i = 0; i < cm_nummodels; i++ )
CM_FreeModel( &cm_models[i] );
}
/*
===============================================================================
@ -635,7 +619,7 @@ static void BSP_LoadPlanes( dlump_t *l )
BSP_LoadVisibility
=================
*/
void BSP_LoadVisibility( dlump_t *l )
static void BSP_LoadVisibility( dlump_t *l )
{
if( !l->filelen )
{
@ -653,7 +637,7 @@ void BSP_LoadVisibility( dlump_t *l )
BSP_LoadEntityString
=================
*/
void BSP_LoadEntityString( dlump_t *l )
static void BSP_LoadEntityString( dlump_t *l )
{
byte *in;
@ -724,7 +708,7 @@ CM_MakeHull0
Duplicate the drawing hull structure as a clipping hull
=================
*/
void CM_MakeHull0( void )
static void CM_MakeHull0( void )
{
mnode_t *in, *child;
dclipnode_t *out;
@ -757,7 +741,6 @@ void CM_MakeHull0( void )
}
}
/*
=================
CM_BrushModel
@ -910,7 +893,100 @@ static void CM_SpriteModel( model_t *mod, byte *buffer )
loadmodel->maxs[2] = phdr->bounds[1] / 2;
}
void CM_FreeWorld( void )
static model_t *CM_ModForName( const char *name, bool world )
{
byte *buf;
model_t *mod;
int i, size;
if( !name || !name[0] )
return NULL;
// fast check for worldmodel
if( !com.strcmp( name, cm_models[0].name ))
return &cm_models[0];
// check for submodel
if( name[0] == '*' )
{
i = com.atoi( name + 1 );
if( i < 1 || !worldmodel || i >= worldmodel->numsubmodels )
{
MsgDev( D_ERROR, "CM_InlineModel: bad submodel number %d\n", i );
return NULL;
}
return &cm_inline[i];
}
// search the currently loaded models
for( i = 0, mod = cm_models; i < cm_nummodels; i++, mod++ )
{
if( !mod->name[0] ) continue;
if( !com.strcmp( name, mod->name ))
{
// prolonge registration
mod->registration_sequence = cm.registration_sequence;
return mod;
}
}
// find a free model slot spot
for( i = 0, mod = cm_models; i < cm_nummodels; i++, mod++ )
if( !mod->name[0] ) break; // free spot
if( i == cm_nummodels )
{
if( cm_nummodels == MAX_MODELS )
Host_Error( "Mod_ForName: MAX_MODELS limit exceeded\n" );
cm_nummodels++;
}
buf = FS_LoadFile( name, &size );
if( !buf )
{
MsgDev( D_ERROR, "CM_LoadModel: %s couldn't load\n", name );
return NULL;
}
// if it's world - calc the map checksum
if( world ) cm.checksum = LittleLong( Com_BlockChecksum( buf, size ));
MsgDev( D_NOTE, "CM_LoadModel: %s\n", name );
com.strncpy( mod->name, name, sizeof( mod->name ));
mod->registration_sequence = cm.registration_sequence; // register mod
mod->type = mod_bad;
loadmodel = mod;
// call the apropriate loader
switch( LittleLong( *(uint *)buf ))
{
case IDSTUDIOHEADER:
CM_StudioModel( mod, buf );
break;
case IDSPRITEHEADER:
CM_SpriteModel( mod, buf );
break;
default:
CM_BrushModel( mod, buf );
break;
}
Mem_Free( buf );
if( mod->type == mod_bad )
{
CM_FreeModel( mod );
// check for loading problems
if( world ) Host_Error( "Mod_ForName: %s unknown format\n", name );
else MsgDev( D_ERROR, "Mod_ForName: %s unknown format\n", name );
return NULL;
}
return mod;
}
static void CM_FreeWorld( void )
{
if( worldmodel )
CM_FreeModel( &cm_models[0] );
@ -923,14 +999,6 @@ void CM_FreeWorld( void )
worldmodel = NULL;
}
void CM_FreeModels( void )
{
int i;
for( i = 0; i < cm_nummodels; i++ )
CM_FreeModel( &cm_models[i] );
}
/*
==================
CM_BeginRegistration
@ -980,9 +1048,6 @@ void CM_BeginRegistration( const char *name, bool clientload, uint *checksum )
if( checksum ) *checksum = cm.checksum;
CM_BmodelInitBoxHull ();
CM_StudioInitBoxHull (); // hitbox tracing
CM_ClearLightStyles();
CM_CalcPHS ();
}
@ -1086,98 +1151,6 @@ void Mod_GetBounds( int handle, vec3_t mins, vec3_t maxs )
}
}
model_t *CM_ModForName( const char *name, bool world )
{
byte *buf;
model_t *mod;
int i, size;
if( !name || !name[0] )
return NULL;
// fast check for worldmodel
if( !com.strcmp( name, cm_models[0].name ))
return &cm_models[0];
// check for submodel
if( name[0] == '*' )
{
i = com.atoi( name + 1 );
if( i < 1 || !worldmodel || i >= worldmodel->numsubmodels )
{
MsgDev( D_ERROR, "CM_InlineModel: bad submodel number %d\n", i );
return NULL;
}
return &cm_inline[i];
}
// search the currently loaded models
for( i = 0, mod = cm_models; i < cm_nummodels; i++, mod++ )
{
if( !mod->name[0] ) continue;
if( !com.strcmp( name, mod->name ))
{
// prolonge registration
mod->registration_sequence = cm.registration_sequence;
return mod;
}
}
// find a free model slot spot
for( i = 0, mod = cm_models; i < cm_nummodels; i++, mod++ )
if( !mod->name[0] ) break; // free spot
if( i == cm_nummodels )
{
if( cm_nummodels == MAX_MODELS )
Host_Error( "Mod_ForName: MAX_MODELS limit exceeded\n" );
cm_nummodels++;
}
buf = FS_LoadFile( name, &size );
if( !buf )
{
MsgDev( D_ERROR, "CM_LoadModel: %s couldn't load\n", name );
return NULL;
}
// if it's world - calc the map checksum
if( world ) cm.checksum = LittleLong( Com_BlockChecksum( buf, size ));
MsgDev( D_NOTE, "CM_LoadModel: %s\n", name );
com.strncpy( mod->name, name, sizeof( mod->name ));
mod->registration_sequence = cm.registration_sequence; // register mod
mod->type = mod_bad;
loadmodel = mod;
// call the apropriate loader
switch( LittleLong( *(uint *)buf ))
{
case IDSTUDIOHEADER:
CM_StudioModel( mod, buf );
break;
case IDSPRITEHEADER:
CM_SpriteModel( mod, buf );
break;
default:
CM_BrushModel( mod, buf );
break;
}
Mem_Free( buf );
if( mod->type == mod_bad )
{
// check for loading problems
if( world ) Host_Error( "CMod_ForName: %s unknown format\n", name );
else MsgDev( D_ERROR, "CMod_ForName: %s unknown format\n", name );
CM_FreeModel( mod );
return NULL;
}
return mod;
}
bool CM_RegisterModel( const char *name, int index )
{
model_t *mod;

View File

@ -1,804 +0,0 @@
//=======================================================================
// Copyright XashXT Group 2009 ©
// cm_studio.c - stduio models tracing
//=======================================================================
#include "cm_local.h"
#include "studio.h"
#include "mathlib.h"
#include "matrix_lib.h"
#include "edict.h"
#include "byteorder.h"
#include "const.h"
struct
{
studiohdr_t *hdr;
mstudiomodel_t *submodel;
mstudiobodyparts_t *bodypart;
matrix4x4 rotmatrix;
matrix4x4 bones[MAXSTUDIOBONES];
mplane_t planes[12];
trace_t trace;
} studio;
/*
===============================================================================
STUDIO MODELS
===============================================================================
*/
int CM_StudioExtractBbox( studiohdr_t *phdr, int sequence, float *mins, float *maxs )
{
mstudioseqdesc_t *pseqdesc;
pseqdesc = (mstudioseqdesc_t *)((byte *)phdr + phdr->seqindex);
if( sequence == -1 ) return 0;
VectorCopy( pseqdesc[sequence].bbmin, mins );
VectorCopy( pseqdesc[sequence].bbmax, maxs );
return 1;
}
int CM_StudioBodyVariations( int handle )
{
studiohdr_t *pstudiohdr;
mstudiobodyparts_t *pbodypart;
int i, count;
pstudiohdr = (studiohdr_t *)Mod_Extradata( handle );
if( !pstudiohdr ) return 0;
count = 1;
pbodypart = (mstudiobodyparts_t *)((byte *)pstudiohdr + pstudiohdr->bodypartindex);
// each body part has nummodels variations so there are as many total variations as there
// are in a matrix of each part by each other part
for( i = 0; i < pstudiohdr->numbodyparts; i++ )
{
count = count * pbodypart[i].nummodels;
}
return count;
}
/*
====================
CM_StudioSetUpTransform
====================
*/
void CM_StudioSetUpTransform( edict_t *e )
{
float *ang, *org, scale = 1.0f;
org = e->v.origin;
ang = e->v.angles;
if( e->v.scale != 0.0f )
scale = e->v.scale;
Matrix4x4_CreateFromEntity( studio.rotmatrix, org[0], org[1], org[2], ang[PITCH], ang[YAW], ang[ROLL], scale );
}
/*
====================
StudioCalcBoneAdj
====================
*/
void CM_StudioCalcBoneAdj( float dadt, float *adj, const byte *pcontroller1, const byte *pcontroller2 )
{
int i, j;
float value;
mstudiobonecontroller_t *pbonecontroller;
pbonecontroller = (mstudiobonecontroller_t *)((byte *)studio.hdr + studio.hdr->bonecontrollerindex);
for( j = 0; j < studio.hdr->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 - dadt)) - 128) * (360.0/256.0) + 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.0 - dadt)) / 255.0;
if( value < 0 ) value = 0;
if( value > 1.0 ) value = 1.0;
value = (1.0 - 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.0);
break;
case STUDIO_X:
case STUDIO_Y:
case STUDIO_Z:
adj[j] = value;
break;
}
}
}
/*
====================
CM_StudioCalcBoneQuaterion
====================
*/
void CM_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 );
}
}
/*
====================
CM_StudioCalcBonePosition
====================
*/
void CM_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.0 - 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.0 - 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]];
}
}
}
/*
====================
CM_StudioCalcRotations
====================
*/
void CM_StudioCalcRotations( edict_t *e, float pos[][3], vec4_t *q, mstudioseqdesc_t *pseqdesc, mstudioanim_t *panim, float f )
{
int i;
int frame;
mstudiobone_t *pbone;
float adj[MAXSTUDIOCONTROLLERS];
float s, dadt = 1.0f; // noInterp
if( f > pseqdesc->numframes - 1 )
f = 0;
else if( f < -0.01 )
f = -0.01;
frame = (int)f;
s = (f - frame);
// add in programtic controllers
pbone = (mstudiobone_t *)((byte *)studio.hdr + studio.hdr->boneindex);
CM_StudioCalcBoneAdj( dadt, adj, e->v.controller, e->v.controller );
for (i = 0; i < studio.hdr->numbones; i++, pbone++, panim++)
{
CM_StudioCalcBoneQuaterion( frame, s, pbone, panim, adj, q[i] );
CM_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.0 - (f - (int)(f))) / (pseqdesc->numframes)) * e->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
====================
*/
float CM_StudioEstimateFrame( edict_t *e, mstudioseqdesc_t *pseqdesc )
{
double f;
if( pseqdesc->numframes <= 1 )
f = 0;
else f = (e->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;
}
/*
====================
CM_StudioSlerpBones
====================
*/
void CM_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 < studio.hdr->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;
}
}
/*
====================
CM_StudioGetAnim
====================
*/
mstudioanim_t *CM_StudioGetAnim( model_t *m_pSubModel, mstudioseqdesc_t *pseqdesc )
{
mstudioseqgroup_t *pseqgroup;
cache_user_t *paSequences;
size_t filesize;
byte *buf;
pseqgroup = (mstudioseqgroup_t *)((byte *)studio.hdr + studio.hdr->seqgroupindex) + pseqdesc->seqgroup;
if( pseqdesc->seqgroup == 0 )
return (mstudioanim_t *)((byte *)studio.hdr + 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;
}
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 != LittleLong(*(uint *)buf ))
Host_Error( "CM_StudioGetAnim: %s is corrpted\n", modelpath );
MsgDev( D_INFO, "loading %s\n", filepath );
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);
}
/*
====================
CM_StudioSetupBones
====================
*/
void CM_StudioSetupBones( edict_t *e )
{
int i, oldseq;
double f;
mstudiobone_t *pbones;
mstudioseqdesc_t *pseqdesc;
mstudioanim_t *panim;
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];
oldseq = e->v.sequence; // TraceCode can't change sequence
if( e->v.sequence >= studio.hdr->numseq ) e->v.sequence = 0;
pseqdesc = (mstudioseqdesc_t *)((byte *)studio.hdr + studio.hdr->seqindex) + e->v.sequence;
f = CM_StudioEstimateFrame( e, pseqdesc );
panim = CM_StudioGetAnim( CM_ClipHandleToModel( e->v.modelindex ), pseqdesc );
CM_StudioCalcRotations( e, pos, q, pseqdesc, panim, f );
if( pseqdesc->numblends > 1 )
{
float s;
float dadt = 1.0f;
panim += studio.hdr->numbones;
CM_StudioCalcRotations( e, pos2, q2, pseqdesc, panim, f );
s = (e->v.blending[0] * dadt + e->v.blending[0] * (1.0 - dadt)) / 255.0;
CM_StudioSlerpBones( q, pos, q2, pos2, s );
if( pseqdesc->numblends == 4 )
{
panim += studio.hdr->numbones;
CM_StudioCalcRotations( e, pos3, q3, pseqdesc, panim, f );
panim += studio.hdr->numbones;
CM_StudioCalcRotations( e, pos4, q4, pseqdesc, panim, f );
s = (e->v.blending[0] * dadt + e->v.blending[0] * (1.0 - dadt)) / 255.0;
CM_StudioSlerpBones( q3, pos3, q4, pos4, s );
s = (e->v.blending[1] * dadt + e->v.blending[1] * (1.0 - dadt)) / 255.0;
CM_StudioSlerpBones( q, pos, q3, pos3, s );
}
}
pbones = (mstudiobone_t *)((byte *)studio.hdr + studio.hdr->boneindex);
for( i = 0; i < studio.hdr->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( studio.bones[i], studio.rotmatrix, bonematrix );
else Matrix4x4_ConcatTransforms( studio.bones[i], studio.bones[pbones[i].parent], bonematrix );
}
e->v.sequence = oldseq; // restore original value
}
/*
====================
StudioCalcAttachments
====================
*/
static void CM_StudioCalcAttachments( edict_t *e, int iAttachment, float *org, float *ang )
{
int i;
mstudioattachment_t *pAtt;
vec3_t axis[3];
vec3_t localOrg, localAng;
if( studio.hdr->numattachments > MAXSTUDIOATTACHMENTS )
{
studio.hdr->numattachments = MAXSTUDIOATTACHMENTS; // reduce it
MsgDev( D_WARN, "CM_StudioCalcAttahments: too many attachments on %s\n", studio.hdr->name );
}
iAttachment = bound( 0, iAttachment, studio.hdr->numattachments );
// calculate attachment points
pAtt = (mstudioattachment_t *)((byte *)studio.hdr + studio.hdr->attachmentindex);
for( i = 0; i < studio.hdr->numattachments; i++ )
{
if( i == iAttachment )
{
// compute pos and angles
Matrix4x4_VectorTransform( studio.bones[pAtt[i].bone], pAtt[i].org, localOrg );
Matrix4x4_VectorTransform( studio.bones[pAtt[i].bone], pAtt[i].vectors[0], axis[0] );
Matrix4x4_VectorTransform( studio.bones[pAtt[i].bone], pAtt[i].vectors[1], axis[1] );
Matrix4x4_VectorTransform( studio.bones[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
}
}
}
void CM_StudioInitBoxHull( void )
{
int i, side;
mplane_t *p;
for( i = 0; i < 6; i++ )
{
side = i & 1;
// planes
p = &studio.planes[i*2];
p->type = i>>1;
p->signbits = 0;
VectorClear( p->normal );
p->normal[i>>1] = 1.0f;
p = &studio.planes[i*2+1];
p->type = 3 + (i>>1);
p->signbits = 0;
VectorClear( p->normal );
p->normal[i>>1] = -1;
p->signbits = SignbitsForPlane( p->normal );
}
}
void CM_StudioBoxHullFromBounds( const vec3_t mins, const vec3_t maxs )
{
studio.planes[0].dist = maxs[0];
studio.planes[1].dist = -maxs[0];
studio.planes[2].dist = mins[0];
studio.planes[3].dist = -mins[0];
studio.planes[4].dist = maxs[1];
studio.planes[5].dist = -maxs[1];
studio.planes[6].dist = mins[1];
studio.planes[7].dist = -mins[1];
studio.planes[8].dist = maxs[2];
studio.planes[9].dist = -maxs[2];
studio.planes[10].dist = mins[2];
studio.planes[11].dist = -mins[2];
}
bool CM_StudioSetup( edict_t *e )
{
model_t *mod = CM_ClipHandleToModel( e->v.modelindex );
if( mod && mod->type == mod_studio && mod->extradata )
{
studio.hdr = (studiohdr_t *)mod->extradata;
CM_StudioSetUpTransform( e );
CM_StudioSetupBones( e );
return true;
}
return false;
}
bool CM_StudioTraceBox( vec3_t start, vec3_t end )
{
int i;
mplane_t *plane, *clipplane;
float enterFrac, leaveFrac;
bool getout, startout;
float d1, d2;
float f;
enterFrac = -1.0;
leaveFrac = 1.0;
clipplane = NULL;
getout = false;
startout = false;
// compare the trace against all planes of the brush
// find the latest time the trace crosses a plane towards the interior
// and the earliest time the trace crosses a plane towards the exterior
for( i = 0; i < 6; i++ )
{
plane = studio.planes + i * 2 + (i & 1);
d1 = DotProduct( start, plane->normal ) - plane->dist;
d2 = DotProduct( end, plane->normal ) - plane->dist;
if( d2 > 0.0f ) getout = TRUE; // endpoint is not in solid
if( d1 > 0.0f ) startout = TRUE;
// if completely in front of face, no intersection with the entire brush
if( d1 > 0 && ( d2 >= DIST_EPSILON || d2 >= d1 ))
return false;
// if it doesn't cross the plane, the plane isn't relevent
if( d1 <= 0 && d2 <= 0 )
continue;
// crosses face
if( d1 > d2 )
{
// enter
f = (d1 - DIST_EPSILON) / (d1 - d2);
if( f < 0.0f ) f = 0.0f;
if( f > enterFrac )
{
enterFrac = f;
clipplane = plane;
}
}
else
{
// leave
f = (d1 + DIST_EPSILON) / (d1 - d2);
if( f > 1.0f ) f = 1.0f;
if( f < leaveFrac )
{
leaveFrac = f;
}
}
}
// all planes have been checked, and the trace was not
// completely outside the brush
if( !startout )
{
// original point was inside brush
if( !getout ) studio.trace.flFraction = 0.0f;
return true;
}
if( enterFrac < leaveFrac )
{
if( enterFrac > -1 && enterFrac < studio.trace.flFraction )
{
if( enterFrac < 0.0f )
enterFrac = 0.0f;
studio.trace.flFraction = enterFrac;
VectorCopy( clipplane->normal, studio.trace.vecPlaneNormal );
studio.trace.flPlaneDist = clipplane->dist;
return true;
}
}
return false;
}
bool CM_StudioTrace( edict_t *e, const vec3_t start, const vec3_t end, trace_t *tr )
{
matrix4x4 m;
vec3_t start_l, end_l;
int i, outBone;
if( !CM_StudioSetup( e ) || !studio.hdr->numhitboxes )
{
tr->iHitgroup = -1;
return false;
}
Mem_Set( &studio.trace, 0, sizeof( trace_t ));
VectorCopy( end, studio.trace.vecEndPos );
studio.trace.fAllSolid = true;
studio.trace.flFraction = 1.0f;
studio.trace.iHitgroup = -1;
outBone = -1;
for( i = 0; i < studio.hdr->numhitboxes; i++ )
{
mstudiobbox_t *phitbox = (mstudiobbox_t *)((byte*)studio.hdr + studio.hdr->hitboxindex) + i;
Matrix4x4_Invert_Simple( m, studio.bones[phitbox->bone] );
Matrix4x4_VectorTransform( m, start, start_l );
Matrix4x4_VectorTransform( m, end, end_l );
CM_StudioBoxHullFromBounds( phitbox->bbmin, phitbox->bbmax );
if( CM_StudioTraceBox( start_l, end_l ))
{
outBone = phitbox->bone;
studio.trace.iHitgroup = phitbox->group;
}
if( studio.trace.flFraction == 0.0f )
break;
}
if( studio.trace.flFraction > 0.0f )
studio.trace.fAllSolid = false;
// all hitboxes were swept, get trace result
if( outBone >= 0 )
{
tr->flFraction = studio.trace.flFraction;
tr->iHitgroup = studio.trace.iHitgroup;
tr->fAllSolid = studio.trace.fAllSolid;
tr->pHit = e;
Matrix4x4_VectorRotate( studio.bones[outBone], studio.trace.vecPlaneNormal, tr->vecPlaneNormal );
if( tr->flFraction == 1.0f )
{
VectorCopy( end, tr->vecEndPos );
}
else
{
mstudiobone_t *pbone = (mstudiobone_t *)((byte*)studio.hdr + studio.hdr->boneindex) + outBone;
// MsgDev( D_INFO, "Bone name %s\n", pbone->name ); // debug
VectorLerp( start, tr->flFraction, end, tr->vecEndPos );
}
tr->flPlaneDist = DotProduct( tr->vecEndPos, tr->vecPlaneNormal );
return true;
}
return false;
}
void CM_StudioGetAttachment( edict_t *e, int iAttachment, float *org, float *ang )
{
if( !CM_StudioSetup( e ) || studio.hdr->numattachments <= 0 )
{
// reset attachments
if( org ) VectorCopy( e->v.origin, org );
if( ang ) VectorCopy( e->v.angles, ang );
return;
}
CM_StudioCalcAttachments( e, iAttachment, org, ang );
}
void CM_GetBonePosition( edict_t* e, int iBone, float *org, float *ang )
{
matrix3x3 axis;
if( !CM_StudioSetup( e ) || studio.hdr->numbones <= 0 )
{
// reset bones
if( org ) VectorCopy( e->v.origin, org );
if( ang ) VectorCopy( e->v.angles, ang );
return;
}
iBone = bound( 0, iBone, studio.hdr->numbones );
Matrix3x3_FromMatrix4x4( axis, studio.bones[iBone] );
if( org ) Matrix4x4_OriginFromMatrix( studio.bones[iBone], org );
if( ang ) Matrix3x3_ToAngles( axis, ang, true );
}

View File

@ -1,510 +0,0 @@
//=======================================================================
// Copyright XashXT Group 2009 ©
// cm_trace.c - geometry tracing
//=======================================================================
#include "cm_local.h"
#include "edict.h"
#include "mathlib.h"
#include "matrix_lib.h"
float CM_DistanceToIntersect( const vec3_t org, const vec3_t dir, const vec3_t plane_origin, const vec3_t plane_normal )
{
float d = -(DotProduct( plane_normal, plane_origin ));
float numerator = DotProduct( plane_normal, org ) + d;
float denominator = DotProduct( plane_normal, dir );
if( fabs( denominator ) < EQUAL_EPSILON )
return -1.0f; // normal is orthogonal to vector, no intersection
return -( numerator / denominator );
}
/*
===============================================================================
BOX TRACING
===============================================================================
*/
/*
================
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 *CM_HullForEntity( edict_t *ent, vec3_t mins, vec3_t maxs, vec3_t offset )
{
hull_t *hull;
model_t *model;
vec3_t size, hullmins, hullmaxs;
// 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( "Entity %i SOLID_BSP without MOVETYPE_PUSH\n", ent->serialnumber );
model = CM_ClipHandleToModel( ent->v.modelindex );
if( !model || model->type != mod_brush && model->type != mod_world )
Host_Error( "Entity %i SOLID_BSP with a non bsp model\n", ent->serialnumber );
VectorSubtract( maxs, mins, size );
if( size[0] < 3 )
{
// point hull
hull = &model->hulls[0];
}
else if( size[0] <= 36 )
{
if( size[2] <= 36 )
{
// head hull (ducked)
hull = &model->hulls[3];
}
else
{
// human hull
hull = &model->hulls[1];
}
}
else
{
// large hull
hull = &model->hulls[2];
}
// 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 = CM_HullForBox( hullmins, hullmaxs );
VectorCopy( ent->v.origin, offset );
}
return hull;
}
/*
==================
CM_HullForBsp
assume edict is valid
==================
*/
hull_t *CM_HullForBsp( edict_t *ent, const vec3_t mins, const vec3_t maxs, float *offset )
{
hull_t *hull;
model_t *model;
vec3_t size;
// decide which clipping hull to use, based on the size
model = CM_ClipHandleToModel( ent->v.modelindex );
if( !model || ( model->type != mod_brush && model->type != mod_world ))
Host_Error( "Entity %i SOLID_BSP with a non bsp model %i\n", ent->serialnumber, model->type );
VectorSubtract( maxs, mins, size );
if( size[0] < 3 )
{
// point hull
hull = &model->hulls[0];
}
else if( size[0] <= 36 )
{
if( size[2] <= 36 )
{
// head hull (ducked)
hull = &model->hulls[3];
}
else
{
// human hull
hull = &model->hulls[1];
}
}
else
{
// large hull
hull = &model->hulls[2];
}
// calculate an offset value to center the origin
VectorSubtract( hull->clip_mins, mins, offset );
VectorAdd( offset, ent->v.origin, offset );
return hull;
}
/*
==================
CM_RecursiveHullCheck
==================
*/
bool CM_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;
loc0:
// 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( "CM_RecursiveHullCheck: bad node number\n" );
// 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 )
{
num = node->children[0];
goto loc0;
}
if( t1 < 0 && t2 < 0 )
{
num = node->children[1];
goto loc0;
}
// put the crosspoint DIST_EPSILON pixels on the near side
side = (t1 < 0);
if( side ) frac = ( t1 + DIST_EPSILON ) / ( t1 - t2 );
else frac = ( t1 - DIST_EPSILON ) / ( t1 - t2 );
if( frac < 0 ) frac = 0;
if( frac > 1 ) frac = 1;
midf = p1f + ( p2f - p1f ) * frac;
VectorLerp( p1, frac, p2, mid );
// move up to the node
if( !CM_RecursiveHullCheck( hull, node->children[side], p1f, midf, p1, mid, trace ))
return false;
// this recursion can not be optimized because mid would need to be duplicated on a stack
if( CM_HullPointContents( hull, node->children[side^1], mid ) != CONTENTS_SOLID )
{
// go past the node
return CM_RecursiveHullCheck( hull, node->children[side^1], midf, p2f, mid, p2, trace );
}
// never got out of the solid area
if( trace->fAllSolid )
return false;
// 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( CM_HullPointContents( hull, hull->firstclipnode, mid ) == CONTENTS_SOLID )
{
// shouldn't really happen, but does occasionally
frac -= 0.1f;
if( frac < 0 )
{
trace->flFraction = midf;
VectorCopy( mid, trace->vecEndPos );
MsgDev( D_INFO, "backup past 0\n" );
return false;
}
midf = p1f + ( p2f - p1f ) * frac;
VectorLerp( p1, frac, p2, mid );
}
trace->flFraction = midf;
VectorCopy( mid, trace->vecEndPos );
return false;
}
/*
==================
CM_ClipMove
Handles selection or creation of a clipping hull, and offseting (and
eventually rotation) of the end points
==================
*/
trace_t CM_ClipMove( edict_t *ent, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, int flags )
{
vec3_t offset, temp;
vec3_t start_l, end_l;
trace_t trace;
matrix4x4 matrix;
hull_t *hull;
// fill in a default trace
Mem_Set( &trace, 0, sizeof( trace_t ));
VectorCopy( end, trace.vecEndPos );
trace.flFraction = 1.0f;
trace.fAllSolid = true;
trace.iHitgroup = -1;
// get the clipping hull
hull = CM_HullForEntity( ent, mins, maxs, offset );
VectorSubtract( start, offset, start_l );
VectorSubtract( end, offset, end_l );
// rotate start and end into the models frame of reference
if( ent->v.solid == SOLID_BSP && !VectorIsNull( ent->v.angles ))
{
matrix4x4 imatrix;
Matrix4x4_CreateFromEntity( matrix, ent->v.origin[0], ent->v.origin[1], ent->v.origin[2], ent->v.angles[PITCH], ent->v.angles[YAW], ent->v.angles[ROLL], 1.0f );
Matrix4x4_Invert_Simple( imatrix, matrix );
Matrix4x4_VectorTransform( imatrix, start, start_l );
Matrix4x4_VectorTransform( imatrix, end, end_l );
#if 1
// calc hull offsets (monsters use this)
VectorCopy( start_l, temp );
VectorMAMAM( 1, temp, 1, mins, -1, hull->clip_mins, start_l );
VectorCopy( end_l, temp );
VectorMAMAM( 1, temp, 1, mins, -1, hull->clip_mins, end_l );
#endif
}
if(!( flags & FMOVE_SIMPLEBOX ) && CM_GetModelType( ent->v.modelindex ) == mod_studio )
{
if( CM_StudioTrace( ent, start, end, &trace )); // continue tracing bbox if hitbox missing
else CM_RecursiveHullCheck( hull, hull->firstclipnode, 0, 1, start_l, end_l, &trace );
}
else
{
// trace a line through the apropriate clipping hull
CM_RecursiveHullCheck( hull, hull->firstclipnode, 0, 1, start_l, end_l, &trace );
}
// rotate endpos back to world frame of reference
if( ent->v.solid == SOLID_BSP && !VectorIsNull( ent->v.angles ))
{
if( trace.flFraction != 1.0f )
{
vec3_t temp;
// compute endpos
trace.vecEndPos[0] = start[0] + trace.flFraction * ( end[0] - start[0] );
trace.vecEndPos[1] = start[1] + trace.flFraction * ( end[1] - start[1] );
trace.vecEndPos[2] = start[2] + trace.flFraction * ( end[2] - start[2] );
VectorCopy( trace.vecPlaneNormal, temp );
Matrix4x4_TransformPositivePlane( matrix, temp, trace.flPlaneDist, trace.vecPlaneNormal, &trace.flPlaneDist );
}
}
else
{
// special case for non-rotated bmodels
// fix trace up by the offset when we hit bmodel
if( trace.flFraction != 1.0f && trace.iHitgroup == -1 )
VectorAdd( trace.vecEndPos, offset, trace.vecEndPos );
trace.flPlaneDist = DotProduct( trace.vecEndPos, trace.vecPlaneNormal );
}
// did we clip the move?
if( trace.flFraction < 1.0f || trace.fStartSolid )
trace.pHit = ent;
if(!( flags & FMOVE_SIMPLEBOX ) && CM_GetModelType( ent->v.modelindex ) == mod_studio )
{
if( VectorIsNull( mins ) && VectorIsNull( maxs ) && trace.iHitgroup == -1 )
{
// NOTE: studio traceline doesn't check studio bbox hitboxes only
trace.flFraction = 1.0f;
trace.pHit = NULL; // clear entity when any hitbox not intersected
}
}
return trace;
}
/*
==================
CM_TraceTexture
find the face where the traceline hit
==================
*/
const char *CM_TraceTexture( edict_t *pTextureEntity, const vec3_t v1, const vec3_t v2 )
{
vec3_t intersect, temp, vecStartPos;
msurface_t **mark, *surf, *hitface = NULL;
float d1, d2, min_diff = 9999.9f;
vec3_t forward, right, up;
vec3_t vecPos1, vecPos2;
model_t *bmodel;
mleaf_t *endleaf;
mplane_t *plane;
trace_t trace;
int i;
trace = CM_ClipMove( pTextureEntity, v1, vec3_origin, vec3_origin, v2, FMOVE_SIMPLEBOX );
if( !trace.pHit ) return NULL; // trace entity must be valid
bmodel = CM_ClipHandleToModel( trace.pHit->v.modelindex );
if( !bmodel || bmodel->type != mod_brush && bmodel->type != mod_world )
return NULL;
// making trace adjustments
VectorSubtract( v1, trace.pHit->v.origin, vecStartPos );
VectorSubtract( trace.vecEndPos, trace.pHit->v.origin, trace.vecEndPos );
// rotate start and end into the models frame of reference
if( trace.pHit->v.solid == SOLID_BSP && !VectorIsNull( trace.pHit->v.angles ))
{
VectorCopy( trace.pHit->v.angles, temp );
AngleVectors( temp, forward, right, up );
VectorCopy( vecStartPos, temp );
vecStartPos[0] = DotProduct( temp, forward );
vecStartPos[1] = -DotProduct( temp, right );
vecStartPos[2] = DotProduct( temp, up );
VectorCopy( trace.vecEndPos, temp );
trace.vecEndPos[0] = DotProduct( temp, forward );
trace.vecEndPos[1] = -DotProduct( temp, right );
trace.vecEndPos[2] = DotProduct( temp, up );
}
VectorSubtract( trace.vecEndPos, vecStartPos, forward );
VectorNormalize( forward );
// nudge endpos back to can be trace face between two points
VectorMA( trace.vecEndPos, 5.0f, trace.vecPlaneNormal, vecPos1 );
VectorMA( trace.vecEndPos, -5.0f, trace.vecPlaneNormal, vecPos2 );
endleaf = CM_PointInLeaf( trace.vecEndPos, bmodel->nodes + bmodel->hulls[0].firstclipnode );
mark = endleaf->firstmarksurface;
// find a plane with endpos on one side and hitpos on the other side...
for( i = 0; i < endleaf->nummarksurfaces; i++ )
{
surf = *mark++;
plane = surf->plane;
d1 = DotProduct( vecPos1, plane->normal ) - plane->dist;
d2 = DotProduct( vecPos2, plane->normal ) - plane->dist;
if(( d1 > 0.0f && d2 <= 0.0f ) || ( d1 <= 0.0f && d2 > 0.0f ))
{
// found a plane, find the intersection point in the plane...
vec3_t plane_origin, angle1, angle2;
float dist, anglef, angle_sum = 0.0f;
int i, e;
VectorScale( plane->normal, plane->dist, plane_origin );
dist = CM_DistanceToIntersect( vecStartPos, forward, plane_origin, plane->normal );
if( dist < 0.0f ) return NULL; // can't find intersection
VectorScale( forward, dist, temp );
VectorAdd( vecStartPos, temp, intersect );
// loop through all of the vertexes of all the edges of this face and
// find the angle between vertex-n, v_intersect and vertex-n+1, then add
// all these angles together. if the sum of these angles is 360 degrees
// (or 2 PI radians), then the intersect point lies within that polygon.
// loop though all of the edges, getting the vertexes...
for( i = 0; i < surf->numedges; i++ )
{
vec3_t vertex1, vertex2;
// get the coordinates of the vertex of this edge...
e = worldmodel->surfedges[surf->firstedge + i];
if( e < 0 )
{
VectorCopy(worldmodel->vertexes[worldmodel->edges[-e].v[1]], vertex1);
VectorCopy(worldmodel->vertexes[worldmodel->edges[-e].v[0]], vertex2);
}
else
{
VectorCopy(worldmodel->vertexes[worldmodel->edges[e].v[0]], vertex1);
VectorCopy(worldmodel->vertexes[worldmodel->edges[e].v[1]], vertex2);
}
// now create vectors from the vertexes to the plane intersect point...
VectorSubtract( vertex1, intersect, angle1 );
VectorSubtract( vertex2, intersect, angle2 );
VectorNormalize( angle1 );
VectorNormalize( angle2 );
// find the angle between these vectors...
anglef = DotProduct( angle1, angle2 );
anglef = acos( anglef );
angle_sum += anglef;
}
// is the sum of the angles 360 degrees (2 PI)?...
if(( angle_sum >= ( M_PI2 - EQUAL_EPSILON )) && ( angle_sum <= ( M_PI2 + EQUAL_EPSILON )))
{
// find the difference between the sum and 2 PI...
float diff = fabs( angle_sum - M_PI2 );
if( diff < min_diff ) // is this the BEST so far?...
{
min_diff = diff;
hitface = surf;
}
}
}
}
if( hitface && hitface->texinfo && hitface->texinfo->texture )
return hitface->texinfo->texture->name;
return NULL;
}

View File

@ -1,8 +0,0 @@
//=======================================================================
// Copyright XashXT Group 2009 ©
// net_sound.h - sound message options
//=======================================================================
#ifndef NET_SOUND_H
#define NET_SOUND_H
#endif//NET_SOUND_H

View File

@ -8,16 +8,77 @@
#include "matrix_lib.h"
#include "pm_local.h"
static float PM_DistanceToIntersect( const vec3_t org, const vec3_t dir, const vec3_t origin, const vec3_t normal )
{
float d = -(DotProduct( normal, origin ));
float numerator = DotProduct( normal, org ) + d;
float denominator = DotProduct( normal, dir );
if( fabs( denominator ) < EQUAL_EPSILON )
return -1.0f; // normal is orthogonal to vector, no intersection
/*
==================
PM_RecursiveSurfCheck
return -( numerator / denominator );
==================
*/
msurface_t *PM_RecursiveSurfCheck( mnode_t *node, vec3_t p1, vec3_t p2 )
{
float t1, t2, frac;
int side, ds, dt;
mplane_t *plane;
msurface_t *surf;
vec3_t mid;
int i;
if( node->contents < 0 )
return NULL;
plane = node->plane;
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 PM_RecursiveSurfCheck( node->children[0], p1, p2 );
if( t1 < 0 && t2 < 0 )
return PM_RecursiveSurfCheck( node->children[1], p1, p2 );
frac = t1 / ( t1 - t2 );
if( frac < 0.0f ) frac = 0.0f;
if( frac > 1.0f ) frac = 1.0f;
VectorLerp( p1, frac, p2, mid );
side = (t1 < 0);
// now this is weird.
surf = PM_RecursiveSurfCheck( node->children[side], p1, mid );
if( surf != NULL || ( t1 >= 0 && t2 >= 0 ) || ( t1 < 0 && t2 < 0 ))
{
return surf;
}
surf = node->firstface;
for( i = 0; i < node->numfaces; i++, surf++ )
{
ds = (int)((float)DotProduct( mid, surf->texinfo->vecs[0] ) + surf->texinfo->vecs[0][3] );
dt = (int)((float)DotProduct( mid, surf->texinfo->vecs[1] ) + surf->texinfo->vecs[1][3] );
if( ds >= surf->texturemins[0] && dt >= surf->texturemins[1] )
{
int s = ds - surf->texturemins[0];
int t = dt - surf->texturemins[1];
if( s <= surf->extents[0] && t <= surf->extents[1] )
return surf;
}
}
return PM_RecursiveSurfCheck( node->children[side^1], mid, p2 );
}
/*
@ -25,132 +86,51 @@ static float PM_DistanceToIntersect( const vec3_t org, const vec3_t dir, const v
PM_TraceTexture
find the face where the traceline hit
assume physentity is valid
==================
*/
const char *PM_TraceTexture( physent_t *pe, vec3_t v1, vec3_t v2 )
const char *PM_TraceTexture( physent_t *pe, vec3_t start, vec3_t end )
{
vec3_t intersect, temp, vecStartPos;
msurface_t **mark, *surf, *hitface = NULL;
float d1, d2, min_diff = 9999.9f;
vec3_t forward, vecPos1, vecPos2;
msurface_t *surf;
matrix4x4 matrix;
model_t *bmodel;
mleaf_t *endleaf;
mplane_t *plane;
pmtrace_t trace;
int i;
if( !PM_TraceModel( pe, v1, vec3_origin, vec3_origin, v2, &trace, PM_STUDIO_IGNORE ))
return NULL; // not intersect
hull_t *hull;
vec3_t start_l, end_l;
vec3_t temp, offset;
bmodel = pe->model;
if( !bmodel || bmodel->type != mod_brush && bmodel->type != mod_world )
return NULL;
// making trace adjustments
VectorSubtract( v1, pe->origin, vecStartPos );
VectorSubtract( trace.endpos, pe->origin, trace.endpos );
hull = PM_HullForBsp( pe, vec3_origin, vec3_origin, offset );
VectorSubtract( start, offset, start_l );
VectorSubtract( end, offset, end_l );
// rotate start and end into the models frame of reference
if( pe->solid == SOLID_BSP && !VectorIsNull( pe->angles ))
if( !VectorIsNull( pe->angles ))
{
matrix4x4 matrix, imatrix;
Matrix4x4_CreateFromEntity( matrix, pe->origin[0], pe->origin[1], pe->origin[2], pe->angles[PITCH], pe->angles[YAW], pe->angles[ROLL], 1.0f );
matrix4x4 imatrix;
float *org = pe->origin;
float *ang = pe->angles;
Matrix4x4_CreateFromEntity( matrix, org[0], org[1], org[2], ang[PITCH], ang[YAW], ang[ROLL], 1.0f );
Matrix4x4_Invert_Simple( imatrix, matrix );
VectorCopy( vecStartPos, temp );
Matrix4x4_VectorTransform( imatrix, temp, vecStartPos );
VectorCopy( trace.endpos, temp );
Matrix4x4_VectorTransform( imatrix, temp, trace.endpos );
Matrix4x4_VectorTransform( imatrix, start, start_l );
Matrix4x4_VectorTransform( imatrix, end, end_l );
#if 1
// calc hull offsets (monsters use this)
VectorCopy( start_l, temp );
VectorMAMAM( 1, temp, 1, vec3_origin, -1, hull->clip_mins, start_l );
VectorCopy( end_l, temp );
VectorMAMAM( 1, temp, 1, vec3_origin, -1, hull->clip_mins, end_l );
#endif
}
VectorSubtract( trace.endpos, vecStartPos, forward );
VectorNormalize( forward );
surf = PM_RecursiveSurfCheck( &bmodel->nodes[hull->firstclipnode], start_l, end_l );
if( !surf ) return NULL;
// nudge endpos back to can be trace face between two points
VectorMA( trace.endpos, 5.0f, trace.plane.normal, vecPos1 );
VectorMA( trace.endpos, -5.0f, trace.plane.normal, vecPos2 );
endleaf = CM_PointInLeaf( trace.endpos, bmodel->nodes + bmodel->hulls[0].firstclipnode );
mark = endleaf->firstmarksurface;
// find a plane with endpos on one side and hitpos on the other side...
for( i = 0; i < endleaf->nummarksurfaces; i++ )
{
surf = *mark++;
plane = surf->plane;
d1 = DotProduct( vecPos1, plane->normal ) - plane->dist;
d2 = DotProduct( vecPos2, plane->normal ) - plane->dist;
if(( d1 > 0.0f && d2 <= 0.0f ) || ( d1 <= 0.0f && d2 > 0.0f ))
{
// found a plane, find the intersection point in the plane...
vec3_t plane_origin, angle1, angle2;
float dist, anglef, angle_sum = 0.0f;
int i, e;
VectorScale( plane->normal, plane->dist, plane_origin );
dist = PM_DistanceToIntersect( vecStartPos, forward, plane_origin, plane->normal );
if( dist < 0.0f ) return NULL; // can't find intersection
VectorScale( forward, dist, temp );
VectorAdd( vecStartPos, temp, intersect );
// loop through all of the vertexes of all the edges of this face and
// find the angle between vertex-n, v_intersect and vertex-n+1, then add
// all these angles together. if the sum of these angles is 360 degrees
// (or 2 PI radians), then the intersect point lies within that polygon.
// loop though all of the edges, getting the vertexes...
for( i = 0; i < surf->numedges; i++ )
{
vec3_t vertex1, vertex2;
// get the coordinates of the vertex of this edge...
e = worldmodel->surfedges[surf->firstedge + i];
if( e < 0 )
{
VectorCopy(worldmodel->vertexes[worldmodel->edges[-e].v[1]], vertex1);
VectorCopy(worldmodel->vertexes[worldmodel->edges[-e].v[0]], vertex2);
}
else
{
VectorCopy(worldmodel->vertexes[worldmodel->edges[e].v[0]], vertex1);
VectorCopy(worldmodel->vertexes[worldmodel->edges[e].v[1]], vertex2);
}
// now create vectors from the vertexes to the plane intersect point...
VectorSubtract( vertex1, intersect, angle1 );
VectorSubtract( vertex2, intersect, angle2 );
VectorNormalize( angle1 );
VectorNormalize( angle2 );
// find the angle between these vectors...
anglef = DotProduct( angle1, angle2 );
anglef = acos( anglef );
angle_sum += anglef;
}
// is the sum of the angles 360 degrees (2 PI)?...
if(( angle_sum >= ( M_PI2 - EQUAL_EPSILON )) && ( angle_sum <= ( M_PI2 + EQUAL_EPSILON )))
{
// find the difference between the sum and 2 PI...
float diff = fabs( angle_sum - M_PI2 );
if( diff < min_diff ) // is this the BEST so far?...
{
min_diff = diff;
hitface = surf;
}
}
}
}
if( hitface && hitface->texinfo && hitface->texinfo->texture )
return hitface->texinfo->texture->name;
return NULL;
return surf->texinfo->texture->name;
}

View File

@ -183,30 +183,27 @@ hull_t *PM_HullForBsp( physent_t *pe, const vec3_t mins, const vec3_t maxs, floa
VectorSubtract( maxs, mins, size );
if( size[0] < 3 )
if( size[0] <= 8.0f )
{
// point hull
hull = &model->hulls[0];
}
else if( size[0] <= 36 )
{
if( size[2] <= 36 )
{
// head hull (ducked)
hull = &model->hulls[3];
}
else
{
// human hull
hull = &model->hulls[1];
}
hull = &pe->model->hulls[0];
VectorCopy( hull->clip_mins, offset );
}
else
{
// large hull
hull = &model->hulls[2];
if( size[0] <= 36.0f )
{
if( size[2] <= 36.0f )
hull = &pe->model->hulls[3];
else hull = &pe->model->hulls[1];
}
else hull = &pe->model->hulls[2];
VectorSubtract( hull->clip_mins, mins, offset );
}
// calculate an offset value to center the origin
VectorAdd( offset, pe->origin, offset );
// calculate an offset value to center the origin
VectorSubtract( hull->clip_mins, mins, offset );
VectorAdd( offset, pe->origin, offset );

View File

@ -1,8 +0,0 @@
//=======================================================================
// Copyright XashXT Group 2010 ©
// pm_utils.c - misc movement utilities
//=======================================================================
#include "common.h"
#include "pm_local.h"

View File

@ -178,18 +178,10 @@ SOURCE=.\client\cl_world.c
# End Source File
# Begin Source File
SOURCE=.\common\cm_debug.c
# End Source File
# Begin Source File
SOURCE=.\common\cm_light.c
# End Source File
# Begin Source File
SOURCE=.\common\cm_main.c
# End Source File
# Begin Source File
SOURCE=.\common\cm_model.c
# End Source File
# Begin Source File
@ -198,18 +190,10 @@ SOURCE=.\common\cm_portals.c
# End Source File
# Begin Source File
SOURCE=.\common\cm_studio.c
# End Source File
# Begin Source File
SOURCE=.\common\cm_test.c
# End Source File
# Begin Source File
SOURCE=.\common\cm_trace.c
# End Source File
# Begin Source File
SOURCE=.\common\con_utils.c
# End Source File
# Begin Source File
@ -270,10 +254,6 @@ SOURCE=.\common\pm_trace.c
# End Source File
# Begin Source File
SOURCE=.\common\pm_utils.c
# End Source File
# Begin Source File
SOURCE=.\server\sv_client.c
# End Source File
# Begin Source File

View File

@ -93,6 +93,13 @@ void Host_EndGame( const char *message, ... )
Host_AbortCurrentFrame ();
}
static void Host_DrawDebugCollision( cmdraw_t drawPoly )
{
if( !drawPoly ) return;
// FIXME: get collision polys here
}
void Host_FreeRender( void )
{
if( render_dll.link )
@ -116,7 +123,7 @@ bool Host_InitRender( void )
ri.UpdateScreen = SCR_UpdateScreen;
ri.StudioEvent = CL_StudioEvent;
ri.StudioFxTransform = CL_StudioFxTransform;
ri.ShowCollision = CM_DrawCollision;
ri.ShowCollision = Host_DrawDebugCollision;
ri.GetClientEdict = CL_GetEntityByIndex;
ri.GetPlayerInfo = CL_GetPlayerInfo;
ri.GetLocalPlayer = CL_GetLocalPlayer;

View File

@ -470,7 +470,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 );
script_t *CM_GetEntityScript( void );
_inline edict_t *SV_EDICT_NUM( int n, const char * file, const int line )
{
@ -518,6 +517,7 @@ int SV_HullPointContents( hull_t *hull, int num, const vec3_t p );
trace_t SV_TraceHull( edict_t *ent, int hullNum, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end );
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_MoveHull( const vec3_t start, int hullNumber, const vec3_t end, int type, edict_t *e );
const char *SV_TraceTexture( edict_t *ent, const vec3_t start, const vec3_t end );
trace_t SV_MoveToss( edict_t *tossent, edict_t *ignore );
void SV_LinkEdict( edict_t *ent, bool touch_triggers );
void SV_TouchLinks( edict_t *ent, areanode_t *node );

View File

@ -1819,10 +1819,7 @@ static const char *pfnTraceTexture( edict_t *pTextureEntity, const float *v1, co
return NULL;
}
if( VectorIsNAN( v1 ) || VectorIsNAN( v2 ))
Host_Error( "TraceTexture: NAN errors detected '%f %f %f', '%f %f %f'\n", v1[0], v1[1], v1[2], v2[0], v2[1], v2[2] );
return CM_TraceTexture( pTextureEntity, v1, v2 );
return SV_TraceTexture( pTextureEntity, v1, v2 );
}
/*

View File

@ -322,7 +322,7 @@ bool SV_SpawnServer( const char *mapname, const char *startspot )
com.sprintf( sv.configstrings[CS_MAPCHECKSUM], "%i", checksum );
sv.worldmodel = CM_ClipHandleToModel( 1 ); // get world pointer
for( i = 1; i < CM_NumBmodels(); i++ )
for( i = 1; i < sv.worldmodel->numsubmodels; i++ )
{
com.sprintf( sv.configstrings[CS_MODELS+1+i], "*%i", i );
CM_RegisterModel( sv.configstrings[CS_MODELS+1+i], i+1 );

View File

@ -1576,8 +1576,8 @@ void SV_Physics( void )
}
}
// let everything in the world think and move
CM_Frame( sv_time( ));
// animate lightstyles (used for GetEntityIllum)
CM_RunLightStyles( sv.time );
// at end of frame kill all entities which supposed to it
SV_FreeOldEntities();

View File

@ -9,6 +9,12 @@
#include "pm_local.h"
#include "matrix_lib.h"
// more precision but doesn't matched with HL gameplay
// g-cont. this is pretty generic solution for maps with different hull sizes
// but in HL this got 'wrong' sizes for pushables :(
//#define HULL_AUTOSELECT
typedef struct moveclip_s
{
vec3_t boxmins, boxmaxs; // enclose the test object along entire move
@ -120,7 +126,7 @@ hull_t *SV_HullForEntity( edict_t *ent, int hullNumber, vec3_t mins, vec3_t maxs
if( hullNumber == -1 )
{
#if 0 // more precision but doesn't matched with HL gameplay
#ifdef HULL_AUTOSELECT
float curdiff;
float lastdiff = 999;
int i;
@ -209,8 +215,8 @@ hull_t *SV_HullForBsp( edict_t *ent, const vec3_t mins, const vec3_t maxs, float
hull_t *hull;
model_t *model;
vec3_t size;
float curdiff, lastdiff = 999;
int i, hullNumber = 0;
float curdiff = 0, lastdiff = 999;
int i = 0, hullNumber = 0;
// decide which clipping hull to use, based on the size
model = CM_ClipHandleToModel( ent->v.modelindex );
@ -220,6 +226,8 @@ hull_t *SV_HullForBsp( edict_t *ent, const vec3_t mins, const vec3_t maxs, float
VectorSubtract( maxs, mins, size );
#ifdef HULL_AUTOSELECT // more precision but doesn't matched with HL gameplay
// select the hull automatically
for( i = 0; i < 4; i++ )
{
@ -233,10 +241,32 @@ hull_t *SV_HullForBsp( edict_t *ent, const vec3_t mins, const vec3_t maxs, float
}
}
// TraceHull stuff
hull = &model->hulls[hullNumber];
// calculate an offset value to center the origin
VectorSubtract( hull->clip_mins, mins, offset );
// NOTE: never get offset of drawing hull
if( !hullNumber ) VectorCopy( hull->clip_mins, offset );
else VectorSubtract( hull->clip_mins, mins, offset );
#else
if( size[0] <= 8.0f )
{
hull = &model->hulls[0];
VectorCopy( hull->clip_mins, offset );
}
else
{
if( size[0] <= 36.0f )
{
if( size[2] <= 36.0f )
hull = &model->hulls[3];
else hull = &model->hulls[1];
}
else hull = &model->hulls[2];
VectorSubtract( hull->clip_mins, mins, offset );
}
#endif
VectorAdd( offset, ent->v.origin, offset );
return hull;
@ -935,81 +965,131 @@ trace_t SV_TraceHull( edict_t *ent, int hullNum, const vec3_t start, vec3_t mins
return trace;
}
/* DESCRIPTION: SurfaceAtPoint
// LOCATION:
// PATH: TraceTexture, recursive
//
// A weird one. First, it seems to recursively call itself to dig deep into
// the node tree, treating its own failure as a sign that it's dug deep
// enough. Then, it loops through some odd texture stuff, looking for
// a match. A match of what? Don't know yet.
/*
==================
SV_RecursiveSurfCheck
==================
*/
msurface_t *SV_RecursiveSurfCheck( model_t *model, mnode_t *node, vec3_t v1, vec3_t v2 )
msurface_t *SV_RecursiveSurfCheck( mnode_t *node, vec3_t p1, vec3_t p2 )
{
double var_4, var_8, var_c;
int var_10, var_10_2;
mplane_t * var_14_plane;
vec3_t var_20;
msurface_t * var_24_surface;
int var_28, var_2c;
int var_30, var_34;
int var_38;
mtexinfo_t * var_3C_texinfo;
float t1, t2, frac;
int side, ds, dt;
mplane_t *plane;
msurface_t *surf;
vec3_t mid;
int i;
if( node->contents < 0 )
return NULL;
if(node->contents < 0) { return(NULL); }
plane = node->plane;
var_14_plane = node->plane;
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;
}
var_4 = ((v1[0] * var_14_plane->normal[0]) + (v1[1] * var_14_plane->normal[1]) + (v1[2] * var_14_plane->normal[2])) - var_14_plane->dist;
var_8 = ((v2[0] * var_14_plane->normal[0]) + (v2[1] * var_14_plane->normal[1]) + (v2[2] * var_14_plane->normal[2])) - var_14_plane->dist;
if( t1 >= 0 && t2 >= 0 )
return SV_RecursiveSurfCheck( node->children[0], p1, p2 );
if( t1 < 0 && t2 < 0 )
return SV_RecursiveSurfCheck( node->children[1], p1, p2 );
if(var_4 < 0) { var_10 = 1; }
else { var_10 = 0; }
frac = t1 / ( t1 - t2 );
if(var_8 < 0) { var_10_2 = 1; }
else { var_10_2 = 0; }
if( frac < 0.0f ) frac = 0.0f;
if( frac > 1.0f ) frac = 1.0f;
if(var_10 == var_10_2) {
VectorLerp( p1, frac, p2, mid );
return(SV_RecursiveSurfCheck(model, node->children[var_10], v1, v2));
}
side = (t1 < 0);
var_c = var_4 / (var_4 - var_8);
// now this is weird.
surf = SV_RecursiveSurfCheck( node->children[side], p1, mid );
var_20[0] = ((v2[0] - v1[0]) * var_c) + v1[0];
var_20[1] = ((v2[1] - v1[1]) * var_c) + v1[1];
var_20[2] = ((v2[2] - v1[2]) * var_c) + v1[2];
if( surf != NULL || ( t1 >= 0 && t2 >= 0 ) || ( t1 < 0 && t2 < 0 ))
{
return surf;
}
//Now THIS is weird.
var_24_surface = SV_RecursiveSurfCheck(model, node->children[var_10], v1, var_20);
if(var_24_surface != NULL || var_10 == var_10_2) { return(var_24_surface); } //Second check not possible as in asm... I think.
surf = node->firstface;
for( i = 0; i < node->numfaces; i++, surf++ )
{
ds = (int)((float)DotProduct( mid, surf->texinfo->vecs[0] ) + surf->texinfo->vecs[0][3] );
dt = (int)((float)DotProduct( mid, surf->texinfo->vecs[1] ) + surf->texinfo->vecs[1][3] );
var_24_surface = node->firstface;
if( ds >= surf->texturemins[0] && dt >= surf->texturemins[1] )
{
int s = ds - surf->texturemins[0];
int t = dt - surf->texturemins[1];
for(var_38 = 0; var_38 < node->numfaces; var_38++, var_24_surface++) {
if( s <= surf->extents[0] && t <= surf->extents[1] )
return surf;
}
}
var_3C_texinfo = var_24_surface->texinfo;
return SV_RecursiveSurfCheck( node->children[side^1], mid, p2 );
}
var_28 = (var_20[0] * var_3C_texinfo->vecs[0][0]) + (var_20[1] * var_3C_texinfo->vecs[0][1]) + (var_20[2] * var_3C_texinfo->vecs[0][2]) + var_3C_texinfo->vecs[0][3];
var_2c = (var_20[0] * var_3C_texinfo->vecs[1][0]) + (var_20[1] * var_3C_texinfo->vecs[1][1]) + (var_20[2] * var_3C_texinfo->vecs[1][2]) + var_3C_texinfo->vecs[1][3];
/*
==================
SV_TraceTexture
if(var_28 >= var_24_surface->texturemins[0] && var_2c >= var_24_surface->texturemins[1]) {
find the face where the traceline hit
assume pTextureEntity is valid
==================
*/
const char *SV_TraceTexture( edict_t *ent, const vec3_t start, const vec3_t end )
{
msurface_t *surf;
matrix4x4 matrix;
model_t *bmodel;
hull_t *hull;
vec3_t start_l, end_l;
vec3_t temp, offset;
var_30 = var_28 - var_24_surface->texturemins[0];
var_34 = var_2c - var_24_surface->texturemins[1];
bmodel = CM_ClipHandleToModel( ent->v.modelindex );
if( !bmodel || bmodel->type != mod_brush && bmodel->type != mod_world )
return NULL;
if(var_30 <= var_24_surface->extents[0] && var_34 <= var_24_surface->extents[1]) {
hull = SV_HullForBsp( ent, vec3_origin, vec3_origin, offset );
return(var_24_surface);
}
}
}
VectorSubtract( start, offset, start_l );
VectorSubtract( end, offset, end_l );
if(var_10 == 1) { var_10 = 0; }
else { var_10 = 1; }
return(SV_RecursiveSurfCheck( model, node->children[var_10], var_20, v2 ));
// rotate start and end into the models frame of reference
if( !VectorIsNull( ent->v.angles ))
{
matrix4x4 imatrix;
float *org = ent->v.origin;
float *ang = ent->v.angles;
Matrix4x4_CreateFromEntity( matrix, org[0], org[1], org[2], ang[PITCH], ang[YAW], ang[ROLL], 1.0f );
Matrix4x4_Invert_Simple( imatrix, matrix );
Matrix4x4_VectorTransform( imatrix, start, start_l );
Matrix4x4_VectorTransform( imatrix, end, end_l );
#if 1
// calc hull offsets (monsters use this)
VectorCopy( start_l, temp );
VectorMAMAM( 1, temp, 1, vec3_origin, -1, hull->clip_mins, start_l );
VectorCopy( end_l, temp );
VectorMAMAM( 1, temp, 1, vec3_origin, -1, hull->clip_mins, end_l );
#endif
}
surf = SV_RecursiveSurfCheck( &bmodel->nodes[hull->firstclipnode], start_l, end_l );
if( !surf ) return NULL;
return surf->texinfo->texture->name;
}
/*
@ -1044,7 +1124,7 @@ static void SV_ClipToLinks( areanode_t *node, moveclip_t *clip )
Host_Error( "trigger in clipping list\n" );
// completely ignore all edicts but brushes
if( clip->type == MOVE_NOMONSTERS && touch->v.solid != SOLID_BSP )
if( clip->type == MOVE_NOMONSTERS && modType != mod_brush )
continue;
if( clip->type == MOVE_WORLDONLY )