2012-11-26 18:58:24 +00:00
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Doom 3 BFG Edition GPL Source Code
2012-11-28 15:47:07 +00:00
Copyright ( C ) 1993 - 2012 id Software LLC , a ZeniMax Media company .
2012-11-26 18:58:24 +00:00
2012-11-28 15:47:07 +00:00
This file is part of the Doom 3 BFG Edition GPL Source Code ( " Doom 3 BFG Edition Source Code " ) .
2012-11-26 18:58:24 +00:00
Doom 3 BFG Edition Source Code 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 .
Doom 3 BFG Edition Source Code 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 .
You should have received a copy of the GNU General Public License
along with Doom 3 BFG Edition Source Code . If not , see < http : //www.gnu.org/licenses/>.
In addition , the Doom 3 BFG Edition Source Code is also subject to certain additional terms . You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code . If not , please request a copy in writing from id Software at the address below .
If you have questions concerning this license or the applicable additional terms , you may contact in writing id Software LLC , c / o ZeniMax Media Inc . , Suite 120 , Rockville , Maryland 20850 USA .
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-12-22 15:18:19 +00:00
# include "precompiled.h"
2012-11-26 18:58:24 +00:00
# pragma hdrstop
# include "Game_local.h"
CLASS_DECLARATION ( idEntity , idBrittleFracture )
2012-11-28 15:47:07 +00:00
EVENT ( EV_Activate , idBrittleFracture : : Event_Activate )
EVENT ( EV_Touch , idBrittleFracture : : Event_Touch )
2012-11-26 18:58:24 +00:00
END_CLASS
const int SHARD_ALIVE_TIME = 5000 ;
const int SHARD_FADE_START = 2000 ;
2012-11-28 15:47:07 +00:00
static const char * brittleFracture_SnapshotName = " _BrittleFracture_Snapshot_ " ;
2012-11-26 18:58:24 +00:00
/*
= = = = = = = = = = = = = = = =
idBrittleFracture : : idBrittleFracture
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
idBrittleFracture : : idBrittleFracture ( )
{
2012-11-26 18:58:24 +00:00
material = NULL ;
decalMaterial = NULL ;
decalSize = 0.0f ;
maxShardArea = 0.0f ;
maxShatterRadius = 0.0f ;
minShatterRadius = 0.0f ;
linearVelocityScale = 0.0f ;
angularVelocityScale = 0.0f ;
shardMass = 0.0f ;
density = 0.0f ;
friction = 0.0f ;
bouncyness = 0.0f ;
fxFracture . Clear ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
bounds . Clear ( ) ;
disableFracture = false ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
lastRenderEntityUpdate = - 1 ;
changed = false ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
fl . networkSync = true ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
isXraySurface = false ;
}
/*
= = = = = = = = = = = = = = = =
idBrittleFracture : : ~ idBrittleFracture
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
idBrittleFracture : : ~ idBrittleFracture ( )
{
2012-11-26 18:58:24 +00:00
int i ;
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < shards . Num ( ) ; i + + )
{
2012-11-26 18:58:24 +00:00
shards [ i ] - > decals . DeleteContents ( true ) ;
delete shards [ i ] ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// make sure the render entity is freed before the model is freed
FreeModelDef ( ) ;
renderModelManager - > FreeModel ( renderEntity . hModel ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Free our events list memory
storedEvents . Clear ( ) ;
}
/*
= = = = = = = = = = = = = = = =
idBrittleFracture : : Save
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idBrittleFracture : : Save ( idSaveGame * savefile ) const
{
2012-11-26 18:58:24 +00:00
savefile - > WriteInt ( health ) ;
entityFlags_s flags = fl ;
LittleBitField ( & flags , sizeof ( flags ) ) ;
savefile - > Write ( & flags , sizeof ( flags ) ) ;
// setttings
savefile - > WriteMaterial ( material ) ;
savefile - > WriteMaterial ( decalMaterial ) ;
savefile - > WriteFloat ( decalSize ) ;
savefile - > WriteFloat ( maxShardArea ) ;
savefile - > WriteFloat ( maxShatterRadius ) ;
savefile - > WriteFloat ( minShatterRadius ) ;
savefile - > WriteFloat ( linearVelocityScale ) ;
savefile - > WriteFloat ( angularVelocityScale ) ;
savefile - > WriteFloat ( shardMass ) ;
savefile - > WriteFloat ( density ) ;
savefile - > WriteFloat ( friction ) ;
savefile - > WriteFloat ( bouncyness ) ;
savefile - > WriteString ( fxFracture ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// state
savefile - > WriteBounds ( bounds ) ;
savefile - > WriteBool ( disableFracture ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
savefile - > WriteInt ( lastRenderEntityUpdate ) ;
savefile - > WriteBool ( changed ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
savefile - > WriteModel ( defaultRenderModel ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// So we can re-break the object on load if needed
savefile - > WriteInt ( storedEvents . Num ( ) ) ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < storedEvents . Num ( ) ; + + i )
{
2012-11-26 18:58:24 +00:00
savefile - > WriteInt ( storedEvents [ i ] . eventType ) ;
savefile - > WriteVec3 ( storedEvents [ i ] . point ) ;
savefile - > WriteVec3 ( storedEvents [ i ] . vector ) ;
}
savefile - > WriteBool ( isXraySurface ) ;
}
/*
= = = = = = = = = = = = = = = =
idBrittleFracture : : Restore
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idBrittleFracture : : Restore ( idRestoreGame * savefile )
{
2012-11-26 18:58:24 +00:00
savefile - > ReadInt ( health ) ;
savefile - > Read ( & fl , sizeof ( fl ) ) ;
LittleBitField ( & fl , sizeof ( fl ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// setttings
savefile - > ReadMaterial ( material ) ;
savefile - > ReadMaterial ( decalMaterial ) ;
savefile - > ReadFloat ( decalSize ) ;
savefile - > ReadFloat ( maxShardArea ) ;
savefile - > ReadFloat ( maxShatterRadius ) ;
savefile - > ReadFloat ( minShatterRadius ) ;
savefile - > ReadFloat ( linearVelocityScale ) ;
savefile - > ReadFloat ( angularVelocityScale ) ;
savefile - > ReadFloat ( shardMass ) ;
savefile - > ReadFloat ( density ) ;
savefile - > ReadFloat ( friction ) ;
savefile - > ReadFloat ( bouncyness ) ;
savefile - > ReadString ( fxFracture ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// state
2012-11-28 15:47:07 +00:00
savefile - > ReadBounds ( bounds ) ;
2012-11-26 18:58:24 +00:00
savefile - > ReadBool ( disableFracture ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
savefile - > ReadInt ( lastRenderEntityUpdate ) ;
savefile - > ReadBool ( changed ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
savefile - > ReadModel ( defaultRenderModel ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Reset all brittle Fractures so we can re-break them if necessary
fl . takedamage = true ;
CreateFractures ( defaultRenderModel ) ;
FindNeighbours ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
int numEvents = 0 ;
bool resolveBreaks = false ;
savefile - > ReadInt ( numEvents ) ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < numEvents ; i + + )
{
2012-11-26 18:58:24 +00:00
fractureEvent_s restoredEvent ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
savefile - > ReadInt ( restoredEvent . eventType ) ;
savefile - > ReadVec3 ( restoredEvent . point ) ;
savefile - > ReadVec3 ( restoredEvent . vector ) ;
2012-11-28 15:47:07 +00:00
if ( restoredEvent . eventType = = EVENT_PROJECT_DECAL )
{
2012-11-26 18:58:24 +00:00
ProjectDecal ( restoredEvent . point , restoredEvent . vector , gameLocal . time , NULL ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
Shatter ( restoredEvent . point , restoredEvent . vector , gameLocal . time ) ;
}
resolveBreaks = true ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// remove any dropped shards
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; resolveBreaks & & i < shards . Num ( ) ; i + + )
{
if ( shards [ i ] - > droppedTime ! = - 1 )
{
2012-11-26 18:58:24 +00:00
RemoveShard ( i ) ;
i - - ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
renderEntity . hModel = renderModelManager - > AllocModel ( ) ;
renderEntity . hModel - > InitEmpty ( brittleFracture_SnapshotName ) ;
renderEntity . callback = idBrittleFracture : : ModelCallback ;
renderEntity . noShadow = true ;
renderEntity . noSelfShadow = true ;
renderEntity . noDynamicInteractions = false ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
savefile - > ReadBool ( isXraySurface ) ;
}
/*
= = = = = = = = = = = = = = = =
idBrittleFracture : : Spawn
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idBrittleFracture : : Spawn ( )
{
2012-11-26 18:58:24 +00:00
// get shard properties
decalMaterial = declManager - > FindMaterial ( spawnArgs . GetString ( " mtr_decal " ) ) ;
decalSize = spawnArgs . GetFloat ( " decalSize " , " 40 " ) ;
maxShardArea = spawnArgs . GetFloat ( " maxShardArea " , " 200 " ) * 2.0f ;
maxShardArea = idMath : : ClampFloat ( 100 , 10000 , maxShardArea ) ;
maxShatterRadius = spawnArgs . GetFloat ( " maxShatterRadius " , " 40 " ) ;
minShatterRadius = spawnArgs . GetFloat ( " minShatterRadius " , " 10 " ) ;
linearVelocityScale = spawnArgs . GetFloat ( " linearVelocityScale " , " 0.1 " ) ;
angularVelocityScale = spawnArgs . GetFloat ( " angularVelocityScale " , " 40 " ) ;
fxFracture = spawnArgs . GetString ( " fx " ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// make sure that max is greater than min ( otherwise negative number square root happens )
2012-11-28 15:47:07 +00:00
if ( maxShatterRadius < minShatterRadius )
{
2012-11-26 18:58:24 +00:00
idLib : : Warning ( " BrittleFracture, minShatterRadius(%2f) is greater than maxShatterRadius(%2f). Unknown results will ensue. " , minShatterRadius , maxShatterRadius ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// get rigid body properties
shardMass = spawnArgs . GetFloat ( " shardMass " , " 20 " ) ;
shardMass = idMath : : ClampFloat ( 0.001f , 1000.0f , shardMass ) ;
spawnArgs . GetFloat ( " density " , " 0.1 " , density ) ;
density = idMath : : ClampFloat ( 0.001f , 1000.0f , density ) ;
spawnArgs . GetFloat ( " friction " , " 0.4 " , friction ) ;
friction = idMath : : ClampFloat ( 0.0f , 1.0f , friction ) ;
spawnArgs . GetFloat ( " bouncyness " , " 0.01 " , bouncyness ) ;
bouncyness = idMath : : ClampFloat ( 0.0f , 1.0f , bouncyness ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
disableFracture = spawnArgs . GetBool ( " disableFracture " , " 0 " ) ;
health = spawnArgs . GetInt ( " health " , " 40 " ) ;
fl . takedamage = true ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// FIXME: set "bleed" so idProjectile calls AddDamageEffect
spawnArgs . SetBool ( " bleed " , 1 ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// check for xray surface
2012-11-28 15:47:07 +00:00
if ( renderEntity . hModel ! = NULL )
{
const idRenderModel * model = renderEntity . hModel ;
2012-11-26 18:58:24 +00:00
isXraySurface = false ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < model - > NumSurfaces ( ) ; i + + )
{
const modelSurface_t * surf = model - > Surface ( i ) ;
if ( idStr ( surf - > shader - > GetName ( ) ) = = " textures/smf/window_scratch " )
{
2012-11-26 18:58:24 +00:00
isXraySurface = true ;
break ;
}
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
CreateFractures ( renderEntity . hModel ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
FindNeighbours ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
defaultRenderModel = renderEntity . hModel ;
renderEntity . hModel = renderModelManager - > AllocModel ( ) ;
renderEntity . hModel - > InitEmpty ( brittleFracture_SnapshotName ) ;
renderEntity . callback = idBrittleFracture : : ModelCallback ;
renderEntity . noShadow = true ;
renderEntity . noSelfShadow = true ;
renderEntity . noDynamicInteractions = false ;
}
/*
= = = = = = = = = = = = = = = =
idBrittleFracture : : AddShard
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idBrittleFracture : : AddShard ( idClipModel * clipModel , idFixedWinding & w )
{
shard_t * shard = new ( TAG_PARTICLE ) shard_t ;
2012-11-26 18:58:24 +00:00
shard - > clipModel = clipModel ;
shard - > droppedTime = - 1 ;
shard - > winding = w ;
shard - > decals . Clear ( ) ;
shard - > edgeHasNeighbour . AssureSize ( w . GetNumPoints ( ) , false ) ;
shard - > neighbours . Clear ( ) ;
shard - > atEdge = false ;
shards . Append ( shard ) ;
}
/*
= = = = = = = = = = = = = = = =
idBrittleFracture : : RemoveShard
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idBrittleFracture : : RemoveShard ( int index )
{
2012-11-26 18:58:24 +00:00
int i ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
delete shards [ index ] ;
shards . RemoveIndex ( index ) ;
physicsObj . RemoveIndex ( index ) ;
2012-11-28 15:47:07 +00:00
for ( i = index ; i < shards . Num ( ) ; i + + )
{
2012-11-26 18:58:24 +00:00
shards [ i ] - > clipModel - > SetId ( i ) ;
}
}
/*
= = = = = = = = = = = = = = = =
idBrittleFracture : : UpdateRenderEntity
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idBrittleFracture : : UpdateRenderEntity ( renderEntity_s * renderEntity , const renderView_t * renderView ) const
{
2012-11-26 18:58:24 +00:00
int i , j , k , n , msec , numTris , numDecalTris ;
float fade ;
dword packedColor ;
2012-11-28 15:47:07 +00:00
srfTriangles_t * tris , * decalTris ;
2012-11-26 18:58:24 +00:00
modelSurface_t surface ;
2012-11-28 15:47:07 +00:00
idDrawVert * v ;
2012-11-26 18:58:24 +00:00
idPlane plane ;
idMat3 tangents ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// this may be triggered by a model trace or other non-view related source,
// to which we should look like an empty model
2012-11-28 15:47:07 +00:00
if ( ! renderView )
{
2012-11-26 18:58:24 +00:00
return false ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// don't regenerate it if it is current
2012-11-28 15:47:07 +00:00
if ( lastRenderEntityUpdate = = gameLocal . time | | ! changed )
{
2012-11-26 18:58:24 +00:00
return false ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
lastRenderEntityUpdate = gameLocal . time ;
changed = false ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
numTris = 0 ;
numDecalTris = 0 ;
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < shards . Num ( ) ; i + + )
{
2012-11-26 18:58:24 +00:00
n = shards [ i ] - > winding . GetNumPoints ( ) ;
2012-11-28 15:47:07 +00:00
if ( n > 2 )
{
2012-11-26 18:58:24 +00:00
numTris + = n - 2 ;
}
2012-11-28 15:47:07 +00:00
for ( k = 0 ; k < shards [ i ] - > decals . Num ( ) ; k + + )
{
2012-11-26 18:58:24 +00:00
n = shards [ i ] - > decals [ k ] - > GetNumPoints ( ) ;
2012-11-28 15:47:07 +00:00
if ( n > 2 )
{
2012-11-26 18:58:24 +00:00
numDecalTris + = n - 2 ;
}
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// FIXME: re-use model surfaces
renderEntity - > hModel - > InitEmpty ( brittleFracture_SnapshotName ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// allocate triangle surfaces for the fractures and decals
tris = renderEntity - > hModel - > AllocSurfaceTriangles ( numTris * 3 , material - > ShouldCreateBackSides ( ) ? numTris * 6 : numTris * 3 ) ;
decalTris = renderEntity - > hModel - > AllocSurfaceTriangles ( numDecalTris * 3 , decalMaterial - > ShouldCreateBackSides ( ) ? numDecalTris * 6 : numDecalTris * 3 ) ;
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < shards . Num ( ) ; i + + )
{
const idVec3 & origin = shards [ i ] - > clipModel - > GetOrigin ( ) ;
const idMat3 & axis = shards [ i ] - > clipModel - > GetAxis ( ) ;
2012-11-26 18:58:24 +00:00
fade = 1.0f ;
2012-11-28 15:47:07 +00:00
if ( shards [ i ] - > droppedTime > = 0 )
{
2012-11-26 18:58:24 +00:00
msec = gameLocal . time - shards [ i ] - > droppedTime - SHARD_FADE_START ;
2012-11-28 15:47:07 +00:00
if ( msec > 0 )
{
fade = 1.0f - ( float ) msec / ( SHARD_ALIVE_TIME - SHARD_FADE_START ) ;
2012-11-26 18:58:24 +00:00
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
packedColor = PackColor ( idVec4 ( renderEntity - > shaderParms [ SHADERPARM_RED ] * fade ,
2012-11-28 15:47:07 +00:00
renderEntity - > shaderParms [ SHADERPARM_GREEN ] * fade ,
renderEntity - > shaderParms [ SHADERPARM_BLUE ] * fade ,
fade ) ) ;
const idWinding & winding = shards [ i ] - > winding ;
2012-11-26 18:58:24 +00:00
winding . GetPlane ( plane ) ;
tangents = ( plane . Normal ( ) * axis ) . ToMat3 ( ) ;
2012-11-28 15:47:07 +00:00
for ( j = 2 ; j < winding . GetNumPoints ( ) ; j + + )
{
2012-11-26 18:58:24 +00:00
v = & tris - > verts [ tris - > numVerts + + ] ;
v - > Clear ( ) ;
v - > xyz = origin + winding [ 0 ] . ToVec3 ( ) * axis ;
v - > SetTexCoord ( winding [ 0 ] . s , winding [ 0 ] . t ) ;
v - > SetNormal ( tangents [ 0 ] ) ;
v - > SetTangent ( tangents [ 1 ] ) ;
v - > SetBiTangent ( tangents [ 2 ] ) ;
v - > SetColor ( packedColor ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
v = & tris - > verts [ tris - > numVerts + + ] ;
v - > Clear ( ) ;
2012-11-28 15:47:07 +00:00
v - > xyz = origin + winding [ j - 1 ] . ToVec3 ( ) * axis ;
v - > SetTexCoord ( winding [ j - 1 ] . s , winding [ j - 1 ] . t ) ;
2012-11-26 18:58:24 +00:00
v - > SetNormal ( tangents [ 0 ] ) ;
v - > SetTangent ( tangents [ 1 ] ) ;
v - > SetBiTangent ( tangents [ 2 ] ) ;
v - > SetColor ( packedColor ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
v = & tris - > verts [ tris - > numVerts + + ] ;
v - > Clear ( ) ;
v - > xyz = origin + winding [ j ] . ToVec3 ( ) * axis ;
v - > SetTexCoord ( winding [ j ] . s , winding [ j ] . t ) ;
v - > SetNormal ( tangents [ 0 ] ) ;
v - > SetTangent ( tangents [ 1 ] ) ;
v - > SetBiTangent ( tangents [ 2 ] ) ;
v - > SetColor ( packedColor ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
tris - > indexes [ tris - > numIndexes + + ] = tris - > numVerts - 3 ;
tris - > indexes [ tris - > numIndexes + + ] = tris - > numVerts - 2 ;
tris - > indexes [ tris - > numIndexes + + ] = tris - > numVerts - 1 ;
2012-11-28 15:47:07 +00:00
if ( material - > ShouldCreateBackSides ( ) )
{
2012-11-26 18:58:24 +00:00
tris - > indexes [ tris - > numIndexes + + ] = tris - > numVerts - 2 ;
tris - > indexes [ tris - > numIndexes + + ] = tris - > numVerts - 3 ;
tris - > indexes [ tris - > numIndexes + + ] = tris - > numVerts - 1 ;
}
}
2012-11-28 15:47:07 +00:00
for ( k = 0 ; k < shards [ i ] - > decals . Num ( ) ; k + + )
{
const idWinding & decalWinding = * shards [ i ] - > decals [ k ] ;
for ( j = 2 ; j < decalWinding . GetNumPoints ( ) ; j + + )
{
2012-11-26 18:58:24 +00:00
v = & decalTris - > verts [ decalTris - > numVerts + + ] ;
v - > Clear ( ) ;
v - > xyz = origin + decalWinding [ 0 ] . ToVec3 ( ) * axis ;
v - > SetTexCoord ( decalWinding [ 0 ] . s , decalWinding [ 0 ] . t ) ;
v - > SetNormal ( tangents [ 0 ] ) ;
v - > SetTangent ( tangents [ 1 ] ) ;
v - > SetBiTangent ( tangents [ 2 ] ) ;
v - > SetColor ( packedColor ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
v = & decalTris - > verts [ decalTris - > numVerts + + ] ;
v - > Clear ( ) ;
2012-11-28 15:47:07 +00:00
v - > xyz = origin + decalWinding [ j - 1 ] . ToVec3 ( ) * axis ;
v - > SetTexCoord ( decalWinding [ j - 1 ] . s , decalWinding [ j - 1 ] . t ) ;
2012-11-26 18:58:24 +00:00
v - > SetNormal ( tangents [ 0 ] ) ;
v - > SetTangent ( tangents [ 1 ] ) ;
v - > SetBiTangent ( tangents [ 2 ] ) ;
v - > SetColor ( packedColor ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
v = & decalTris - > verts [ decalTris - > numVerts + + ] ;
v - > Clear ( ) ;
v - > xyz = origin + decalWinding [ j ] . ToVec3 ( ) * axis ;
v - > SetTexCoord ( decalWinding [ j ] . s , decalWinding [ j ] . t ) ;
v - > SetNormal ( tangents [ 0 ] ) ;
v - > SetTangent ( tangents [ 1 ] ) ;
v - > SetBiTangent ( tangents [ 2 ] ) ;
v - > SetColor ( packedColor ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
decalTris - > indexes [ decalTris - > numIndexes + + ] = decalTris - > numVerts - 3 ;
decalTris - > indexes [ decalTris - > numIndexes + + ] = decalTris - > numVerts - 2 ;
decalTris - > indexes [ decalTris - > numIndexes + + ] = decalTris - > numVerts - 1 ;
2012-11-28 15:47:07 +00:00
if ( decalMaterial - > ShouldCreateBackSides ( ) )
{
2012-11-26 18:58:24 +00:00
decalTris - > indexes [ decalTris - > numIndexes + + ] = decalTris - > numVerts - 2 ;
decalTris - > indexes [ decalTris - > numIndexes + + ] = decalTris - > numVerts - 3 ;
decalTris - > indexes [ decalTris - > numIndexes + + ] = decalTris - > numVerts - 1 ;
}
}
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
tris - > tangentsCalculated = true ;
decalTris - > tangentsCalculated = true ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
SIMDProcessor - > MinMax ( tris - > bounds [ 0 ] , tris - > bounds [ 1 ] , tris - > verts , tris - > numVerts ) ;
SIMDProcessor - > MinMax ( decalTris - > bounds [ 0 ] , decalTris - > bounds [ 1 ] , decalTris - > verts , decalTris - > numVerts ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
memset ( & surface , 0 , sizeof ( surface ) ) ;
surface . shader = material ;
surface . id = 0 ;
surface . geometry = tris ;
renderEntity - > hModel - > AddSurface ( surface ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
memset ( & surface , 0 , sizeof ( surface ) ) ;
surface . shader = decalMaterial ;
surface . id = 1 ;
surface . geometry = decalTris ;
renderEntity - > hModel - > AddSurface ( surface ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return true ;
}
/*
= = = = = = = = = = = = = = = =
idBrittleFracture : : ModelCallback
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idBrittleFracture : : ModelCallback ( renderEntity_s * renderEntity , const renderView_t * renderView )
{
const idBrittleFracture * ent ;
ent = static_cast < idBrittleFracture * > ( gameLocal . entities [ renderEntity - > entityNum ] ) ;
if ( ent = = NULL )
{
2012-11-26 18:58:24 +00:00
gameLocal . Error ( " idBrittleFracture::ModelCallback: callback with NULL game entity " ) ;
return false ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return ent - > UpdateRenderEntity ( renderEntity , renderView ) ;
}
/*
= = = = = = = = = = = = = = = =
idBrittleFracture : : Present
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idBrittleFracture : : Present ( )
{
2012-11-26 18:58:24 +00:00
// don't present to the renderer if the entity hasn't changed
2012-11-28 15:47:07 +00:00
if ( ! ( thinkFlags & TH_UPDATEVISUALS ) )
{
2012-11-26 18:58:24 +00:00
return ;
}
BecomeInactive ( TH_UPDATEVISUALS ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
renderEntity . bounds = bounds ;
renderEntity . origin . Zero ( ) ;
renderEntity . axis . Identity ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// force an update because the bounds/origin/axis may stay the same while the model changes
renderEntity . forceUpdate = true ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// add to refresh list
2012-11-28 15:47:07 +00:00
if ( modelDefHandle = = - 1 )
{
2012-11-26 18:58:24 +00:00
modelDefHandle = gameRenderWorld - > AddEntityDef ( & renderEntity ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
gameRenderWorld - > UpdateEntityDef ( modelDefHandle , & renderEntity ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
changed = true ;
}
/*
= = = = = = = = = = = = = = = =
idBrittleFracture : : Think
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idBrittleFracture : : Think ( )
{
2012-11-26 18:58:24 +00:00
int i , startTime , endTime , droppedTime ;
2012-11-28 15:47:07 +00:00
shard_t * shard ;
2012-11-26 18:58:24 +00:00
bool atRest = true , fading = false ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// remove overdue shards
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < shards . Num ( ) ; i + + )
{
2012-11-26 18:58:24 +00:00
droppedTime = shards [ i ] - > droppedTime ;
2012-11-28 15:47:07 +00:00
if ( droppedTime ! = - 1 )
{
if ( gameLocal . time - droppedTime > SHARD_ALIVE_TIME )
{
2012-11-26 18:58:24 +00:00
RemoveShard ( i ) ;
i - - ;
}
fading = true ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// remove the entity when nothing is visible
2012-11-28 15:47:07 +00:00
if ( ! shards . Num ( ) )
{
2012-11-26 18:58:24 +00:00
PostEventMS ( & EV_Remove , 0 ) ;
return ;
}
2012-11-28 15:47:07 +00:00
if ( thinkFlags & TH_PHYSICS )
{
2012-11-26 18:58:24 +00:00
startTime = gameLocal . previousTime ;
endTime = gameLocal . time ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// run physics on shards
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < shards . Num ( ) ; i + + )
{
2012-11-26 18:58:24 +00:00
shard = shards [ i ] ;
2012-11-28 15:47:07 +00:00
if ( shard - > droppedTime = = - 1 )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
shard - > physicsObj . Evaluate ( endTime - startTime , endTime ) ;
2012-11-28 15:47:07 +00:00
if ( ! shard - > physicsObj . IsAtRest ( ) )
{
2012-11-26 18:58:24 +00:00
atRest = false ;
}
}
2012-11-28 15:47:07 +00:00
if ( atRest )
{
2012-11-26 18:58:24 +00:00
BecomeInactive ( TH_PHYSICS ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
BecomeActive ( TH_PHYSICS ) ;
}
}
2012-11-28 15:47:07 +00:00
if ( ! atRest | | bounds . IsCleared ( ) )
{
2012-11-26 18:58:24 +00:00
bounds . Clear ( ) ;
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < shards . Num ( ) ; i + + )
{
2012-11-26 18:58:24 +00:00
bounds . AddBounds ( shards [ i ] - > clipModel - > GetAbsBounds ( ) ) ;
}
}
2012-11-28 15:47:07 +00:00
if ( fading )
{
2012-11-26 18:58:24 +00:00
BecomeActive ( TH_UPDATEVISUALS | TH_THINK ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
BecomeInactive ( TH_THINK ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
RunPhysics ( ) ;
Present ( ) ;
}
/*
= = = = = = = = = = = = = = = =
idBrittleFracture : : ApplyImpulse
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idBrittleFracture : : ApplyImpulse ( idEntity * ent , int id , const idVec3 & point , const idVec3 & impulse )
{
2012-11-26 18:58:24 +00:00
2012-11-28 15:47:07 +00:00
if ( id < 0 | | id > = shards . Num ( ) )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
if ( shards [ id ] - > droppedTime ! = - 1 )
{
2012-11-26 18:58:24 +00:00
shards [ id ] - > physicsObj . ApplyImpulse ( 0 , point , impulse ) ;
2012-11-28 15:47:07 +00:00
}
else if ( health < = 0 & & ! disableFracture )
{
2012-11-26 18:58:24 +00:00
Shatter ( point , impulse , gameLocal . time ) ;
}
}
/*
= = = = = = = = = = = = = = = =
idBrittleFracture : : AddForce
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idBrittleFracture : : AddForce ( idEntity * ent , int id , const idVec3 & point , const idVec3 & force )
{
2012-11-26 18:58:24 +00:00
2012-11-28 15:47:07 +00:00
if ( id < 0 | | id > = shards . Num ( ) )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
if ( shards [ id ] - > droppedTime ! = - 1 )
{
2012-11-26 18:58:24 +00:00
shards [ id ] - > physicsObj . AddForce ( 0 , point , force ) ;
2012-11-28 15:47:07 +00:00
}
else if ( health < = 0 & & ! disableFracture )
{
2012-11-26 18:58:24 +00:00
Shatter ( point , force , gameLocal . time ) ;
}
}
/*
= = = = = = = = = = = = = = = =
idBrittleFracture : : ProjectDecal
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idBrittleFracture : : ProjectDecal ( const idVec3 & point , const idVec3 & dir , const int time , const char * damageDefName )
{
2012-11-26 18:58:24 +00:00
int i , j , bits , clipBits ;
float a , c , s ;
idVec2 st [ MAX_POINTS_ON_WINDING ] ;
idVec3 origin ;
idMat3 axis , axistemp ;
idPlane textureAxis [ 2 ] ;
2012-11-28 15:47:07 +00:00
if ( common - > IsServer ( ) )
{
2012-11-26 18:58:24 +00:00
idBitMsg msg ;
byte msgBuf [ MAX_EVENT_PARAM_SIZE ] ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
msg . InitWrite ( msgBuf , sizeof ( msgBuf ) ) ;
msg . BeginWriting ( ) ;
msg . WriteFloat ( point [ 0 ] ) ;
msg . WriteFloat ( point [ 1 ] ) ;
msg . WriteFloat ( point [ 2 ] ) ;
msg . WriteFloat ( dir [ 0 ] ) ;
msg . WriteFloat ( dir [ 1 ] ) ;
msg . WriteFloat ( dir [ 2 ] ) ;
ServerSendEvent ( EVENT_PROJECT_DECAL , & msg , true ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// store the event so we can rebuilt the fracture after loading a save
fractureEvent_s fractureEvent ;
fractureEvent . eventType = EVENT_PROJECT_DECAL ;
fractureEvent . point = point ;
fractureEvent . vector = dir ;
storedEvents . Append ( fractureEvent ) ;
2012-11-28 15:47:07 +00:00
if ( time > = gameLocal . time )
{
2012-11-26 18:58:24 +00:00
// try to get the sound from the damage def
2012-11-28 15:47:07 +00:00
const idDeclEntityDef * damageDef = NULL ;
const idSoundShader * sndShader = NULL ;
if ( damageDefName )
{
2012-11-26 18:58:24 +00:00
damageDef = gameLocal . FindEntityDef ( damageDefName , false ) ;
2012-11-28 15:47:07 +00:00
if ( damageDef )
{
const char * sndName = damageDef - > dict . GetString ( " snd_shatter " , " " ) ;
if ( sndName [ 0 ] ! = 0 )
{
2012-11-26 18:58:24 +00:00
sndShader = declManager - > FindSound ( sndName ) ;
}
}
}
2012-11-28 15:47:07 +00:00
if ( sndShader )
{
2012-11-26 18:58:24 +00:00
StartSoundShader ( sndShader , SND_CHANNEL_ANY , 0 , false , NULL ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
StartSound ( " snd_bullethole " , SND_CHANNEL_ANY , 0 , false , NULL ) ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
a = gameLocal . random . RandomFloat ( ) * idMath : : TWO_PI ;
c = cos ( a ) ;
s = - sin ( a ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
axis [ 2 ] = - dir ;
axis [ 2 ] . Normalize ( ) ;
axis [ 2 ] . NormalVectors ( axistemp [ 0 ] , axistemp [ 1 ] ) ;
axis [ 0 ] = axistemp [ 0 ] * c + axistemp [ 1 ] * s ;
axis [ 1 ] = axistemp [ 0 ] * s + axistemp [ 1 ] * - c ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
textureAxis [ 0 ] = axis [ 0 ] * ( 1.0f / decalSize ) ;
textureAxis [ 0 ] [ 3 ] = - ( point * textureAxis [ 0 ] . Normal ( ) ) + 0.5f ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
textureAxis [ 1 ] = axis [ 1 ] * ( 1.0f / decalSize ) ;
textureAxis [ 1 ] [ 3 ] = - ( point * textureAxis [ 1 ] . Normal ( ) ) + 0.5f ;
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < shards . Num ( ) ; i + + )
{
idFixedWinding & winding = shards [ i ] - > winding ;
2012-11-26 18:58:24 +00:00
origin = shards [ i ] - > clipModel - > GetOrigin ( ) ;
axis = shards [ i ] - > clipModel - > GetAxis ( ) ;
float d0 , d1 ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
clipBits = - 1 ;
2012-11-28 15:47:07 +00:00
for ( j = 0 ; j < winding . GetNumPoints ( ) ; j + + )
{
2012-11-26 18:58:24 +00:00
idVec3 p = origin + winding [ j ] . ToVec3 ( ) * axis ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
st [ j ] . x = d0 = textureAxis [ 0 ] . Distance ( p ) ;
st [ j ] . y = d1 = textureAxis [ 1 ] . Distance ( p ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
bits = IEEE_FLT_SIGNBITSET ( d0 ) ;
d0 = 1.0f - d0 ;
bits | = IEEE_FLT_SIGNBITSET ( d1 ) < < 2 ;
d1 = 1.0f - d1 ;
bits | = IEEE_FLT_SIGNBITSET ( d0 ) < < 1 ;
bits | = IEEE_FLT_SIGNBITSET ( d1 ) < < 3 ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
clipBits & = bits ;
}
2012-11-28 15:47:07 +00:00
if ( clipBits )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
idFixedWinding * decal = new ( TAG_PARTICLE ) idFixedWinding ;
2012-11-26 18:58:24 +00:00
shards [ i ] - > decals . Append ( decal ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
decal - > SetNumPoints ( winding . GetNumPoints ( ) ) ;
2012-11-28 15:47:07 +00:00
for ( j = 0 ; j < winding . GetNumPoints ( ) ; j + + )
{
( * decal ) [ j ] . ToVec3 ( ) = winding [ j ] . ToVec3 ( ) ;
( * decal ) [ j ] . s = st [ j ] . x ;
( * decal ) [ j ] . t = st [ j ] . y ;
2012-11-26 18:58:24 +00:00
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
BecomeActive ( TH_UPDATEVISUALS ) ;
}
/*
= = = = = = = = = = = = = = = =
idBrittleFracture : : DropShard
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idBrittleFracture : : DropShard ( shard_t * shard , const idVec3 & point , const idVec3 & dir , const float impulse , const int time )
{
2012-11-26 18:58:24 +00:00
int i , j , clipModelId ;
float dist , f ;
idVec3 dir2 , origin ;
idMat3 axis ;
2012-11-28 15:47:07 +00:00
shard_t * neighbour ;
2012-11-26 18:58:24 +00:00
// don't display decals on dropped shards
shard - > decals . DeleteContents ( true ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// remove neighbour pointers of neighbours pointing to this shard
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < shard - > neighbours . Num ( ) ; i + + )
{
2012-11-26 18:58:24 +00:00
neighbour = shard - > neighbours [ i ] ;
2012-11-28 15:47:07 +00:00
for ( j = 0 ; j < neighbour - > neighbours . Num ( ) ; j + + )
{
if ( neighbour - > neighbours [ j ] = = shard )
{
2012-11-26 18:58:24 +00:00
neighbour - > neighbours . RemoveIndex ( j ) ;
break ;
}
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// remove neighbour pointers
shard - > neighbours . Clear ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// remove the clip model from the static physics object
clipModelId = shard - > clipModel - > GetId ( ) ;
physicsObj . SetClipModel ( NULL , 1.0f , clipModelId , false ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
origin = shard - > clipModel - > GetOrigin ( ) ;
axis = shard - > clipModel - > GetAxis ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// set the dropped time for fading
shard - > droppedTime = time ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
dir2 = origin - point ;
dist = dir2 . Normalize ( ) ;
2012-11-28 15:47:07 +00:00
f = dist > maxShatterRadius ? 1.0f : idMath : : Sqrt ( idMath : : Fabs ( dist - minShatterRadius ) ) * ( 1.0f / idMath : : Sqrt ( idMath : : Fabs ( maxShatterRadius - minShatterRadius ) ) ) ;
2012-11-26 18:58:24 +00:00
// setup the physics
shard - > physicsObj . SetSelf ( this ) ;
shard - > physicsObj . SetClipModel ( shard - > clipModel , density ) ;
shard - > physicsObj . SetMass ( shardMass ) ;
shard - > physicsObj . SetOrigin ( origin ) ;
shard - > physicsObj . SetAxis ( axis ) ;
shard - > physicsObj . SetBouncyness ( bouncyness ) ;
shard - > physicsObj . SetFriction ( 0.6f , 0.6f , friction ) ;
shard - > physicsObj . SetGravity ( gameLocal . GetGravity ( ) ) ;
shard - > physicsObj . SetContents ( CONTENTS_RENDERMODEL ) ;
shard - > physicsObj . SetClipMask ( MASK_SOLID | CONTENTS_MOVEABLECLIP ) ;
shard - > physicsObj . ApplyImpulse ( 0 , origin , impulse * linearVelocityScale * dir ) ;
shard - > physicsObj . SetAngularVelocity ( dir . Cross ( dir2 ) * ( f * angularVelocityScale ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
shard - > clipModel - > SetId ( clipModelId ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
BecomeActive ( TH_PHYSICS ) ;
}
/*
= = = = = = = = = = = = = = = =
idBrittleFracture : : Shatter
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idBrittleFracture : : Shatter ( const idVec3 & point , const idVec3 & impulse , const int time )
{
2012-11-26 18:58:24 +00:00
int i ;
idVec3 dir ;
2012-11-28 15:47:07 +00:00
shard_t * shard ;
2012-11-26 18:58:24 +00:00
float m ;
2012-11-28 15:47:07 +00:00
if ( common - > IsServer ( ) )
{
2012-11-26 18:58:24 +00:00
idBitMsg msg ;
byte msgBuf [ MAX_EVENT_PARAM_SIZE ] ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
msg . InitWrite ( msgBuf , sizeof ( msgBuf ) ) ;
msg . BeginWriting ( ) ;
msg . WriteFloat ( point [ 0 ] ) ;
msg . WriteFloat ( point [ 1 ] ) ;
msg . WriteFloat ( point [ 2 ] ) ;
msg . WriteFloat ( impulse [ 0 ] ) ;
msg . WriteFloat ( impulse [ 1 ] ) ;
msg . WriteFloat ( impulse [ 2 ] ) ;
ServerSendEvent ( EVENT_SHATTER , & msg , true ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Store off the event so we can rebuilt the object if we reload a savegame
fractureEvent_s fractureEvent ;
fractureEvent . eventType = EVENT_SHATTER ;
fractureEvent . point = point ;
fractureEvent . vector = impulse ;
storedEvents . Append ( fractureEvent ) ;
2012-11-28 15:47:07 +00:00
if ( time > ( gameLocal . time - SHARD_ALIVE_TIME ) )
{
2012-11-26 18:58:24 +00:00
StartSound ( " snd_shatter " , SND_CHANNEL_ANY , 0 , false , NULL ) ;
}
2012-11-28 15:47:07 +00:00
if ( ! IsBroken ( ) )
{
2012-11-26 18:58:24 +00:00
Break ( ) ;
}
2012-11-28 15:47:07 +00:00
if ( fxFracture . Length ( ) )
{
2012-11-26 18:58:24 +00:00
idEntityFx : : StartFx ( fxFracture , & point , & GetPhysics ( ) - > GetAxis ( ) , this , true ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
dir = impulse ;
m = dir . Normalize ( ) ;
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < shards . Num ( ) ; i + + )
{
2012-11-26 18:58:24 +00:00
shard = shards [ i ] ;
2012-11-28 15:47:07 +00:00
if ( shard - > droppedTime ! = - 1 )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
if ( ( shard - > clipModel - > GetOrigin ( ) - point ) . LengthSqr ( ) > Square ( maxShatterRadius ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
DropShard ( shard , point , dir , m , time ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
DropFloatingIslands ( point , impulse , time ) ;
}
/*
= = = = = = = = = = = = = = = =
idBrittleFracture : : DropFloatingIslands
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idBrittleFracture : : DropFloatingIslands ( const idVec3 & point , const idVec3 & impulse , const int time )
{
2012-11-26 18:58:24 +00:00
int i , j , numIslands ;
int queueStart , queueEnd ;
2012-11-28 15:47:07 +00:00
shard_t * curShard , * nextShard , * * queue ;
2012-11-26 18:58:24 +00:00
bool touchesEdge ;
idVec3 dir ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
dir = impulse ;
dir . Normalize ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
numIslands = 0 ;
2012-11-28 15:47:07 +00:00
queue = ( shard_t * * ) _alloca16 ( shards . Num ( ) * sizeof ( shard_t * * ) ) ;
for ( i = 0 ; i < shards . Num ( ) ; i + + )
{
2012-11-26 18:58:24 +00:00
shards [ i ] - > islandNum = 0 ;
}
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < shards . Num ( ) ; i + + )
{
if ( shards [ i ] - > droppedTime ! = - 1 )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
if ( shards [ i ] - > islandNum )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
queueStart = 0 ;
2012-11-26 18:58:24 +00:00
queueEnd = 1 ;
queue [ 0 ] = shards [ i ] ;
2012-11-28 15:47:07 +00:00
shards [ i ] - > islandNum = numIslands + 1 ;
2012-11-26 18:58:24 +00:00
touchesEdge = false ;
2012-11-28 15:47:07 +00:00
if ( shards [ i ] - > atEdge )
{
2012-11-26 18:58:24 +00:00
touchesEdge = true ;
}
2012-11-28 15:47:07 +00:00
for ( curShard = queue [ queueStart ] ; queueStart < queueEnd ; curShard = queue [ + + queueStart ] )
{
for ( j = 0 ; j < curShard - > neighbours . Num ( ) ; j + + )
{
2012-11-26 18:58:24 +00:00
nextShard = curShard - > neighbours [ j ] ;
2012-11-28 15:47:07 +00:00
if ( nextShard - > droppedTime ! = - 1 )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
if ( nextShard - > islandNum )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
queue [ queueEnd + + ] = nextShard ;
2012-11-28 15:47:07 +00:00
nextShard - > islandNum = numIslands + 1 ;
if ( nextShard - > atEdge )
{
2012-11-26 18:58:24 +00:00
touchesEdge = true ;
}
}
}
numIslands + + ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// if the island is not connected to the world at any edges
2012-11-28 15:47:07 +00:00
if ( ! touchesEdge )
{
for ( j = 0 ; j < queueEnd ; j + + )
{
2012-11-26 18:58:24 +00:00
DropShard ( queue [ j ] , point , dir , 0.0f , time ) ;
}
}
}
}
/*
= = = = = = = = = = = = = = = =
idBrittleFracture : : Break
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idBrittleFracture : : Break ( )
{
2012-11-26 18:58:24 +00:00
fl . takedamage = false ;
physicsObj . SetContents ( CONTENTS_RENDERMODEL | CONTENTS_TRIGGER ) ;
}
/*
= = = = = = = = = = = = = = = =
idBrittleFracture : : IsBroken
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idBrittleFracture : : IsBroken ( ) const
{
2012-11-26 18:58:24 +00:00
return ( fl . takedamage = = false ) ;
}
/*
= = = = = = = = = = = = = = = =
idBrittleFracture : : Killed
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idBrittleFracture : : Killed ( idEntity * inflictor , idEntity * attacker , int damage , const idVec3 & dir , int location )
{
if ( ! disableFracture )
{
2012-11-26 18:58:24 +00:00
ActivateTargets ( this ) ;
Break ( ) ;
}
}
/*
= = = = = = = = = = = = = = = =
idBrittleFracture : : AddDamageEffect
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idBrittleFracture : : AddDamageEffect ( const trace_t & collision , const idVec3 & velocity , const char * damageDefName )
{
if ( ! disableFracture )
{
2012-11-26 18:58:24 +00:00
ProjectDecal ( collision . c . point , collision . c . normal , gameLocal . time , damageDefName ) ;
}
}
static float fractureSplitTable [ ] = { 1365.123f , 5.324f , 1125.34f , 50.34f , 555.252f , 100.12f , 230.53f , 10000.87f , 10000.87f } ;
/*
= = = = = = = = = = = = = = = =
idBrittleFracture : : Fracture_r
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idBrittleFracture : : Fracture_r ( idFixedWinding & w , idRandom2 & random )
{
2012-11-26 18:58:24 +00:00
int i , j , bestPlane ;
float a , c , s , dist , bestDist ;
idVec3 origin ;
idPlane windingPlane , splitPlanes [ 2 ] ;
idMat3 axis , axistemp ;
idFixedWinding back ;
idTraceModel trm ;
2012-11-28 15:47:07 +00:00
idClipModel * clipModel ;
while ( 1 )
{
2012-11-26 18:58:24 +00:00
origin = w . GetCenter ( ) ;
w . GetPlane ( windingPlane ) ;
2012-11-28 15:47:07 +00:00
if ( w . GetArea ( ) < maxShardArea )
{
2012-11-26 18:58:24 +00:00
break ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// randomly create a split plane
axis [ 2 ] = windingPlane . Normal ( ) ;
2012-11-28 15:47:07 +00:00
if ( isXraySurface )
{
2012-11-26 18:58:24 +00:00
a = idMath : : TWO_PI / 2.f ;
}
2012-11-28 15:47:07 +00:00
else
{
2012-11-26 18:58:24 +00:00
a = random . RandomFloat ( ) * idMath : : TWO_PI ;
}
c = cos ( a ) ;
s = - sin ( a ) ;
axis [ 2 ] . NormalVectors ( axistemp [ 0 ] , axistemp [ 1 ] ) ;
axis [ 0 ] = axistemp [ 0 ] * c + axistemp [ 1 ] * s ;
axis [ 1 ] = axistemp [ 0 ] * s + axistemp [ 1 ] * - c ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// get the best split plane
bestDist = 0.0f ;
bestPlane = 0 ;
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < 2 ; i + + )
{
2012-11-26 18:58:24 +00:00
splitPlanes [ i ] . SetNormal ( axis [ i ] ) ;
splitPlanes [ i ] . FitThroughPoint ( origin ) ;
2012-11-28 15:47:07 +00:00
for ( j = 0 ; j < w . GetNumPoints ( ) ; j + + )
{
2012-11-26 18:58:24 +00:00
dist = splitPlanes [ i ] . Distance ( w [ j ] . ToVec3 ( ) ) ;
2012-11-28 15:47:07 +00:00
if ( dist > bestDist )
{
2012-11-26 18:58:24 +00:00
bestDist = dist ;
bestPlane = i ;
}
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// split the winding
2012-11-28 15:47:07 +00:00
if ( ! w . Split ( & back , splitPlanes [ bestPlane ] ) )
{
2012-11-26 18:58:24 +00:00
break ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// recursively create shards for the back winding
Fracture_r ( back , random ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// translate the winding to it's center
origin = w . GetCenter ( ) ;
2012-11-28 15:47:07 +00:00
for ( j = 0 ; j < w . GetNumPoints ( ) ; j + + )
{
2012-11-26 18:58:24 +00:00
w [ j ] . ToVec3 ( ) - = origin ;
}
w . RemoveEqualPoints ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
trm . SetupPolygon ( w ) ;
trm . Shrink ( CM_CLIP_EPSILON ) ;
2012-11-28 15:47:07 +00:00
clipModel = new ( TAG_PHYSICS ) idClipModel ( trm , false ) ;
2012-11-26 18:58:24 +00:00
physicsObj . SetClipModel ( clipModel , 1.0f , shards . Num ( ) ) ;
physicsObj . SetOrigin ( GetPhysics ( ) - > GetOrigin ( ) + origin , shards . Num ( ) ) ;
physicsObj . SetAxis ( GetPhysics ( ) - > GetAxis ( ) , shards . Num ( ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
AddShard ( clipModel , w ) ;
}
/*
= = = = = = = = = = = = = = = =
CompareVec5
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool CompareVec5 ( const idVec5 & v0 , const idVec5 & v1 )
{
2012-11-26 18:58:24 +00:00
float dx = v0 . x - v1 . x ;
float dy = v0 . y - v1 . y ;
float dz = v0 . z - v1 . z ;
float ds = v0 . s - v1 . s ;
float dt = v0 . t - v1 . t ;
float d = ( dx * dx ) + ( dy * dy ) + ( dz * dz ) + ( ds * ds ) + ( dt + dt ) ;
return ( d = = 0.0f ) ;
}
/*
= = = = = = = = = = = = = = = =
idBrittleFracture : : CreateFractures
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idBrittleFracture : : CreateFractures ( const idRenderModel * renderModel )
{
if ( ! renderModel | | renderModel - > NumSurfaces ( ) < 1 )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
physicsObj . SetSelf ( this ) ;
physicsObj . SetOrigin ( GetPhysics ( ) - > GetOrigin ( ) , 0 ) ;
physicsObj . SetAxis ( GetPhysics ( ) - > GetAxis ( ) , 0 ) ;
2012-11-28 15:47:07 +00:00
const modelSurface_t * surf = renderModel - > Surface ( 0 ) ;
2012-11-26 18:58:24 +00:00
material = surf - > shader ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idMat3 physAxis ;
physAxis = physicsObj . GetAxis ( ) ;
2012-11-28 15:47:07 +00:00
if ( isXraySurface )
{
2012-11-26 18:58:24 +00:00
idFixedWinding w ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < 4 ; i + + )
{
const idDrawVert * v = & surf - > geometry - > verts [ i ] ;
2012-11-26 18:58:24 +00:00
w . AddPoint ( idVec5 ( v - > xyz , v - > GetTexCoord ( ) ) ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idRandom2 random ( entityNumber ) ;
Fracture_r ( w , random ) ;
2012-11-28 15:47:07 +00:00
}
else
2012-11-26 18:58:24 +00:00
{
2012-11-28 15:47:07 +00:00
const idDrawVert * verts = surf - > geometry - > verts ;
triIndex_t * indexes = surf - > geometry - > indexes ;
for ( int j = 0 ; j < surf - > geometry - > numIndexes ; j + = 3 )
{
2012-11-26 18:58:24 +00:00
int i0 = indexes [ j + 0 ] ;
int i1 = indexes [ j + 1 ] ;
int i2 = indexes [ j + 2 ] ;
idFixedWinding w ;
w . AddPoint ( idVec5 ( verts [ i2 ] . xyz , verts [ i2 ] . GetTexCoord ( ) ) ) ;
w . AddPoint ( idVec5 ( verts [ i1 ] . xyz , verts [ i1 ] . GetTexCoord ( ) ) ) ;
w . AddPoint ( idVec5 ( verts [ i0 ] . xyz , verts [ i0 ] . GetTexCoord ( ) ) ) ;
idPlane p1 ;
w . GetPlane ( p1 ) ;
2012-11-28 15:47:07 +00:00
for ( int k = j + 3 ; k < surf - > geometry - > numIndexes & & ( w . GetNumPoints ( ) + 1 < MAX_POINTS_ON_WINDING ) ; k + = 3 )
{
2012-11-26 18:58:24 +00:00
int i3 = indexes [ k + 0 ] ;
int i4 = indexes [ k + 1 ] ;
int i5 = indexes [ k + 2 ] ;
idFixedWinding w2 ;
w2 . AddPoint ( idVec5 ( verts [ i5 ] . xyz , verts [ i5 ] . GetTexCoord ( ) ) ) ;
w2 . AddPoint ( idVec5 ( verts [ i4 ] . xyz , verts [ i4 ] . GetTexCoord ( ) ) ) ;
w2 . AddPoint ( idVec5 ( verts [ i3 ] . xyz , verts [ i3 ] . GetTexCoord ( ) ) ) ;
idPlane p2 ;
w2 . GetPlane ( p2 ) ;
2012-11-28 15:47:07 +00:00
if ( p1 ! = p2 )
{
2012-11-26 18:58:24 +00:00
break ;
}
bool found = false ;
2012-11-28 15:47:07 +00:00
for ( int w1i = 0 ; w1i < w . GetNumPoints ( ) ; w1i + + )
{
for ( int w2i = 0 ; w2i < w2 . GetNumPoints ( ) ; w2i + + )
{
if ( CompareVec5 ( w [ w1i ] , w2 [ w2i ] ) & & CompareVec5 ( w [ ( w1i + 1 ) % w . GetNumPoints ( ) ] , w2 [ ( w2i + 2 ) % w2 . GetNumPoints ( ) ] ) )
{
w . InsertPoint ( w2 [ ( w2i + 1 ) % w2 . GetNumPoints ( ) ] , ( w1i + 1 ) % w . GetNumPoints ( ) ) ;
2012-11-26 18:58:24 +00:00
j = k ;
found = true ;
break ;
}
}
2012-11-28 15:47:07 +00:00
if ( found )
{
2012-11-26 18:58:24 +00:00
break ;
}
}
2012-11-28 15:47:07 +00:00
if ( ! found )
{
2012-11-26 18:58:24 +00:00
break ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idRandom2 random ( entityNumber ) ;
Fracture_r ( w , random ) ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
physicsObj . SetContents ( material - > GetContentFlags ( ) ) ;
SetPhysics ( & physicsObj ) ;
}
/*
= = = = = = = = = = = = = = = =
idBrittleFracture : : FindNeighbours
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idBrittleFracture : : FindNeighbours ( )
{
2012-11-26 18:58:24 +00:00
int i , j , k , l ;
idVec3 p1 , p2 , dir ;
idMat3 axis ;
idPlane plane [ 4 ] ;
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < shards . Num ( ) ; i + + )
{
shard_t * shard1 = shards [ i ] ;
const idWinding & w1 = shard1 - > winding ;
const idVec3 & origin1 = shard1 - > clipModel - > GetOrigin ( ) ;
const idMat3 & axis1 = shard1 - > clipModel - > GetAxis ( ) ;
for ( k = 0 ; k < w1 . GetNumPoints ( ) ; k + + )
{
2012-11-26 18:58:24 +00:00
p1 = origin1 + w1 [ k ] . ToVec3 ( ) * axis1 ;
2012-11-28 15:47:07 +00:00
p2 = origin1 + w1 [ ( k + 1 ) % w1 . GetNumPoints ( ) ] . ToVec3 ( ) * axis1 ;
2012-11-26 18:58:24 +00:00
dir = p2 - p1 ;
dir . Normalize ( ) ;
axis = dir . ToMat3 ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
plane [ 0 ] . SetNormal ( dir ) ;
plane [ 0 ] . FitThroughPoint ( p1 ) ;
plane [ 1 ] . SetNormal ( - dir ) ;
plane [ 1 ] . FitThroughPoint ( p2 ) ;
plane [ 2 ] . SetNormal ( axis [ 1 ] ) ;
plane [ 2 ] . FitThroughPoint ( p1 ) ;
plane [ 3 ] . SetNormal ( axis [ 2 ] ) ;
plane [ 3 ] . FitThroughPoint ( p1 ) ;
2012-11-28 15:47:07 +00:00
for ( j = 0 ; j < shards . Num ( ) ; j + + )
{
if ( i = = j )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
shard_t * shard2 = shards [ j ] ;
for ( l = 0 ; l < shard1 - > neighbours . Num ( ) ; l + + )
{
if ( shard1 - > neighbours [ l ] = = shard2 )
{
2012-11-26 18:58:24 +00:00
break ;
}
}
2012-11-28 15:47:07 +00:00
if ( l < shard1 - > neighbours . Num ( ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
const idWinding & w2 = shard2 - > winding ;
const idVec3 & origin2 = shard2 - > clipModel - > GetOrigin ( ) ;
const idMat3 & axis2 = shard2 - > clipModel - > GetAxis ( ) ;
for ( l = w2 . GetNumPoints ( ) - 1 ; l > = 0 ; l - - )
{
2012-11-26 18:58:24 +00:00
p1 = origin2 + w2 [ l ] . ToVec3 ( ) * axis2 ;
2012-11-28 15:47:07 +00:00
p2 = origin2 + w2 [ ( l - 1 + w2 . GetNumPoints ( ) ) % w2 . GetNumPoints ( ) ] . ToVec3 ( ) * axis2 ;
if ( plane [ 0 ] . Side ( p2 , 0.1f ) = = SIDE_FRONT & & plane [ 1 ] . Side ( p1 , 0.1f ) = = SIDE_FRONT )
{
if ( plane [ 2 ] . Side ( p1 , 0.1f ) = = SIDE_ON & & plane [ 3 ] . Side ( p1 , 0.1f ) = = SIDE_ON )
{
if ( plane [ 2 ] . Side ( p2 , 0.1f ) = = SIDE_ON & & plane [ 3 ] . Side ( p2 , 0.1f ) = = SIDE_ON )
{
2012-11-26 18:58:24 +00:00
shard1 - > neighbours . Append ( shard2 ) ;
shard1 - > edgeHasNeighbour [ k ] = true ;
shard2 - > neighbours . Append ( shard1 ) ;
2012-11-28 15:47:07 +00:00
shard2 - > edgeHasNeighbour [ ( l - 1 + w2 . GetNumPoints ( ) ) % w2 . GetNumPoints ( ) ] = true ;
2012-11-26 18:58:24 +00:00
break ;
}
}
}
}
}
}
2012-11-28 15:47:07 +00:00
for ( k = 0 ; k < w1 . GetNumPoints ( ) ; k + + )
{
if ( ! shard1 - > edgeHasNeighbour [ k ] )
{
2012-11-26 18:58:24 +00:00
break ;
}
}
2012-11-28 15:47:07 +00:00
if ( k < w1 . GetNumPoints ( ) )
{
2012-11-26 18:58:24 +00:00
shard1 - > atEdge = true ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
shard1 - > atEdge = false ;
}
}
}
/*
= = = = = = = = = = = = = = = =
idBrittleFracture : : Event_Activate
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idBrittleFracture : : Event_Activate ( idEntity * activator )
{
2012-11-26 18:58:24 +00:00
disableFracture = false ;
2012-11-28 15:47:07 +00:00
if ( health < = 0 )
{
2012-11-26 18:58:24 +00:00
Break ( ) ;
}
}
/*
= = = = = = = = = = = = = = = =
idBrittleFracture : : Event_Touch
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idBrittleFracture : : Event_Touch ( idEntity * other , trace_t * trace )
{
2012-11-26 18:58:24 +00:00
idVec3 point , impulse ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Let the server handle this, clients dont' predict it
2012-11-28 15:47:07 +00:00
if ( common - > IsClient ( ) )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
if ( ! IsBroken ( ) )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
if ( trace - > c . id < 0 | | trace - > c . id > = shards . Num ( ) )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
point = shards [ trace - > c . id ] - > clipModel - > GetOrigin ( ) ;
impulse = other - > GetPhysics ( ) - > GetLinearVelocity ( ) * other - > GetPhysics ( ) - > GetMass ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
Shatter ( point , impulse , gameLocal . time ) ;
}
/*
= = = = = = = = = = = = = = = =
idBrittleFracture : : ClientThink
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idBrittleFracture : : ClientThink ( const int curTime , const float fraction , const bool predict )
{
2012-11-26 18:58:24 +00:00
// only think forward because the state is not synced through snapshots
2012-11-28 15:47:07 +00:00
if ( ! gameLocal . isNewFrame )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
Think ( ) ;
}
/*
= = = = = = = = = = = = = = = =
idBrittleFracture : : ClientPredictionThink
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idBrittleFracture : : ClientPredictionThink ( )
{
2012-11-26 18:58:24 +00:00
// only think forward because the state is not synced through snapshots
2012-11-28 15:47:07 +00:00
if ( ! gameLocal . isNewFrame )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
Think ( ) ;
}
/*
= = = = = = = = = = = = = = = =
idBrittleFracture : : ClientReceiveEvent
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idBrittleFracture : : ClientReceiveEvent ( int event , int time , const idBitMsg & msg )
{
2012-11-26 18:58:24 +00:00
idVec3 point , dir ;
2012-11-28 15:47:07 +00:00
switch ( event )
{
case EVENT_PROJECT_DECAL :
{
2012-11-26 18:58:24 +00:00
point [ 0 ] = msg . ReadFloat ( ) ;
point [ 1 ] = msg . ReadFloat ( ) ;
point [ 2 ] = msg . ReadFloat ( ) ;
dir [ 0 ] = msg . ReadFloat ( ) ;
dir [ 1 ] = msg . ReadFloat ( ) ;
dir [ 2 ] = msg . ReadFloat ( ) ;
ProjectDecal ( point , dir , time , NULL ) ;
return true ;
}
2012-11-28 15:47:07 +00:00
case EVENT_SHATTER :
{
2012-11-26 18:58:24 +00:00
point [ 0 ] = msg . ReadFloat ( ) ;
point [ 1 ] = msg . ReadFloat ( ) ;
point [ 2 ] = msg . ReadFloat ( ) ;
dir [ 0 ] = msg . ReadFloat ( ) ;
dir [ 1 ] = msg . ReadFloat ( ) ;
dir [ 2 ] = msg . ReadFloat ( ) ;
Shatter ( point , dir , time ) ;
return true ;
}
2012-11-28 15:47:07 +00:00
default :
{
2012-11-26 18:58:24 +00:00
return idEntity : : ClientReceiveEvent ( event , time , msg ) ;
}
}
}