Files
GTASource/game/physics/Rope.cpp

850 lines
25 KiB
C++
Raw Normal View History

2025-02-23 17:40:52 +08:00
#if __BANK
#include "bank/bkmgr.h"
#include "bank/bank.h"
#include "bank/combo.h"
#include "bank/slider.h"
#include "debug/DebugScene.h"
#include "grcore/debugdraw.h"
#include "input/keyboard.h"
#include "input/keys.h"
#include "scene/Entity.h"
#include "physics.h"
#include "Rope.h"
#include "fwpheffects/ropemanager.h"
#include "fwpheffects/ropedatamanager.h"
#include "physics/gtaArchetype.h"
#include "Peds/Rendering/PedVariationStream.h"
#include "Peds/ped.h"
#include "renderer/Entities/PedDrawHandler.h"
//#pragma optimize("", off)
namespace rage
{
EXT_PFD_DECLARE_ITEM(Ropes);
bkBank* ropeBank = NULL;
bkButton* clearButton = NULL;
bkButton* reloadButton = NULL;
bkButton* addBankButton = NULL;
s32 iComponent= s32(NULL);
Vector3 s_Offset = Vector3( 0.0f, 0.0f, 0.0f );
Vec3V s_RopeStart;
s32 iClicked = 0;
#define BIG_FLOAT 999999.0f
#define BONE_NAME_LEN 16
phInst* entityEnd = NULL;
CEntity* pEntityEnd = NULL;
Vector3 ropeEnd( BIG_FLOAT, BIG_FLOAT, BIG_FLOAT );
const char* s_RopeTypeNames[NUM_ROPE_TYPES_IN_XML] = { NULL };
char s_BoneNameA[BONE_NAME_LEN];
char s_BoneNameB[BONE_NAME_LEN];
// TODO: work in progress - cloth debug purposes
CEntity* pLastPickedPed = NULL;
void clothBankManager::DetachFromDrawableCallback(clothVariationData* pClothVarData)
{
Assert( pLastPickedPed );
Assert( pClothVarData );
const ePedVarComp varComp = (const ePedVarComp)clothManager::ms_ComponentIndex;//PV_COMP_UPPR;
CPed* pPed = (CPed*)pLastPickedPed;
CPedDrawHandler* pPedDrawHandler = (CPedDrawHandler*)&(pLastPickedPed->GetDrawHandler());
Assert( pPedDrawHandler );
CPedStreamRenderGfx* pGfxData = pPedDrawHandler->GetPedRenderGfx();
Assert( pGfxData );
CPedVariationData& varData = pPedDrawHandler->GetVarData();
varData.ResetClothData( varComp );
pGfxData->m_clothData[varComp] = NULL;
#if HAS_RENDER_MODE_SHADOWS
pPed->ClearRenderFlags(CEntity::RenderFlag_USE_CUSTOMSHADOWS);
#endif
pPed->m_CClothController[varComp] = NULL;
pClothVarData->DeleteBuffers();
// TODO: do something ??
// pCharCloth->SetEntityVerticesPtr( pClothVarData->GetClothVertices(clothManager::GetBufferIndex()) );
// pCharCloth->SetEntityParentMtxPtr( pClothVarData->GetClothParentMatrixPtr() );
// const crSkeleton* pSkeleton = pPed->GetSkeleton();
// Assert( pSkeleton );
// const Mat34V* parentMtx = pSkeleton->GetParentMtx();
// Assert( parentMtx );
// pCharCloth->SetParentMtx( *parentMtx );
// gDrawListMgr->CharClothRemove( pClothVarData );
}
void clothBankManager::AttachToDrawableCallback(clothVariationData* pClothVarData)
{
Assert( pLastPickedPed );
Assert( pClothVarData );
const ePedVarComp varComp = (const ePedVarComp)clothManager::ms_ComponentIndex; //PV_COMP_UPPR;
CPed* pPed = (CPed*)pLastPickedPed;
CPedDrawHandler* pPedDrawHandler = (CPedDrawHandler*)&(pLastPickedPed->GetDrawHandler());
Assert( pPedDrawHandler );
CPedStreamRenderGfx* pGfxData = pPedDrawHandler->GetPedRenderGfx();
Assert( pGfxData );
CPedVariationData& varData = pPedDrawHandler->GetVarData();
varData.SetClothData( varComp, pClothVarData );
pGfxData->m_clothData[varComp] = pClothVarData;
#if HAS_RENDER_MODE_SHADOWS
pPed->SetRenderFlag(CEntity::RenderFlag_USE_CUSTOMSHADOWS);
#endif
characterCloth* pCharCloth = pClothVarData->GetCloth();
Assert( pCharCloth );
characterClothController* pCharClothController = pCharCloth->GetClothController();
Assert( pCharClothController );
pPed->m_CClothController[varComp] = pCharClothController;
// NOTE: needed only for rendering
const int numVerts = pCharClothController->GetCurrentCloth()->GetNumVertices();
pClothVarData->AllocateBuffers( numVerts );
const int bufferIdx = clothManager::GetBufferIndex();
pCharCloth->SetEntityVerticesPtr( pClothVarData->GetClothVertices(bufferIdx) );
pCharCloth->SetEntityParentMtxPtr( pClothVarData->GetClothParentMatrixPtr(bufferIdx) );
const crSkeleton* pSkeleton = pPed->GetSkeleton();
Assert( pSkeleton );
const Mat34V* parentMtx = pSkeleton->GetParentMtx();
Assert( parentMtx );
pCharCloth->SetParentMtx( *parentMtx );
for(int i = 0; i < NUM_CLOTH_BUFFERS; ++i)
{
Vec3V* RESTRICT verts = pClothVarData->GetClothVertices(i);
Assert( verts );
// NOTE: don't want to crash if the game run out of streaming memory
if( verts )
{
Vec3V* RESTRICT origVerts = pCharClothController->GetCloth(0)->GetClothData().GetVertexPointer();
Assert( origVerts );
// origVerts should exists, if this fails there is bug somewhere in cloth instancing
for(int j=0; j<numVerts; ++j)
{
verts[j] = origVerts[j];
#if RSG_PC || RSG_DURANGO || RSG_ORBIS
// clear out W channel to prevent NaNs in shader vars
verts[j].SetW(MAGIC_ZERO);
#endif
}
}
}
}
void clothBankManager::PickPed()
{
if( clothManager::ms_EnablePedPick )
{
Vector3 l_Offset = Vector3( 0.0f, 0.0f, 0.0f );
s32 iComp = s32(NULL);
CEntity* pEntity = CDebugScene::GetEntityUnderMouse( &l_Offset, &iComp, ArchetypeFlags::GTA_PED_TYPE );
if( pEntity && pEntity->GetIsPhysical() && ioMapper::DebugKeyPressed(fwClothDebug::sm_ConfirmSelectionKey) )
{
clothManager::ms_PedSkeleton = (const crSkeleton*)pEntity->GetSkeleton();
clothManager::ms_EnablePedPick = false;
#if CLOTH_INSTANCE_FROM_DATA
clothManager* pClothManager = CPhysics::GetClothManager();
Assert( pClothManager );
pClothManager->m_AttachToDrawableCB = clothBankManager::AttachToDrawableCallback;
pClothManager->m_DetachFromDrawableCB = clothBankManager::DetachFromDrawableCallback;
#endif
pLastPickedPed = pEntity;
}
}
}
void clothBankManager::PickVehicle()
{
if( clothManager::ms_EnableVehiclePick )
{
Vector3 l_Offset = Vector3( 0.0f, 0.0f, 0.0f );
s32 iComp = s32(NULL);
CEntity* pEntity = CDebugScene::GetEntityUnderMouse( &l_Offset, &iComp, ArchetypeFlags::GTA_VEHICLE_TYPE );
if( pEntity && pEntity->GetIsPhysical() && ioMapper::DebugKeyPressed(fwClothDebug::sm_ConfirmSelectionKey) )
{
Assert( pEntity->GetCurrentPhysicsInst() );
clothManager::ms_VehicleFrame = (const Mat34V*)&(pEntity->GetCurrentPhysicsInst()->GetMatrix());
clothManager::ms_EnableVehiclePick = false;
}
}
}
bkBank* ropeBankManager::GetBank()
{
return ropeBank;
}
ropeBankManager::ropeBankManager()
: m_RopeManager(NULL)
, m_pLastSelected(NULL)
, m_MaxRopeLen(5.0f)
, m_MinRopeLen(0.5f)
, m_RopeLen(5.0f)
, m_LenA(2.5f)
, m_LenB(2.5f)
, m_RopeLenChangeRate(0.5f)
, m_Selection(false)
, m_CreateEnabled(false)
, m_UseDefaultPosRopeStart(false)
, m_UseDefaultPosRopeEnd(false)
, m_HasCollision(false)
, m_ComponentPartA(0)
, m_ComponentPartB(0)
, m_NumSegments(6)
, m_NumIterations(DEFAULT_ROPE_ITERATIONS)
, m_WorldPos(Vector3(Vector3::ZeroType))
, m_AttachAtPos(false)
, m_PPUonly(false)
, m_LockFromFront(true)
, m_TimeMultiplier(1.0f)
, m_Friction(1.0f)
, m_Breakable(false)
, m_Pinned(true)
, m_RopeTypeIndex(0)
{
s_BoneNameA[0] = 0;
s_BoneNameB[0] = 0;
}
ropeBankManager::~ropeBankManager()
{
AssertMsg(m_RopeList.GetHead()==NULL , "Leaked a ropeInstance in the active list");
}
void ropeBankManager::AddBank()
{
ropeBankManager* bankMgr = CPhysics::GetRopeBankManager();
Assert( bankMgr );
ropeBank->Remove( *(bkWidget*)addBankButton );
addBankButton = NULL;
ropeDataManager::LoadRopeTexures();
CPhysics::GetRopeManager()->AddWidgets(ropeBank);
int ropeTypesCount = ropeDataManager::GetTypeDataCount();
for( int i = 0; i < ropeTypesCount; ++i )
{
s_RopeTypeNames[i] = ropeDataManager::GetRopeDataMgr()->GetTypeDataName(i);
}
ropeBank->AddCombo( "Rope Types", &bankMgr->m_RopeTypeIndex, ropeTypesCount, s_RopeTypeNames );
ropeBank->AddToggle( "Create rope", &bankMgr->m_CreateEnabled );
ropeBank->AddToggle( "Attach to Entity", &bankMgr->m_Selection );
ropeBank->AddToggle( "Use Default Entity Position Rope Start", &bankMgr->m_UseDefaultPosRopeStart );
ropeBank->AddToggle( "Use Default Entity Position Rope End", &bankMgr->m_UseDefaultPosRopeEnd );
ropeBank->AddToggle( "Attach at world pos", &bankMgr->m_AttachAtPos );
ropeBank->AddSlider( "World pos", &bankMgr->m_WorldPos,
VEC3V_TO_VECTOR3(Vec3VFromF32(-100000.0f)),
VEC3V_TO_VECTOR3(Vec3VFromF32( 100000.0f)),
VEC3V_TO_VECTOR3(Vec3V(V_FLT_SMALL_5)) );
ropeBank->AddToggle( "Pick Edges", &bankMgr->m_DebugPickEdges );
ropeBank->AddToggle( "Enable rope collision", &bankMgr->m_HasCollision );
ropeBank->AddToggle( "Rope on PPU ONLY", &bankMgr->m_PPUonly );
ropeBank->AddToggle( "Lock rope from front", &bankMgr->m_LockFromFront );
ropeBank->AddToggle( "Break rope from gunshot", &bankMgr->m_Breakable );
ropeBank->AddToggle( "Pin rope by default", &bankMgr->m_Pinned );
ropeBank->AddSlider( "Rope friction", &bankMgr->m_Friction, 0.0f, 1.0f, bankMgr->m_Friction, datCallback( MFA( ropeBankManager::SetFrictionCB ), bankMgr) );
ropeBank->AddSlider( "Rope weight scale", &bankMgr->m_TimeMultiplier, 0.001f, 20.0f, bankMgr->m_TimeMultiplier );
ropeBank->AddSlider( "Rope Max Length", &bankMgr->m_MaxRopeLen, 0.1f, 100.0f, bankMgr->m_MaxRopeLen );
ropeBank->AddSlider( "Rope Min Length", &bankMgr->m_MinRopeLen, 0.1f, 100.0f, bankMgr->m_MinRopeLen );
ropeBank->AddSlider( "Rope Length", &bankMgr->m_RopeLen, 0.1f, 100.0f, bankMgr->m_RopeLen );
ropeBank->AddSlider( "Rope A Length", &bankMgr->m_LenA, 0.1f, 100.0f, bankMgr->m_LenA );
ropeBank->AddSlider( "Rope B Length", &bankMgr->m_LenB, 0.1f, 100.0f, bankMgr->m_LenB );
ropeBank->AddSlider( "Rope Length Change Rate", &bankMgr->m_RopeLenChangeRate, 0.1f, 10.0f, bankMgr->m_RopeLenChangeRate );
ropeBank->AddSlider( "Component part A", &bankMgr->m_ComponentPartA, 0, 100, 1 );
ropeBank->AddSlider( "Component part B", &bankMgr->m_ComponentPartB, 0, 100, 1 );
ropeBank->AddSlider( "Number of rope segments", &bankMgr->m_NumSegments, 0, 100, 1 );
ropeBank->AddSlider( "Number of iterations", &bankMgr->m_NumIterations, 1, 100, 1 );
ropeBank->AddText( "Bone Name part A", s_BoneNameA, BONE_NAME_LEN, false );
ropeBank->AddText( "Bone Name part B", s_BoneNameB, BONE_NAME_LEN, false );
clearButton = ropeBank->AddButton( "Press to clear end pos", ropeBankManager::ClearEndPos );
Assert( clearButton );
reloadButton = ropeBank->AddButton( "Reload all ropes", ropeBankManager::ReloadAllNodes );
Assert( reloadButton );
ropeDataManager::AddWidgets(*ropeBank);
bankMgr->LoadFromRopeManager();
}
void ropeBankManager::SetFrictionCB()
{
// set rope friction to the ropemanager, not the material
}
void ropeBankManager::LoadFromRopeManager()
{
Assert( m_RopeManager );
rage::atDNode<ropeInstance*>* node = m_RopeManager->GetActiveList()->GetHead();
while( node )
{
ropeInstance* rope = (ropeInstance*)node->Data;
Assert( rope );
bkGroup* ropeGroup = rope->m_RAGGroup;
if( ropeGroup )
{
ropeBank->DeleteGroup( *ropeGroup );
}
phInst* attachedA = rope->GetInstanceA();
if( !attachedA )
attachedA = rope->GetAttachedTo();
AddRopeGroup( rope, attachedA, rope->GetInstanceB() );
node = node->GetNext();
}
}
void ropeBankManager::InitWidgets(ropeManager* ptr)
{
Assert(ptr);
m_RopeManager = ptr;
ropeBank = &BANKMGR.CreateBank("Rope Management");
addBankButton = ropeBank->AddButton( "Create Widgets", ropeBankManager::AddBank );
}
void ropeBankManager::DestroyWidgets()
{
if( ropeBank )
{
BANKMGR.DestroyBank( *ropeBank );
ropeBank = 0;
}
}
void ropeBankManager::DetachFromObjectB( void* data )
{
Assert( data );
atDNode<RopeBankData> *node = (atDNode<RopeBankData>*)data;
ropeInstance* rope = ((RopeBankData*)&node->Data)->rope;
Assert( rope );
bkButton* button = ((RopeBankData*)&node->Data)->button;
Assert( button );
phInst* inst = ((RopeBankData*)&node->Data)->instB;
Assert( inst );
rope->DetachFromObject( inst );
ropeBank->Remove( *(bkWidget*)button );
m_RopeList.PopNode( *node );
delete node;
}
void ropeBankManager::DetachFromObjectA( void* data )
{
Assert( data );
atDNode<RopeBankData> *node = (atDNode<RopeBankData>*)data;
ropeInstance* rope = ((RopeBankData*)&node->Data)->rope;
Assert( rope );
bkButton* button = ((RopeBankData*)&node->Data)->button;
Assert( button );
phInst* inst = ((RopeBankData*)&node->Data)->instA;
Assert( inst );
rope->DetachFromObject( inst );
ropeBank->Remove( *(bkWidget*)button );
m_RopeList.PopNode( *node );
delete node;
}
void ropeBankManager::DeleteAllNodes( ropeInstance* rope )
{
// go through all nodes and delete those sharing this rope
bool searchAgain;
do
{
searchAgain = false;
for (atDNode<RopeBankData> *node = m_RopeList.GetHead(); node; node=node->GetNext())
{
if( ((RopeBankData*)&node->Data)->rope == rope )
{
ropeBank->Remove( *(bkWidget*)(((RopeBankData*)&node->Data)->button) );
m_RopeList.PopNode( *node );
delete node;
searchAgain = true;
break;
}
}
} while ( searchAgain );
}
void ropeBankManager::ReloadAllNodes()
{
Assert( ropeBank );
rage::atDList<ropeBankManager::RopeBankData>& nodeList = CPhysics::GetRopeBankManager()->GetRopeList();
atDNode<RopeBankData> *node = nodeList.GetHead();
while( node )
{
ropeBank->Remove( *(bkWidget*)(((ropeBankManager::RopeBankData*)&node->Data)->button) );
nodeList.PopNode( *node );
delete node;
node = nodeList.GetHead();
}
CPhysics::GetRopeBankManager()->LoadFromRopeManager();
}
void ropeBankManager::DeleteRope( void* data )
{
Assert( data );
atDNode<RopeBankData> *node = (atDNode<RopeBankData>*)data;
ropeInstance* rope = ((RopeBankData*)&node->Data)->rope;
Assert( rope );
bkGroup* ropeGroup = rope->m_RAGGroup;
Assert( ropeGroup );
bkButton* button = ((RopeBankData*)&node->Data)->button;
Assert( button );
ropeBank->Remove( *(bkWidget*)button );
m_RopeManager->RemoveRope( rope );
m_RopeList.PopNode( *node );
DeleteAllNodes( rope );
delete node;
ropeBank->DeleteGroup( *ropeGroup );
}
void ropeBankManager::AttachToArray( void* data )
{
Assert( data );
atDNode<RopeBankData> *node = (atDNode<RopeBankData>*)data;
ropeInstance* rope = ((RopeBankData*)&node->Data)->rope;
Assert( rope );
// NOTE: this is the last rope start
static float constraintRateChange = 1.0f;
rope->AttachObjectsToConstraintArray( s_RopeStart, VECTOR3_TO_VEC3V(s_Offset), ((RopeBankData*)&node->Data)->instA, m_pLastSelected->GetCurrentPhysicsInst(), 0, 0, m_RopeLen, constraintRateChange );
}
void ropeBankManager::StartWinding( void* data )
{
Assert( data );
atDNode<RopeBankData> *node = (atDNode<RopeBankData>*)data;
ropeInstance* rope = ((RopeBankData*)&node->Data)->rope;
Assert( rope );
rope->StartWindingFront();
}
#if !__RESOURCECOMPILER
void ropeBankManager::Load( void* data )
{
Assert( data );
atDNode<RopeBankData> *node = (atDNode<RopeBankData>*)data;
ropeInstance* rope = ((RopeBankData*)&node->Data)->rope;
Assert( rope );
rope->Load( "ropeDebug" );
}
void ropeBankManager::Save( void* data )
{
Assert( data );
atDNode<RopeBankData> *node = (atDNode<RopeBankData>*)data;
ropeInstance* rope = ((RopeBankData*)&node->Data)->rope;
Assert( rope );
rope->Save( "ropeDebug" );
}
#endif // !__RESOURCECOMPILER
void ropeBankManager::ToggleDebugInfo( void* data )
{
Assert( data );
atDNode<RopeBankData> *node = (atDNode<RopeBankData>*)data;
ropeInstance* rope = ((RopeBankData*)&node->Data)->rope;
Assert( rope );
rope->ToggleDebugInfo();
}
void ropeBankManager::StopWinding( void* data )
{
Assert( data );
atDNode<RopeBankData> *node = (atDNode<RopeBankData>*)data;
ropeInstance* rope = ((RopeBankData*)&node->Data)->rope;
Assert( rope );
rope->StopWindingFront();
}
void ropeBankManager::StartUnwindingFront( void* data )
{
Assert( data );
atDNode<RopeBankData> *node = (atDNode<RopeBankData>*)data;
ropeInstance* rope = ((RopeBankData*)&node->Data)->rope;
Assert( rope );
rope->StartUnwindingFront();
}
void ropeBankManager::StopUnwindingFront( void* data )
{
Assert( data );
atDNode<RopeBankData> *node = (atDNode<RopeBankData>*)data;
ropeInstance* rope = ((RopeBankData*)&node->Data)->rope;
Assert( rope );
rope->StopUnwindingFront();
}
void ropeBankManager::StartUnwindingBack( void* data )
{
Assert( data );
atDNode<RopeBankData> *node = (atDNode<RopeBankData>*)data;
ropeInstance* rope = ((RopeBankData*)&node->Data)->rope;
Assert( rope );
rope->StartUnwindingBack();
}
void ropeBankManager::StopUnwindingBack( void* data )
{
Assert( data );
atDNode<RopeBankData> *node = (atDNode<RopeBankData>*)data;
ropeInstance* rope = ((RopeBankData*)&node->Data)->rope;
Assert( rope );
rope->StopUnwindingBack();
}
void ropeBankManager::ToggleRopeCollision( void* data )
{
Assert( data );
atDNode<RopeBankData> *node = (atDNode<RopeBankData>*)data;
ropeInstance* rope = ((RopeBankData*)&node->Data)->rope;
Assert( rope );
int typeFlags, includeFlags;
rope->GetPhysInstFlags( typeFlags, includeFlags );
if( typeFlags || includeFlags )
{
rope->SetPhysInstFlags( 0, 0 );
}
else
{
rope->SetPhysInstFlags( ArchetypeFlags::GTA_OBJECT_TYPE, ArchetypeFlags::GTA_OBJECT_INCLUDE_TYPES & (~ArchetypeFlags::GTA_VEHICLE_TYPE) );
}
}
void ropeBankManager::BreakRope( void* data )
{
Assert( data );
atDNode<RopeBankData> *node = (atDNode<RopeBankData>*)data;
ropeInstance* rope = ((RopeBankData*)&node->Data)->rope;
Assert( rope );
ropeInstance* ropeA = NULL;
ropeInstance* ropeB = NULL;
m_RopeManager->BreakRope( rope, ropeA, ropeB, m_LenA, m_LenB, m_MinRopeLen, m_NumSegments );
Assert( ropeA ); // technically this should never happen
Assert( ropeB ); // technically this should never happen
AddRopeGroup( ropeA, rope->GetInstanceA(), rope->GetInstanceB() );
AddRopeGroup( ropeB, rope->GetInstanceA(), rope->GetInstanceB() );
DeleteRope( data );
}
void ropeBankManager::Update(float /*elapsed*/)
{
if( m_DebugPickEdges )
{
Assert( m_RopeManager );
rage::atDNode<ropeInstance*>* node = m_RopeManager->GetActiveList()->GetHead();
while( node )
{
ropeInstance* rope = (ropeInstance*)node->Data;
Assert( rope );
m_RopeManager->PickEdges( Vector3(Vector3::ZeroType), rope->GetEnvCloth()->GetCloth() );
node = node->GetNext();
}
}
if( !m_CreateEnabled || !(ioMapper::DebugKeyDown(KEY_CONTROL)) )
return;
bool ropeAdded = false;
ropeInstance* rope = NULL;
phInst* entityStart = NULL;
if( ioMouse::GetPressedButtons() & ioMouse::MOUSE_LEFT )
{
iClicked |= ioMouse::MOUSE_LEFT;
}
if( ioMouse::GetPressedButtons() & ioMouse::MOUSE_RIGHT )
{
iClicked |= ioMouse::MOUSE_RIGHT;
}
if( ropeBankManager::m_Selection )
{
PF_DRAW_SPHERE_COLOR(Ropes, 0.1f, ropeEnd, Color32(1.0f, 1.0f, 0.0f, 1.0f));
CEntity* pEntity = CDebugScene::GetEntityUnderMouse( &s_Offset, &iComponent, ArchetypeFlags::GTA_ALL_TYPES_MOVER|ArchetypeFlags::GTA_RAGDOLL_TYPE|ArchetypeFlags::GTA_PROJECTILE_TYPE);
if(pEntity && pEntity->GetIsPhysical())
{
m_pLastSelected = pEntity;
const Vector3 vLastSelectedPosition = VEC3V_TO_VECTOR3(m_pLastSelected->GetTransform().GetPosition());
Vector3 localOffset = s_Offset - vLastSelectedPosition;
entityStart = m_pLastSelected->GetCurrentPhysicsInst();
char buff[256];
sprintf( buff, " x: %f, y: %f, z: %f, 0x%p", localOffset.x, localOffset.y, localOffset.z, entityStart );
grcDebugDraw::Text( s_Offset, Color32(1.0f, 1.0f, 1.0f), 0,0, buff );
PF_DRAW_SPHERE_COLOR(Ropes, 0.1f, s_Offset, Color32(1.0f, 1.0f, 0.0f, 1.0f));
if( (ioMouse::GetReleasedButtons() & ioMouse::MOUSE_RIGHT) && (iClicked & ioMouse::MOUSE_RIGHT) )
{
ropeEnd = s_Offset;
if( m_UseDefaultPosRopeEnd )
ropeEnd = vLastSelectedPosition;
entityEnd = entityStart;
pEntityEnd = m_pLastSelected;
}
if( (ioMouse::GetReleasedButtons() & ioMouse::MOUSE_LEFT) && (iClicked & ioMouse::MOUSE_LEFT) )
{
Vec3V rot( 0.0f, 0.0f, -0.5f*PI );
s_RopeStart = VECTOR3_TO_VEC3V(s_Offset);
if( m_UseDefaultPosRopeStart )
s_RopeStart = m_pLastSelected->GetTransform().GetPosition();
rope = m_RopeManager->AddRope( s_RopeStart, rot, m_RopeLen, m_MinRopeLen, m_MaxRopeLen, m_RopeLenChangeRate, m_RopeTypeIndex, m_NumSegments, m_PPUonly, m_LockFromFront, m_TimeMultiplier, m_Breakable, m_Pinned, m_NumIterations );
Assert( rope );
rope->SetNewUniqueId();
if( entityEnd )
{
int endVertex = rope->GetEnvCloth()->GetNumRopeVertices()-1;
rope->Pin( endVertex, VECTOR3_TO_VEC3V(ropeEnd) );
Assert( m_pLastSelected );
Assert( pEntityEnd );
int notEmptyStringA = strcmp(s_BoneNameA,"");
int notEmptyStringB = strcmp(s_BoneNameB,"");
const crSkeleton* pSkelPartA = ( notEmptyStringA ? m_pLastSelected->GetSkeleton() : NULL);
const crSkeleton* pSkelPartB = ( notEmptyStringB ? pEntityEnd->GetSkeleton() : NULL);
if( notEmptyStringA )
s_RopeStart = Vec3V(V_ZERO);
if( notEmptyStringB )
ropeEnd.Zero();
rope->AttachObjects( s_RopeStart, VECTOR3_TO_VEC3V(ropeEnd), entityStart, entityEnd, m_ComponentPartA, m_ComponentPartB, m_MaxRopeLen, 0.0f, 1.0f, 1.0f, true, pSkelPartA, pSkelPartB, notEmptyStringA ? s_BoneNameA: NULL, notEmptyStringB ? s_BoneNameB: NULL );
}
else
{
int notEmptyStringA = strcmp(s_BoneNameA,"");
const crSkeleton* skel = notEmptyStringA ? (pEntity->GetIsTypePed() ? (static_cast<CEntity*>(pEntity))->GetSkeleton(): NULL) : NULL;
if( notEmptyStringA )
s_RopeStart = Vec3V(V_ZERO);
rope->AttachToObject( s_RopeStart, entityStart, m_ComponentPartA, skel, notEmptyStringA ? s_BoneNameA: NULL );
}
if( m_HasCollision )
rope->SetPhysInstFlags( ArchetypeFlags::GTA_OBJECT_TYPE, ArchetypeFlags::GTA_OBJECT_INCLUDE_TYPES & (~ArchetypeFlags::GTA_VEHICLE_TYPE) );
ropeAdded = true;
iClicked = 0;
}
}
}
else
{
PF_DRAW_SPHERE_COLOR(Ropes, 0.1f, ropeEnd, Color32(1.0f, 1.0f, 0.0f, 1.0f));
Vector3 Pos;
if( m_AttachAtPos )
{
Pos = m_WorldPos;
}
else
{
CDebugScene::GetWorldPositionUnderMouse(Pos, ArchetypeFlags::GTA_OBJECT_TYPE|ArchetypeFlags::GTA_PICKUP_TYPE|ArchetypeFlags::GTA_MAP_TYPE_WEAPON, NULL, NULL, false);
}
if( (ioMouse::GetReleasedButtons() & ioMouse::MOUSE_RIGHT) && (iClicked & ioMouse::MOUSE_RIGHT) )
{
ropeEnd = Pos;
}
if( (ioMouse::GetReleasedButtons() & ioMouse::MOUSE_LEFT) && (iClicked & ioMouse::MOUSE_LEFT) )
{
Vec3V rot( 0.0f, 0.0f, -0.5f*PI );
rope = m_RopeManager->AddRope( VECTOR3_TO_VEC3V(Pos), rot, m_RopeLen, m_MinRopeLen, m_MaxRopeLen, m_RopeLenChangeRate, m_RopeTypeIndex, m_NumSegments, m_PPUonly, m_LockFromFront, m_TimeMultiplier, m_Breakable, m_Pinned );
Assert( rope );
rope->SetNewUniqueId();
if( ropeEnd.x < BIG_FLOAT )
{
int endVertex = rope->GetEnvCloth()->GetNumRopeVertices()-1;
rope->Pin( endVertex, VECTOR3_TO_VEC3V(ropeEnd) );
}
ClearEndPos();
if( m_HasCollision )
rope->SetPhysInstFlags( ArchetypeFlags::GTA_OBJECT_TYPE, ArchetypeFlags::GTA_OBJECT_INCLUDE_TYPES & (~ArchetypeFlags::GTA_VEHICLE_TYPE) );
ropeAdded = true;
iClicked = 0;
}
}
if( ropeAdded )
{
Assert(rope);
AddRopeGroup( rope, entityStart, entityEnd );
entityEnd = NULL;
pEntityEnd = NULL;
}
}
void ropeBankManager::ClearEndPos()
{
ropeEnd.x = ropeEnd.y = ropeEnd.z = BIG_FLOAT;
}
void ropeBankManager::AddRopeGroup( ropeInstance* pRope, phInst* instA, phInst* instB )
{
if( addBankButton )
return;
Assert( pRope );
char groupTag[256];
sprintf( groupTag, "Rope: 0x%p", pRope );
pRope->m_RAGGroup = ropeBank->PushGroup( groupTag ,false );
//ragGroup->AddToggle("Pick Verts", &cInstance->m_DebugPickVerts, datCallback( MFA1( clothManager::ResetSelection0 ), this, cInstance ), "Activate vertex/vertices selection for this cloth." );
pRope->m_RAGGroup->AddToggle("Pick Verts", &pRope->m_DebugPickVerts );
AddButton( "Delete rope", pRope, instA, instB, MFA1(ropeBankManager::DeleteRope) );
if( instA )
{
char buttonTitleA[256];
sprintf( buttonTitleA, "Detach rope from object: 0x%p", instA );
AddButton( buttonTitleA, pRope, instA, instB, MFA1(ropeBankManager::DetachFromObjectA) );
}
if( instB )
{
char buttonTitleB[256];
sprintf( buttonTitleB, "Detach rope from object: 0x%p", instB );
AddButton( buttonTitleB, pRope, instA, instB, MFA1(ropeBankManager::DetachFromObjectB) );
}
AddButton( "Start winding", pRope, instA, instB, MFA1(ropeBankManager::StartWinding) );
AddButton( "Stop winding", pRope, instA, instB, MFA1(ropeBankManager::StopWinding) );
AddButton( "Start unwinding from front", pRope, instA, instB, MFA1(ropeBankManager::StartUnwindingFront) );
AddButton( "Stop unwinding from front", pRope, instA, instB, MFA1(ropeBankManager::StopUnwindingFront) );
if( instA && instB )
{
AddButton( "Start unwinding from back", pRope, instA, instB, MFA1(ropeBankManager::StartUnwindingBack) );
AddButton( "Stop unwinding from back", pRope, instA, instB, MFA1(ropeBankManager::StopUnwindingBack) );
}
if( instA && !instB )
{
AddButton( "Attach in array last selected", pRope, instA, instB, MFA1(ropeBankManager::AttachToArray) );
}
AddButton( "Break rope", pRope, instA, instB, MFA1(ropeBankManager::BreakRope) );
AddButton( "Debug Info On/Off", pRope, instA, instB, MFA1(ropeBankManager::ToggleDebugInfo) );
AddButton( "Load", pRope, instA, instB, MFA1(ropeBankManager::Load) );
AddButton( "Save", pRope, instA, instB, MFA1(ropeBankManager::Save) );
ropeBank->PopGroup();
}
void ropeBankManager::AddButton( const char* buttonText, ropeInstance* rope, phInst* instA, phInst* instB, rage::Member1 cbaddress )
{
atDNode<RopeBankData> *nodeInfo = rage_new atDNode<RopeBankData>;
Assert(nodeInfo);
RopeBankData* pinfo = &nodeInfo->Data;
pinfo->rope = rope;
bkButton* ropeButton = ropeBank->AddButton( buttonText, datCallback( cbaddress, this, (CallbackData)nodeInfo, false ) );
Assert(ropeButton);
pinfo->button = ropeButton;
pinfo->instA = instA;
pinfo->instB = instB;
m_RopeList.Append( *nodeInfo );
}
} // namespace rage
#endif // __BANK ... etc