20 Mar 2012
This commit is contained in:
parent
ef39a73480
commit
48f7021630
|
@ -1,4 +1,8 @@
|
|||
build ????
|
||||
Physic: fix trace bug when model is missing
|
||||
Client: implement function TriScreenToWorld
|
||||
|
||||
build 1850
|
||||
|
||||
Physic: add check for liquid brushes that has only hull0
|
||||
Render: draw decals without culling on the transparent surfaces
|
||||
|
@ -26,6 +30,7 @@ Network: implemented QueryCvarValue and QueryCvarValue2
|
|||
Physic: new pm-trace code, new server trace code, new studio hitbox trace code
|
||||
Client: rewrite demo record and playback
|
||||
Render: add support for STUDIO_NF_FULLBRIGHT
|
||||
Physic: fix pmove trace bug
|
||||
|
||||
build 1770
|
||||
|
||||
|
|
|
@ -76,6 +76,7 @@ struct
|
|||
demodirectory_t directory;
|
||||
int framecount;
|
||||
float starttime;
|
||||
float realstarttime;
|
||||
int entryIndex;
|
||||
} demo;
|
||||
|
||||
|
@ -346,6 +347,7 @@ void CL_WriteDemoHeader( const char *name )
|
|||
FS_Seek( cls.demoheader, savepos, SEEK_SET );
|
||||
|
||||
demo.starttime = CL_GetDemoRecordClock(); // setup the demo starttime
|
||||
demo.realstarttime = demo.starttime;
|
||||
demo.framecount = 0;
|
||||
|
||||
// now move on to entry # 1, the first data chunk.
|
||||
|
@ -397,7 +399,7 @@ void CL_StopRecord( void )
|
|||
|
||||
curpos = FS_Tell( cls.demofile );
|
||||
demo.entry->length = curpos - demo.entry->offset;
|
||||
demo.entry->playback_time = stoptime - demo.starttime;
|
||||
demo.entry->playback_time = stoptime - demo.realstarttime;
|
||||
demo.entry->playback_frames = demo.framecount;
|
||||
|
||||
// Now write out the directory and free it and touch up the demo header.
|
||||
|
@ -422,7 +424,7 @@ void CL_StopRecord( void )
|
|||
menu.globals->demoname[0] = '\0';
|
||||
|
||||
Msg( "Completed demo\n" );
|
||||
MsgDev( D_INFO, "Recording time %.2f\n", stoptime - demo.starttime );
|
||||
MsgDev( D_INFO, "Recording time %.2f\n", stoptime - demo.realstarttime );
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -802,10 +804,11 @@ CL_GetComment
|
|||
qboolean CL_GetComment( const char *demoname, char *comment )
|
||||
{
|
||||
file_t *demfile;
|
||||
char buf_data[2048];
|
||||
int r, maxClients, curSize;
|
||||
string maptitle;
|
||||
sizebuf_t buf;
|
||||
demoheader_t demohdr;
|
||||
demodirectory_t directory;
|
||||
demoentry_t entry;
|
||||
float playtime = 0.0f;
|
||||
int i;
|
||||
|
||||
if( !comment ) return false;
|
||||
|
||||
|
@ -816,68 +819,44 @@ qboolean CL_GetComment( const char *demoname, char *comment )
|
|||
return false;
|
||||
}
|
||||
|
||||
// read the first demo packet. extract info from it
|
||||
// get the length
|
||||
r = FS_Read( demfile, &curSize, 4 );
|
||||
if( r != 4 )
|
||||
// read in the m_DemoHeader
|
||||
FS_Read( demfile, &demohdr, sizeof( demoheader_t ));
|
||||
|
||||
if( demohdr.id != IDEMOHEADER )
|
||||
{
|
||||
FS_Close( demfile );
|
||||
Q_strncpy( comment, "<corrupted>", MAX_STRING );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( curSize == -1 )
|
||||
{
|
||||
FS_Close( demfile );
|
||||
Q_strncpy( comment, "<corrupted>", MAX_STRING );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( curSize > sizeof( buf_data ))
|
||||
{
|
||||
FS_Close( demfile );
|
||||
Q_strncpy( comment, "<not compatible>", MAX_STRING );
|
||||
return false;
|
||||
}
|
||||
|
||||
// init the message (set maxsize to cursize so overflow check will be working properly)
|
||||
BF_Init( &buf, "DemoRead", buf_data, curSize );
|
||||
r = FS_Read( demfile, buf.pData, curSize );
|
||||
|
||||
if( r != curSize )
|
||||
{
|
||||
FS_Close( demfile );
|
||||
Q_strncpy( comment, "<truncated file>", MAX_STRING );
|
||||
return false;
|
||||
}
|
||||
|
||||
// skip server data ident
|
||||
BF_ReadByte( &buf );
|
||||
|
||||
if( PROTOCOL_VERSION != BF_ReadLong( &buf ))
|
||||
if( demohdr.net_protocol != PROTOCOL_VERSION || demohdr.dem_protocol != DEMO_PROTOCOL )
|
||||
{
|
||||
FS_Close( demfile );
|
||||
Q_strncpy( comment, "<invalid protocol>", MAX_STRING );
|
||||
return false;
|
||||
}
|
||||
|
||||
BF_ReadLong( &buf ); // server count
|
||||
BF_ReadLong( &buf ); // checksum
|
||||
BF_ReadByte( &buf ); // playernum
|
||||
maxClients = BF_ReadByte( &buf );
|
||||
if( BF_ReadWord( &buf ) > GI->max_edicts )
|
||||
// now read in the directory structure.
|
||||
FS_Seek( demfile, demohdr.directory_offset, SEEK_SET );
|
||||
FS_Read( demfile, &directory.numentries, sizeof( int ));
|
||||
|
||||
if( directory.numentries < 1 || directory.numentries > 1024 )
|
||||
{
|
||||
FS_Close( demfile );
|
||||
Q_strncpy( comment, "<too many edicts>", MAX_STRING );
|
||||
Q_strncpy( comment, "<corrupted>", MAX_STRING );
|
||||
return false;
|
||||
}
|
||||
|
||||
for( i = 0; i < directory.numentries; i++ )
|
||||
{
|
||||
FS_Read( demfile, &entry, sizeof( demoentry_t ));
|
||||
playtime += entry.playback_time;
|
||||
}
|
||||
|
||||
// split comment to sections
|
||||
Q_strncpy( comment, BF_ReadString( &buf ), CS_SIZE ); // mapname
|
||||
Q_strncpy( maptitle, BF_ReadString( &buf ), MAX_STRING ); // maptitle
|
||||
if( !Q_strlen( maptitle )) Q_strncpy( maptitle, "<no title>", MAX_STRING );
|
||||
Q_strncpy( comment + CS_SIZE, maptitle, CS_SIZE );
|
||||
Q_strncpy( comment + CS_SIZE * 2, va( "%i", maxClients ), CS_TIME );
|
||||
Q_strncpy( comment, demohdr.mapname, CS_SIZE );
|
||||
Q_strncpy( comment + CS_SIZE, "<No Title>", CS_SIZE ); // FIXME: write titles or somewhat
|
||||
Q_strncpy( comment + CS_SIZE * 2, va( "%g sec", playtime ), CS_TIME );
|
||||
|
||||
// all done
|
||||
FS_Close( demfile );
|
||||
|
|
|
@ -2828,6 +2828,12 @@ int TriSpriteTexture( model_t *pSpriteModel, int frame )
|
|||
if(( gl_texturenum = R_GetSpriteTexture( pSpriteModel, frame )) == 0 )
|
||||
return 0;
|
||||
|
||||
if( gl_texturenum <= 0 || gl_texturenum > MAX_TEXTURES )
|
||||
{
|
||||
MsgDev( D_ERROR, "TriSpriteTexture: bad index %i\n", gl_texturenum );
|
||||
gl_texturenum = tr.defaultTexture;
|
||||
}
|
||||
|
||||
psprite = pSpriteModel->cache.data;
|
||||
if( psprite->texFormat == SPR_ALPHTEST )
|
||||
{
|
||||
|
|
|
@ -66,7 +66,7 @@ qboolean CL_CopyEntityToPhysEnt( physent_t *pe, cl_entity_t *ent )
|
|||
break;
|
||||
default:
|
||||
pe->model = NULL;
|
||||
pe->studiomodel = NULL;
|
||||
pe->studiomodel = (mod->type == mod_studio) ? mod : NULL;
|
||||
VectorCopy( ent->curstate.mins, pe->mins );
|
||||
VectorCopy( ent->curstate.maxs, pe->maxs );
|
||||
break;
|
||||
|
|
|
@ -191,6 +191,13 @@ static int R_TransEntityCompare( const cl_entity_t **a, const cl_entity_t **b )
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
R_WorldToScreen
|
||||
|
||||
Convert a given point from world into screen space
|
||||
===============
|
||||
*/
|
||||
qboolean R_WorldToScreen( const vec3_t point, vec3_t screen )
|
||||
{
|
||||
matrix4x4 worldToScreen;
|
||||
|
@ -203,7 +210,6 @@ qboolean R_WorldToScreen( const vec3_t point, vec3_t screen )
|
|||
Matrix4x4_Copy( worldToScreen, RI.worldviewProjectionMatrix );
|
||||
screen[0] = worldToScreen[0][0] * point[0] + worldToScreen[0][1] * point[1] + worldToScreen[0][2] * point[2] + worldToScreen[0][3];
|
||||
screen[1] = worldToScreen[1][0] * point[0] + worldToScreen[1][1] * point[1] + worldToScreen[1][2] * point[2] + worldToScreen[1][3];
|
||||
// z = worldToScreen[2][0] * point[0] + worldToScreen[2][1] * point[1] + worldToScreen[2][2] * point[2] + worldToScreen[2][3];
|
||||
w = worldToScreen[3][0] * point[0] + worldToScreen[3][1] * point[1] + worldToScreen[3][2] * point[2] + worldToScreen[3][3];
|
||||
screen[2] = 0.0f; // just so we have something valid here
|
||||
|
||||
|
@ -223,26 +229,28 @@ qboolean R_WorldToScreen( const vec3_t point, vec3_t screen )
|
|||
return behind;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
R_ScreenToWorld
|
||||
|
||||
Convert a given point from screen into world space
|
||||
===============
|
||||
*/
|
||||
void R_ScreenToWorld( const vec3_t screen, vec3_t point )
|
||||
{
|
||||
matrix4x4 screenToWorld;
|
||||
vec3_t temp;
|
||||
float w;
|
||||
|
||||
if( !point || !screen )
|
||||
return;
|
||||
|
||||
// g-cont. does we need a full invert here?
|
||||
Matrix4x4_Invert_Simple( screenToWorld, RI.worldviewProjectionMatrix );
|
||||
temp[0] = 2.0f * (screen[0] - RI.viewport[0]) / RI.viewport[2] - 1;
|
||||
temp[1] = -2.0f * (screen[1] - RI.viewport[1]) / RI.viewport[3] + 1;
|
||||
temp[2] = 0.0f; // just so we have something valid here
|
||||
Matrix4x4_Invert_Full( screenToWorld, RI.worldviewProjectionMatrix );
|
||||
|
||||
point[0] = temp[0] * screenToWorld[0][0] + temp[1] * screenToWorld[0][1] + temp[2] * screenToWorld[0][2] + screenToWorld[0][3];
|
||||
point[1] = temp[0] * screenToWorld[1][0] + temp[1] * screenToWorld[1][1] + temp[2] * screenToWorld[1][2] + screenToWorld[1][3];
|
||||
point[2] = temp[0] * screenToWorld[2][0] + temp[1] * screenToWorld[2][1] + temp[2] * screenToWorld[2][2] + screenToWorld[2][3];
|
||||
w = temp[0] * screenToWorld[3][0] + temp[1] * screenToWorld[3][1] + temp[2] * screenToWorld[3][2] + screenToWorld[3][3];
|
||||
if( w ) VectorScale( point, ( 1.0f / w ), point );
|
||||
point[0] = screen[0] * screenToWorld[0][0] + screen[1] * screenToWorld[0][1] + screen[2] * screenToWorld[0][2] + screenToWorld[0][3];
|
||||
point[1] = screen[0] * screenToWorld[1][0] + screen[1] * screenToWorld[1][1] + screen[2] * screenToWorld[1][2] + screenToWorld[1][3];
|
||||
point[2] = screen[0] * screenToWorld[2][0] + screen[1] * screenToWorld[2][1] + screen[2] * screenToWorld[2][2] + screenToWorld[2][3];
|
||||
w = screen[0] * screenToWorld[3][0] + screen[1] * screenToWorld[3][1] + screen[2] * screenToWorld[3][2] + screenToWorld[3][3];
|
||||
if( w != 0.0f ) VectorScale( point, ( 1.0f / w ), point );
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -1253,6 +1253,14 @@ void R_DrawBrushModel( cl_entity_t *e )
|
|||
clmodel = e->model;
|
||||
RI.currentWaveHeight = RI.currententity->curstate.scale * 32.0f;
|
||||
|
||||
// don't reflect this entity in mirrors
|
||||
if( e->curstate.effects & EF_NOREFLECT && RI.params & RP_MIRRORVIEW )
|
||||
return;
|
||||
|
||||
// draw only in mirrors
|
||||
if( e->curstate.effects & EF_REFLECTONLY && !( RI.params & RP_MIRRORVIEW ))
|
||||
return;
|
||||
|
||||
if( !VectorIsNull( e->angles ))
|
||||
{
|
||||
for( i = 0; i < 3; i++ )
|
||||
|
|
|
@ -68,6 +68,7 @@ qboolean Cmd_GetMapList( const char *s, char *completedname, int length )
|
|||
const char *ext = FS_FileExtension( t->filenames[i] );
|
||||
char *ents = NULL, *pfile;
|
||||
qboolean gearbox = false;
|
||||
qboolean xash_ext = false;
|
||||
|
||||
if( Q_stricmp( ext, "bsp" )) continue;
|
||||
Q_strncpy( message, "^1error^7", sizeof( message ));
|
||||
|
@ -75,17 +76,18 @@ qboolean Cmd_GetMapList( const char *s, char *completedname, int length )
|
|||
|
||||
if( f )
|
||||
{
|
||||
dheader_t *header;
|
||||
dheader_t *header, tmphdr;
|
||||
int xash_ident;
|
||||
|
||||
Q_memset( buf, 0, MAX_SYSPATH );
|
||||
FS_Read( f, buf, MAX_SYSPATH );
|
||||
ver = *(uint *)buf;
|
||||
Q_memset( &tmphdr, 0, sizeof( tmphdr ));
|
||||
FS_Read( f, &tmphdr, sizeof( tmphdr ));
|
||||
ver = tmphdr.version;
|
||||
header = &tmphdr;
|
||||
|
||||
switch( ver )
|
||||
{
|
||||
case Q1BSP_VERSION:
|
||||
case HLBSP_VERSION:
|
||||
header = (dheader_t *)buf;
|
||||
if( header->lumps[LUMP_ENTITIES].fileofs <= 1024 && !(header->lumps[LUMP_ENTITIES].filelen % sizeof(dplane_t)))
|
||||
{
|
||||
lumpofs = header->lumps[LUMP_PLANES].fileofs;
|
||||
|
@ -98,6 +100,9 @@ qboolean Cmd_GetMapList( const char *s, char *completedname, int length )
|
|||
lumplen = header->lumps[LUMP_ENTITIES].filelen;
|
||||
gearbox = false;
|
||||
}
|
||||
FS_Read( f, &xash_ident, sizeof( xash_ident ));
|
||||
if( xash_ident == (('H'<<24)+('S'<<16)+('A'<<8)+'X'))
|
||||
xash_ext = true; // we found extra lumps!
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -146,6 +151,7 @@ qboolean Cmd_GetMapList( const char *s, char *completedname, int length )
|
|||
break;
|
||||
case HLBSP_VERSION:
|
||||
if( gearbox ) Q_strncpy( buf, "Blue-Shift", sizeof( buf ));
|
||||
else if( xash_ext ) Q_strncpy( buf, "Xash3D", sizeof( buf ));
|
||||
else Q_strncpy( buf, "Half-Life", sizeof( buf ));
|
||||
break;
|
||||
default: Q_strncpy( buf, "??", sizeof( buf )); break;
|
||||
|
|
|
@ -1884,6 +1884,7 @@ file_t *FS_Open( const char *filepath, const char *mode, qboolean gamedironly )
|
|||
{
|
||||
// some stupid mappers used leading '/' or '\' in path to models or sounds
|
||||
if( filepath[0] == '/' || filepath[0] == '\\' ) filepath++;
|
||||
if( filepath[0] == '/' || filepath[0] == '\\' ) filepath++;
|
||||
}
|
||||
|
||||
if( FS_CheckNastyPath( filepath, false ))
|
||||
|
|
|
@ -158,6 +158,8 @@ void Matrix4x4_ConvertToEntity( const matrix4x4 in, vec3_t angles, vec3_t origin
|
|||
void Matrix4x4_SetOrigin( matrix4x4 out, float x, float y, float z );
|
||||
void Matrix4x4_Invert_Simple( matrix4x4 out, const matrix4x4 in1 );
|
||||
void Matrix4x4_OriginFromMatrix( const matrix4x4 in, float *out );
|
||||
void Matrix4x4_Transpose( matrix4x4 out, const matrix4x4 in1 );
|
||||
qboolean Matrix4x4_Invert_Full( matrix4x4 out, const matrix4x4 in1 );
|
||||
|
||||
extern vec3_t vec3_origin;
|
||||
extern const matrix3x4 matrix3x4_identity;
|
||||
|
|
|
@ -503,3 +503,284 @@ void Matrix4x4_Invert_Simple( matrix4x4 out, const matrix4x4 in1 )
|
|||
out[3][2] = 0;
|
||||
out[3][3] = 1;
|
||||
}
|
||||
|
||||
void Matrix4x4_Transpose( matrix4x4 out, const matrix4x4 in1 )
|
||||
{
|
||||
out[0][0] = in1[0][0];
|
||||
out[0][1] = in1[1][0];
|
||||
out[0][2] = in1[2][0];
|
||||
out[0][3] = in1[3][0];
|
||||
out[1][0] = in1[0][1];
|
||||
out[1][1] = in1[1][1];
|
||||
out[1][2] = in1[2][1];
|
||||
out[1][3] = in1[3][1];
|
||||
out[2][0] = in1[0][2];
|
||||
out[2][1] = in1[1][2];
|
||||
out[2][2] = in1[2][2];
|
||||
out[2][3] = in1[3][2];
|
||||
out[3][0] = in1[0][3];
|
||||
out[3][1] = in1[1][3];
|
||||
out[3][2] = in1[2][3];
|
||||
out[3][3] = in1[3][3];
|
||||
}
|
||||
|
||||
qboolean Matrix4x4_Invert_Full( matrix4x4 out, const matrix4x4 in1 )
|
||||
{
|
||||
float *temp;
|
||||
float *r[4];
|
||||
float rtemp[4][8];
|
||||
float m[4];
|
||||
float s;
|
||||
|
||||
r[0] = rtemp[0];
|
||||
r[1] = rtemp[1];
|
||||
r[2] = rtemp[2];
|
||||
r[3] = rtemp[3];
|
||||
|
||||
r[0][0] = in1[0][0];
|
||||
r[0][1] = in1[0][1];
|
||||
r[0][2] = in1[0][2];
|
||||
r[0][3] = in1[0][3];
|
||||
r[0][4] = 1.0;
|
||||
r[0][5] = 0.0;
|
||||
r[0][6] = 0.0;
|
||||
r[0][7] = 0.0;
|
||||
|
||||
r[1][0] = in1[1][0];
|
||||
r[1][1] = in1[1][1];
|
||||
r[1][2] = in1[1][2];
|
||||
r[1][3] = in1[1][3];
|
||||
r[1][5] = 1.0;
|
||||
r[1][4] = 0.0;
|
||||
r[1][6] = 0.0;
|
||||
r[1][7] = 0.0;
|
||||
|
||||
r[2][0] = in1[2][0];
|
||||
r[2][1] = in1[2][1];
|
||||
r[2][2] = in1[2][2];
|
||||
r[2][3] = in1[2][3];
|
||||
r[2][6] = 1.0;
|
||||
r[2][4] = 0.0;
|
||||
r[2][5] = 0.0;
|
||||
r[2][7] = 0.0;
|
||||
|
||||
r[3][0] = in1[3][0];
|
||||
r[3][1] = in1[3][1];
|
||||
r[3][2] = in1[3][2];
|
||||
r[3][3] = in1[3][3];
|
||||
r[3][4] = 0.0;
|
||||
r[3][5] = 0.0;
|
||||
r[3][6] = 0.0;
|
||||
r[3][7] = 1.0;
|
||||
|
||||
if( fabs( r[3][0] ) > fabs( r[2][0] ))
|
||||
{
|
||||
temp = r[3];
|
||||
r[3] = r[2];
|
||||
r[2] = temp;
|
||||
}
|
||||
|
||||
if( fabs( r[2][0] ) > fabs( r[1][0] ))
|
||||
{
|
||||
temp = r[2];
|
||||
r[2] = r[1];
|
||||
r[1] = temp;
|
||||
}
|
||||
|
||||
if( fabs( r[1][0] ) > fabs( r[0][0] ))
|
||||
{
|
||||
temp = r[1];
|
||||
r[1] = r[0];
|
||||
r[0] = temp;
|
||||
}
|
||||
|
||||
if( r[0][0] )
|
||||
{
|
||||
m[1] = r[1][0] / r[0][0];
|
||||
m[2] = r[2][0] / r[0][0];
|
||||
m[3] = r[3][0] / r[0][0];
|
||||
|
||||
s = r[0][1];
|
||||
r[1][1] -= m[1] * s;
|
||||
r[2][1] -= m[2] * s;
|
||||
r[3][1] -= m[3] * s;
|
||||
|
||||
s = r[0][2];
|
||||
r[1][2] -= m[1] * s;
|
||||
r[2][2] -= m[2] * s;
|
||||
r[3][2] -= m[3] * s;
|
||||
|
||||
s = r[0][3];
|
||||
r[1][3] -= m[1] * s;
|
||||
r[2][3] -= m[2] * s;
|
||||
r[3][3] -= m[3] * s;
|
||||
|
||||
s = r[0][4];
|
||||
if( s )
|
||||
{
|
||||
r[1][4] -= m[1] * s;
|
||||
r[2][4] -= m[2] * s;
|
||||
r[3][4] -= m[3] * s;
|
||||
}
|
||||
|
||||
s = r[0][5];
|
||||
if( s )
|
||||
{
|
||||
r[1][5] -= m[1] * s;
|
||||
r[2][5] -= m[2] * s;
|
||||
r[3][5] -= m[3] * s;
|
||||
}
|
||||
|
||||
s = r[0][6];
|
||||
if( s )
|
||||
{
|
||||
r[1][6] -= m[1] * s;
|
||||
r[2][6] -= m[2] * s;
|
||||
r[3][6] -= m[3] * s;
|
||||
}
|
||||
|
||||
s = r[0][7];
|
||||
if( s )
|
||||
{
|
||||
r[1][7] -= m[1] * s;
|
||||
r[2][7] -= m[2] * s;
|
||||
r[3][7] -= m[3] * s;
|
||||
}
|
||||
|
||||
if( fabs( r[3][1] ) > fabs( r[2][1] ))
|
||||
{
|
||||
temp = r[3];
|
||||
r[3] = r[2];
|
||||
r[2] = temp;
|
||||
}
|
||||
if( fabs( r[2][1] ) > fabs( r[1][1] ))
|
||||
{
|
||||
temp = r[2];
|
||||
r[2] = r[1];
|
||||
r[1] = temp;
|
||||
}
|
||||
|
||||
if( r[1][1] )
|
||||
{
|
||||
m[2] = r[2][1] / r[1][1];
|
||||
m[3] = r[3][1] / r[1][1];
|
||||
r[2][2] -= m[2] * r[1][2];
|
||||
r[3][2] -= m[3] * r[1][2];
|
||||
r[2][3] -= m[2] * r[1][3];
|
||||
r[3][3] -= m[3] * r[1][3];
|
||||
|
||||
s = r[1][4];
|
||||
if( s )
|
||||
{
|
||||
r[2][4] -= m[2] * s;
|
||||
r[3][4] -= m[3] * s;
|
||||
}
|
||||
|
||||
s = r[1][5];
|
||||
if( s )
|
||||
{
|
||||
r[2][5] -= m[2] * s;
|
||||
r[3][5] -= m[3] * s;
|
||||
}
|
||||
|
||||
s = r[1][6];
|
||||
if( s )
|
||||
{
|
||||
r[2][6] -= m[2] * s;
|
||||
r[3][6] -= m[3] * s;
|
||||
}
|
||||
|
||||
s = r[1][7];
|
||||
if( s )
|
||||
{
|
||||
r[2][7] -= m[2] * s;
|
||||
r[3][7] -= m[3] * s;
|
||||
}
|
||||
|
||||
if( fabs( r[3][2] ) > fabs( r[2][2] ))
|
||||
{
|
||||
temp = r[3];
|
||||
r[3] = r[2];
|
||||
r[2] = temp;
|
||||
}
|
||||
|
||||
if( r[2][2] )
|
||||
{
|
||||
m[3] = r[3][2] / r[2][2];
|
||||
r[3][3] -= m[3] * r[2][3];
|
||||
r[3][4] -= m[3] * r[2][4];
|
||||
r[3][5] -= m[3] * r[2][5];
|
||||
r[3][6] -= m[3] * r[2][6];
|
||||
r[3][7] -= m[3] * r[2][7];
|
||||
|
||||
if( r[3][3] )
|
||||
{
|
||||
s = 1.0 / r[3][3];
|
||||
r[3][4] *= s;
|
||||
r[3][5] *= s;
|
||||
r[3][6] *= s;
|
||||
r[3][7] *= s;
|
||||
|
||||
m[2] = r[2][3];
|
||||
s = 1.0 / r[2][2];
|
||||
r[2][4] = s * (r[2][4] - r[3][4] * m[2]);
|
||||
r[2][5] = s * (r[2][5] - r[3][5] * m[2]);
|
||||
r[2][6] = s * (r[2][6] - r[3][6] * m[2]);
|
||||
r[2][7] = s * (r[2][7] - r[3][7] * m[2]);
|
||||
|
||||
m[1] = r[1][3];
|
||||
r[1][4] -= r[3][4] * m[1];
|
||||
r[1][5] -= r[3][5] * m[1];
|
||||
r[1][6] -= r[3][6] * m[1];
|
||||
r[1][7] -= r[3][7] * m[1];
|
||||
|
||||
m[0] = r[0][3];
|
||||
r[0][4] -= r[3][4] * m[0];
|
||||
r[0][5] -= r[3][5] * m[0];
|
||||
r[0][6] -= r[3][6] * m[0];
|
||||
r[0][7] -= r[3][7] * m[0];
|
||||
|
||||
m[1] = r[1][2];
|
||||
s = 1.0 / r[1][1];
|
||||
r[1][4] = s * (r[1][4] - r[2][4] * m[1]);
|
||||
r[1][5] = s * (r[1][5] - r[2][5] * m[1]);
|
||||
r[1][6] = s * (r[1][6] - r[2][6] * m[1]);
|
||||
r[1][7] = s * (r[1][7] - r[2][7] * m[1]);
|
||||
|
||||
m[0] = r[0][2];
|
||||
r[0][4] -= r[2][4] * m[0];
|
||||
r[0][5] -= r[2][5] * m[0];
|
||||
r[0][6] -= r[2][6] * m[0];
|
||||
r[0][7] -= r[2][7] * m[0];
|
||||
|
||||
m[0] = r[0][1];
|
||||
s = 1.0 / r[0][0];
|
||||
r[0][4] = s * (r[0][4] - r[1][4] * m[0]);
|
||||
r[0][5] = s * (r[0][5] - r[1][5] * m[0]);
|
||||
r[0][6] = s * (r[0][6] - r[1][6] * m[0]);
|
||||
r[0][7] = s * (r[0][7] - r[1][7] * m[0]);
|
||||
|
||||
out[0][0] = r[0][4];
|
||||
out[0][1] = r[0][5];
|
||||
out[0][2] = r[0][6];
|
||||
out[0][3] = r[0][7];
|
||||
out[1][0] = r[1][4];
|
||||
out[1][1] = r[1][5];
|
||||
out[1][2] = r[1][6];
|
||||
out[1][3] = r[1][7];
|
||||
out[2][0] = r[2][4];
|
||||
out[2][1] = r[2][5];
|
||||
out[2][2] = r[2][6];
|
||||
out[2][3] = r[2][7];
|
||||
out[3][0] = r[3][4];
|
||||
out[3][1] = r[3][5];
|
||||
out[3][2] = r[3][6];
|
||||
out[3][3] = r[3][7];
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
|
@ -1,934 +0,0 @@
|
|||
/*
|
||||
pm_studio.c - stduio models tracing
|
||||
Copyright (C) 2010 Uncle Mike
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "studio.h"
|
||||
#include "mathlib.h"
|
||||
#include "mod_local.h"
|
||||
#include "pm_local.h"
|
||||
#include "pm_movevars.h"
|
||||
#include "world.h"
|
||||
|
||||
static studiohdr_t *pm_studiohdr;
|
||||
static mplane_t pm_hitboxplanes[6]; // there a temp hitbox
|
||||
static matrix3x4 pm_studiomatrix;
|
||||
static matrix3x4 pm_studiobones[MAXSTUDIOBONES];
|
||||
typedef qboolean (*pfnTrace)( pmtrace_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;
|
||||
|
||||
/*
|
||||
====================
|
||||
PM_InitStudioHull
|
||||
====================
|
||||
*/
|
||||
void PM_InitStudioHull( void )
|
||||
{
|
||||
int i, side;
|
||||
mplane_t *p;
|
||||
|
||||
for( i = 0; i < 6; i++ )
|
||||
{
|
||||
side = i & 1;
|
||||
|
||||
// planes
|
||||
p = &pm_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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
PM_HullForHitbox
|
||||
====================
|
||||
*/
|
||||
static void PM_HullForHitbox( const vec3_t mins, const vec3_t maxs )
|
||||
{
|
||||
pm_hitboxplanes[0].dist = maxs[0];
|
||||
pm_hitboxplanes[1].dist = -mins[0];
|
||||
pm_hitboxplanes[2].dist = maxs[1];
|
||||
pm_hitboxplanes[3].dist = -mins[1];
|
||||
pm_hitboxplanes[4].dist = maxs[2];
|
||||
pm_hitboxplanes[5].dist = -mins[2];
|
||||
}
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
STUDIO MODELS TRACING
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
/*
|
||||
====================
|
||||
StudioPlayerBlend
|
||||
|
||||
====================
|
||||
*/
|
||||
void PM_StudioPlayerBlend( mstudioseqdesc_t *pseqdesc, int *pBlend, float *pPitch )
|
||||
{
|
||||
// calc up/down pointing
|
||||
*pBlend = (*pPitch * 3);
|
||||
|
||||
if( *pBlend < pseqdesc->blendstart[0] )
|
||||
{
|
||||
*pPitch -= pseqdesc->blendstart[0] / 3.0f;
|
||||
*pBlend = 0;
|
||||
}
|
||||
else if( *pBlend > pseqdesc->blendend[0] )
|
||||
{
|
||||
*pPitch -= pseqdesc->blendend[0] / 3.0f;
|
||||
*pBlend = 255;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( pseqdesc->blendend[0] - pseqdesc->blendstart[0] < 0.1f ) // catch qc error
|
||||
*pBlend = 127;
|
||||
else *pBlend = 255.0f * (*pBlend - pseqdesc->blendstart[0]) / (pseqdesc->blendend[0] - pseqdesc->blendstart[0]);
|
||||
*pPitch = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
StudioCalcBoneAdj
|
||||
|
||||
====================
|
||||
*/
|
||||
static void PM_StudioCalcBoneAdj( float *adj, const byte *pcontroller )
|
||||
{
|
||||
int i, j;
|
||||
float value;
|
||||
mstudiobonecontroller_t *pbonecontroller;
|
||||
|
||||
pbonecontroller = (mstudiobonecontroller_t *)((byte *)pm_studiohdr + pm_studiohdr->bonecontrollerindex);
|
||||
|
||||
for( j = 0; j < pm_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 )
|
||||
{
|
||||
value = pcontroller[i] * (360.0/256.0) + pbonecontroller[j].start;
|
||||
}
|
||||
else
|
||||
{
|
||||
value = pcontroller[i] / 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.0);
|
||||
break;
|
||||
case STUDIO_X:
|
||||
case STUDIO_Y:
|
||||
case STUDIO_Z:
|
||||
adj[j] = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
StudioCalcBoneQuaterion
|
||||
|
||||
====================
|
||||
*/
|
||||
static void PM_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 PM_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 PM_StudioCalcRotations( physent_t *pe, const byte *pcontroller, 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;
|
||||
|
||||
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 *)pm_studiohdr + pm_studiohdr->boneindex);
|
||||
|
||||
PM_StudioCalcBoneAdj( adj, pcontroller );
|
||||
|
||||
for( i = 0; i < pm_studiohdr->numbones; i++, pbone++, panim++ )
|
||||
{
|
||||
PM_StudioCalcBoneQuaterion( frame, s, pbone, panim, adj, q[i] );
|
||||
PM_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)) * 1.0f; // 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 PM_StudioEstimateFrame( physent_t *pe, mstudioseqdesc_t *pseqdesc )
|
||||
{
|
||||
double f;
|
||||
|
||||
if( pseqdesc->numframes <= 1 )
|
||||
f = 0;
|
||||
else f = (pe->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 PM_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 < pm_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;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
PM_StudioGetAnim
|
||||
|
||||
====================
|
||||
*/
|
||||
static mstudioanim_t *PM_StudioGetAnim( model_t *m_pSubModel, mstudioseqdesc_t *pseqdesc )
|
||||
{
|
||||
mstudioseqgroup_t *pseqgroup;
|
||||
cache_user_t *paSequences;
|
||||
size_t filesize;
|
||||
byte *buf;
|
||||
|
||||
pseqgroup = (mstudioseqgroup_t *)((byte *)pm_studiohdr + pm_studiohdr->seqgroupindex) + pseqdesc->seqgroup;
|
||||
if( pseqdesc->seqgroup == 0 )
|
||||
return (mstudioanim_t *)((byte *)pm_studiohdr + pseqgroup->data + pseqdesc->animindex);
|
||||
|
||||
paSequences = (cache_user_t *)m_pSubModel->submodels;
|
||||
|
||||
if( paSequences == NULL )
|
||||
{
|
||||
paSequences = (cache_user_t *)Mem_Alloc( com_studiocache, MAXSTUDIOGROUPS * sizeof( cache_user_t ));
|
||||
m_pSubModel->submodels = (void *)paSequences;
|
||||
}
|
||||
|
||||
// check for already loaded
|
||||
if( !Mod_CacheCheck(( cache_user_t *)&( paSequences[pseqdesc->seqgroup] )))
|
||||
{
|
||||
string filepath, modelname, modelpath;
|
||||
|
||||
FS_FileBase( m_pSubModel->name, modelname );
|
||||
FS_ExtractFilePath( m_pSubModel->name, modelpath );
|
||||
Q_snprintf( filepath, sizeof( filepath ), "%s/%s%i%i.mdl", modelpath, modelname, pseqdesc->seqgroup / 10, pseqdesc->seqgroup % 10 );
|
||||
|
||||
buf = FS_LoadFile( filepath, &filesize, false );
|
||||
if( !buf || !filesize ) Host_Error( "StudioGetAnim: can't load %s\n", filepath );
|
||||
if( IDSEQGRPHEADER != *(uint *)buf )
|
||||
Host_Error( "StudioGetAnim: %s is corrupted\n", filepath );
|
||||
|
||||
MsgDev( D_INFO, "loading: %s\n", filepath );
|
||||
|
||||
paSequences[pseqdesc->seqgroup].data = Mem_Alloc( com_studiocache, filesize );
|
||||
Q_memcpy( paSequences[pseqdesc->seqgroup].data, buf, filesize );
|
||||
Mem_Free( buf );
|
||||
}
|
||||
return (mstudioanim_t *)((byte *)paSequences[pseqdesc->seqgroup].data + pseqdesc->animindex);
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
PM_StudioSetupBones
|
||||
====================
|
||||
*/
|
||||
static void PM_StudioSetupBones( playermove_t *pmove, physent_t *pe, const vec3_t angles, const vec3_t origin, const byte *pcontroller, const byte *pblending )
|
||||
{
|
||||
int i, oldseq;
|
||||
float scale = 1.0f;
|
||||
double f;
|
||||
|
||||
mstudiobone_t *pbones;
|
||||
mstudioseqdesc_t *pseqdesc;
|
||||
mstudioanim_t *panim;
|
||||
|
||||
static float pos[MAXSTUDIOBONES][3];
|
||||
static vec4_t q[MAXSTUDIOBONES];
|
||||
matrix3x4 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 = pe->sequence; // TraceCode can't change sequence
|
||||
|
||||
if( pe->sequence >= pm_studiohdr->numseq ) pe->sequence = 0;
|
||||
pseqdesc = (mstudioseqdesc_t *)((byte *)pm_studiohdr + pm_studiohdr->seqindex) + pe->sequence;
|
||||
|
||||
f = PM_StudioEstimateFrame( pe, pseqdesc );
|
||||
|
||||
panim = PM_StudioGetAnim( pe->studiomodel, pseqdesc );
|
||||
PM_StudioCalcRotations( pe, pcontroller, pos, q, pseqdesc, panim, f );
|
||||
|
||||
if( pseqdesc->numblends > 1 )
|
||||
{
|
||||
float s;
|
||||
|
||||
panim += pm_studiohdr->numbones;
|
||||
PM_StudioCalcRotations( pe, pcontroller, pos2, q2, pseqdesc, panim, f );
|
||||
|
||||
s = (float)pe->blending[0] / 255.0f;
|
||||
|
||||
PM_StudioSlerpBones( q, pos, q2, pos2, s );
|
||||
|
||||
if( pseqdesc->numblends == 4 )
|
||||
{
|
||||
panim += pm_studiohdr->numbones;
|
||||
PM_StudioCalcRotations( pe, pcontroller, pos3, q3, pseqdesc, panim, f );
|
||||
|
||||
panim += pm_studiohdr->numbones;
|
||||
PM_StudioCalcRotations( pe, pcontroller, pos4, q4, pseqdesc, panim, f );
|
||||
|
||||
s = (float)pe->blending[0] / 255.0f;
|
||||
PM_StudioSlerpBones( q3, pos3, q4, pos4, s );
|
||||
|
||||
s = (float)pe->blending[1] / 255.0f;
|
||||
PM_StudioSlerpBones( q, pos, q3, pos3, s );
|
||||
}
|
||||
}
|
||||
|
||||
if( pmove->movevars->studio_scale && pe->fuser1 > 0.0f )
|
||||
scale = pe->fuser1;
|
||||
else if( pe->player && pmove->movevars->clienttrace != 0.0f )
|
||||
scale = pmove->movevars->clienttrace * 0.5f;
|
||||
|
||||
Matrix3x4_CreateFromEntity( pm_studiomatrix, angles, origin, scale );
|
||||
|
||||
pbones = (mstudiobone_t *)((byte *)pm_studiohdr + pm_studiohdr->boneindex);
|
||||
|
||||
for( i = 0; i < pm_studiohdr->numbones; i++ )
|
||||
{
|
||||
Matrix3x4_FromOriginQuat( bonematrix, q[i], pos[i] );
|
||||
if( pbones[i].parent == -1 )
|
||||
Matrix3x4_ConcatTransforms( pm_studiobones[i], pm_studiomatrix, bonematrix );
|
||||
else Matrix3x4_ConcatTransforms( pm_studiobones[i], pm_studiobones[pbones[i].parent], bonematrix );
|
||||
}
|
||||
|
||||
pe->sequence = oldseq; // restore original value
|
||||
}
|
||||
|
||||
static qboolean PM_StudioSetupModel( playermove_t *pmove, physent_t *pe )
|
||||
{
|
||||
model_t *mod = pe->studiomodel;
|
||||
vec3_t angles;
|
||||
|
||||
if( !mod || !mod->cache.data )
|
||||
return false;
|
||||
|
||||
pm_studiohdr = (studiohdr_t *)mod->cache.data;
|
||||
VectorCopy( pe->angles, angles );
|
||||
|
||||
// calc blending for player
|
||||
if( pe->player )
|
||||
{
|
||||
mstudioseqdesc_t *pseqdesc;
|
||||
byte controller[4];
|
||||
byte blending[2];
|
||||
int iBlend;
|
||||
|
||||
pseqdesc = (mstudioseqdesc_t *)((byte *)pm_studiohdr + pm_studiohdr->seqindex) + pe->sequence;
|
||||
|
||||
PM_StudioPlayerBlend( pseqdesc, &iBlend, &angles[PITCH] );
|
||||
|
||||
controller[0] = controller[1] = controller[2] = controller[3] = 0x7F;
|
||||
blending[0] = (byte)iBlend;
|
||||
blending[1] = 0;
|
||||
|
||||
PM_StudioSetupBones( pmove, pe, angles, pe->origin, controller, blending );
|
||||
}
|
||||
else
|
||||
{
|
||||
PM_StudioSetupBones( pmove, pe, angles, pe->origin, pe->controller, pe->blending );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
qboolean PM_StudioExtractBbox( playermove_t *pmove, physent_t *pe, model_t *mod, int sequence, float *mins, float *maxs )
|
||||
{
|
||||
mstudioseqdesc_t *pseqdesc;
|
||||
studiohdr_t *phdr;
|
||||
float scale = 1.0f;
|
||||
|
||||
ASSERT( mod != NULL );
|
||||
|
||||
if( mod->type != mod_studio || !mod->cache.data )
|
||||
return false;
|
||||
|
||||
phdr = (studiohdr_t *)mod->cache.data;
|
||||
if( !phdr->numhitboxes ) return false;
|
||||
|
||||
pseqdesc = (mstudioseqdesc_t *)((byte *)phdr + phdr->seqindex);
|
||||
|
||||
if( sequence < 0 || sequence >= phdr->numseq )
|
||||
return false;
|
||||
|
||||
if( pmove->movevars->studio_scale && pe->fuser1 > 0.0f )
|
||||
scale = pe->fuser1;
|
||||
|
||||
VectorScale( pseqdesc[sequence].bbmin, scale, mins );
|
||||
VectorScale( pseqdesc[sequence].bbmax, scale, maxs );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
PM_ClipBoxToHitbox
|
||||
|
||||
trace hitbox
|
||||
================
|
||||
*/
|
||||
qboolean PM_ClipBoxToHitbox( pmtrace_t *trace )
|
||||
{
|
||||
int i;
|
||||
mplane_t *p, *clipplane;
|
||||
float enterfrac, leavefrac, distfrac;
|
||||
float d, d1, d2;
|
||||
qboolean getout, startout;
|
||||
float f;
|
||||
|
||||
enterfrac = -1.0f;
|
||||
leavefrac = 1.0f;
|
||||
clipplane = NULL;
|
||||
|
||||
getout = false;
|
||||
startout = false;
|
||||
|
||||
for( i = 0; i < 6; i++ )
|
||||
{
|
||||
p = &pm_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->startsolid = true;
|
||||
if( !getout ) trace->allsolid = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
if( enterfrac - FRAC_EPSILON <= leavefrac )
|
||||
{
|
||||
if( enterfrac > -1.0f && enterfrac < trace_realfraction )
|
||||
{
|
||||
if( enterfrac < 0 )
|
||||
enterfrac = 0;
|
||||
trace_realfraction = enterfrac;
|
||||
trace->fraction = enterfrac - DIST_EPSILON * distfrac;
|
||||
VectorCopy( clipplane->normal, trace->plane.normal );
|
||||
trace->plane.dist = clipplane->dist;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
PM_TestBoxInHitbox
|
||||
|
||||
test point trace in hibox
|
||||
================
|
||||
*/
|
||||
qboolean PM_TestBoxInHitbox( pmtrace_t *trace )
|
||||
{
|
||||
int i;
|
||||
mplane_t *p;
|
||||
|
||||
for( i = 0; i < 6; i++ )
|
||||
{
|
||||
p = &pm_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->fraction = trace_realfraction = 0;
|
||||
trace->startsolid = trace->allsolid = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
PM_StudioIntersect
|
||||
|
||||
testing for potentially intersection of trace and animation bboxes
|
||||
================
|
||||
*/
|
||||
static qboolean PM_StudioIntersect( playermove_t *pmove, physent_t *pe, 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;
|
||||
|
||||
// create the bounding box of the entire move
|
||||
World_MoveBounds( start, mins, maxs, end, trace_mins, trace_maxs );
|
||||
|
||||
if( !PM_StudioExtractBbox( pmove, pe, pe->studiomodel, pe->sequence, anim_mins, anim_maxs ))
|
||||
return false; // invalid sequence
|
||||
|
||||
if( !VectorIsNull( pe->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] = pe->origin[i] - max;
|
||||
anim_maxs[i] = pe->origin[i] + max;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
VectorAdd( anim_mins, pe->origin, anim_mins );
|
||||
VectorAdd( anim_maxs, pe->origin, anim_maxs );
|
||||
}
|
||||
|
||||
// check intersection with trace entire move and animation bbox
|
||||
return BoundsIntersect( trace_mins, trace_maxs, anim_mins, anim_maxs );
|
||||
}
|
||||
|
||||
qboolean PM_StudioTrace( playermove_t *pmove, physent_t *pe, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, pmtrace_t *ptr )
|
||||
{
|
||||
vec3_t start_l, end_l;
|
||||
int i, outBone = -1;
|
||||
pfnTrace StudioTrace = NULL;
|
||||
|
||||
// assume we didn't hit anything
|
||||
Q_memset( ptr, 0, sizeof( pmtrace_t ));
|
||||
VectorCopy( end, ptr->endpos );
|
||||
ptr->fraction = trace_realfraction = 1.0f;
|
||||
ptr->hitgroup = -1;
|
||||
ptr->ent = -1;
|
||||
|
||||
if( !PM_StudioIntersect( pmove, pe, start, mins, maxs, end ))
|
||||
return false;
|
||||
|
||||
if( !PM_StudioSetupModel( pmove, pe ))
|
||||
return false;
|
||||
|
||||
if( VectorCompare( start, end ))
|
||||
StudioTrace = PM_TestBoxInHitbox;
|
||||
else StudioTrace = PM_ClipBoxToHitbox;
|
||||
|
||||
// go to check individual hitboxes
|
||||
for( i = 0; i < pm_studiohdr->numhitboxes; i++ )
|
||||
{
|
||||
mstudiobbox_t *phitbox = (mstudiobbox_t *)((byte*)pm_studiohdr + pm_studiohdr->hitboxindex) + i;
|
||||
|
||||
// transform traceline into local bone space
|
||||
Matrix3x4_VectorITransform( pm_studiobones[phitbox->bone], start, start_l );
|
||||
Matrix3x4_VectorITransform( pm_studiobones[phitbox->bone], end, end_l );
|
||||
|
||||
PM_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( StudioTrace( ptr ))
|
||||
{
|
||||
outBone = phitbox->bone;
|
||||
ptr->hitgroup = phitbox->group;
|
||||
}
|
||||
|
||||
if( ptr->allsolid )
|
||||
break;
|
||||
}
|
||||
|
||||
// all hitboxes were swept, get trace result
|
||||
if( outBone >= 0 )
|
||||
{
|
||||
vec3_t temp;
|
||||
|
||||
VectorCopy( ptr->plane.normal, temp );
|
||||
ptr->fraction = bound( 0, ptr->fraction, 1.0f );
|
||||
VectorLerp( start, ptr->fraction, end, ptr->endpos );
|
||||
Matrix3x4_TransformPositivePlane( pm_studiobones[outBone], temp, ptr->plane.dist, ptr->plane.normal, &ptr->plane.dist );
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
|
@ -301,7 +301,6 @@ pmtrace_t PM_PlayerTraceExt( playermove_t *pmove, vec3_t start, vec3_t end, int
|
|||
Q_memset( &trace_total, 0, sizeof( trace_total ));
|
||||
VectorCopy( end, trace_total.endpos );
|
||||
trace_total.fraction = 1.0f;
|
||||
trace_total.hitgroup = -1;
|
||||
trace_total.ent = -1;
|
||||
|
||||
for( i = 0; i < numents; i++ )
|
||||
|
@ -386,7 +385,6 @@ pmtrace_t PM_PlayerTraceExt( playermove_t *pmove, vec3_t start, vec3_t end, int
|
|||
VectorCopy( end, trace_bbox.endpos );
|
||||
trace_bbox.allsolid = true;
|
||||
trace_bbox.fraction = 1.0f;
|
||||
trace_bbox.hitgroup = -1;
|
||||
|
||||
if( hullcount < 1 )
|
||||
{
|
||||
|
@ -407,7 +405,6 @@ pmtrace_t PM_PlayerTraceExt( playermove_t *pmove, vec3_t start, vec3_t end, int
|
|||
VectorCopy( end, trace_hitbox.endpos );
|
||||
trace_hitbox.allsolid = true;
|
||||
trace_hitbox.fraction = 1.0f;
|
||||
trace_hitbox.hitgroup = -1;
|
||||
|
||||
PM_RecursiveHullCheck( &hull[j], hull[j].firstclipnode, 0, 1, start_l, end_l, &trace_hitbox );
|
||||
|
||||
|
|
|
@ -83,7 +83,7 @@ qboolean SV_CopyEdictToPhysEnt( physent_t *pe, edict_t *ed )
|
|||
break;
|
||||
default:
|
||||
pe->model = NULL;
|
||||
pe->studiomodel = NULL;
|
||||
pe->studiomodel = (mod->type == mod_studio) ? mod : NULL;
|
||||
VectorCopy( ed->v.mins, pe->mins );
|
||||
VectorCopy( ed->v.maxs, pe->maxs );
|
||||
Q_strcpy( pe->name, SV_ClassName( ed ));
|
||||
|
|
|
@ -890,13 +890,11 @@ void SV_ClipMoveToEntity( edict_t *ent, const vec3_t start, vec3_t mins, vec3_t
|
|||
Q_memset( trace, 0, sizeof( trace_t ));
|
||||
VectorCopy( end, trace->endpos );
|
||||
trace->fraction = 1.0;
|
||||
trace->hitgroup = -1;
|
||||
trace->allsolid = 1;
|
||||
|
||||
model = Mod_Handle( ent->v.modelindex );
|
||||
ASSERT( model );
|
||||
|
||||
if( model->type == mod_studio )
|
||||
if( model && model->type == mod_studio )
|
||||
{
|
||||
hull = SV_HullForStudioModel( ent, mins, maxs, offset, &hullcount );
|
||||
}
|
||||
|
@ -936,7 +934,6 @@ void SV_ClipMoveToEntity( edict_t *ent, const vec3_t start, vec3_t mins, vec3_t
|
|||
Q_memset( &trace_hitbox, 0, sizeof( trace_t ));
|
||||
VectorCopy( end, trace_hitbox.endpos );
|
||||
trace_hitbox.fraction = 1.0;
|
||||
trace_hitbox.hitgroup = -1;
|
||||
trace_hitbox.allsolid = 1;
|
||||
|
||||
SV_RecursiveHullCheck( &hull[i], hull[i].firstclipnode, 0.0f, 1.0f, start_l, end_l, &trace_hitbox );
|
||||
|
|
Reference in New Issue