1656 lines
52 KiB
C++
1656 lines
52 KiB
C++
//
|
|
// name: DynamicEntity.cpp
|
|
// description: Class describing an entity that is not static
|
|
//
|
|
|
|
// Rage headers
|
|
#include "breakableglass/breakable.h"
|
|
#include "creature/creature.h"
|
|
#include "creature/componentskeleton.h"
|
|
#include "creature/componentblendshapes.h"
|
|
#include "creature/componentextradofs.h"
|
|
#include "creature/componentshadervars.h"
|
|
#include "cranimation/frame.h"
|
|
#include "cranimation/animtrack.h"
|
|
#include "crskeleton/skeleton.h"
|
|
#include "crskeleton/skeletondata.h"
|
|
#include "grblendshapes/manager.h"
|
|
#include "grmodel/matrixset.h"
|
|
#include "fragment/cache.h"
|
|
#include "cloth/clothcontroller.h"
|
|
#include "cloth/charactercloth.h"
|
|
#include "profile/cputrace.h"
|
|
#include "profile/element.h"
|
|
#include "profile/page.h"
|
|
#include "profile/group.h"
|
|
#include "spatialdata/sphere.h"
|
|
|
|
// Framework headers
|
|
#include "fwanimation/animdirector.h"
|
|
#include "fwanimation/directorcomponentcreature.h"
|
|
#include "fwanimation\expressionsets.h"
|
|
#include "fwutil/PtrList.h"
|
|
#include "fwscene/stores/blendshapestore.h"
|
|
#include "fwsys/metadatastore.h"
|
|
#include "fwscene/world/WorldLimits.h"
|
|
#include "fwscene/world/WorldRepMulti.h"
|
|
#include "fwsys/metadatastore.h"
|
|
|
|
// Game headers
|
|
#include "animation/CreatureMetadata.h"
|
|
#include "animation/Move.h"
|
|
#include "animation/MovePed.h"
|
|
#include "animation/debug/AnimViewer.h"
|
|
#include "camera/CamInterface.h"
|
|
#include "cutscene/CutSceneManagerNew.h"
|
|
#include "debug/debugscene.h"
|
|
#include "game/config.h"
|
|
#include "pathserver/PathServer.h"
|
|
#include "physics/breakable.h"
|
|
#include "physics/GtaInst.h"
|
|
#include "physics/physics.h"
|
|
#include "renderer/Entities/DynamicEntityDrawHandler.h"
|
|
#include "renderer/renderer.h"
|
|
#include "scene/DynamicEntity.h"
|
|
#include "scene/Physical.h"
|
|
#include "scene/portals/portalTracker.h"
|
|
#include "scene/world/gameWorld.h"
|
|
#include "script/script.h"
|
|
#include "script/gta_thread.h"
|
|
#include "script/script_channel.h"
|
|
#include "script/Handlers/GameScriptEntity.h"
|
|
#include "shaders/ShaderLib.h"
|
|
#include "shaders/CustomShaderEffectPed.h"
|
|
#include "streaming/streaming.h"
|
|
#include "system/TaskScheduler.h"
|
|
#include "system/ThreadPriorities.h"
|
|
#include "TimeCycle/TimeCycleAsyncQueryMgr.h"
|
|
#include "vehicles/vehicle.h"
|
|
// TEMP
|
|
#include "peds/ped.h"
|
|
#include "modelinfo/PedModelInfo.h"
|
|
#include "Peds/rendering/pedVariationPack.h"
|
|
#include "peds/rendering/PedVariationStream.h"
|
|
|
|
// #include "system/findsize.h"
|
|
//FindSize(CPortalTracker); // 16
|
|
#if __DEV
|
|
#if RSG_PC
|
|
CompileTimeAssertSize(CPortalTracker, 160, 160); // Larger due to the obfuscated position
|
|
#else //RSG_PC
|
|
CompileTimeAssertSize(CPortalTracker, 112, 112);
|
|
#endif //RSG_PC
|
|
#endif // __DEV
|
|
|
|
ANIM_OPTIMISATIONS()
|
|
SCENE_OPTIMISATIONS()
|
|
|
|
#define FORCE_DRAW_DYNAMICBOUNDS 0
|
|
|
|
#define OBJECT_PROXIMITY_FOR_ANIM_UPDATE (30.0f) // 30 metres.
|
|
|
|
u8 CDynamicEntity::sm_FrameCountForVisibility = 0;
|
|
bool CDynamicEntity::sm_CanUseCachedVisibilityThisFrame = true;
|
|
|
|
//
|
|
// name: CDynamicEntity::CDynamicEntity
|
|
// description: constructor
|
|
CDynamicEntity::CDynamicEntity(const eEntityOwnedBy ownedBy)
|
|
: CEntity( ownedBy )
|
|
{
|
|
fwEntity::SetBaseFlag( fwEntity::IS_DYNAMIC );
|
|
|
|
|
|
// flags init
|
|
m_nDEflags.bForcePrePhysicsAnimUpdate = false;
|
|
m_nDEflags.bIsBreakableGlass = false;
|
|
m_nDEflags.bCheckedForDead = false;
|
|
m_nDEflags.bIsGolfBall = false;
|
|
m_nDEflags.bFrozenByInterior = false;
|
|
m_nDEflags.bFrozen = false;
|
|
m_nDEflags.nStatus = STATUS_ABANDONED;
|
|
m_nDEflags.nPopType = POPTYPE_UNKNOWN;
|
|
m_nDEflags.bIsOutOfMap = false;
|
|
m_nDEflags.bOverridePhysicsBounds = false;
|
|
m_nDEflags.bHasMovedSinceLastPreRender = true;
|
|
m_nDEflags.bUseExtendedBoundingBox = false;
|
|
m_nDEflags.bIsStraddlingPortal = false;
|
|
REPLAY_ONLY(m_nDEflags.bReplayWarpedThisFrame = false;)
|
|
|
|
m_portalTracker.SetOwner(this);
|
|
m_portalTracker.SetLoadsCollisions(false);
|
|
|
|
SetIsVisibleInSomeViewportThisFrame(false);
|
|
|
|
m_randomSeed = (u16)(fwRandom::GetRandomNumber()); // middle bits tend to be more random when using crappy C rand function
|
|
m_portalStraddlingContainerIndex = 0xFF;
|
|
}
|
|
|
|
//
|
|
// name: CDynamicEntity::~CDynamicEntity
|
|
// description: destructor
|
|
CDynamicEntity::~CDynamicEntity()
|
|
{
|
|
DEV_BREAK_IF_FOCUS( CDebugScene::ShouldDebugBreakOnDestroyOfFocusEntity(), this );
|
|
DEV_BREAK_ON_PROXIMITY( CDebugScene::ShouldDebugBreakOnProximityOfDestroyCallingEntity(), VEC3V_TO_VECTOR3(this->GetTransform().GetPosition()) );
|
|
|
|
ASSERT_ONLY(CScriptEntityExtension* pExtension = GetExtension<CScriptEntityExtension>());
|
|
|
|
aiFatalAssertf(!(pExtension && pExtension->GetScriptHandler()), "A script entity is being destroyed without the script handler being informed");
|
|
|
|
if (IsStraddlingPortal())
|
|
{
|
|
RemoveFromStraddlingPortalsContainer();
|
|
}
|
|
|
|
DeleteDrawable();
|
|
|
|
// better not be in an interior when we trash the portal tracker - otherwise the room
|
|
// will contain a ref to the deleted portal tracker
|
|
Assert(!m_nFlags.bInMloRoom);
|
|
|
|
// Since the scene update system owns the scene udpate extension, we need
|
|
// to give it a chance to reclaim it.
|
|
fwSceneUpdate::RemoveFromSceneUpdate(*this, ~0U, true);
|
|
}
|
|
|
|
//
|
|
// name: CDynamicEntity::Add
|
|
// description: Add to world, while storing pointers to all the ptrnodes generated
|
|
void CDynamicEntity::Add()
|
|
{
|
|
gWorldMgr.AddToWorld(this,GetBoundRect());
|
|
}
|
|
|
|
//
|
|
// name: CDynamicEntity::Remove
|
|
// description: Remove entity from world
|
|
void CDynamicEntity::Remove()
|
|
{
|
|
gWorldMgr.RemoveFromWorld(this);
|
|
}
|
|
|
|
// name: CDynamicEntity::AddToInterior
|
|
// description: add entity to the active object list for an interior (which is set in entity, in advance of this call)
|
|
void CDynamicEntity::AddToInterior(fwInteriorLocation interiorLocation){
|
|
|
|
Assert(!GetIsInExterior()); // make sure not in exterior already
|
|
|
|
DEV_BREAK_ON_PROXIMITY( CDebugScene::ShouldDebugBreakOnProximityOfAddToInteriorCallingEntity(), VEC3V_TO_VECTOR3(this->GetTransform().GetPosition()) );
|
|
|
|
CInteriorInst* pIntInst = CInteriorInst::GetInteriorForLocation( interiorLocation );
|
|
|
|
if (pIntInst){
|
|
pIntInst->AddObjectInstance(this, interiorLocation);
|
|
Assert(m_nFlags.bInMloRoom == true);
|
|
return; // success
|
|
}
|
|
|
|
// failure
|
|
Assertf(false,"Can't add dynamicEntity to interior : there is no CInteriorInst created for it. Dumping entity...");
|
|
CDebug::DumpEntity(this);
|
|
}
|
|
|
|
// name: CDynamicEntity::RemoveFromInterior
|
|
// description: remove entity from the interior which it is in
|
|
void CDynamicEntity::RemoveFromInterior(){
|
|
|
|
DEV_BREAK_ON_PROXIMITY( CDebugScene::ShouldDebugBreakOnProximityOfRemoveFromInteriorCallingEntity(), VEC3V_TO_VECTOR3(this->GetTransform().GetPosition()) );
|
|
Assert(m_nFlags.bInMloRoom);
|
|
|
|
CInteriorInst* pIntInst = CInteriorInst::GetInteriorForLocation( this->GetInteriorLocation() );
|
|
Assertf(pIntInst, "Cannot remove object from interior - interior isn't valid");
|
|
if (pIntInst){
|
|
pIntInst->RemoveObjectInstance(this);
|
|
}
|
|
else
|
|
{
|
|
Assertf(false,"Trying to remove entity from interior with invalid interior id. Dumping entity...");
|
|
CDebug::DumpEntity(this);
|
|
}
|
|
|
|
m_portalTracker.m_roomIdx = 0;
|
|
m_portalTracker.m_pInteriorProxy = NULL;
|
|
}
|
|
|
|
fwExpressionSet* CDynamicEntity::GetExpressionSet()
|
|
{
|
|
CBaseModelInfo* pModelInfo = GetBaseModelInfo();
|
|
|
|
if (pModelInfo && (pModelInfo->GetExpressionSet() != EXPRESSION_SET_ID_INVALID))
|
|
{
|
|
return fwExpressionSetManager::GetExpressionSet(pModelInfo->GetExpressionSet());
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// name: GetBoundRadius
|
|
// description: Return the radius of the bounding sphere
|
|
float CDynamicEntity::GetBoundRadius() const
|
|
{
|
|
phInst* pInst = GetFragInst();
|
|
if(pInst==NULL)
|
|
pInst = GetCurrentPhysicsInst();
|
|
|
|
if(pInst && !m_nDEflags.bOverridePhysicsBounds)
|
|
return pInst->GetArchetype()->GetBound()->GetRadiusAroundCentroid() + GetForceAddToBoundRadius();
|
|
|
|
return GetBaseModelInfo()->GetBoundingSphereRadius() + GetForceAddToBoundRadius();
|
|
}
|
|
|
|
//
|
|
// name: CDynamicEntity::GetBoundCentre
|
|
// description: Return bound centre in world space
|
|
Vector3 CDynamicEntity::GetBoundCentre() const
|
|
{
|
|
phInst* pInst = GetFragInst();
|
|
if(pInst==NULL)
|
|
pInst = GetCurrentPhysicsInst();
|
|
|
|
if(pInst && !m_nDEflags.bOverridePhysicsBounds)
|
|
{
|
|
Vector3 output;
|
|
RCC_MATRIX34(pInst->GetMatrix()).Transform(VEC3V_TO_VECTOR3(pInst->GetArchetype()->GetBound()->GetCentroidOffset()), output);
|
|
return output;
|
|
}
|
|
else
|
|
{
|
|
return CEntity::GetBoundCentre();
|
|
}
|
|
}
|
|
|
|
//
|
|
// name: CDynamicEntity::GetBoundCentre
|
|
// description: Return bound centre in world space
|
|
void CDynamicEntity::GetBoundCentre(Vector3& centre) const
|
|
{
|
|
phInst* pInst = GetFragInst();
|
|
if(pInst==NULL)
|
|
pInst = GetCurrentPhysicsInst();
|
|
|
|
if(pInst && !m_nDEflags.bOverridePhysicsBounds)
|
|
{
|
|
RCC_MATRIX34(pInst->GetMatrix()).Transform(VEC3V_TO_VECTOR3(pInst->GetArchetype()->GetBound()->GetCentroidOffset()), centre);
|
|
}
|
|
else
|
|
{
|
|
CEntity::GetBoundCentre(centre);
|
|
}
|
|
}
|
|
|
|
float CDynamicEntity::GetBoundCentreAndRadius(Vector3& centre) const
|
|
{
|
|
phInst* pInst = GetFragInst();
|
|
phBound* pBound = NULL;
|
|
if(pInst==NULL)
|
|
pInst = GetCurrentPhysicsInst();
|
|
|
|
if(pInst && !m_nDEflags.bOverridePhysicsBounds)// && m_nFlags.bLightObject==false)
|
|
{
|
|
pBound = pInst->GetArchetype()->GetBound();
|
|
|
|
RCC_MATRIX34(pInst->GetMatrix()).Transform(VEC3V_TO_VECTOR3(pInst->GetArchetype()->GetBound()->GetCentroidOffset()), centre);
|
|
|
|
return pBound->GetRadiusAroundCentroid();
|
|
}
|
|
else
|
|
{
|
|
return CEntity::GetBoundCentreAndRadius(centre);
|
|
}
|
|
}
|
|
|
|
float CDynamicEntity::GetExtendedBoundCentreAndRadius(Vector3& centre) const
|
|
{
|
|
phInst* pInst = GetFragInst();
|
|
if(pInst==NULL)
|
|
pInst = GetCurrentPhysicsInst();
|
|
|
|
spdSphere sphere;
|
|
|
|
if(pInst && !m_nDEflags.bOverridePhysicsBounds)
|
|
{
|
|
// [SPHERE-OPTIMISE]
|
|
phBound* pBound = pInst->GetArchetype()->GetBound();
|
|
sphere.Set(pBound->GetCentroidOffset(), pBound->GetRadiusAroundCentroidV());
|
|
|
|
if( m_nDEflags.bIsBreakableGlass )
|
|
{
|
|
fragInst *pFragInst = (fragInst*)pInst;
|
|
|
|
if(fragCacheEntry* pCacheEntry = pFragInst->GetCacheEntry())
|
|
{
|
|
if(fragHierarchyInst* pHierInst = pCacheEntry->GetHierInst())
|
|
{
|
|
for(int glassIndex = 0; glassIndex != pHierInst->numGlassInfos; ++ glassIndex)
|
|
{
|
|
bgGlassHandle handle = pHierInst->glassInfos[glassIndex].handle;
|
|
if(handle != bgGlassHandle_Invalid)
|
|
{
|
|
ScalarV inflatedRadius = sphere.InflateSphere(spdSphere(VECTOR4_TO_VEC4V(bgGlassManager::GetGlassBreakable(handle).GetBoundingSphere())));
|
|
sphere.SetRadius(inflatedRadius);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
const Vec3V transformedCenter = Transform( pInst->GetMatrix(), sphere.GetCenter() );
|
|
sphere.Set( transformedCenter, sphere.GetRadius() );
|
|
}
|
|
else
|
|
{
|
|
const float radius = CEntity::GetBoundCentreAndRadius(centre);
|
|
sphere.Set( VECTOR3_TO_VEC3V(centre), ScalarV(radius) );
|
|
}
|
|
|
|
// GtaV B*128062: Some animations cause the entity bounds to be way off the entity position. In these cases,
|
|
// even though the entity (position) is clearly in view, it's culled in the visibility pipeline and its
|
|
// skeleton is not updated. So we need to enlarge the bounds to include the entity position. - AP
|
|
centre = VEC3V_TO_VECTOR3( sphere.GetCenter() );
|
|
return (sphere.GetRadius() + Mag(sphere.GetCenter() - this->GetTransform().GetPosition())).Getf();
|
|
}
|
|
|
|
//
|
|
// name: CDynamicEntity::GetBoundingBoxMin
|
|
// description: Return bounding box min
|
|
const Vector3& CDynamicEntity::GetBoundingBoxMin() const
|
|
{
|
|
phInst* pInst = GetFragInst();
|
|
if(pInst==NULL)
|
|
{
|
|
pInst = GetCurrentPhysicsInst();
|
|
}
|
|
|
|
if(pInst && !m_nDEflags.bOverridePhysicsBounds)
|
|
{
|
|
const phArchetype* pArchetype = pInst->GetArchetype();
|
|
if( AssertVerify(pArchetype) )
|
|
{
|
|
const phBound* pBound = pArchetype->GetBound();
|
|
if( AssertVerify(pBound) )
|
|
{
|
|
return RCC_VECTOR3(pBound->GetBoundingBoxMin());
|
|
}
|
|
}
|
|
}
|
|
|
|
return CEntity::GetBoundingBoxMin();
|
|
}
|
|
|
|
//
|
|
// name: CDynamicEntity::GetBoundingBoxMax
|
|
// description: Return bounding box max
|
|
const Vector3& CDynamicEntity::GetBoundingBoxMax() const
|
|
{
|
|
phInst* pInst = GetFragInst();
|
|
if(pInst==NULL)
|
|
{
|
|
pInst = GetCurrentPhysicsInst();
|
|
}
|
|
|
|
if(pInst && !m_nDEflags.bOverridePhysicsBounds)
|
|
{
|
|
const phArchetype* pArchetype = pInst->GetArchetype();
|
|
if( AssertVerify(pArchetype) )
|
|
{
|
|
const phBound* pBound = pArchetype->GetBound();
|
|
if( AssertVerify(pBound) )
|
|
{
|
|
return RCC_VECTOR3(pBound->GetBoundingBoxMax());
|
|
}
|
|
}
|
|
}
|
|
|
|
return CEntity::GetBoundingBoxMax();
|
|
}
|
|
|
|
__forceinline phInst* CDynamicEntity::GetBoundBoxInline(spdAABB& box) const // private non-virtual inline implementation
|
|
{
|
|
Vec3V bbmin, bbmax;
|
|
bool bAddClothBox = false;
|
|
|
|
phInst* pInst = GetFragInst();
|
|
if(pInst==NULL)
|
|
{
|
|
pInst = GetCurrentPhysicsInst();
|
|
}
|
|
#if !USE_CLOTH_PHINST
|
|
else
|
|
{
|
|
const fragCacheEntry* pCacheEntry = ((fragInst*)pInst)->GetCacheEntry();
|
|
if( pCacheEntry )
|
|
{
|
|
const fragHierarchyInst* pHierInst = pCacheEntry->GetHierInst();
|
|
const bool hasCloth = ( pHierInst && (0 != pHierInst->envCloth)) ? true: false;
|
|
if( hasCloth )
|
|
{
|
|
environmentCloth* pEnvCloth = pHierInst->envCloth;
|
|
Assert( pEnvCloth );
|
|
Assert( pEnvCloth->GetBehavior() );
|
|
if( !pEnvCloth->GetBehavior()->IsMotionSeparated())
|
|
{
|
|
bbmin = pEnvCloth->GetBBMinWorldSpace();
|
|
bbmax = pEnvCloth->GetBBMaxWorldSpace();
|
|
bAddClothBox = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (pInst && !m_nDEflags.bOverridePhysicsBounds)// && m_nFlags.bLightObject==false)
|
|
{
|
|
box.Set(
|
|
pInst->GetArchetype()->GetBound()->GetBoundingBoxMin(),
|
|
pInst->GetArchetype()->GetBound()->GetBoundingBoxMax());
|
|
}
|
|
else
|
|
{
|
|
box = GetBaseModelInfo()->GetBoundingBox();
|
|
}
|
|
|
|
box.Transform(GetMatrix());
|
|
|
|
if( bAddClothBox )
|
|
{
|
|
Vec3V minV = box.GetMin();
|
|
Vec3V maxV = box.GetMax();
|
|
VecBoolV nonZeroIfNewMin = IsLessThan( bbmin, minV );
|
|
VecBoolV nonZeroIfNewMax = IsGreaterThan( bbmax, maxV );
|
|
|
|
box.SetMin( SelectFT( nonZeroIfNewMin, minV, bbmin ) );
|
|
box.SetMax( SelectFT( nonZeroIfNewMax, maxV, bbmax ) );
|
|
}
|
|
|
|
return pInst;
|
|
}
|
|
|
|
FASTRETURNCHECK(const spdAABB &) CDynamicEntity::GetBoundBox(spdAABB& box) const
|
|
{
|
|
GetBoundBoxInline(box);
|
|
return box;
|
|
}
|
|
|
|
FASTRETURNCHECK(const spdAABB &) CDynamicEntity::GetLocalSpaceBoundBox(spdAABB& box) const
|
|
{
|
|
phInst* pInst = GetFragInst();
|
|
if(pInst==NULL)
|
|
pInst = GetCurrentPhysicsInst();
|
|
|
|
if (pInst && !m_nDEflags.bOverridePhysicsBounds)
|
|
{
|
|
box.Set(
|
|
pInst->GetArchetype()->GetBound()->GetBoundingBoxMin(),
|
|
pInst->GetArchetype()->GetBound()->GetBoundingBoxMax());
|
|
}
|
|
else
|
|
{
|
|
box = GetBaseModelInfo()->GetBoundingBox();
|
|
}
|
|
|
|
return box;
|
|
}
|
|
|
|
void CDynamicEntity::GetExtendedBoundBox(spdAABB& box) const
|
|
{
|
|
phInst* pInst = GetBoundBoxInline(box);
|
|
|
|
#if FORCE_DRAW_DYNAMICBOUNDS
|
|
grcDebugDraw::BoxAxisAligned(box.GetMin(),box.GetMax(),Color32(0x00,0xff,0),false);
|
|
#endif // FORCE_DRAW_DYNAMICBOUNDS
|
|
|
|
if( m_nDEflags.bIsBreakableGlass && pInst!=NULL)
|
|
{
|
|
fragInst *pFragInst = (fragInst*)pInst;
|
|
|
|
if(fragCacheEntry* pCacheEntry = pFragInst->GetCacheEntry())
|
|
{
|
|
if(fragHierarchyInst* pHierInst = pCacheEntry->GetHierInst())
|
|
{
|
|
for(int glassIndex = 0; glassIndex != pHierInst->numGlassInfos; ++ glassIndex)
|
|
{
|
|
bgGlassHandle handle = pHierInst->glassInfos[glassIndex].handle;
|
|
if(handle != bgGlassHandle_Invalid)
|
|
{
|
|
// The alpha update will happen on the centroid of the box, even if the box is huge
|
|
// To counter this, we double extend the box so that its centre stays where it was
|
|
// while it still contains all the glass shard.
|
|
|
|
spdAABB glassBoxA;
|
|
spdAABB glassBoxB;
|
|
Vec3V bbMin, bbMax;
|
|
const bgBreakable &breakable = bgGlassManager::GetGlassBreakable(handle);
|
|
|
|
breakable.GetBoundingBox(RC_VECTOR3(bbMin), RC_VECTOR3(bbMax));
|
|
|
|
Assertf((bbMin.GetXf() > WORLDLIMITS_XMIN) && (bbMin.GetYf() > WORLDLIMITS_YMIN) && (bbMin.GetZf() > WORLDLIMITS_ZMIN), "[0] Entity: %s %s - X= %5.3f : Y= %5.3f : Z= %5.3f", GetModelName(), PopTypeIsMission()? "(mission owned)":"", bbMin.GetXf(), bbMin.GetYf(), bbMin.GetZf());
|
|
Assertf((bbMax.GetXf() < WORLDLIMITS_XMAX) && (bbMax.GetYf() < WORLDLIMITS_YMAX) && (bbMax.GetZf() < WORLDLIMITS_ZMAX), "[1] Entity: %s %s - X= %5.3f : Y= %5.3f : Z= %5.3f", GetModelName(), PopTypeIsMission()? "(mission owned)":"", bbMax.GetXf(), bbMax.GetYf(), bbMax.GetZf());
|
|
|
|
glassBoxA.Set(bbMin, bbMax);
|
|
glassBoxB.Set(-bbMax, -bbMin);
|
|
|
|
Matrix34 breakableMatrix = breakable.GetTransform();
|
|
Assertf((breakableMatrix.d.x < WORLDLIMITS_XMAX) && (breakableMatrix.d.y < WORLDLIMITS_YMAX) && (breakableMatrix.d.z < WORLDLIMITS_ZMAX), "[2] Entity: %s %s - Brekable matrix pos X= %5.3f : Y= %5.3f : Z= %5.3f", GetModelName(), PopTypeIsMission()? "(mission owned)":"", breakableMatrix.d.x, breakableMatrix.d.y, breakableMatrix.d.z);
|
|
|
|
glassBoxA.Transform(RCC_MAT34V(breakableMatrix));
|
|
glassBoxB.Transform(RCC_MAT34V(breakableMatrix));
|
|
|
|
#if FORCE_DRAW_DYNAMICBOUNDS
|
|
grcDebugDraw::BoxAxisAligned(glassBoxA.GetMin(),glassBoxA.GetMax(),Color32(0xff,0,0),false);
|
|
grcDebugDraw::BoxAxisAligned(glassBoxB.GetMin(),glassBoxB.GetMax(),Color32(0,0,0xff),false);
|
|
#endif // FORCE_DRAW_DYNAMICBOUNDS
|
|
|
|
box.GrowAABB(glassBoxA);
|
|
box.GrowAABB(glassBoxB);
|
|
|
|
Assertf((box.GetMin().GetXf() > WORLDLIMITS_XMIN) && (box.GetMin().GetYf() > WORLDLIMITS_YMIN) && (box.GetMin().GetZf() > WORLDLIMITS_ZMIN), "[5] Entity: %s %s - X= %5.3f : Y= %5.3f : Z= %5.3f", GetModelName(), PopTypeIsMission()? "(mission owned)":"", box.GetMin().GetXf(), box.GetMin().GetYf(), box.GetMin().GetZf());
|
|
Assertf((box.GetMax().GetXf() < WORLDLIMITS_XMAX) && (box.GetMax().GetYf() < WORLDLIMITS_YMAX) && (box.GetMax().GetZf() < WORLDLIMITS_ZMAX), "[6] Entity: %s %s - X= %5.3f : Y= %5.3f : Z= %5.3f", GetModelName(), PopTypeIsMission()? "(mission owned)":"", box.GetMax().GetXf(), box.GetMax().GetYf(), box.GetMax().GetZf());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Assertf((box.GetMin().GetXf() > WORLDLIMITS_XMIN) && (box.GetMin().GetYf() > WORLDLIMITS_YMIN) && (box.GetMin().GetZf() > WORLDLIMITS_ZMIN), "[7] Entity: %s %s - X= %5.3f : Y= %5.3f : Z= %5.3f", GetModelName(), PopTypeIsMission()? "(mission owned)":"", box.GetMin().GetXf(), box.GetMin().GetYf(), box.GetMin().GetZf());
|
|
Assertf((box.GetMax().GetXf() < WORLDLIMITS_XMAX) && (box.GetMax().GetYf() < WORLDLIMITS_YMAX) && (box.GetMax().GetZf() < WORLDLIMITS_ZMAX), "[8] Entity: %s %s - X= %5.3f : Y= %5.3f : Z= %5.3f", GetModelName(), PopTypeIsMission()? "(mission owned)":"", box.GetMax().GetXf(), box.GetMax().GetYf(), box.GetMax().GetZf());
|
|
|
|
// GtaV B*128062: Some animations cause the entity bounds to be way off the entity position. In these cases,
|
|
// even though the entity (position) is clearly in view, it's culled in the visibility pipeline and its
|
|
// skeleton is not updated. So we need to enlarge the bounds to include the entity position. - AP
|
|
if ( GetAnimDirector() != NULL )
|
|
{
|
|
const Vec3V entityPosition = this->GetTransform().GetPosition();
|
|
const Vec3V boxExtent = box.GetExtent();
|
|
box.GrowPoint( entityPosition - boxExtent );
|
|
box.GrowPoint( entityPosition + boxExtent );
|
|
}
|
|
|
|
// When running IK, the weapon may not always render since visibility scanning uses the pre-IK position for the weapon.
|
|
// To workaround this, the bounding box for the weapon is stretched so that it never gets culled.
|
|
if ( Unlikely(m_nDEflags.bUseExtendedBoundingBox) )
|
|
{
|
|
const Vec3V entityPosition = this->GetTransform().GetPosition();
|
|
Vec3V boxExtent = box.GetExtent();
|
|
TUNE_GROUP_FLOAT(EXTENDED_BOUND_BOX, EXTENT_HEIGHT_OFFSET, 1.0f, -2.0f, 2.0f, 0.01f);
|
|
TUNE_GROUP_FLOAT(EXTENDED_BOUND_BOX, EXTENT_XY_OFFSET, 1.0f, -2.0f, 2.0f, 0.01f);
|
|
const float fBoxHeight = boxExtent.GetZf();
|
|
boxExtent.SetXf(fBoxHeight + EXTENT_XY_OFFSET);
|
|
boxExtent.SetYf(fBoxHeight + EXTENT_XY_OFFSET);
|
|
boxExtent.SetZf(fBoxHeight + EXTENT_HEIGHT_OFFSET);
|
|
box.GrowPoint( entityPosition - boxExtent );
|
|
box.GrowPoint( entityPosition + boxExtent );
|
|
}
|
|
|
|
#if FORCE_DRAW_DYNAMICBOUNDS
|
|
grcDebugDraw::BoxAxisAligned(box.GetMin(),box.GetMax(),Color32(0xffffffff),false);
|
|
#endif // FORCE_DRAW_DYNAMICBOUNDS
|
|
}
|
|
|
|
|
|
//
|
|
// name: CDynamicEntity::AddToMovingList
|
|
// description: Add to list of objects to be processed
|
|
void CDynamicEntity::AddToSceneUpdate()
|
|
{
|
|
Assertf(CSystem::IsThisThreadId(SYS_THREAD_UPDATE), "CDynamicEntity::AddToSceneUpdate call being made from outside the main thread!");
|
|
|
|
// If we are updating through the animation queue, we don't want to set SU_UPDATE or SU_UPDATE_VEHICLE.
|
|
u32 flagsToAdd = CGameWorld::SU_RESET_VISIBILITY;
|
|
|
|
if(!GetUpdatingThroughAnimQueue())
|
|
{
|
|
flagsToAdd |= GetMainSceneUpdateFlag();
|
|
}
|
|
|
|
if(GetAnimDirector())
|
|
{
|
|
flagsToAdd |= GetStartAnimSceneUpdateFlag();
|
|
}
|
|
|
|
bool addPreSimPhysicsUpdate = true;
|
|
if (GetType() == ENTITY_TYPE_PED)
|
|
{
|
|
flagsToAdd |= CGameWorld::SU_ADD_SHOCKING_EVENTS
|
|
| CGameWorld::SU_UPDATE_PERCEPTION
|
|
| CGameWorld::SU_UPDATE_PAUSED;
|
|
|
|
CPed* pPed = static_cast<CPed*>(this);
|
|
|
|
// Normally, we manage SU_PRESIM_PHYSICS_UPDATE for peds in CPed::ProcessPrePhysics(),
|
|
// but when we insert in the scene it's probably best to not set that flag for low LOD
|
|
// peds from the start.
|
|
const bool bIsUsingLowLodPhysics = pPed->IsUsingLowLodPhysics();
|
|
if(bIsUsingLowLodPhysics || pPed->GetPedResetFlag(CPED_RESET_FLAG_OverridePhysics))
|
|
{
|
|
addPreSimPhysicsUpdate = false;
|
|
}
|
|
}
|
|
|
|
if (GetIsDynamic())
|
|
{
|
|
flagsToAdd |= CGameWorld::SU_START_ANIM_UPDATE_POST_CAMERA;
|
|
}
|
|
|
|
if (GetIsTypeVehicle() && ((CVehicle*)this)->GetVehicleType()==VEHICLE_TYPE_TRAIN)
|
|
{
|
|
flagsToAdd |= CGameWorld::SU_TRAIN;
|
|
}
|
|
|
|
if (GetIsPhysical())
|
|
{
|
|
if(addPreSimPhysicsUpdate)
|
|
{
|
|
flagsToAdd |= CGameWorld::SU_PRESIM_PHYSICS_UPDATE;
|
|
}
|
|
flagsToAdd |= CGameWorld::SU_PHYSICS_PRE_UPDATE
|
|
| CGameWorld::SU_PHYSICS_POST_UPDATE;
|
|
}
|
|
|
|
fwSceneUpdate::AddToSceneUpdate(*this, flagsToAdd);
|
|
}
|
|
|
|
//
|
|
// name: CDynamicEntity::RemoveFromMovingList
|
|
// description: Remove from list of objects to be processed
|
|
void CDynamicEntity::RemoveFromSceneUpdate()
|
|
{
|
|
Assertf(CSystem::IsThisThreadId(SYS_THREAD_UPDATE), "CDynamicEntity::RemoveFromSceneUpdate call being made from outside the main thread!");
|
|
|
|
fwSceneUpdate::RemoveFromSceneUpdate(*this, 0xffffffff);
|
|
}
|
|
|
|
//
|
|
// name: CDynamicEntity::AddSceneUpdateFlags
|
|
// description: Adds individual flags to the scene update flag list
|
|
void CDynamicEntity::AddSceneUpdateFlags(u32 flags)
|
|
{
|
|
fwSceneUpdate::AddToSceneUpdate(*this, flags);
|
|
}
|
|
|
|
//
|
|
// name: CDynamicEntity::RemoveSceneUpdateFlags
|
|
// description: Removes individual flags from the scene update flag list
|
|
void CDynamicEntity::RemoveSceneUpdateFlags(u32 flags)
|
|
{
|
|
fwSceneUpdate::RemoveFromSceneUpdate(*this, flags);
|
|
}
|
|
|
|
//
|
|
// name: CDynamicEntity::GetIsMainSceneUpdateFlagSet
|
|
// description: Returns whether the main scene update flag is set
|
|
bool CDynamicEntity::GetIsMainSceneUpdateFlagSet() const
|
|
{
|
|
const fwSceneUpdateExtension *extension = GetExtension<fwSceneUpdateExtension>();
|
|
|
|
if(extension && (extension->m_sceneUpdateFlags & GetMainSceneUpdateFlag()) != 0)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//
|
|
// name: UpdateSkeleton
|
|
// description: Update the skeleton for an entity
|
|
RAGETRACE_DECL(CDynamicEntity_UpdateSkeleton);
|
|
void CDynamicEntity::UpdateSkeleton()
|
|
{
|
|
RAGETRACE_SCOPE(CDynamicEntity_UpdateSkeleton);
|
|
|
|
WaitForAnyActiveAnimUpdateToComplete();
|
|
|
|
if(GetSkeleton())
|
|
{
|
|
GetSkeleton()->Update();
|
|
|
|
fragInst* pFragInst = GetFragInst();
|
|
if (pFragInst && pFragInst->GetCached() && (!GetIsTypePed() || CPhysics::GetLevel()->IsActive(pFragInst->GetLevelIndex())))
|
|
{
|
|
fragHierarchyInst* hierInst = pFragInst->GetCacheEntry()->GetHierInst();
|
|
|
|
// if fragment is articulated then update skeleton using special function
|
|
if(hierInst->body && pFragInst->IsInLevel() && CPhysics::GetLevel()->IsActive(pFragInst->GetLevelIndex()))
|
|
{
|
|
GetFragInst()->SyncSkeletonToArticulatedBody();
|
|
}
|
|
// otherwise do the matrix zero'ing ourselves
|
|
else
|
|
{
|
|
pFragInst->ZeroSkeletonMatricesByGroup(GetSkeleton(), hierInst->damagedSkeleton);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// name: InverseUpdateSkeleton
|
|
// description: Inverse update the skeleton for an entity
|
|
void CDynamicEntity::InverseUpdateSkeleton()
|
|
{
|
|
WaitForAnyActiveAnimUpdateToComplete();
|
|
|
|
if(GetSkeleton())
|
|
{
|
|
GetSkeleton()->InverseUpdate();
|
|
}
|
|
}
|
|
|
|
//
|
|
// name: ProcessPaused
|
|
// description: Do this when the dynamic entity is paused
|
|
// Should be called even when paused
|
|
void CDynamicEntity::UpdatePaused()
|
|
{
|
|
fwDynamicEntityComponent *dynComp = GetDynamicComponent();
|
|
|
|
if (dynComp)
|
|
{
|
|
// Reset the extracted velocity
|
|
//dynComp->SetAnimatedVelocity(VEC3_ZERO);
|
|
|
|
// Reset the extracted angular velocity
|
|
//dynComp->SetAnimatedAngularVelocity(0.0f);
|
|
}
|
|
}
|
|
|
|
//
|
|
// name: StartAnimUpdate
|
|
// description:
|
|
void CDynamicEntity::StartAnimUpdate(float fTimeStep)
|
|
{
|
|
DEV_BREAK_IF_FOCUS( CDebugScene::ShouldDebugBreakOnUpdateAnimOfFocusEntity(), this );
|
|
DEV_BREAK_ON_PROXIMITY( CDebugScene::ShouldDebugBreakOnProximityOfUpdateAnimCallingEntity(), VEC3V_TO_VECTOR3(this->GetTransform().GetPosition()) );
|
|
|
|
fwDynamicEntityComponent *dynComp = CreateDynamicComponentIfMissing();
|
|
|
|
// Reset the animated velocity
|
|
dynComp->SetAnimatedVelocity(VEC3_ZERO);
|
|
|
|
// Reset the animated angular velocity
|
|
dynComp->SetAnimatedAngularVelocity(0.0f);
|
|
|
|
// Pre update the anim director - must always be called
|
|
if(GetSkeleton() && GetAnimDirector())
|
|
{
|
|
GetAnimDirector()->PreUpdate(fTimeStep);
|
|
|
|
bool bDoAnimUpdate = GetIsVisibleInSomeViewportThisFrame() || m_nDEflags.bForcePrePhysicsAnimUpdate;
|
|
|
|
// Objects should also check their proximity to the camera for anim updates.
|
|
// Required for audio events to be heard for nearby, off-screen objects.
|
|
if (!bDoAnimUpdate && GetIsTypeObject())
|
|
{
|
|
const float fDist = GetBoundRadius() + OBJECT_PROXIMITY_FOR_ANIM_UPDATE;
|
|
|
|
Vector3 tempDir(VEC3V_TO_VECTOR3(this->GetTransform().GetPosition()));
|
|
tempDir -= camInterface::GetPos();
|
|
|
|
if (tempDir.Mag2() <= fDist*fDist)
|
|
{
|
|
bDoAnimUpdate = true;
|
|
}
|
|
}
|
|
|
|
if (GetIsTypeVehicle() &&
|
|
(static_cast<CVehicle*>(this)->m_nVehicleFlags.bForcePostCameraAnimUpdate ||
|
|
static_cast<CVehicle*>(this)->m_nVehicleFlags.bForcePostCameraAnimUpdateUseZeroTimeStep))
|
|
{
|
|
// Intentionally falls through to the StopUpdatingThroughAnimQueue() call below.
|
|
}
|
|
else if(bDoAnimUpdate)
|
|
{
|
|
fwAnimDirector* pParentAnimDirector = NULL;
|
|
|
|
// For the driver to update before its vehicle, if this is the vehicle, we find the
|
|
// anim director of the parent, and pass that in to StartUpdatePrePhysics().
|
|
CDynamicEntity* pParentEntity = GetProcessControlOrderParent();
|
|
if(pParentEntity)
|
|
{
|
|
pParentAnimDirector = pParentEntity->GetAnimDirector();
|
|
|
|
#if __ASSERT
|
|
// Verify that GetStartAnimSceneUpdateFlag() returns the right value in order to
|
|
// ensure that the dependency indicated by GetProcessControlOrderParent() can be achieved.
|
|
// Note: we could also check the actual flags in fwSceneUpdateExtension to make sure they
|
|
// are set accordingly.
|
|
if(pParentAnimDirector)
|
|
{
|
|
Assert(pParentEntity->GetStartAnimSceneUpdateFlag() == CGameWorld::SU_START_ANIM_UPDATE_PRE_PHYSICS);
|
|
Assert(GetStartAnimSceneUpdateFlag() == CGameWorld::SU_START_ANIM_UPDATE_PRE_PHYSICS_PASS2);
|
|
}
|
|
#endif // __ASSERT
|
|
|
|
}
|
|
|
|
GetAnimDirector()->StartUpdatePrePhysics(fTimeStep, ( GetIsTypePed() && static_cast<CPed*>(this)->GetPedResetFlag(CPED_RESET_FLAG_ForcePostCameraAnimUpdate) ), pParentAnimDirector );
|
|
|
|
// If we were not already updating through the animation queue, and we should update through
|
|
// the animation queue now, set the internal flag to remember that we are in this mode now,
|
|
// and clear out the regular update flags.
|
|
if(!GetUpdatingThroughAnimQueue() && CGameWorld::ShouldUpdateThroughAnimQueue(*this))
|
|
{
|
|
SetUpdatingThroughAnimQueue(true);
|
|
RemoveSceneUpdateFlags(CGameWorld::SU_UPDATE | CGameWorld::SU_UPDATE_VEHICLE);
|
|
}
|
|
|
|
// Return to avoid calling StopUpdatingThroughAnimQueue().
|
|
return;
|
|
}
|
|
}
|
|
|
|
// If we did not call fwAnimDirector::StartUpdatePrePhysics() above, this object
|
|
// won't end up in the update queue, so if we are currently trying to update using
|
|
// that, switch back to regular updates.
|
|
StopUpdatingThroughAnimQueue();
|
|
}
|
|
|
|
//
|
|
// name: UpdateVelocityAndAngularVelocity
|
|
// description:
|
|
void CDynamicEntity::UpdateVelocityAndAngularVelocity(float fTimeStep)
|
|
{
|
|
if(GetSkeleton() && GetAnimDirector())
|
|
{
|
|
GetAnimDirector()->UpdateVelocityAndAngularVelocity(fTimeStep);
|
|
}
|
|
}
|
|
|
|
//
|
|
// name: UpdateAnimAfterCameraUpdate
|
|
// description: Update the animation director for an entity
|
|
void CDynamicEntity::StartAnimUpdateAfterCamera(float fTimeStep)
|
|
{
|
|
DEV_BREAK_IF_FOCUS( CDebugScene::ShouldDebugBreakOnUpdateAnimAfterCameraUpdateOfFocusEntity(), this );
|
|
DEV_BREAK_ON_PROXIMITY( CDebugScene::ShouldDebugBreakOnProximityOfUpdateAnimAfterCameraUpdateCallingEntity(), VEC3V_TO_VECTOR3(this->GetTransform().GetPosition()) );
|
|
|
|
// First, do a quick rejection based on visibility, unless we are doing a camera cut.
|
|
if(sm_CanUseCachedVisibilityThisFrame && !GetIsVisibleInSomeViewportThisFrame())
|
|
{
|
|
return;
|
|
}
|
|
|
|
fwAnimDirector* pAnimDirector = GetAnimDirector();
|
|
if(pAnimDirector && pAnimDirector->RequiresUpdatePostCamera() && GetSkeleton())
|
|
{
|
|
// If we are doing a camera cut, do a test against the new viewport after the cut,
|
|
// instead of the GetIsVisibleInSomeViewportThisFrame() call.
|
|
if(!sm_CanUseCachedVisibilityThisFrame)
|
|
{
|
|
Vec3V boundCentre;
|
|
float boundRadius = GetBoundCentreAndRadius(RC_VECTOR3(boundCentre));
|
|
bool visible = camInterface::IsSphereVisibleInGameViewport(RCC_VECTOR3(boundCentre), boundRadius);
|
|
if (!visible)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
if(!pAnimDirector->IsUpdated())
|
|
{
|
|
OnEnterViewport();
|
|
}
|
|
|
|
pAnimDirector->StartUpdatePostCamera(fTimeStep);
|
|
}
|
|
}
|
|
|
|
void CDynamicEntity::EndAnimUpdate(float fTimeStep)
|
|
{
|
|
fwAnimDirector* pDirector = GetAnimDirector();
|
|
if(pDirector)
|
|
{
|
|
pDirector->EndUpdatePrePhysics(fTimeStep);
|
|
}
|
|
}
|
|
|
|
//
|
|
// name: UpdatePortalTracker
|
|
// description: update the portal tracker if needed
|
|
void CDynamicEntity::UpdatePortalTracker()
|
|
{
|
|
Assert(GetIsTypeObject() || GetIsTypePed() || GetIsTypeVehicle());
|
|
|
|
m_portalTracker.Update(VEC3V_TO_VECTOR3(GetTransform().GetPosition()));
|
|
}
|
|
|
|
//
|
|
// name: PreRender
|
|
// description: Render a dynamic entity (checks if entity has a skeleton)
|
|
ePrerenderStatus CDynamicEntity::PreRender(const bool bIsVisibleInMainViewport)
|
|
{
|
|
DEV_BREAK_IF_FOCUS( CDebugScene::ShouldDebugBreakOnPreRenderOfFocusEntity(), this );
|
|
DEV_BREAK_ON_PROXIMITY( CDebugScene::ShouldDebugBreakOnProximityOfPreRenderCallingEntity(), VEC3V_TO_VECTOR3(this->GetTransform().GetPosition()) );
|
|
|
|
DEV_ONLY(ApplyBoneOverrides());
|
|
|
|
bool applyDynamicAmbientScale = (bIsVisibleInMainViewport && GetUseAmbientScale() && GetUseDynamicAmbientScale());
|
|
applyDynamicAmbientScale &= (m_nDEflags.bHasMovedSinceLastPreRender);
|
|
|
|
if( applyDynamicAmbientScale )
|
|
{
|
|
CTimeCycleAsyncQueryMgr::AddNonPedEntity(this);
|
|
m_nDEflags.bHasMovedSinceLastPreRender = false;
|
|
}
|
|
|
|
return CEntity::PreRender(bIsVisibleInMainViewport);
|
|
}
|
|
|
|
void CDynamicEntity::PreRender2(const bool UNUSED_PARAM(bIsVisibleInMainViewport))
|
|
{
|
|
}
|
|
|
|
#if __DEV
|
|
|
|
void CDynamicEntity::ApplyBoneOverrides()
|
|
{
|
|
if ( CAnimViewer::m_pDynamicEntity && CAnimViewer::m_pDynamicEntity == this )
|
|
{
|
|
if ( GetSkeleton() )
|
|
{
|
|
if (CAnimViewer::ms_bOverrideBoneRotation || CAnimViewer::ms_bOverrideBoneTranslation || CAnimViewer::ms_bOverrideBoneScale)
|
|
{
|
|
GetSkeleton()->InverseUpdate();
|
|
|
|
// Debug functionality to override a bones rotation
|
|
//NOTE: This is slightly different from pre refactoring since
|
|
// ApplyExpressions() is no longer called after this.
|
|
if (CAnimViewer::ms_bOverrideBoneRotation)
|
|
{
|
|
if (CAnimViewer::ms_bApplyOverrideRelatively)
|
|
{
|
|
Matrix34 bind = MAT34V_TO_MATRIX34(GetSkeletonData().GetDefaultTransform(CAnimViewer::m_boneIndex));
|
|
Matrix34 source = RC_MATRIX34(GetSkeleton()->GetLocalMtx(CAnimViewer::m_boneIndex));
|
|
Matrix34 goal;
|
|
goal.Identity();
|
|
goal.FromEulersXYZ(CAnimViewer::m_rotation);
|
|
goal.Dot(bind);
|
|
|
|
// Set the bone local rotation to the bind + override
|
|
RC_MATRIX34(GetSkeleton()->GetLocalMtx(CAnimViewer::m_boneIndex)).Interpolate(
|
|
source,
|
|
goal,
|
|
CAnimViewer::ms_fOverrideBoneBlend);
|
|
}
|
|
else
|
|
{
|
|
Matrix34 source = RC_MATRIX34(GetSkeleton()->GetLocalMtx(CAnimViewer::m_boneIndex));
|
|
Matrix34 goal = RC_MATRIX34(GetSkeleton()->GetLocalMtx(CAnimViewer::m_boneIndex));
|
|
goal.FromEulersXYZ(CAnimViewer::m_rotation);
|
|
|
|
// Set the bone local rotation to the override
|
|
RC_MATRIX34(GetSkeleton()->GetLocalMtx(CAnimViewer::m_boneIndex)).Interpolate(
|
|
source,
|
|
goal,
|
|
CAnimViewer::ms_fOverrideBoneBlend);
|
|
}
|
|
}
|
|
|
|
if (CAnimViewer::ms_bOverrideBoneTranslation)
|
|
{
|
|
Matrix34 localMatrix = MAT34V_TO_MATRIX34(GetSkeleton()->GetLocalMtx(CAnimViewer::m_boneIndex));
|
|
|
|
if (CAnimViewer::ms_bApplyOverrideRelatively)
|
|
{
|
|
Vector3 translation = CAnimViewer::m_translation;
|
|
translation.Dot3x3(localMatrix);
|
|
|
|
Vector3 bindTranslation = VEC3V_TO_VECTOR3(GetSkeletonData().GetDefaultTransform(CAnimViewer::m_boneIndex).d());
|
|
translation = bindTranslation + translation;
|
|
|
|
Matrix34 source = RC_MATRIX34(GetSkeleton()->GetLocalMtx(CAnimViewer::m_boneIndex));
|
|
Matrix34 goal = RC_MATRIX34(GetSkeleton()->GetLocalMtx(CAnimViewer::m_boneIndex));
|
|
goal.d.Set(translation);
|
|
|
|
// Set the bone local rotation to the override
|
|
RC_MATRIX34(GetSkeleton()->GetLocalMtx(CAnimViewer::m_boneIndex)).Interpolate(
|
|
source,
|
|
goal,
|
|
CAnimViewer::ms_fOverrideBoneBlend);
|
|
}
|
|
else
|
|
{
|
|
Vector3 translation = CAnimViewer::m_translation;
|
|
translation.Dot3x3(localMatrix);
|
|
|
|
Matrix34 source = RC_MATRIX34(GetSkeleton()->GetLocalMtx(CAnimViewer::m_boneIndex));
|
|
Matrix34 goal = RC_MATRIX34(GetSkeleton()->GetLocalMtx(CAnimViewer::m_boneIndex));
|
|
goal.d.Set(translation);
|
|
|
|
// Set the bone local rotation to the override
|
|
RC_MATRIX34(GetSkeleton()->GetLocalMtx(CAnimViewer::m_boneIndex)).Interpolate(
|
|
source,
|
|
goal,
|
|
CAnimViewer::ms_fOverrideBoneBlend);
|
|
}
|
|
}
|
|
|
|
if(CAnimViewer::ms_bOverrideBoneScale)
|
|
{
|
|
Vec3V scale = VECTOR3_TO_VEC3V(CAnimViewer::m_scale);
|
|
if(CAnimViewer::ms_bApplyOverrideRelatively)
|
|
{
|
|
scale *= GetSkeletonData().GetBoneData(CAnimViewer::m_boneIndex)->GetDefaultScale();
|
|
}
|
|
|
|
Mat34V& localMtx = GetSkeleton()->GetLocalMtx(CAnimViewer::m_boneIndex);
|
|
Scale3x3(localMtx, scale, localMtx);
|
|
}
|
|
|
|
GetSkeleton()->Update();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif //_DEV
|
|
|
|
|
|
//
|
|
// name: CDynamicEntity::CreateSkeleton
|
|
// description: Create a skeleton for this entity
|
|
void CDynamicEntity::CreateSkeleton()
|
|
{
|
|
Assertf(GetEntitySkeleton() == NULL, "Skeleton already created");
|
|
|
|
// fragInst's use the skeleton provided from the fragment cache
|
|
fragInst* pEntityFragInst = GetFragInst();
|
|
if (pEntityFragInst && !pEntityFragInst->GetCached())
|
|
{
|
|
pEntityFragInst->PutIntoCache();
|
|
Assertf(GetSkeleton(), "Skeleton not created!");
|
|
return;
|
|
}
|
|
|
|
if (GetIsTypePed() || GetIsTypeVehicle())
|
|
{
|
|
Assertf(GetSkeleton(), "Skeleton not created for %s", GetModelName());
|
|
return;
|
|
}
|
|
|
|
// Create a skeleton
|
|
if (GetDrawable())
|
|
{
|
|
crSkeletonData *pSkeletonData = GetDrawable()->GetSkeletonData();
|
|
if (pSkeletonData)
|
|
{
|
|
crSkeleton *skeleton = rage_new crSkeleton();
|
|
skeleton->Init(*pSkeletonData, NULL);
|
|
SetSkeleton(skeleton);
|
|
|
|
// ensure matrix is in memory all the time
|
|
|
|
// KS - VMATH - oh fuck - only skeletons still needs a matrix ptr!!!!
|
|
Assertf(GetTransformPtr()->IsMatrixTransform(), "Entity %s needs to have a matrix transform, but has type %d", GetModelName(), GetTransformPtr()->GetTypeIdentifier());
|
|
const fwMatrixTransform* m = static_cast<const fwMatrixTransform*>(GetTransformPtr());
|
|
skeleton->SetParentMtx(m->GetMatrixPtr());
|
|
}
|
|
else
|
|
{
|
|
Assertf(0, "%s : has invalid skeleton data", GetBaseModelInfo() ? GetModelName() : "Unknown dynamic entity");
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
Assertf(0, "%s : has invalid drawable", GetBaseModelInfo() ? GetModelName() : "Unknown dynamic entity");
|
|
}
|
|
|
|
Assertf(GetEntitySkeleton(), "%s : failed to create a skeleton", GetBaseModelInfo() ? GetModelName() : "Unknown dynamic entity");
|
|
}
|
|
|
|
fwDrawData* CDynamicEntity::AllocateDrawHandler(rmcDrawable* pDrawable)
|
|
{
|
|
if (m_nFlags.bIsFrag)
|
|
{
|
|
return rage_new CDynamicEntityFragmentDrawHandler(this, pDrawable);
|
|
}
|
|
else if (pDrawable->GetSkeletonData())
|
|
{
|
|
return rage_new CDynamicEntitySkinnedDrawHandler(this, pDrawable);
|
|
}
|
|
else
|
|
{
|
|
if(pDrawable->HasInstancedGeometry())
|
|
{
|
|
return rage_new CEntityInstancedBasicDrawHandler(this, pDrawable);
|
|
}
|
|
return rage_new CEntityBasicDrawHandler(this, pDrawable);
|
|
}
|
|
}
|
|
|
|
void CDynamicEntity::DeleteDrawable()
|
|
{
|
|
DeleteAnimDirector();
|
|
CEntity::DeleteDrawable();
|
|
DeleteSkeleton();
|
|
}
|
|
|
|
void CDynamicEntity::SetHeading(float new_heading)
|
|
{
|
|
m_nDEflags.bHasMovedSinceLastPreRender = true;
|
|
CEntity::SetHeading(new_heading);
|
|
}
|
|
|
|
void CDynamicEntity::SetPosition(const Vector3& vec, bool bUpdateGameWorld, bool bUpdatePhysics, bool bWarp)
|
|
{
|
|
m_nDEflags.bHasMovedSinceLastPreRender = true;
|
|
|
|
if (bWarp)
|
|
{
|
|
// Reset secondary motions
|
|
crCreature* creature = GetCreature();
|
|
if(creature)
|
|
{
|
|
crCreatureComponentPhysical* physicalComp = creature->FindComponent<crCreatureComponentPhysical>();
|
|
if(physicalComp)
|
|
{
|
|
physicalComp->ResetMotions();
|
|
}
|
|
}
|
|
#if GTA_REPLAY
|
|
CReplayMgr::RecordWarpedEntity(this);
|
|
#endif
|
|
}
|
|
|
|
CEntity::SetPosition(vec, bUpdateGameWorld, bUpdatePhysics, bWarp);
|
|
}
|
|
|
|
void CDynamicEntity::SetMatrix(const Matrix34& mat, bool bUpdateGameWorld, bool bUpdatePhysics, bool bWarp)
|
|
{
|
|
if (bWarp)
|
|
{
|
|
// Reset secondary motions
|
|
crCreature* creature = GetCreature();
|
|
if(creature)
|
|
{
|
|
crCreatureComponentPhysical* physicalComp = creature->FindComponent<crCreatureComponentPhysical>();
|
|
if(physicalComp && !IsCloseAll(RCC_MAT34V(mat), GetMatrix(), ScalarV(V_FLT_SMALL_3)))
|
|
{
|
|
physicalComp->ResetMotions();
|
|
}
|
|
}
|
|
#if GTA_REPLAY
|
|
CReplayMgr::RecordWarpedEntity(this);
|
|
#endif
|
|
}
|
|
|
|
m_nDEflags.bHasMovedSinceLastPreRender = true;
|
|
CEntity::SetMatrix(mat, bUpdateGameWorld, bUpdatePhysics, bWarp);
|
|
}
|
|
|
|
void CDynamicEntity::AddShaderVarCreatureComponent(CCustomShaderEffectBase* pShaderEffect)
|
|
{
|
|
if (GetIsTypePed())
|
|
{
|
|
Assert(GetCreature());
|
|
crCreatureComponentShaderVars* shaderVarComponent = GetCreature()->FindComponent<crCreatureComponentShaderVars>();
|
|
|
|
CPedVariationData* pVarData = NULL;
|
|
CPed* pPed = static_cast<CPed*>(this);
|
|
if(pPed)
|
|
{
|
|
pVarData = &pPed->GetPedDrawHandler().GetVarData();
|
|
}
|
|
|
|
CPedModelInfo* pPedModelInfo = static_cast<CPedModelInfo*>(GetBaseModelInfo());
|
|
Assert(pPedModelInfo);
|
|
|
|
CCustomShaderEffectPed* pPedShaderEffect=static_cast<CCustomShaderEffectPed*>(pShaderEffect);
|
|
if (pVarData && pPedModelInfo && pPedShaderEffect)
|
|
{
|
|
// Is a creature metadata file defined in peds.meta for this ped?
|
|
if ( pPedModelInfo->GetCreatureMetadataFileIndex()!=-1)
|
|
{
|
|
atFixedArray<CShaderVariableComponent*, 256> shaderVarMetaDatas;
|
|
|
|
// Create the shader variable components using the creature metadata file
|
|
// The creature metadata file should already be streamed in as it is a dependency of the ped
|
|
#if __ASSERT
|
|
bool bHasCreatureMetaLoaded = g_fwMetaDataStore.HasObjectLoaded(strLocalIndex(pPedModelInfo->GetCreatureMetadataFileIndex()));
|
|
Assert(bHasCreatureMetaLoaded);
|
|
#endif
|
|
CCreatureMetaData *creatureMetaData = g_fwMetaDataStore.Get(strLocalIndex(pPedModelInfo->GetCreatureMetadataFileIndex()))->GetObject<CCreatureMetaData>();
|
|
for (int i=0; i<creatureMetaData->m_shaderVariableComponents.GetCount(); i++)
|
|
{
|
|
CShaderVariableComponent& shaderVarMetaData = creatureMetaData->m_shaderVariableComponents[i];
|
|
animAssert((s32)shaderVarMetaData.m_pedcompID > PV_COMP_INVALID && shaderVarMetaData.m_pedcompID < PV_MAX_COMP);
|
|
|
|
rmcDrawable* pComponent = NULL;
|
|
if (pPedModelInfo->GetIsStreamedGfx())
|
|
{
|
|
pComponent = CPedVariationStream::GetComponent((ePedVarComp)shaderVarMetaData.m_pedcompID, this, *pVarData);
|
|
|
|
}
|
|
else
|
|
{
|
|
pComponent = CPedVariationPack::GetComponent((ePedVarComp)shaderVarMetaData.m_pedcompID, this, *pVarData);
|
|
}
|
|
|
|
if (pComponent)
|
|
{
|
|
shaderVarMetaDatas.Append() = &shaderVarMetaData;
|
|
}
|
|
}
|
|
|
|
u32 shaderMetaDatasHash = atDataHash((u32*)shaderVarMetaDatas.GetElements(), sizeof(CShaderVariableComponent*)*shaderVarMetaDatas.GetCount());
|
|
|
|
if(shaderVarComponent)
|
|
{
|
|
if(shaderVarComponent->GetProjectData() == shaderMetaDatasHash)
|
|
{
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
GetCreature()->RemoveComponentType(crCreatureComponent::kCreatureComponentTypeShaderVars);
|
|
shaderVarComponent = NULL;
|
|
}
|
|
}
|
|
if(shaderVarMetaDatas.GetCount() > 0)
|
|
{
|
|
if(!shaderVarComponent)
|
|
{
|
|
shaderVarComponent = static_cast<crCreatureComponentShaderVars*>(GetCreature()->AddComponentType(crCreatureComponent::kCreatureComponentTypeShaderVars));
|
|
shaderVarComponent->SetProjectData(shaderMetaDatasHash);
|
|
}
|
|
|
|
int numNewPairs = 0;
|
|
for(int i=0; i<shaderVarMetaDatas.GetCount(); ++i)
|
|
{
|
|
CShaderVariableComponent& shaderVarMetaData = *shaderVarMetaDatas[i];
|
|
int numTracks = shaderVarMetaData.m_tracks.GetCount();
|
|
numNewPairs += numTracks;
|
|
}
|
|
|
|
crCreatureComponentShaderVars::FastAddShaderVarDofPairs addPairs(*shaderVarComponent, numNewPairs);
|
|
|
|
for(int i=0; i<shaderVarMetaDatas.GetCount(); ++i)
|
|
{
|
|
CShaderVariableComponent& shaderVarMetaData = *shaderVarMetaDatas[i];
|
|
int numTracks = shaderVarMetaData.m_tracks.GetCount();
|
|
#if __ASSERT
|
|
int numIds = shaderVarMetaData.m_ids.GetCount();
|
|
int numComponents = shaderVarMetaData.m_components.GetCount();
|
|
animAssertf(numIds == numTracks, "Found %d ids while expecting %d",numIds,numTracks);
|
|
animAssertf(numComponents == numTracks, "Found %d components while expecting %d",numComponents,numTracks);
|
|
|
|
numTracks = Min(numTracks,Min(numIds,numComponents));
|
|
#endif // __ASSERT
|
|
fwShaderVarComponentData data;
|
|
data.unpack.m_Hash = shaderVarMetaData.m_shaderVariableHashString.GetHash();
|
|
data.unpack.m_PedCompId = u8(shaderVarMetaData.m_pedcompID);
|
|
data.unpack.m_MaskId = u8(shaderVarMetaData.m_maskID);
|
|
|
|
for(int n=0; n<numTracks; ++n)
|
|
{
|
|
data.unpack.m_Component = shaderVarMetaData.m_components[n];
|
|
addPairs.FastAddPair(shaderVarMetaData.m_tracks[n], shaderVarMetaData.m_ids[n], data.m_Packed);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
GetCreature()->RemoveComponentType(crCreatureComponent::kCreatureComponentTypeShaderVars);
|
|
}
|
|
}
|
|
|
|
//
|
|
// name: CDynamicEntity::RemoveShaderVarCreatureComponent
|
|
// description: Removes the shadervars component from the creature
|
|
void CDynamicEntity::RemoveShaderVarCreatureComponent()
|
|
{
|
|
crCreature *creature = GetCreature();
|
|
if (creature)
|
|
{
|
|
creature->RemoveComponentType(crCreatureComponent::kCreatureComponentTypeShaderVars);
|
|
}
|
|
}
|
|
|
|
#if ENABLE_BLENDSHAPES
|
|
//
|
|
// name: CDynamicEntity::AddBlendshapesCreatureComponent
|
|
// description: Add a blendshape component to the creature
|
|
// add blendshape dofs to the animation frame
|
|
// add blendshape dofs to the static animation frames in the animblender
|
|
void CDynamicEntity::AddBlendshapesCreatureComponent(rmcDrawable& drawable)
|
|
{
|
|
if ( GetCreature() && GetCreature()->FindComponent(crCreatureComponent::kCreatureComponentTypeShaderVars))
|
|
{
|
|
Assertf(0, "Creature already has a CreatureComponentTypeBlendShapes");
|
|
return;
|
|
}
|
|
|
|
fwDynamicEntityComponent *dynComp = GetDynamicComponent();
|
|
if (dynComp)
|
|
{
|
|
crCreature *creature = dynComp->GetCreature();
|
|
if (creature)
|
|
{
|
|
// Add a blendshape component to the creature
|
|
grbTargetManager *targetManager = dynComp->GetTargetManager();
|
|
if(targetManager)
|
|
{
|
|
crCreatureComponentBlendShapes* component = static_cast<crCreatureComponentBlendShapes*>(GetCreature()->AllocateComponent(crCreatureComponent::kCreatureComponentTypeBlendShapes));
|
|
component->Init(*creature, drawable, *targetManager);
|
|
creature->AddComponent(*component);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// name: CDynamicEntity::RemoveBlendshapesCreatureComponent
|
|
// description: Removes the blendshape component from the creature
|
|
void CDynamicEntity::RemoveBlendshapesCreatureComponent()
|
|
{
|
|
crCreature *creature = GetCreature();
|
|
if (creature)
|
|
{
|
|
creature->RemoveComponentType(crCreatureComponent::kCreatureComponentTypeBlendShapes);
|
|
}
|
|
}
|
|
#endif // ENABLE_BLENDSHAPES
|
|
|
|
void CDynamicEntity::CreateAnimDirector(rmcDrawable& ENABLE_BLENDSHAPES_ONLY(drawable), bool addExtraDofsComponent, bool withRagDollComponent, bool withFacialRigComponent, CCustomShaderEffectBase* pCustomShaderEffectBase, grbTargetManager * ENABLE_BLENDSHAPES_ONLY(pgrbTargetManager))
|
|
{
|
|
#if ENABLE_BLENDSHAPES
|
|
InitTargetManager();
|
|
#endif // ENABLE_BLENDSHAPES
|
|
|
|
Assert(!GetCreature());
|
|
crCreature* creature = rage_new crCreature;
|
|
creature->SetComponentFactory(fwAnimDirectorComponentCreature::GetComponentFactory());
|
|
creature->Init(fwAnimDirectorComponentCreature::GetFrameDataFactory(), fwAnimDirectorComponentCreature::GetAccelerator(), GetSkeleton());
|
|
SetCreature(creature);
|
|
|
|
if(addExtraDofsComponent)
|
|
{
|
|
const u16 kNumMoverDofs = 2;
|
|
const u16 kNumExtraDofs = 7;
|
|
static crFrameDataFixedDofs<kNumMoverDofs + kNumExtraDofs> frameData;
|
|
|
|
if(!frameData.GetNumDofs())
|
|
{
|
|
crFrameDataInitializerMover moverInitializer;
|
|
moverInitializer.InitializeFrameData(frameData);
|
|
|
|
u8 tracks[kNumExtraDofs] =
|
|
{
|
|
kTrackFirstPersonCameraWeight,
|
|
kTrackConstraintHelperLeftHandWeight,
|
|
kTrackConstraintHelperRightHandWeight,
|
|
kTrackBoneRotation,
|
|
kTrackBoneTranslation,
|
|
kTrackBoneRotation,
|
|
kTrackBoneTranslation
|
|
};
|
|
u16 ids[kNumExtraDofs] =
|
|
{
|
|
0,
|
|
0,
|
|
0,
|
|
BONETAG_CH_L_HAND,
|
|
BONETAG_CH_L_HAND,
|
|
BONETAG_CH_R_HAND,
|
|
BONETAG_CH_R_HAND
|
|
};
|
|
u8 types[kNumExtraDofs] =
|
|
{
|
|
kFormatTypeFloat,
|
|
kFormatTypeFloat,
|
|
kFormatTypeFloat,
|
|
kFormatTypeQuaternion,
|
|
kFormatTypeVector3,
|
|
kFormatTypeQuaternion,
|
|
kFormatTypeVector3
|
|
};
|
|
crFrameDataInitializerDofs dofsInitializer(kNumExtraDofs, tracks, ids, types, false);
|
|
dofsInitializer.InitializeFrameData(frameData);
|
|
}
|
|
|
|
AddExtraDofsCreatureComponent(frameData);
|
|
}
|
|
|
|
if(pCustomShaderEffectBase)
|
|
{
|
|
AddShaderVarCreatureComponent(pCustomShaderEffectBase);
|
|
}
|
|
|
|
#if ENABLE_BLENDSHAPES
|
|
if(pgrbTargetManager)
|
|
{
|
|
AddBlendshapesCreatureComponent(drawable);
|
|
}
|
|
#endif // ENABLE_BLENDSHAPES
|
|
|
|
fwDynamicEntityComponent* dynamic = CreateDynamicComponentIfMissing();
|
|
dynamic->CreateAnimDirector(*this, withRagDollComponent, withFacialRigComponent);
|
|
|
|
AddSceneUpdateFlags(GetStartAnimSceneUpdateFlag());
|
|
}
|
|
|
|
void CDynamicEntity::DeleteAnimDirector()
|
|
{
|
|
fwDynamicEntityComponent* dynamic = GetDynamicComponent();
|
|
if (dynamic)
|
|
{
|
|
dynamic->DeleteAnimDirector();
|
|
|
|
delete dynamic->GetCreature();
|
|
dynamic->SetCreature(NULL);
|
|
}
|
|
|
|
#if ENABLE_BLENDSHAPES
|
|
ShutdownTargetManager();
|
|
#endif // ENABLE_BLENDSHAPES
|
|
}
|
|
|
|
const GtaThread* CDynamicEntity::GetThreadThatCreatedMe() const
|
|
{
|
|
const CScriptEntityExtension* pExtension = GetExtension<CScriptEntityExtension>();
|
|
|
|
if (pExtension && pExtension->GetScriptHandler())
|
|
{
|
|
return static_cast<const GtaThread*>(pExtension->GetScriptHandler()->GetThread());
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
const CGameScriptId* CDynamicEntity::GetScriptThatCreatedMe() const
|
|
{
|
|
const CScriptEntityExtension* pExtension = GetExtension<CScriptEntityExtension>();
|
|
|
|
if (pExtension && pExtension->GetScriptInfo())
|
|
{
|
|
return static_cast<const CGameScriptId*>(&pExtension->GetScriptInfo()->GetScriptId());
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void CDynamicEntity::SetupMissionState()
|
|
{
|
|
PopTypeSet(POPTYPE_MISSION);
|
|
|
|
m_nDEflags.bCheckedForDead = TRUE;
|
|
|
|
if (!GetIsTypeObject() && AssertVerify(GetPortalTracker()))
|
|
{
|
|
GetPortalTracker()->SetLoadsCollisions(true); //force loading of interior collisions
|
|
CPortalTracker::AddToActivatingTrackerList(GetPortalTracker()); // causes interiors to activate & stay active
|
|
}
|
|
|
|
if (GetNetworkObject() && !IsNetworkClone())
|
|
{
|
|
NetworkInterface::GetObjectManager().ConvertRandomObjectToScriptObject(GetNetworkObject());
|
|
}
|
|
}
|
|
|
|
void CDynamicEntity::CleanupMissionState()
|
|
{
|
|
scriptDisplayf("CDynamicEntity::CleanupMissionState called for script entity with model %s (Entity = 0x%p)", GetModelName(), this);
|
|
|
|
PopTypeSet(POPTYPE_RANDOM_AMBIENT);
|
|
|
|
if (AssertVerify(GetPortalTracker()))
|
|
{
|
|
GetPortalTracker()->SetLoadsCollisions(false);
|
|
CPortalTracker::RemoveFromActivatingTrackerList(GetPortalTracker());
|
|
}
|
|
|
|
if (GetNetworkObject())
|
|
{
|
|
GetNetworkObject()->OnConversionToAmbientObject();
|
|
}
|
|
}
|
|
|
|
void CDynamicEntity::DestroyScriptExtension()
|
|
{
|
|
CScriptEntityExtension* pExtension = GetExtension<CScriptEntityExtension>();
|
|
|
|
if (pExtension)
|
|
{
|
|
Assert(!pExtension->GetScriptHandler());
|
|
GetExtensionList().Destroy(pExtension);
|
|
}
|
|
}
|
|
|
|
void CDynamicEntity::InitClass()
|
|
{
|
|
//CCreatureMetaData::InitClass();
|
|
|
|
fwAnimDirector::InitClass();
|
|
|
|
CBaseIkManager::InitClass();
|
|
|
|
CMovePed::InitClass();
|
|
}
|
|
|
|
void CDynamicEntity::ShutdownClass()
|
|
{
|
|
CMovePed::ShutdownClass();
|
|
|
|
fwAnimDirector::ShutdownClass();
|
|
}
|
|
|
|
eSkelMatrixMode CDynamicEntity::GetSkelMode()
|
|
{
|
|
eSkelMatrixMode mode = SKEL_NORMAL;
|
|
CBaseModelInfo* pModelInfo = GetBaseModelInfo();
|
|
const rmcLodGroup& lodgroup = pModelInfo->GetDrawable()->GetLodGroup();
|
|
if (lodgroup.ContainsLod(LOD_HIGH) && lodgroup.GetLodModel0(LOD_HIGH).IsModelRelative())
|
|
mode = SKEL_MODEL_RELATIVE;
|
|
|
|
return(mode);
|
|
}
|
|
|
|
void CDynamicEntity::AddToStraddlingPortalsContainer()
|
|
{
|
|
Assertf(m_nDEflags.bIsStraddlingPortal == 0, "Entity is already straddling a portal");
|
|
fwStraddlingPortalsContainer *pContainer = static_cast<fwExteriorSceneGraphNode*>(fwWorldRepMulti::GetSceneGraphRoot())->GeStradlingPortalsContainer();
|
|
|
|
if (Verifyf(pContainer->GetEntityCount() < pContainer->GetStorageSize(), "Container for Entities straddling portals is full"))
|
|
{
|
|
fwExteriorSceneGraphNode *pExteriorSceneGraphNode = static_cast<fwExteriorSceneGraphNode*>(fwWorldRepMulti::GetSceneGraphRoot());
|
|
m_portalStraddlingContainerIndex = pExteriorSceneGraphNode->AppendToStraddlingPortalContainer(this);
|
|
// This flag must be set here after the call to AppendToStraddlingPortalContainer or we will end up in a loop recursively calling CGameWorld::UpdateEntityDesc
|
|
m_nDEflags.bIsStraddlingPortal = 1;
|
|
RequestUpdateInWorld();
|
|
}
|
|
|
|
}
|
|
void CDynamicEntity::RemoveFromStraddlingPortalsContainer()
|
|
{
|
|
Assertf(m_nDEflags.bIsStraddlingPortal == 1 && m_portalStraddlingContainerIndex != 0xFF, "Entity is not straddling a portal");
|
|
|
|
m_nDEflags.bIsStraddlingPortal = 0;
|
|
fwExteriorSceneGraphNode *pExteriorSceneGraphNode = static_cast<fwExteriorSceneGraphNode*>(fwWorldRepMulti::GetSceneGraphRoot());
|
|
pExteriorSceneGraphNode->RemoveFromStraddlingPortalContainer(m_portalStraddlingContainerIndex);
|
|
m_portalStraddlingContainerIndex = 0xFF;
|
|
|
|
RequestUpdateInWorld();
|
|
}
|
|
|
|
void CDynamicEntity::UpdateStraddledPortalEntityDesc()
|
|
{
|
|
fwStraddlingPortalsContainer *pContainer = static_cast<fwExteriorSceneGraphNode*>(fwWorldRepMulti::GetSceneGraphRoot())->GeStradlingPortalsContainer();
|
|
u8 bIsStraddlingPortalSave = m_nDEflags.bIsStraddlingPortal;
|
|
|
|
// In order to prevent recursively calling this function we must temporarily turn this flag off
|
|
m_nDEflags.bIsStraddlingPortal = 0;
|
|
CGameWorld::UpdateEntityDesc(this, pContainer->GetEntityDesc(m_portalStraddlingContainerIndex));
|
|
m_nDEflags.bIsStraddlingPortal = bIsStraddlingPortalSave;
|
|
}
|
|
|
|
|
|
|
|
#if __BANK
|
|
void CDynamicEntity::LogBaseFlagChange(s32 nFlag, bool bIsProtected, bool bNewVal, bool bOldVal)
|
|
{
|
|
TUNE_BOOL(DISABLE_COLLISION_FLAG_LOGGING, false);
|
|
|
|
if(DISABLE_COLLISION_FLAG_LOGGING)
|
|
return;
|
|
|
|
if(bNewVal == bOldVal)
|
|
return;
|
|
|
|
if(GetIsDynamic() && PopTypeIsMission())
|
|
{
|
|
if(CAILogManager::IsLogInitialised())
|
|
{
|
|
const char *pFlagNames[3] = {
|
|
"IS_FIXED",
|
|
"IS_FIXED_BY_NETWORK",
|
|
"IS_FIXED_UNTIL_COLLISION",
|
|
};
|
|
|
|
int nNameIndex = -1;
|
|
|
|
if(!bIsProtected)
|
|
{
|
|
switch(nFlag)
|
|
{
|
|
case fwEntity::IS_FIXED:
|
|
nNameIndex = 0;
|
|
break;
|
|
case fwEntity::IS_FIXED_BY_NETWORK:
|
|
nNameIndex = 1;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch(nFlag)
|
|
{
|
|
case fwEntity::IS_FIXED_UNTIL_COLLISION:
|
|
nNameIndex = 2;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(nNameIndex > -1)
|
|
{
|
|
const char *pEntName = AILogging::GetDynamicEntityNameSafe(reinterpret_cast<CDynamicEntity *>(this));
|
|
if(pEntName[0] == 0)
|
|
pEntName = GetModelName();
|
|
|
|
CAILogManager::GetLog().Log(bNewVal ? "[FixedPhysicsFlags] Entity %s had %s flag set.\n" : "[FixedPhysicsFlags] Entity %s had %s flag unset.\n", pEntName, pFlagNames[nNameIndex]);
|
|
|
|
if(CTheScripts::GetCurrentScriptNameAndProgramCounter()[0] != ' ')
|
|
CAILogManager::GetLog().Log("%s\n", CTheScripts::GetCurrentScriptNameAndProgramCounter());
|
|
|
|
AILogging::StackTraceLog();
|
|
CAILogManager::GetLog().Log("[FixedPhysicsFlags] END BASE FLAG CHANGE OUTPUT\n");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif |