From 84041f3491318e3d6f018b056e456a37e47b8458 Mon Sep 17 00:00:00 2001 From: D-AIRY <admin@ds-servers.com> Date: Sun, 6 Apr 2025 01:56:46 +0300 Subject: [PATCH] phys_door_rotating introduced --- proj/sxgame/vs2013/sxgame.vcxproj | 6 + proj/sxgame/vs2013/sxgame.vcxproj.filters | 18 + proj/sxphysics/vs2013/sxphysics.vcxproj | 3 + .../vs2013/sxphysics.vcxproj.filters | 9 + sdks/bullet3 | 2 +- source/game/BaseAmmo.cpp | 13 +- source/game/BaseCharacter.cpp | 2 +- source/game/BaseDoor.cpp | 403 ++++++++++++++++++ source/game/BaseDoor.h | 95 +++++ source/game/DogholeMovementController.cpp | 4 +- .../game/NarrowPassageMovementController.cpp | 4 +- source/game/PhysDoor.cpp | 196 +++++++++ source/game/PhysDoor.h | 46 ++ source/game/PropDoor.cpp | 374 +--------------- source/game/PropDoor.h | 72 +--- source/game/PropDoorRotating.cpp | 52 +++ source/game/PropDoorRotating.h | 40 ++ source/physics/Constraint.cpp | 62 +++ source/physics/Constraint.h | 110 +++++ source/physics/PhyWorld.cpp | 32 ++ source/physics/PhyWorld.h | 8 +- source/physics/Physics.cpp | 6 + source/physics/Physics.h | 2 + source/terrax/ProxyObject.cpp | 1 + source/xcommon/physics/IXConstraint.h | 46 ++ source/xcommon/physics/IXPhysics.h | 5 + source/xcsg/BrushMesh.cpp | 5 + source/xcsg/BrushMesh.h | 2 + source/xcsg/EditorObject.cpp | 5 +- 29 files changed, 1182 insertions(+), 441 deletions(-) create mode 100644 source/game/BaseDoor.cpp create mode 100644 source/game/BaseDoor.h create mode 100644 source/game/PhysDoor.cpp create mode 100644 source/game/PhysDoor.h create mode 100644 source/game/PropDoorRotating.cpp create mode 100644 source/game/PropDoorRotating.h create mode 100644 source/physics/Constraint.cpp create mode 100644 source/physics/Constraint.h create mode 100644 source/xcommon/physics/IXConstraint.h diff --git a/proj/sxgame/vs2013/sxgame.vcxproj b/proj/sxgame/vs2013/sxgame.vcxproj index 719b07cf1..ec55f76d6 100644 --- a/proj/sxgame/vs2013/sxgame.vcxproj +++ b/proj/sxgame/vs2013/sxgame.vcxproj @@ -178,6 +178,7 @@ <ClCompile Include="..\..\..\source\common\file_utils.cpp" /> <ClCompile Include="..\..\..\source\common\guid.cpp" /> <ClCompile Include="..\..\..\source\common\string_utils.cpp" /> + <ClCompile Include="..\..\..\source\game\BaseDoor.cpp" /> <ClCompile Include="..\..\..\source\game\BaseHandle.cpp" /> <ClCompile Include="..\..\..\source\game\BaseLight.cpp" /> <ClCompile Include="..\..\..\source\game\BaseMag.cpp" /> @@ -227,11 +228,13 @@ <ClCompile Include="..\..\..\source\game\NPCBase.cpp" /> <ClCompile Include="..\..\..\source\game\NPCZombie.cpp" /> <ClCompile Include="..\..\..\source\game\PathCorner.cpp" /> + <ClCompile Include="..\..\..\source\game\PhysDoor.cpp" /> <ClCompile Include="..\..\..\source\game\PointChangelevel.cpp" /> <ClCompile Include="..\..\..\source\game\PropBreakable.cpp" /> <ClCompile Include="..\..\..\source\game\PropButton.cpp" /> <ClCompile Include="..\..\..\source\game\PropDebris.cpp" /> <ClCompile Include="..\..\..\source\game\PropDoor.cpp" /> + <ClCompile Include="..\..\..\source\game\PropDoorRotating.cpp" /> <ClCompile Include="..\..\..\source\game\PropDynamic.cpp" /> <ClCompile Include="..\..\..\source\game\PropStatic.cpp" /> <ClCompile Include="..\..\..\source\game\proptable.cpp" /> @@ -270,6 +273,7 @@ <ClInclude Include="..\..\..\source\common\AAString.h" /> <ClInclude Include="..\..\..\source\common\file_utils.h" /> <ClInclude Include="..\..\..\source\common\string_utils.h" /> + <ClInclude Include="..\..\..\source\game\BaseDoor.h" /> <ClInclude Include="..\..\..\source\game\BaseHandle.h" /> <ClInclude Include="..\..\..\source\game\BaseLight.h" /> <ClInclude Include="..\..\..\source\game\Baseline.h" /> @@ -312,12 +316,14 @@ <ClInclude Include="..\..\..\source\game\LogicRelay.h" /> <ClInclude Include="..\..\..\source\game\LogicStringbuilder.h" /> <ClInclude Include="..\..\..\source\game\NarrowPassageMovementController.h" /> + <ClInclude Include="..\..\..\source\game\PhysDoor.h" /> <ClInclude Include="..\..\..\source\game\physics_util.h" /> <ClInclude Include="..\..\..\source\game\PointChangelevel.h" /> <ClInclude Include="..\..\..\source\game\PropBreakable.h" /> <ClInclude Include="..\..\..\source\game\PropButton.h" /> <ClInclude Include="..\..\..\source\game\PropDebris.h" /> <ClInclude Include="..\..\..\source\game\PropDoor.h" /> + <ClInclude Include="..\..\..\source\game\PropDoorRotating.h" /> <ClInclude Include="..\..\..\source\game\PropDynamic.h" /> <ClInclude Include="..\..\..\source\game\PropStatic.h" /> <ClInclude Include="..\..\..\source\game\Random.h" /> diff --git a/proj/sxgame/vs2013/sxgame.vcxproj.filters b/proj/sxgame/vs2013/sxgame.vcxproj.filters index f3634cd06..d71df317e 100644 --- a/proj/sxgame/vs2013/sxgame.vcxproj.filters +++ b/proj/sxgame/vs2013/sxgame.vcxproj.filters @@ -390,6 +390,15 @@ <ClCompile Include="..\..\..\source\game\InfoOverlay.cpp"> <Filter>Source Files\ents\info</Filter> </ClCompile> + <ClCompile Include="..\..\..\source\game\BaseDoor.cpp"> + <Filter>Source Files\ents\props</Filter> + </ClCompile> + <ClCompile Include="..\..\..\source\game\PropDoorRotating.cpp"> + <Filter>Source Files\ents\props</Filter> + </ClCompile> + <ClCompile Include="..\..\..\source\game\PhysDoor.cpp"> + <Filter>Source Files\ents\props</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <ClInclude Include="..\..\..\source\game\sxgame.h"> @@ -683,6 +692,15 @@ <ClInclude Include="..\..\..\source\game\InfoOverlay.h"> <Filter>Header Files\ents\info</Filter> </ClInclude> + <ClInclude Include="..\..\..\source\game\BaseDoor.h"> + <Filter>Header Files\ents\props</Filter> + </ClInclude> + <ClInclude Include="..\..\..\source\game\PropDoorRotating.h"> + <Filter>Header Files\ents\props</Filter> + </ClInclude> + <ClInclude Include="..\..\..\source\game\PhysDoor.h"> + <Filter>Header Files\ents\props</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ResourceCompile Include="..\..\..\source\game\sxgame.rc"> diff --git a/proj/sxphysics/vs2013/sxphysics.vcxproj b/proj/sxphysics/vs2013/sxphysics.vcxproj index e327650bb..5702d4f0b 100644 --- a/proj/sxphysics/vs2013/sxphysics.vcxproj +++ b/proj/sxphysics/vs2013/sxphysics.vcxproj @@ -178,6 +178,7 @@ <ClCompile Include="..\..\..\source\physics\CharacterController.cpp" /> <ClCompile Include="..\..\..\source\physics\CollisionObject.cpp" /> <ClCompile Include="..\..\..\source\physics\CollisionShape.cpp" /> + <ClCompile Include="..\..\..\source\physics\Constraint.cpp" /> <ClCompile Include="..\..\..\source\physics\MutationObserver.cpp" /> <ClCompile Include="..\..\..\source\physics\Physics.cpp" /> <ClCompile Include="..\..\..\source\physics\PhyWorld.cpp" /> @@ -190,6 +191,7 @@ <ClInclude Include="..\..\..\source\physics\CharacterController.h" /> <ClInclude Include="..\..\..\source\physics\CollisionObject.h" /> <ClInclude Include="..\..\..\source\physics\CollisionShape.h" /> + <ClInclude Include="..\..\..\source\physics\Constraint.h" /> <ClInclude Include="..\..\..\source\physics\MutationObserver.h" /> <ClInclude Include="..\..\..\source\physics\PhyWorld.h" /> <ClInclude Include="..\..\..\source\physics\sxphysics.h" /> @@ -197,6 +199,7 @@ <ClInclude Include="..\..\..\source\xcommon\physics\IXCharacterController.h" /> <ClInclude Include="..\..\..\source\xcommon\physics\IXCollisionObject.h" /> <ClInclude Include="..\..\..\source\xcommon\physics\IXCollisionShape.h" /> + <ClInclude Include="..\..\..\source\xcommon\physics\IXConstraint.h" /> <ClInclude Include="..\..\..\source\xcommon\physics\IXMutationObserver.h" /> <ClInclude Include="..\..\..\source\xcommon\physics\IXPhysics.h" /> </ItemGroup> diff --git a/proj/sxphysics/vs2013/sxphysics.vcxproj.filters b/proj/sxphysics/vs2013/sxphysics.vcxproj.filters index cb4b3c015..517aac226 100644 --- a/proj/sxphysics/vs2013/sxphysics.vcxproj.filters +++ b/proj/sxphysics/vs2013/sxphysics.vcxproj.filters @@ -45,6 +45,9 @@ <ClCompile Include="..\..\..\source\physics\CharacterController.cpp"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="..\..\..\source\physics\Constraint.cpp"> + <Filter>Source Files</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <ClInclude Include="..\..\..\source\physics\sxphysics.h"> @@ -92,5 +95,11 @@ <ClInclude Include="..\..\..\source\xcommon\physics\IXMutationObserver.h"> <Filter>Header Files\xcommon</Filter> </ClInclude> + <ClInclude Include="..\..\..\source\xcommon\physics\IXConstraint.h"> + <Filter>Header Files\xcommon</Filter> + </ClInclude> + <ClInclude Include="..\..\..\source\physics\Constraint.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> </Project> \ No newline at end of file diff --git a/sdks/bullet3 b/sdks/bullet3 index 0af01e52b..3770e985d 160000 --- a/sdks/bullet3 +++ b/sdks/bullet3 @@ -1 +1 @@ -Subproject commit 0af01e52bc9053b53d344d52c7258d4e287d718d +Subproject commit 3770e985d18911de4ab0898ba65a2a4545baf7bb diff --git a/source/game/BaseAmmo.cpp b/source/game/BaseAmmo.cpp index 35abac1ee..3265d1272 100644 --- a/source/game/BaseAmmo.cpp +++ b/source/game/BaseAmmo.cpp @@ -211,11 +211,16 @@ void CBaseAmmo::fire(const float3 &_vStart, const float3 &_vDir, CBaseCharacter //shoot decal //SXDecals_ShootDecal(DECAL_TYPE_CONCRETE, BTVEC_F3(cb.m_hitPointWorld[0]), BTVEC_F3(cb.m_hitNormalWorld[0])); //SPE_EffectPlayByName("fire", &BTVEC_F3(cb.m_hitPointWorld), &BTVEC_F3(cb.m_hitNormalWorld)); - /*if(!cb.m_collisionObject->isStaticOrKinematicObject()) + if(!cb.m_aResults[0].pCollisionObject->isStaticOrKinematic()) { - ((btRigidBody*)cb.m_collisionObject)->applyCentralImpulse(F3_BTVEC(vDir * 10.0f)); - cb.m_collisionObject->activate(); - }*/ + IXRigidBody *pBody = cb.m_aResults[0].pCollisionObject->asRigidBody(); + if(pBody) + { + pBody->applyImpulse(vDir * 10.0f, cb.m_aResults[0].vHitPoint); + } + //((btRigidBody*)cb.m_collisionObject)->applyCentralImpulse(F3_BTVEC(vDir * 10.0f)); + //cb.m_collisionObject->activate(); + } //g_pTracer->lineTo(BTVEC_F3(cb.m_hitPointWorld[0]) + SMVector3Normalize(BTVEC_F3(cb.m_hitNormalWorld[0])) * 0.1f, 0.0f); } else diff --git a/source/game/BaseCharacter.cpp b/source/game/BaseCharacter.cpp index 65d093d77..9d7f9cb95 100644 --- a/source/game/BaseCharacter.cpp +++ b/source/game/BaseCharacter.cpp @@ -78,7 +78,7 @@ void CBaseCharacter::onPostLoad() // Для парашютистов, например, предельная скорость составляет от 190 км/ч при максимальном сопротивлении воздуха, когда они падают плашмя, раскинув руки, до 240 км/ч при нырянии «рыбкой» или «солдатиком». m_pCharacter->setFallSpeed(53.0f); //m_pCharacter->setFallSpeed(30.0f); - m_pCharacter->setMaxPenetrationDepth(0.1f); + m_pCharacter->setMaxPenetrationDepth(0.0f/*0.1f*/); //m_pGhostObject->setWorldTransform(startTransform); GetPhysWorld()->addCollisionObject(m_pGhostObject, CG_CHARACTER, CG_ALL & ~(CG_DEBRIS | CG_HITBOX | CG_WATER)); diff --git a/source/game/BaseDoor.cpp b/source/game/BaseDoor.cpp new file mode 100644 index 000000000..9d1c35b2d --- /dev/null +++ b/source/game/BaseDoor.cpp @@ -0,0 +1,403 @@ +#include "BaseDoor.h" + +/*! \skydocent prop_door +Дверь +*/ + +BEGIN_PROPTABLE(CBaseDoor) + //! Открыть + DEFINE_INPUT(inputOpen, "open", "Open", PDF_NONE) + //! Закрыть + DEFINE_INPUT(inputClose, "close", "Close", PDF_NONE) + //! Заблокировать + DEFINE_INPUT(inputLock, "lock", "Lock", PDF_NONE) + //! Разблокировать + DEFINE_INPUT(inputUnlock, "unlock", "Unlock", PDF_NONE) + //! Переключить + DEFINE_INPUT(inputToggle, "toggle", "Toggle", PDF_NONE) + + //! При начале закрытия + DEFINE_OUTPUT(m_onClose, "OnClose", "On close") + //! При завершении закрытия + DEFINE_OUTPUT(m_onClosed, "OnClosed", "On closed") + //! При начале открытия + DEFINE_OUTPUT(m_onOpen, "OnOpen", "On open") + //! При завершении открытия + DEFINE_OUTPUT(m_onOpened, "OnOpened", "On opened") + //! При попытке использовать заблокированную + DEFINE_OUTPUT(m_onUseLocked, "OnUseLocked", "On use locked") + + //! Время до автозакрытия + DEFINE_FIELD_FLOAT(m_fAutoCloseTime, PDFF_NONE, "autoclose_time", "Autoclose time", EDITOR_TIMEFIELD) + //! Повреждение при блокировке + DEFINE_FIELD_FLOAT(m_fBlockDamage, PDFF_NONE, "block_damage", "Block damage", EDITOR_TEXTFIELD) + + DEFINE_FIELD_STRING(m_szSndClose, PDFF_NONE, "snd_close", "Close sound", EDITOR_FILEFIELD) + FILE_OPTION("Select sound", "ogg") + EDITOR_FILE_END() + DEFINE_FIELD_STRING(m_szSndOpen, PDFF_NONE, "snd_open", "Open sound", EDITOR_FILEFIELD) + FILE_OPTION("Select sound", "ogg") + EDITOR_FILE_END() + DEFINE_FIELD_STRING(m_szSndLocked, PDFF_NONE, "snd_locked", "Locked sound", EDITOR_FILEFIELD) + FILE_OPTION("Select sound", "ogg") + EDITOR_FILE_END() + + //! Изначально заблокирована + DEFINE_FLAG(DOOR_START_LOCKED, "Start locked") + //! Запрет открытия игроком + DEFINE_FLAG(DOOR_NO_USE, "Disable player USE") + //! Изначально открыта + DEFINE_FLAG(DOOR_START_OPENED, "Start opened") + //! Автозакрытие по таймеру + DEFINE_FLAG(DOOR_AUTOCLOSE, "Autoclose") + //! Форсированное закрытие двери + DEFINE_FLAG(DOOR_FORCE, "Force close") +END_PROPTABLE() + +REGISTER_ENTITY_NOLISTING(CBaseDoor, base_door, REC_MODEL_FIELD("model")); + +CBaseDoor::~CBaseDoor() +{ + releasePhysics(); + + mem_release(m_pSndClose); + mem_release(m_pSndOpen); + mem_release(m_pSndLocked); +} + +void CBaseDoor::onPostLoad() +{ + m_isLocked = (getFlags() & DOOR_START_LOCKED) != 0; + m_bState = (getFlags() & DOOR_START_OPENED) != 0; + + BaseClass::onPostLoad(); + + IXSoundSystem *pSound = (IXSoundSystem*)(Core_GetIXCore()->getPluginManager()->getInterface(IXSOUNDSYSTEM_GUID)); + if(pSound) + { + IXSoundLayer *pGameLayer = pSound->findLayer("xGame"); + + if(m_szSndClose[0]) + { + m_pSndClose = pGameLayer->newSoundPlayer(m_szSndClose, SOUND_SPACE_3D); + } + if(m_szSndOpen[0]) + { + m_pSndOpen = pGameLayer->newSoundPlayer(m_szSndOpen, SOUND_SPACE_3D); + } + if(m_szSndLocked[0]) + { + m_pSndLocked = pGameLayer->newSoundPlayer(m_szSndLocked, SOUND_SPACE_3D); + } + } +} + +void CBaseDoor::updatePositionFrac(float fPos) +{ + m_fPositionFrac = fPos; + + float2 p1(0.0f, 0.0f); + float2 p2(0.42f, 0.0f); + float2 p3(0.58f, 1.0f); + float2 p4(1.0f, 1.0f); + float t = m_fPositionFrac; + float2 p = powf(1.0f - t, 3.0f) * p1 + 3.0f * powf(1.0f - t, 2.0f) * t * p2 + 3.0f * (1.0f - t) * powf(t, 2.0f) * p3 + powf(t, 3.0f) * p4; + t = p.y; + + updatePos(t); +} + +void CBaseDoor::setMoveTime(float fTime) +{ + m_fMoveTime = fTime; +} + +void CBaseDoor::inputOpen(inputdata_t * pInputdata) +{ + if(m_isLocked) + { + FIRE_OUTPUT(m_onUseLocked, pInputdata->pInflictor); + + SAFE_CALL(m_pSndLocked, setWorldPos, getPos()); + SAFE_CALL(m_pSndLocked, play); + return; + } + if(m_bState) + { + return; + } + m_bState = true; + if(m_isClosing) + { + stop(); + } + + m_pInflictor = pInputdata->pInflictor; + FIRE_OUTPUT(m_onOpen, pInputdata->pInflictor); + + SAFE_CALL(m_pSndOpen, setWorldPos, getPos()); + SAFE_CALL(m_pSndOpen, play); + + m_isOpening = true; + m_idThinkInterval = SET_INTERVAL(think, 0); +} + +void CBaseDoor::inputClose(inputdata_t * pInputdata) +{ + if(m_isLocked) + { + FIRE_OUTPUT(m_onUseLocked, pInputdata->pInflictor); + + SAFE_CALL(m_pSndLocked, setWorldPos, getPos()); + SAFE_CALL(m_pSndLocked, play); + return; + } + if(!m_bState) + { + return; + } + m_bState = false; + if(m_isOpening) + { + stop(); + } + + if(ID_VALID(m_idAutoCloseTimeout)) + { + CLEAR_TIMEOUT(m_idAutoCloseTimeout); + m_idAutoCloseTimeout = -1; + } + + m_pInflictor = pInputdata->pInflictor; + FIRE_OUTPUT(m_onClose, pInputdata->pInflictor); + + SAFE_CALL(m_pSndClose, setWorldPos, getPos()); + SAFE_CALL(m_pSndClose, play); + + m_isClosing = true; + m_idThinkInterval = SET_INTERVAL(think, 0); +} + +void CBaseDoor::inputToggle(inputdata_t * pInputdata) +{ + if(m_bState) + { + inputClose(pInputdata); + } + else + { + inputOpen(pInputdata); + } +} +void CBaseDoor::inputLock(inputdata_t * pInputdata) +{ + m_isLocked = true; +} + +void CBaseDoor::inputUnlock(inputdata_t * pInputdata) +{ + m_isLocked = false; +} + +void CBaseDoor::onUse(CBaseEntity *pUser) +{ + if(getFlags() & DOOR_NO_USE) + { + return; + } + + inputdata_t inputdata; + memset(&inputdata, 0, sizeof(inputdata_t)); + inputdata.pActivator = pUser; + inputdata.pInflictor = pUser; + inputdata.type = PDF_NONE; + + if(getFlags() & DOOR_AUTOCLOSE) + { + inputOpen(&inputdata); + } + else + { + inputToggle(&inputdata); + } + + BaseClass::onUse(pUser); +} + +void CBaseDoor::createPhysBody() +{ + if(m_pCollideShape) + { + float3 vPos = getPos(); + SMQuaternion qRot = getOrient(); + + GetPhysics()->newGhostObject(&m_pGhostObject, true); + m_pGhostObject->setPosition(vPos); + m_pGhostObject->setRotation(qRot); + m_pGhostObject->setCollisionShape(m_pCollideShape); + m_pGhostObject->setCollisionFlags(XCF_KINEMATIC_OBJECT); + m_pGhostObject->setUserPointer(this); + m_pGhostObject->setUserTypeId(1); + + GetPhysWorld()->addCollisionObject(m_pGhostObject, CG_DOOR, CG_CHARACTER | CG_DEFAULT); + + //m_pGhostObject->activate(); + //m_pGhostObject->setActivationState(DISABLE_DEACTIVATION); + } +} +void CBaseDoor::removePhysBody() +{ + if(m_pGhostObject) + { + GetPhysWorld()->removeCollisionObject(m_pGhostObject); + mem_release(m_pGhostObject); + } + + BaseClass::removePhysBody(); +} + +void CBaseDoor::think(float fDT) +{ + testPenetration(); + + if(m_isOpening) + { + m_fPositionFrac += fDT / m_fMoveTime; + if(m_fPositionFrac >= 1.0f) + { + m_fPositionFrac = 1.0f; + FIRE_OUTPUT(m_onOpened, m_pInflictor); + stop(); + + if(getFlags() & DOOR_AUTOCLOSE) + { + m_idAutoCloseTimeout = SET_TIMEOUT(close, m_fAutoCloseTime); + } + } + } + else if(m_isClosing) + { + m_fPositionFrac -= fDT / m_fMoveTime; + if(m_fPositionFrac <= 0.0f) + { + m_fPositionFrac = 0.0f; + FIRE_OUTPUT(m_onClosed, m_pInflictor); + stop(); + } + } + + updatePositionFrac(m_fPositionFrac); +} + +void CBaseDoor::stop() +{ + if(ID_VALID(m_idThinkInterval)) + { + CLEAR_INTERVAL(m_idThinkInterval); + m_idThinkInterval = -1; + } + m_isOpening = false; + m_isClosing = false; + + //@TODO: Stop sound +} + +void CBaseDoor::setPos(const float3 & pos) +{ + BaseClass::setPos(pos); + if(m_pGhostObject) + { + m_pGhostObject->setPosition(pos); + //m_pGhostObject->setInterpolationLinearVelocity(btVector3(-0.02f, 0.0f, 0.0f)); + } +} + +bool CBaseDoor::testPenetration() +{ + bool hasContact = false; + + for(UINT i = 0, l = m_pGhostObject->getOverlappingPairCount(); i < l; ++i) + { + + IXCollisionPair *collisionPair = m_pGhostObject->getOverlappingPair(i); + + IXCollisionObject* obj0 = collisionPair->getObject0(); + IXCollisionObject* obj1 = collisionPair->getObject1(); + + if((obj0 && !obj0->hasContactResponse()) || (obj1 && !obj1->hasContactResponse())) + continue; + + if(!needsCollision(obj0, obj1)) + continue; + + for(UINT j = 0, jl = collisionPair->getContactManifoldCount(); j < jl; ++j) + { + IXContactManifold *manifold = collisionPair->getContactManifold(j); + //btScalar directionSign = manifold->getBody0() == m_pGhostObject ? btScalar(-1.0) : btScalar(1.0); + for(UINT p = 0, pl = manifold->getContactCount(); p<pl; ++p) + { + const IXContactManifoldPoint *pt = manifold->getContact(p); + + float dist = pt->getDistance(); + + if(dist < -DOOR_MAX_PENETRATION_DEPTH) + { + hasContact = true; + const IXCollisionObject *pObject = (obj0 == m_pGhostObject) ? obj1 : obj0; + + if(pObject->getUserPointer() && pObject->getUserTypeId() == 1) + { + CBaseEntity *pEnt = (CBaseEntity*)pObject->getUserPointer(); + if(pEnt) + { + CTakeDamageInfo takeDamageInfo(this, m_fBlockDamage); + takeDamageInfo.m_pInflictor = this; + + pEnt->dispatchDamage(takeDamageInfo); + } + } + } + } + + //manifold->clearManifold(); + } + } + + if(hasContact) + { + if(!(getFlags() & DOOR_FORCE)) + { + inputdata_t inputdata; + memset(&inputdata, 0, sizeof(inputdata_t)); + inputdata.pActivator = this; + inputdata.pInflictor = m_pInflictor; + inputdata.type = PDF_NONE; + inputToggle(&inputdata); + return(false); + } + else + { + return(true); + } + } + return(false); +} + +bool CBaseDoor::needsCollision(const IXCollisionObject *body0, const IXCollisionObject *body1) +{ + bool collides = (body0->getFilterGroup() & body1->getFilterMask()) != 0; + collides = collides && (body1->getFilterGroup() & body0->getFilterMask()); + return(collides); +} + +void CBaseDoor::close(float fDT) +{ + m_idAutoCloseTimeout = -1; + + inputdata_t inputdata; + memset(&inputdata, 0, sizeof(inputdata_t)); + inputdata.pActivator = this; + inputdata.pInflictor = m_pInflictor; + inputdata.type = PDF_NONE; + inputClose(&inputdata); +} diff --git a/source/game/BaseDoor.h b/source/game/BaseDoor.h new file mode 100644 index 000000000..3ceec7ad6 --- /dev/null +++ b/source/game/BaseDoor.h @@ -0,0 +1,95 @@ +/*! +\file +Дверь +*/ + +#ifndef __BASE_DOOR_H +#define __BASE_DOOR_H + +#include "PropDynamic.h" + +#define DOOR_START_LOCKED ENT_FLAG_0 +#define DOOR_NO_USE ENT_FLAG_1 +#define DOOR_START_OPENED ENT_FLAG_2 +#define DOOR_AUTOCLOSE ENT_FLAG_3 +#define DOOR_FORCE ENT_FLAG_4 + +#define DOOR_MAX_PENETRATION_DEPTH 0.16f + +/*! Дверь +\ingroup cbaseanimating +*/ +class CBaseDoor: public CPropDynamic +{ + DECLARE_CLASS(CBaseDoor, CPropDynamic); + DECLARE_PROPTABLE(); +public: + DECLARE_TRIVIAL_CONSTRUCTOR(); + ~CBaseDoor(); + + void onPostLoad() override; + + void onUse(CBaseEntity *pUser); + + //! Устанавливает положение в мире + void setPos(const float3 & pos); + +protected: + virtual void updatePos(float fPosNormalized) {}; + + void updatePositionFrac(float fPos); + void setMoveTime(float fTime); + + void inputOpen(inputdata_t * pInputdata); + void inputClose(inputdata_t * pInputdata); + void inputLock(inputdata_t * pInputdata); + void inputUnlock(inputdata_t * pInputdata); + void inputToggle(inputdata_t * pInputdata); + + void think(float fDT); + ID m_idThinkInterval = -1; + ID m_idAutoCloseTimeout = -1; + + void stop(); + + bool testPenetration(); + bool needsCollision(const IXCollisionObject *body0, const IXCollisionObject *body1); + + output_t m_onClose; + output_t m_onClosed; + output_t m_onOpen; + output_t m_onOpened; + output_t m_onUseLocked; + + void createPhysBody() override; + void removePhysBody() override; + + float m_fAutoCloseTime = 0.0f; + float m_fBlockDamage = 100.0f; + + const char * m_szSndClose; + IXSoundPlayer *m_pSndClose = NULL; + const char * m_szSndOpen; + IXSoundPlayer *m_pSndOpen = NULL; + const char * m_szSndLocked; + IXSoundPlayer *m_pSndLocked = NULL; + + bool m_isLocked = false; + + bool m_bState = false; + + IXGhostObject *m_pGhostObject = NULL; + +private: + float m_fPositionFrac = 0.0f; + float m_fMoveTime = 1.0f; + + bool m_isOpening = false; + bool m_isClosing = false; + + CBaseEntity *m_pInflictor = NULL; + + void close(float fDT); +}; + +#endif diff --git a/source/game/DogholeMovementController.cpp b/source/game/DogholeMovementController.cpp index a4292c0a8..74c4417d4 100644 --- a/source/game/DogholeMovementController.cpp +++ b/source/game/DogholeMovementController.cpp @@ -63,12 +63,12 @@ void CDogholeMovementController::handleMove(const float3 &vDir) void CDogholeMovementController::handleJump() { - m_bWillDismount = true; + //m_bWillDismount = true; } bool CDogholeMovementController::handleUse() { - m_bWillDismount = true; + //m_bWillDismount = true; return(true); } diff --git a/source/game/NarrowPassageMovementController.cpp b/source/game/NarrowPassageMovementController.cpp index d4b9cce1e..7fbf2ce92 100644 --- a/source/game/NarrowPassageMovementController.cpp +++ b/source/game/NarrowPassageMovementController.cpp @@ -60,12 +60,12 @@ void CNarrowPassageMovementController::handleMove(const float3 &vDir) void CNarrowPassageMovementController::handleJump() { - m_bWillDismount = true; + //m_bWillDismount = true; } bool CNarrowPassageMovementController::handleUse() { - m_bWillDismount = true; + //m_bWillDismount = true; return(true); } diff --git a/source/game/PhysDoor.cpp b/source/game/PhysDoor.cpp new file mode 100644 index 000000000..f45584f01 --- /dev/null +++ b/source/game/PhysDoor.cpp @@ -0,0 +1,196 @@ +#include "PhysDoor.h" + +/*! \skydocent phys_door +Физическая дверЪ +*/ + +BEGIN_PROPTABLE(CPhysDoor) + DEFINE_FIELD_VECTORFN(m_vPivot, PDFF_USE_GIZMO, "door_pivot", "Pivot", setPivot, EDITOR_POINTCOORDEX) + EDITOR_KV("lock", "plane") + EDITOR_KV("axis", "y") + EDITOR_KV("local", "1") + EDITOR_END() + + DEFINE_FIELD_VECTORFN(m_vBaseDir, PDFF_USE_GIZMO, "door_base_dir", "Base dir", setBaseDir, EDITOR_POINTCOORDEX) + EDITOR_KV("lock", "plane") + EDITOR_KV("axis", "y") + EDITOR_KV("local", "1") + EDITOR_END() + + DEFINE_FIELD_VECTORFN(m_vLimitDir0, PDFF_USE_GIZMO, "door_limit_dir0", "Limit dir 0", setLimit0Dir, EDITOR_POINTCOORDEX) + EDITOR_KV("lock", "plane") + EDITOR_KV("axis", "y") + EDITOR_KV("local", "1") + EDITOR_END() + + DEFINE_FIELD_VECTORFN(m_vLimitDir1, PDFF_USE_GIZMO, "door_limit_dir1", "Limit dir 1", setLimit1Dir, EDITOR_POINTCOORDEX) + EDITOR_KV("lock", "plane") + EDITOR_KV("axis", "y") + EDITOR_KV("local", "1") + EDITOR_END() +END_PROPTABLE() + +REGISTER_ENTITY(CPhysDoor, phys_door, REC_MODEL_FIELD("model")); + +void CPhysDoor::createPhysBody() +{ + setCollisionGroup(CG_DOOR, CG_STATIC_MASK); + BaseClass::createPhysBody(); + + XHingeConstraintBodyDesc desc = {}; + desc.pBody = m_pRigidBody; + desc.vAxis = getOrient() * float3_t(0.0f, 1.0f, 0.0f); + desc.vPivot = getOrient() * m_vPivot; + GetPhysics()->newHingeConstraint(&m_pHingeConstraint, &desc); + //m_pHingeConstraint->setLimit(-SM_PIDIV2, SM_PIDIV2); + updateLimits(); + //m_pHingeConstraint->setLimit(-100.0f, 100.0f); + GetPhysWorld()->addConstraint(m_pHingeConstraint); +} +void CPhysDoor::removePhysBody() +{ + GetPhysWorld()->removeConstraint(m_pHingeConstraint); + mem_release(m_pHingeConstraint); + BaseClass::removePhysBody(); +} + +void CPhysDoor::setPivot(const float3 &vPivot) +{ + m_vPivot = vPivot; + if(m_pRigidBody) + { + removePhysBody(); + createPhysBody(); + } +} + +void CPhysDoor::setBaseDir(const float3 &vDir) +{ + m_vBaseDir = vDir; + + updateLimits(); +} + +void CPhysDoor::setLimit0Dir(const float3 &vDir) +{ + m_vLimitDir0 = vDir; + + updateLimits(); +} + +void CPhysDoor::setLimit1Dir(const float3 &vDir) +{ + m_vLimitDir1 = vDir; + + updateLimits(); +} + +void CPhysDoor::updateLimits() +{ + if(m_pHingeConstraint) + { + float3 vDir0 = SMVector3Normalize(m_vLimitDir0 - m_vPivot); + float3 vDir1 = SMVector3Normalize(m_vLimitDir1 - m_vPivot); + float3 vBase = SMVector3Normalize(m_vBaseDir - m_vPivot); + + float3 vUp = getOrient() * float3(0.0f, 1.0f, 0.0f); + + float fAngle0 = SMRightAngleBetweenVectors(vBase, vDir0, vUp); + float fAngle1 = SMRightAngleBetweenVectors(vBase, vDir1, vUp); + + float fLim0; + float fLim1; + + if(fAngle0 < fAngle1) + { + fLim0 = -(SM_2PI - fAngle1); + fLim1 = fAngle0; + } + else + { + fLim0 = -(SM_2PI - fAngle0); + fLim1 = fAngle1; + } + m_pHingeConstraint->setLimit(fLim0, fLim1); + LogInfo("setLimit(%f, %f)\n", fLim0, fLim1); + + + + + + /* + float fLim0 = safe_acosf(SMVector3Dot(vDir0, vBase)); + float fLim1 = safe_acosf(SMVector3Dot(vDir1, vBase)); + //float fLim = safe_acosf(SMVector3Dot(SMVector3Normalize(m_vLimitDir0 - m_vPivot), SMVector3Normalize(m_vLimitDir1 - m_vPivot))); + //m_pHingeConstraint->setLimit(-fLim * 0.5f, fLim * 0.5f); + //LogInfo("setLimit(%f, %f)\n", -fLim * 0.5f, fLim * 0.5f); + m_pHingeConstraint->setLimit(-fLim0, fLim1);*/ + } +} + +void CPhysDoor::renderEditor(bool is3D, bool bRenderSelection, IXGizmoRenderer *pRenderer) +{ + if(pRenderer && bRenderSelection) + { + const float4 c_vLineColor = bRenderSelection ? float4(1.0f, 0.0f, 0.0f, 1.0f) : float4(1.0f, 0.0f, 1.0f, 1.0f); + pRenderer->setColor(c_vLineColor); + pRenderer->setLineWidth(is3D ? 0.02f : 1.0f); + + float3 vDir0 = SMVector3Normalize(m_vLimitDir0 - m_vPivot); + float3 vDir1 = SMVector3Normalize(m_vLimitDir1 - m_vPivot); + float3 vBase = SMVector3Normalize(m_vBaseDir - m_vPivot); + + float3 vBasePos = getPos() + getOrient() * m_vPivot; + pRenderer->jumpTo(vBasePos + getOrient() * vDir0); + pRenderer->lineTo(vBasePos); + pRenderer->lineTo(vBasePos + getOrient() * vDir1); + + pRenderer->setColor(float4(1.0f, 1.0f, 0.0f, 1.0f)); + pRenderer->jumpTo(vBasePos); + pRenderer->lineTo(vBasePos + getOrient() * vBase); + + const float c_fStep = SMToRadian(5.0f); + /* + float fLim0 = safe_acosf(SMVector3Dot(vDir0, vBase)); + float fLim1 = safe_acosf(SMVector3Dot(vDir1, vBase)); + + UINT uSteps = (UINT)(fLim0 / c_fStep); + if(!uSteps) + { + uSteps = 1; + } + float fStep = fLim0 / (float)uSteps; + float3 vVec = getOrient() * vBase; + pRenderer->jumpTo(vBasePos + vVec); + for(UINT i = 0; i < uSteps; ++i) + { + pRenderer->lineTo(vBasePos + SMQuaternion(getOrient() * float3(0.0f, 1.0f, 0.0f), (float)(i + 1) * fStep) * vVec); + }*/ + + float3 vUp = getOrient() * float3(0.0f, 1.0f, 0.0f); + + float fAngleDir = SMRightAngleBetweenVectors(vDir0, vDir1, vUp); + float fAngleBase = SMRightAngleBetweenVectors(vDir0, vBase, vUp); + + float3 vVec = vDir1; + if(fAngleBase > fAngleDir) + { + fAngleDir = SM_2PI - fAngleDir; + vVec = vDir0; + } + vVec = getOrient() * vVec; + + UINT uSteps = (UINT)(fAngleDir / c_fStep); + if(!uSteps) + { + uSteps = 1; + } + + float fStep = fAngleDir / (float)uSteps; + pRenderer->jumpTo(vBasePos + vVec); + for(UINT i = 0; i < uSteps; ++i) + { + pRenderer->lineTo(vBasePos + SMQuaternion(vUp, (float)(i + 1) * fStep) * vVec); + } + } +} diff --git a/source/game/PhysDoor.h b/source/game/PhysDoor.h new file mode 100644 index 000000000..f4c782ed1 --- /dev/null +++ b/source/game/PhysDoor.h @@ -0,0 +1,46 @@ +/*! +\file +Модель +*/ + +#ifndef __PHYS_DOOR_H +#define __PHYS_DOOR_H + +#include "PropDynamic.h" + +/*! Модель +\ingroup cbaseanimating +*/ +class CPhysDoor: public CPropDynamic +{ + DECLARE_CLASS(CPhysDoor, CPropDynamic); + DECLARE_PROPTABLE(); +public: + DECLARE_TRIVIAL_CONSTRUCTOR(); + + void setPivot(const float3 &vPivot); + + void renderEditor(bool is3D, bool bRenderSelection, IXGizmoRenderer *pRenderer) override; + +protected: + void createPhysBody() override; + void removePhysBody() override; + +private: + IXHingeConstraint *m_pHingeConstraint = NULL; + + float3_t m_vPivot; + + float3_t m_vBaseDir = float3_t(0.0f, 0.0f, 1.0f); + float3_t m_vLimitDir0 = float3_t(-1.0f, 0.0f, 0.0f); + float3_t m_vLimitDir1 = float3_t(1.0f, 0.0f, 0.0f); + +private: + void setBaseDir(const float3 &vDir); + void setLimit0Dir(const float3 &vDir); + void setLimit1Dir(const float3 &vDir); + + void updateLimits(); +}; + +#endif diff --git a/source/game/PropDoor.cpp b/source/game/PropDoor.cpp index c2c693de2..985a34ab1 100644 --- a/source/game/PropDoor.cpp +++ b/source/game/PropDoor.cpp @@ -11,224 +11,24 @@ See the license in LICENSE */ BEGIN_PROPTABLE(CPropDoor) - //! Открыть - DEFINE_INPUT(inputOpen, "open", "Open", PDF_NONE) - //! Закрыть - DEFINE_INPUT(inputClose, "close", "Close", PDF_NONE) - //! Заблокировать - DEFINE_INPUT(inputLock, "lock", "Lock", PDF_NONE) - //! Разблокировать - DEFINE_INPUT(inputUnlock, "unlock", "Unlock", PDF_NONE) - //! Переключить - DEFINE_INPUT(inputToggle, "toggle", "Toggle", PDF_NONE) - - //! При начале закрытия - DEFINE_OUTPUT(m_onClose, "OnClose", "On close") - //! При завершении закрытия - DEFINE_OUTPUT(m_onClosed, "OnClosed", "On closed") - //! При начале открытия - DEFINE_OUTPUT(m_onOpen, "OnOpen", "On open") - //! При завершении открытия - DEFINE_OUTPUT(m_onOpened, "OnOpened", "On opened") - //! При попытке использовать заблокированную - DEFINE_OUTPUT(m_onUseLocked, "OnUseLocked", "On use locked") - - //! Время до автозакрытия - DEFINE_FIELD_FLOAT(m_fAutoCloseTime, PDFF_NONE, "autoclose_time", "Autoclose time", EDITOR_TIMEFIELD) - //! Повреждение при блокировке - DEFINE_FIELD_FLOAT(m_fBlockDamage, PDFF_NONE, "block_damage", "Block damage", EDITOR_TEXTFIELD) //! Величина смещение (0-авто) DEFINE_FIELD_FLOAT(m_fDistanceOverride, PDFF_NONE, "distance_override", "Distance override", EDITOR_TEXTFIELD) //! Скорость, м/с - DEFINE_FIELD_FLOAT(m_fSpeed, PDFF_NONE, "speed", "Speed", EDITOR_TEXTFIELD) + DEFINE_FIELD_FLOATFN(m_fSpeed, PDFF_NONE, "speed", "Speed", setSpeed, EDITOR_TEXTFIELD) //! Направление открытия DEFINE_FIELD_ANGLES(m_qAngle, PDFF_NONE, "open_angle", "Open angle", EDITOR_ANGLES) - - DEFINE_FIELD_STRING(m_szSndClose, PDFF_NONE, "snd_close", "Close sound", EDITOR_FILEFIELD) - FILE_OPTION("Select sound", "ogg") - EDITOR_FILE_END() - DEFINE_FIELD_STRING(m_szSndOpen, PDFF_NONE, "snd_open", "Open sound", EDITOR_FILEFIELD) - FILE_OPTION("Select sound", "ogg") - EDITOR_FILE_END() - DEFINE_FIELD_STRING(m_szSndLocked, PDFF_NONE, "snd_locked", "Locked sound", EDITOR_FILEFIELD) - FILE_OPTION("Select sound", "ogg") - EDITOR_FILE_END() - - //! Изначально заблокирована - DEFINE_FLAG(DOOR_START_LOCKED, "Start locked") - //! Запрет открытия игроком - DEFINE_FLAG(DOOR_NO_USE, "Disable player USE") - //! Изначально открыта - DEFINE_FLAG(DOOR_START_OPENED, "Start opened") - //! Автозакрытие по таймеру - DEFINE_FLAG(DOOR_AUTOCLOSE, "Autoclose") - //! Форсированное закрытие двери - DEFINE_FLAG(DOOR_FORCE, "Force close") END_PROPTABLE() REGISTER_ENTITY(CPropDoor, prop_door, REC_MODEL_FIELD("model")); -CPropDoor::~CPropDoor() -{ - releasePhysics(); - - mem_release(m_pSndClose); - mem_release(m_pSndOpen); - mem_release(m_pSndLocked); -} - -void CPropDoor::onPostLoad() -{ - m_isLocked = (getFlags() & DOOR_START_LOCKED) != 0; - m_bState = (getFlags() & DOOR_START_OPENED) != 0; - - BaseClass::onPostLoad(); - - IXSoundSystem *pSound = (IXSoundSystem*)(Core_GetIXCore()->getPluginManager()->getInterface(IXSOUNDSYSTEM_GUID)); - if(pSound) - { - IXSoundLayer *pGameLayer = pSound->findLayer("xGame"); - - if(m_szSndClose[0]) - { - m_pSndClose = pGameLayer->newSoundPlayer(m_szSndClose, SOUND_SPACE_3D); - } - if(m_szSndOpen[0]) - { - m_pSndOpen = pGameLayer->newSoundPlayer(m_szSndOpen, SOUND_SPACE_3D); - } - if(m_szSndLocked[0]) - { - m_pSndLocked = pGameLayer->newSoundPlayer(m_szSndLocked, SOUND_SPACE_3D); - } - } -} - -void CPropDoor::inputOpen(inputdata_t * pInputdata) -{ - if(m_isLocked) - { - FIRE_OUTPUT(m_onUseLocked, pInputdata->pInflictor); - - SAFE_CALL(m_pSndLocked, setWorldPos, getPos()); - SAFE_CALL(m_pSndLocked, play); - return; - } - if(m_bState) - { - return; - } - m_bState = true; - if(m_isClosing) - { - stop(); - } - - m_pInflictor = pInputdata->pInflictor; - FIRE_OUTPUT(m_onOpen, pInputdata->pInflictor); - - SAFE_CALL(m_pSndOpen, setWorldPos, getPos()); - SAFE_CALL(m_pSndOpen, play); - - m_isOpening = true; - m_idThinkInterval = SET_INTERVAL(think, 0); -} -void CPropDoor::inputClose(inputdata_t * pInputdata) -{ - if(m_isLocked) - { - FIRE_OUTPUT(m_onUseLocked, pInputdata->pInflictor); - - SAFE_CALL(m_pSndLocked, setWorldPos, getPos()); - SAFE_CALL(m_pSndLocked, play); - return; - } - if(!m_bState) - { - return; - } - m_bState = false; - if(m_isOpening) - { - stop(); - } - - if(ID_VALID(m_idAutoCloseTimeout)) - { - CLEAR_TIMEOUT(m_idAutoCloseTimeout); - m_idAutoCloseTimeout = -1; - } - - m_pInflictor = pInputdata->pInflictor; - FIRE_OUTPUT(m_onClose, pInputdata->pInflictor); - - SAFE_CALL(m_pSndClose, setWorldPos, getPos()); - SAFE_CALL(m_pSndClose, play); - - m_isClosing = true; - m_idThinkInterval = SET_INTERVAL(think, 0); -} -void CPropDoor::inputToggle(inputdata_t * pInputdata) -{ - if(m_bState) - { - inputClose(pInputdata); - } - else - { - inputOpen(pInputdata); - } -} -void CPropDoor::inputLock(inputdata_t * pInputdata) -{ - m_isLocked = true; -} -void CPropDoor::inputUnlock(inputdata_t * pInputdata) -{ - m_isLocked = false; -} - -void CPropDoor::onUse(CBaseEntity *pUser) -{ - if(getFlags() & DOOR_NO_USE) - { - return; - } - - inputdata_t inputdata; - memset(&inputdata, 0, sizeof(inputdata_t)); - inputdata.pActivator = pUser; - inputdata.pInflictor = pUser; - inputdata.type = PDF_NONE; - - if(getFlags() & DOOR_AUTOCLOSE) - { - inputOpen(&inputdata); - } - else - { - inputToggle(&inputdata); - } - - BaseClass::onUse(pUser); -} - void CPropDoor::createPhysBody() { if(m_pCollideShape) { - float3 vPos = getPos(); + m_vStartPos = getPos(); SMQuaternion qRot = getOrient(); - GetPhysics()->newGhostObject(&m_pGhostObject, true); - m_pGhostObject->setPosition(vPos); - m_pGhostObject->setRotation(qRot); - m_pGhostObject->setCollisionShape(m_pCollideShape); - m_pGhostObject->setCollisionFlags(XCF_KINEMATIC_OBJECT); - m_pGhostObject->setUserPointer(this); - m_pGhostObject->setUserTypeId(1); - - GetPhysWorld()->addCollisionObject(m_pGhostObject, CG_DOOR, CG_CHARACTER | CG_DEFAULT); + BaseClass::createPhysBody(); //m_pGhostObject->activate(); //m_pGhostObject->setActivationState(DISABLE_DEACTIVATION); @@ -267,177 +67,23 @@ void CPropDoor::createPhysBody() m_fDistance = fMax - fMin; } - m_vStartPos = vPos; m_vEndPos = (float3)(m_vStartPos + vDir * m_fDistance); + setMoveTime(m_fDistance / m_fSpeed); if(m_bState) { - setPos(m_vEndPos); - m_fPositionFrac = 1.0f; - } - } -} -void CPropDoor::removePhysBody() -{ - if(m_pGhostObject) - { - GetPhysWorld()->removeCollisionObject(m_pGhostObject); - mem_release(m_pGhostObject); - } - - BaseClass::removePhysBody(); -} - -void CPropDoor::think(float fDT) -{ - testPenetration(); - - if(m_isOpening) - { - m_fPositionFrac += fDT * m_fSpeed / m_fDistance; - if(m_fPositionFrac >= 1.0f) - { - m_fPositionFrac = 1.0f; - FIRE_OUTPUT(m_onOpened, m_pInflictor); - stop(); - - if(getFlags() & DOOR_AUTOCLOSE) - { - m_idAutoCloseTimeout = SET_TIMEOUT(close, m_fAutoCloseTime); - } - } - } - else if(m_isClosing) - { - m_fPositionFrac -= fDT * m_fSpeed / m_fDistance; - if(m_fPositionFrac <= 0.0f) - { - m_fPositionFrac = 0.0f; - FIRE_OUTPUT(m_onClosed, m_pInflictor); - stop(); - } - } - - float2 p1(0.0f, 0.0f); - float2 p2(0.42f, 0.0f); - float2 p3(0.58f, 1.0f); - float2 p4(1.0f, 1.0f); - float t = m_fPositionFrac; - float2 p = powf(1.0f - t, 3.0f) * p1 + 3.0f * powf(1.0f - t, 2.0f) * t * p2 + 3.0f * (1.0f - t) * powf(t, 2.0f) * p3 + powf(t, 3.0f) * p4; - t = p.y; - - setPos(SMVectorLerp(m_vStartPos, m_vEndPos, t)); -} - -void CPropDoor::stop() -{ - if(ID_VALID(m_idThinkInterval)) - { - CLEAR_INTERVAL(m_idThinkInterval); - m_idThinkInterval = -1; - } - m_isOpening = false; - m_isClosing = false; - - //@TODO: Stop sound -} - -void CPropDoor::setPos(const float3 & pos) -{ - BaseClass::setPos(pos); - if(m_pGhostObject) - { - m_pGhostObject->setPosition(pos); - //m_pGhostObject->setInterpolationLinearVelocity(btVector3(-0.02f, 0.0f, 0.0f)); - } -} - -bool CPropDoor::testPenetration() -{ - bool hasContact = false; - - for(UINT i = 0, l = m_pGhostObject->getOverlappingPairCount(); i < l; ++i) - { - - IXCollisionPair *collisionPair = m_pGhostObject->getOverlappingPair(i); - - IXCollisionObject* obj0 = collisionPair->getObject0(); - IXCollisionObject* obj1 = collisionPair->getObject1(); - - if((obj0 && !obj0->hasContactResponse()) || (obj1 && !obj1->hasContactResponse())) - continue; - - if(!needsCollision(obj0, obj1)) - continue; - - for(UINT j = 0, jl = collisionPair->getContactManifoldCount(); j < jl; ++j) - { - IXContactManifold *manifold = collisionPair->getContactManifold(j); - //btScalar directionSign = manifold->getBody0() == m_pGhostObject ? btScalar(-1.0) : btScalar(1.0); - for(UINT p = 0, pl = manifold->getContactCount(); p<pl; ++p) - { - const IXContactManifoldPoint *pt = manifold->getContact(p); - - float dist = pt->getDistance(); - - if(dist < -DOOR_MAX_PENETRATION_DEPTH) - { - hasContact = true; - const IXCollisionObject *pObject = (obj0 == m_pGhostObject) ? obj1 : obj0; - - if(pObject->getUserPointer() && pObject->getUserTypeId() == 1) - { - CBaseEntity *pEnt = (CBaseEntity*)pObject->getUserPointer(); - if(pEnt) - { - CTakeDamageInfo takeDamageInfo(this, m_fBlockDamage); - takeDamageInfo.m_pInflictor = this; - - pEnt->dispatchDamage(takeDamageInfo); - } - } - } - } - - //manifold->clearManifold(); - } - } - - if(hasContact) - { - if(!(getFlags() & DOOR_FORCE)) - { - inputdata_t inputdata; - memset(&inputdata, 0, sizeof(inputdata_t)); - inputdata.pActivator = this; - inputdata.pInflictor = m_pInflictor; - inputdata.type = PDF_NONE; - inputToggle(&inputdata); - return(false); - } - else - { - return(true); + updatePositionFrac(1.0f); } } - return(false); } -bool CPropDoor::needsCollision(const IXCollisionObject *body0, const IXCollisionObject *body1) +void CPropDoor::setSpeed(float fSpeed) { - bool collides = (body0->getFilterGroup() & body1->getFilterMask()) != 0; - collides = collides && (body1->getFilterGroup() & body0->getFilterMask()); - return(collides); + m_fSpeed = fSpeed; + setMoveTime(m_fDistance / m_fSpeed); } -void CPropDoor::close(float fDT) +void CPropDoor::updatePos(float fPosNormalized) { - m_idAutoCloseTimeout = -1; - - inputdata_t inputdata; - memset(&inputdata, 0, sizeof(inputdata_t)); - inputdata.pActivator = this; - inputdata.pInflictor = m_pInflictor; - inputdata.type = PDF_NONE; - inputClose(&inputdata); + setPos(SMVectorLerp(m_vStartPos, m_vEndPos, fPosNormalized)); } diff --git a/source/game/PropDoor.h b/source/game/PropDoor.h index 125fe229e..c125b193e 100644 --- a/source/game/PropDoor.h +++ b/source/game/PropDoor.h @@ -12,95 +12,37 @@ See the license in LICENSE #ifndef __PROP_DOOR_H #define __PROP_DOOR_H -#include "PropDynamic.h" - -#define DOOR_START_LOCKED ENT_FLAG_0 -#define DOOR_NO_USE ENT_FLAG_1 -#define DOOR_START_OPENED ENT_FLAG_2 -#define DOOR_AUTOCLOSE ENT_FLAG_3 -#define DOOR_FORCE ENT_FLAG_4 +#include "BaseDoor.h" //! базовое направление для двери #define DOOR_BASE_DIR float3(0, 0, -1.0f) -#define DOOR_MAX_PENETRATION_DEPTH 0.16f - /*! Дверь \ingroup cbaseanimating */ -class CPropDoor: public CPropDynamic +class CPropDoor: public CBaseDoor { - DECLARE_CLASS(CPropDoor, CPropDynamic); + DECLARE_CLASS(CPropDoor, CBaseDoor); DECLARE_PROPTABLE(); public: DECLARE_TRIVIAL_CONSTRUCTOR(); - ~CPropDoor(); - - void onPostLoad() override; - - void onUse(CBaseEntity *pUser); - - //! Устанавливает положение в мире - void setPos(const float3 & pos); protected: - void inputOpen(inputdata_t * pInputdata); - void inputClose(inputdata_t * pInputdata); - void inputLock(inputdata_t * pInputdata); - void inputUnlock(inputdata_t * pInputdata); - void inputToggle(inputdata_t * pInputdata); - - void think(float fDT); - ID m_idThinkInterval = -1; - ID m_idAutoCloseTimeout = -1; - - void stop(); - - bool testPenetration(); - bool needsCollision(const IXCollisionObject *body0, const IXCollisionObject *body1); - - output_t m_onClose; - output_t m_onClosed; - output_t m_onOpen; - output_t m_onOpened; - output_t m_onUseLocked; + void updatePos(float fPosNormalized) override; - virtual void createPhysBody(); - virtual void removePhysBody(); + void createPhysBody() override; - float m_fAutoCloseTime = 0.0f; float m_fDistanceOverride = 0.0f; float m_fSpeed = 0.1f; SMQuaternion m_qAngle; - float m_fBlockDamage = 100.0f; - - const char * m_szSndClose; - IXSoundPlayer *m_pSndClose = NULL; - const char * m_szSndOpen; - IXSoundPlayer *m_pSndOpen = NULL; - const char * m_szSndLocked; - IXSoundPlayer *m_pSndLocked = NULL; - - bool m_isLocked = false; - - bool m_bState = false; - - IXGhostObject *m_pGhostObject = NULL; private: + void setSpeed(float fSpeed); + float m_fDistance = 0.0f; float3_t m_vStartPos; float3_t m_vEndPos; - - float m_fPositionFrac = 0.0f; - - bool m_isOpening = false; - bool m_isClosing = false; - - CBaseEntity *m_pInflictor = NULL; - - void close(float fDT); }; #endif diff --git a/source/game/PropDoorRotating.cpp b/source/game/PropDoorRotating.cpp new file mode 100644 index 000000000..9720624e4 --- /dev/null +++ b/source/game/PropDoorRotating.cpp @@ -0,0 +1,52 @@ +#include "PropDoorRotating.h" + +/*! \skydocent prop_door +Дверь +*/ + +BEGIN_PROPTABLE(CPropDoorRotating) + //! Величина смещение (0-авто) + DEFINE_FIELD_FLOAT(m_fDistanceOverride, PDFF_NONE, "distance_override", "Distance override", EDITOR_TEXTFIELD) + //! Скорость, м/с + DEFINE_FIELD_FLOATFN(m_fSpeed, PDFF_NONE, "speed", "Speed", setSpeed, EDITOR_TEXTFIELD) + //! Направление открытия + DEFINE_FIELD_ANGLES(m_qAngle, PDFF_NONE, "open_angle", "Open angle", EDITOR_ANGLES) +END_PROPTABLE() + +// REGISTER_ENTITY(CPropDoorRotating, prop_door_rotating, REC_MODEL_FIELD("model")); + +CPropDoorRotating::~CPropDoorRotating() +{ + releasePhysics(); + + mem_release(m_pSndClose); + mem_release(m_pSndOpen); + mem_release(m_pSndLocked); +} + +void CPropDoorRotating::createPhysBody() +{ + if(m_pCollideShape) + { + float3 vPos = getPos(); + SMQuaternion qRot = getOrient(); + + GetPhysics()->newGhostObject(&m_pGhostObject, true); + m_pGhostObject->setPosition(vPos); + m_pGhostObject->setRotation(qRot); + m_pGhostObject->setCollisionShape(m_pCollideShape); + m_pGhostObject->setCollisionFlags(XCF_KINEMATIC_OBJECT); + m_pGhostObject->setUserPointer(this); + m_pGhostObject->setUserTypeId(1); + + GetPhysWorld()->addCollisionObject(m_pGhostObject, CG_DOOR, CG_STATIC_MASK); + + //m_pGhostObject->activate(); + //m_pGhostObject->setActivationState(DISABLE_DEACTIVATION); + } +} + +void CPropDoorRotating::setSpeed(float fSpeed) +{ + +} diff --git a/source/game/PropDoorRotating.h b/source/game/PropDoorRotating.h new file mode 100644 index 000000000..aea441ddf --- /dev/null +++ b/source/game/PropDoorRotating.h @@ -0,0 +1,40 @@ +/*! +\file +Дверь +*/ + +#ifndef __PROP_DOOR_ROTATING_H +#define __PROP_DOOR_ROTATING_H + +#include "BaseDoor.h" + +/*! Дверь +\ingroup cbaseanimating +*/ +class CPropDoorRotating: public CBaseDoor +{ + DECLARE_CLASS(CPropDoorRotating, CBaseDoor); + DECLARE_PROPTABLE(); +public: + DECLARE_TRIVIAL_CONSTRUCTOR(); + ~CPropDoorRotating(); + +protected: + virtual void updatePos(float fPosNormalized) {}; + + void createPhysBody() override; + + float m_fDistanceOverride = 0.0f; + float m_fSpeed = 0.1f; + SMQuaternion m_qAngle; + +private: + void setSpeed(float fSpeed); + + float m_fDistance = 0.0f; + + float3_t m_vStartPos; + float3_t m_vEndPos; +}; + +#endif diff --git a/source/physics/Constraint.cpp b/source/physics/Constraint.cpp new file mode 100644 index 000000000..fc144c096 --- /dev/null +++ b/source/physics/Constraint.cpp @@ -0,0 +1,62 @@ +#include "Constraint.h" +#include "CollisionObject.h" + +btTypedConstraint* GetConstraint(IXBaseConstraint *pConstraint) +{ + btTypedConstraint *pBtConstraint = NULL; + switch(pConstraint->getType()) + { + case XCT_HINGE: + pBtConstraint = ((CHingeConstraint*)pConstraint->asHinge())->getBtConstraint(); + break; + default: + assert(!"Unknown constraint type!"); + break; + } + assert(pBtConstraint); + + return(pBtConstraint); +} + +//############################################################################# + +CHingeConstraint::CHingeConstraint(const XHingeConstraintBodyDesc *pBodyA, const XHingeConstraintBodyDesc *pBodyB, bool useReferenceFrameA): + BaseClass(XCT_HINGE) +{ + setBodyA(pBodyA->pBody); + btRigidBody *pRigidBodyA = ((CRigidBody*)pBodyA->pBody)->getBtRigidBody(); + btVector3 vPivotA = F3_BTVEC(pBodyA->vPivot); + btVector3 vAxisA = F3_BTVEC(pBodyA->vAxis); + if(pBodyB) + { + setBodyB(pBodyB->pBody); + + btRigidBody *pRigidBodyB = ((CRigidBody*)pBodyB->pBody)->getBtRigidBody(); + btVector3 vPivotB = F3_BTVEC(pBodyB->vPivot); + btVector3 vAxisB = F3_BTVEC(pBodyB->vAxis); + + m_pConstraint = new btHingeConstraint(*pRigidBodyA, *pRigidBodyB, vPivotA, vPivotB, vAxisA, vAxisB, useReferenceFrameA); + } + else + { + m_pConstraint = new btHingeConstraint(*pRigidBodyA, vPivotA, vAxisA, useReferenceFrameA); + } + + m_pConstraint->setDbgDrawSize(0.5f); + + setConstraint(m_pConstraint); +} +CHingeConstraint::~CHingeConstraint() +{ + mem_delete(m_pConstraint); +} + +void XMETHODCALLTYPE CHingeConstraint::setAngularOnly(bool yesNo) +{ + m_pConstraint->setAngularOnly(yesNo); +} + +void XMETHODCALLTYPE CHingeConstraint::setLimit(float fLow, float fHigh, float fSoftness, float fBiasFactor, float fRelaxationFactor) +{ + m_pConstraint->setLimit(fLow, fHigh, fSoftness, fBiasFactor, fRelaxationFactor); +} diff --git a/source/physics/Constraint.h b/source/physics/Constraint.h new file mode 100644 index 000000000..49be90500 --- /dev/null +++ b/source/physics/Constraint.h @@ -0,0 +1,110 @@ +#ifndef __CONSTRAINT_H +#define __CONSTRAINT_H + +#include <btBulletDynamicsCommon.h> +#include <xcommon/physics/IXConstraint.h> +#include <xcommon/physics/IXCollisionObject.h> + +btTypedConstraint* GetConstraint(IXBaseConstraint *pConstraint); + +template<class T> +class CConstraint: public IXUnknownImplementation<T> +{ +public: + typedef CConstraint<T> BaseClass; + + CConstraint(XCONSTRAINT_TYPE type) : + m_type(type) + { + } + + ~CConstraint() + { + mem_release(m_pBodyA); + mem_release(m_pBodyB); + } + + void XMETHODCALLTYPE setUserPointer(void *pUser) override + { + m_pUserPointer = pUser; + } + void* XMETHODCALLTYPE getUserPointer() const override + { + return(m_pUserPointer); + } + + void XMETHODCALLTYPE setUserTypeId(int iUser) override + { + m_iUserTypeId = iUser; + } + int XMETHODCALLTYPE getUserTypeId() const override + { + return(m_iUserTypeId); + } + + XCONSTRAINT_TYPE XMETHODCALLTYPE getType() const override + { + return(m_type); + } + + IXHingeConstraint* XMETHODCALLTYPE asHinge() override + { + return(NULL); + } + + btTypedConstraint* getBtConstraint() + { + return(m_pBtConstraint); + } + +protected: + void setConstraint(btTypedConstraint *pBtConstraint) + { + m_pBtConstraint = pBtConstraint; + pBtConstraint->setUserConstraintPtr((IXBaseConstraint*)this); + } + + void setBodyA(IXRigidBody *pBody) + { + m_pBodyA = pBody; + add_ref(pBody); + } + + void setBodyB(IXRigidBody *pBody) + { + m_pBodyB = pBody; + add_ref(pBody); + } + +private: + XCONSTRAINT_TYPE m_type; + void *m_pUserPointer = NULL; + btTypedConstraint *m_pBtConstraint = NULL; + int m_iUserTypeId = -1; + + IXRigidBody *m_pBodyA = NULL; + IXRigidBody *m_pBodyB = NULL; +}; + +//############################################################################# + +class CHingeConstraint: public CConstraint<IXHingeConstraint> +{ +public: + CHingeConstraint(const XHingeConstraintBodyDesc *pBodyA, const XHingeConstraintBodyDesc *pBodyB = NULL, bool useReferenceFrameA = false); + ~CHingeConstraint(); + + IXHingeConstraint* XMETHODCALLTYPE asHinge() override + { + return(this); + } + + void XMETHODCALLTYPE setAngularOnly(bool yesNo) override; + + void XMETHODCALLTYPE setLimit(float fLow, float fHigh, float fSoftness = 0.9f, float fBiasFactor = 0.3f, float fRelaxationFactor = 1.0f) override; + +private: + btHingeConstraint *m_pConstraint; +}; + +#endif diff --git a/source/physics/PhyWorld.cpp b/source/physics/PhyWorld.cpp index c4eb6d186..c5d5176de 100644 --- a/source/physics/PhyWorld.cpp +++ b/source/physics/PhyWorld.cpp @@ -11,6 +11,8 @@ See the license in LICENSE #include "CollisionObject.h" +#include "Constraint.h" + //#include <BulletDynamics/MLCPSolvers/btDantzigSolver.h> //#include <BulletDynamics/MLCPSolvers/btMLCPSolver.h> @@ -393,8 +395,18 @@ void CPhyWorld::runQueue() m_pDynamicsWorld->updateSingleAabb(i.pBtObj); } break; + + case QIT_ADD_CONSTRAINT: + // TODO disable collision between linked bodies + m_pDynamicsWorld->addConstraint(GetConstraint(i.pConstraint)); + break; + + case QIT_REMOVE_CONSTRAINT: + m_pDynamicsWorld->removeConstraint(GetConstraint(i.pConstraint)); + break; } mem_release(i.pObj); + mem_release(i.pConstraint); } } @@ -453,6 +465,26 @@ void CPhyWorld::updateSingleAABB(IXCollisionObject *pObj, btCollisionObject *pBt enqueue({QIT_UPDATE_SINGLE_AABB, pObj, 0, 0, pBtObj}); } +void XMETHODCALLTYPE CPhyWorld::addConstraint(IXBaseConstraint *pConstraint) +{ + assert(pConstraint); + + // One ref for world, the second for queue + add_ref(pConstraint); + add_ref(pConstraint); + enqueue({QIT_ADD_CONSTRAINT, NULL, 0, 0, NULL, pConstraint}); +} +void XMETHODCALLTYPE CPhyWorld::removeConstraint(IXBaseConstraint *pConstraint) +{ + if(!pConstraint) + { + return; + } + + add_ref(pConstraint); + enqueue({QIT_REMOVE_CONSTRAINT, NULL, 0, 0, NULL, pConstraint}); +} + //############################################################## void XMETHODCALLTYPE CPhyWorld::CRenderable::renderStage(X_RENDER_STAGE stage, IXRenderableVisibility *pVisibility) diff --git a/source/physics/PhyWorld.h b/source/physics/PhyWorld.h index 00a0a53ba..28dedc01b 100644 --- a/source/physics/PhyWorld.h +++ b/source/physics/PhyWorld.h @@ -168,6 +168,9 @@ public: void XMETHODCALLTYPE convexSweepTest(IXConvexShape *pShape, const transform_t &xfFrom, const transform_t &xfTo, IXConvexCallback *pCallback, COLLISION_GROUP collisionGroup = CG_DEFAULT, COLLISION_GROUP collisionMask = CG_ALL) override; + void XMETHODCALLTYPE addConstraint(IXBaseConstraint *pConstraint) override; + void XMETHODCALLTYPE removeConstraint(IXBaseConstraint *pConstraint) override; + template<class T> void updateSingleAABB(T *pObj) { @@ -198,7 +201,9 @@ private: { QIT_ADD_COLLISION_OBJECT, QIT_REMOVE_COLLISION_OBJECT, - QIT_UPDATE_SINGLE_AABB + QIT_UPDATE_SINGLE_AABB, + QIT_ADD_CONSTRAINT, + QIT_REMOVE_CONSTRAINT }; struct QueueItem @@ -208,6 +213,7 @@ private: int iGroup; int iMask; btCollisionObject *pBtObj; + IXBaseConstraint *pConstraint; }; Queue<QueueItem> m_queue; diff --git a/source/physics/Physics.cpp b/source/physics/Physics.cpp index 34a9850cb..69c6d0100 100644 --- a/source/physics/Physics.cpp +++ b/source/physics/Physics.cpp @@ -7,6 +7,7 @@ #include "MutationObserver.h" #include <core/sxcore.h> #include <LinearMath/btGeometryUtil.h> +#include "Constraint.h" CPhysics::CPhysics(CPhyWorld *pDefaultWorld): m_pDefaultWorld(pDefaultWorld) @@ -193,3 +194,8 @@ UINT XMETHODCALLTYPE CPhysics::adjustConvexHullForMargin(UINT uPoints, const flo return(uResultVertexCount); } + +void XMETHODCALLTYPE CPhysics::newHingeConstraint(IXHingeConstraint **ppOut, const XHingeConstraintBodyDesc *pBodyA, const XHingeConstraintBodyDesc *pBodyB, bool useReferenceFrameA) +{ + *ppOut = new CHingeConstraint(pBodyA, pBodyB, useReferenceFrameA); +} diff --git a/source/physics/Physics.h b/source/physics/Physics.h index b03133fca..8e89e7d53 100644 --- a/source/physics/Physics.h +++ b/source/physics/Physics.h @@ -30,6 +30,8 @@ public: UINT XMETHODCALLTYPE adjustConvexHullForMargin(UINT uPoints, const float3_t *pInPoints, IXBuffer **ppOutBuffer, float *pfMargin = NULL, byte u8Stride = sizeof(float3_t), bool bOptimize = true) override; + void XMETHODCALLTYPE newHingeConstraint(IXHingeConstraint **ppOut, const XHingeConstraintBodyDesc *pBodyA, const XHingeConstraintBodyDesc *pBodyB = NULL, bool useReferenceFrameA = false) override; + private: CPhyWorld *m_pDefaultWorld; }; diff --git a/source/terrax/ProxyObject.cpp b/source/terrax/ProxyObject.cpp index 20d1e4131..f812b3d79 100644 --- a/source/terrax/ProxyObject.cpp +++ b/source/terrax/ProxyObject.cpp @@ -120,6 +120,7 @@ void XMETHODCALLTYPE CProxyObject::render(bool is3D, bool bRenderSelection, IXGi { m_aObjects[i].pObj->render(is3D, bRenderSelection, pGizmoRenderer); } + m_pTargetObject->render(is3D, bRenderSelection, pGizmoRenderer); } bool XMETHODCALLTYPE CProxyObject::rayTest(const float3 &vStart, const float3 &vEnd, float3 *pvOut, float3 *pvNormal, ID *pidMtrl, bool bReturnNearestPoint) diff --git a/source/xcommon/physics/IXConstraint.h b/source/xcommon/physics/IXConstraint.h new file mode 100644 index 000000000..a8ebf3368 --- /dev/null +++ b/source/xcommon/physics/IXConstraint.h @@ -0,0 +1,46 @@ +#ifndef __IXCONSTRAINT_H +#define __IXCONSTRAINT_H + +#include <gdefines.h> +#include "IXCollisionObject.h" + +enum XCONSTRAINT_TYPE +{ + XCT_HINGE +}; + +class IXHingeConstraint; + +class IXBaseConstraint: public IXUnknown +{ +public: + virtual void XMETHODCALLTYPE setUserPointer(void *pUser) = 0; + virtual void* XMETHODCALLTYPE getUserPointer() const = 0; + + virtual void XMETHODCALLTYPE setUserTypeId(int iUser) = 0; + virtual int XMETHODCALLTYPE getUserTypeId() const = 0; + + virtual XCONSTRAINT_TYPE XMETHODCALLTYPE getType() const = 0; + + virtual IXHingeConstraint* XMETHODCALLTYPE asHinge() = 0; +}; + +//############################################################################# + +struct XHingeConstraintBodyDesc +{ + IXRigidBody *pBody; + float3_t vPivot; + float3_t vAxis; +}; + +class IXHingeConstraint: public IXBaseConstraint +{ +public: + virtual void XMETHODCALLTYPE setAngularOnly(bool yesNo) = 0; + + virtual void XMETHODCALLTYPE setLimit(float fLow, float fHigh, float fSoftness = 0.9f, float fBiasFactor = 0.3f, float fRelaxationFactor = 1.0f) = 0; +}; + + +#endif diff --git a/source/xcommon/physics/IXPhysics.h b/source/xcommon/physics/IXPhysics.h index 5597e5326..b79336738 100644 --- a/source/xcommon/physics/IXPhysics.h +++ b/source/xcommon/physics/IXPhysics.h @@ -6,6 +6,7 @@ #include "IXCollisionObject.h" #include "IXCharacterController.h" #include "IXMutationObserver.h" +#include "IXConstraint.h" /* typedef enum PHY_ScalarType @@ -66,6 +67,8 @@ public: virtual void XMETHODCALLTYPE convexSweepTest(IXConvexShape *pShape, const transform_t &xfFrom, const transform_t &xfTo, IXConvexCallback *pCallback, COLLISION_GROUP collisionGroup = CG_DEFAULT, COLLISION_GROUP collisionMask = CG_ALL) = 0; + virtual void XMETHODCALLTYPE addConstraint(IXBaseConstraint *pConstraint) = 0; + virtual void XMETHODCALLTYPE removeConstraint(IXBaseConstraint *pConstraint) = 0; // add/remove action // convexSweepTest // add/remove constraint @@ -104,6 +107,8 @@ public: virtual IXPhysicsWorld* XMETHODCALLTYPE getWorld(void *pReserved = NULL) = 0; virtual UINT XMETHODCALLTYPE adjustConvexHullForMargin(UINT uPoints, const float3_t *pInPoints, IXBuffer **ppOutBuffer, float *pfMargin = NULL, byte u8Stride = sizeof(float3_t), bool bOptimize = true) = 0; + + virtual void XMETHODCALLTYPE newHingeConstraint(IXHingeConstraint **ppOut, const XHingeConstraintBodyDesc *pBodyA, const XHingeConstraintBodyDesc *pBodyB = NULL, bool useReferenceFrameA = false) = 0; }; #endif diff --git a/source/xcsg/BrushMesh.cpp b/source/xcsg/BrushMesh.cpp index a1a1cba20..874754644 100644 --- a/source/xcsg/BrushMesh.cpp +++ b/source/xcsg/BrushMesh.cpp @@ -2404,6 +2404,11 @@ void CBrushMesh::setColor(const float3_t &vColor) SAFE_CALL(m_pModel, setColor, (float4)vColor); } +bool CBrushMesh::isFinalized() const +{ + return(m_isFinalized); +} + //########################################################################## Subset& CMeshBuilder::getSubset(UINT id) diff --git a/source/xcsg/BrushMesh.h b/source/xcsg/BrushMesh.h index 39f72d434..02a6ffb90 100644 --- a/source/xcsg/BrushMesh.h +++ b/source/xcsg/BrushMesh.h @@ -126,6 +126,8 @@ public: void setColor(const float3_t &vColor); + bool isFinalized() const; + private: void buildModel(bool bBuildPhysbox = true); void setupFromOutline(COutline *pOutline, UINT uContour, float fHeight); diff --git a/source/xcsg/EditorObject.cpp b/source/xcsg/EditorObject.cpp index 47fcd5fd4..990e9d32c 100644 --- a/source/xcsg/EditorObject.cpp +++ b/source/xcsg/EditorObject.cpp @@ -214,7 +214,10 @@ void XMETHODCALLTYPE CEditorObject::create() m_isRemoved = false; for(UINT i = 0, l = m_aBrushes.size(); i < l; ++i) { - m_aBrushes[i]->enable(true); + if(!m_aBrushes[i]->isFinalized()) + { + m_aBrushes[i]->enable(true); + } } m_isVisible = true; //SAFE_CALL(m_pModel, onObjectAdded, this); -- GitLab