From f5e9b360da48dfd248a9a7edec7fc0eb189fe7fe Mon Sep 17 00:00:00 2001 From: phevosccp Date: Thu, 20 Aug 2026 10:08:38 +0000 Subject: [PATCH 01/14] Release the RTPC emitter reference when the bind action stops Stop unregistered the updateable but kept the action's reference to the emitter, so the emitter outlived the action that was driving it. --- trinity/Controllers/Actions/Tr2ActionBindRTPC.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/trinity/Controllers/Actions/Tr2ActionBindRTPC.cpp b/trinity/Controllers/Actions/Tr2ActionBindRTPC.cpp index acbe8e8dc..050b18579 100644 --- a/trinity/Controllers/Actions/Tr2ActionBindRTPC.cpp +++ b/trinity/Controllers/Actions/Tr2ActionBindRTPC.cpp @@ -85,6 +85,7 @@ void Tr2ActionBindRTPC::StartWithController( ITr2ActionController* controller ) void Tr2ActionBindRTPC::Stop( ITr2ActionController& controller ) { controller.UnRegisterUpdateable( *this ); + m_emitter = nullptr; } void Tr2ActionBindRTPC::StopWithController( ITr2ActionController* controller ) From aa133e6d828d84a25de79f8bd841c3ed0a13f256 Mon Sep 17 00:00:00 2001 From: phevosccp Date: Thu, 20 Aug 2026 10:08:39 +0000 Subject: [PATCH 02/14] Add name and enabled to IEveVolume Volumes gain a persisted enabled attribute, so a placement can switch between trigger shapes without editing the shape list, and a name accessor so per-placement names can be read back off a volume. Implemented for the box, sphere and ellipsoid shapes. Only EveTriggerVolume honours the flag so far: fog volumes, post process volumes, lighting overrides, procedural containers and distribution placement generators still evaluate every volume they are given. --- trinity/Eve/Volume/EveBoxVolume.cpp | 11 +++++++++++ trinity/Eve/Volume/EveBoxVolume.h | 3 +++ trinity/Eve/Volume/EveBoxVolume_Blue.cpp | 1 + trinity/Eve/Volume/EveEllipsoidVolume.cpp | 11 +++++++++++ trinity/Eve/Volume/EveEllipsoidVolume.h | 3 +++ trinity/Eve/Volume/EveEllipsoidVolume_Blue.cpp | 1 + trinity/Eve/Volume/EveSphereVolume.cpp | 11 +++++++++++ trinity/Eve/Volume/EveSphereVolume.h | 3 +++ trinity/Eve/Volume/EveSphereVolume_Blue.cpp | 1 + trinity/Eve/Volume/IEveVolume.h | 2 ++ 10 files changed, 47 insertions(+) diff --git a/trinity/Eve/Volume/EveBoxVolume.cpp b/trinity/Eve/Volume/EveBoxVolume.cpp index 1bdf2a8ac..3e15f3c70 100644 --- a/trinity/Eve/Volume/EveBoxVolume.cpp +++ b/trinity/Eve/Volume/EveBoxVolume.cpp @@ -12,6 +12,7 @@ Vector3 const EveBoxVolume::MAX_AABB = Vector3( 0.5, 0.5, 0.5 ); Vector3 const EveBoxVolume::MIN_AABB = Vector3( -0.5, -0.5, -0.5 ); EveBoxVolume::EveBoxVolume( IRoot* lockobj ) : + m_enabled( true ), m_position( 0, 0, 0 ), m_scaling( 0, 0, 0 ), m_innerScaling( 0, 0, 0 ), @@ -38,6 +39,16 @@ bool EveBoxVolume::Initialize() return true; } +const char* EveBoxVolume::GetName() const +{ + return m_name.c_str(); +} + +bool EveBoxVolume::IsEnabled() const +{ + return m_enabled; +} + void EveBoxVolume::RenderDebugInfo( ITr2DebugRenderer2& renderer, const Matrix& parentTransform, const Color& baseColor ) { renderer.DrawBox( this, m_boxTransform * parentTransform, MIN_AABB, MAX_AABB, Tr2DebugRenderer::Wireframe, baseColor * 0.5f ); diff --git a/trinity/Eve/Volume/EveBoxVolume.h b/trinity/Eve/Volume/EveBoxVolume.h index 4afa5d7ea..3312a5765 100644 --- a/trinity/Eve/Volume/EveBoxVolume.h +++ b/trinity/Eve/Volume/EveBoxVolume.h @@ -25,6 +25,8 @@ BLUE_CLASS( EveBoxVolume ) : ///////////////////////////////////////////////////////////////////////////////////// // IEveVolume + const char* GetName() const override; + bool IsEnabled() const override; void RenderDebugInfo( ITr2DebugRenderer2 & renderer, const Matrix& parentTransform, const Color& baseColor ) override; float GetIntensity( Vector3 position ) override; const CcpMath::Sphere GetBoundingSphere() const override; @@ -39,6 +41,7 @@ BLUE_CLASS( EveBoxVolume ) : private: void Setup(); BlueSharedString m_name; + bool m_enabled; ///< Disabled volumes are ignored by their owner, e.g. to switch shapes via external parameters. Vector3 m_position; Vector3 m_scaling; diff --git a/trinity/Eve/Volume/EveBoxVolume_Blue.cpp b/trinity/Eve/Volume/EveBoxVolume_Blue.cpp index 6afd4b048..0f8e62521 100644 --- a/trinity/Eve/Volume/EveBoxVolume_Blue.cpp +++ b/trinity/Eve/Volume/EveBoxVolume_Blue.cpp @@ -15,6 +15,7 @@ const Be::ClassInfo* EveBoxVolume::ExposeToBlue() MAP_INTERFACE( IInitialize ) MAP_ATTRIBUTE( "name", m_name, "", Be::READWRITE | Be::PERSIST ) + MAP_ATTRIBUTE( "enabled", m_enabled, "Disabled volumes are ignored by their owner, e.g. to switch shapes via external parameters", Be::READWRITE | Be::PERSIST ) MAP_ATTRIBUTE( "position", m_position, "", Be::READWRITE | Be::PERSIST | Be::NOTIFY ) MAP_ATTRIBUTE( "scaling", m_scaling, "", Be::READWRITE | Be::PERSIST | Be::NOTIFY ) MAP_ATTRIBUTE( "innerScaling", m_innerScaling, "", Be::READWRITE | Be::PERSIST | Be::NOTIFY ) diff --git a/trinity/Eve/Volume/EveEllipsoidVolume.cpp b/trinity/Eve/Volume/EveEllipsoidVolume.cpp index b0d26afd9..2a24186e1 100644 --- a/trinity/Eve/Volume/EveEllipsoidVolume.cpp +++ b/trinity/Eve/Volume/EveEllipsoidVolume.cpp @@ -8,6 +8,7 @@ #include "include/TriMath.h" EveEllipsoidVolume::EveEllipsoidVolume( IRoot* lockobj ) : + m_enabled( true ), m_position( 0, 0, 0 ), m_shape( 0, 0, 0 ), m_innerShape( 0, 0, 0 ), @@ -69,6 +70,16 @@ void EveEllipsoidVolume::RenderDebugInfo( ITr2DebugRenderer2& renderer, const Ma } } +const char* EveEllipsoidVolume::GetName() const +{ + return m_name.c_str(); +} + +bool EveEllipsoidVolume::IsEnabled() const +{ + return m_enabled; +} + const CcpMath::Sphere EveEllipsoidVolume::GetBoundingSphere() const { return m_boundingSphere; diff --git a/trinity/Eve/Volume/EveEllipsoidVolume.h b/trinity/Eve/Volume/EveEllipsoidVolume.h index 855d1cc47..48997e800 100644 --- a/trinity/Eve/Volume/EveEllipsoidVolume.h +++ b/trinity/Eve/Volume/EveEllipsoidVolume.h @@ -19,6 +19,8 @@ BLUE_CLASS( EveEllipsoidVolume ) : ///////////////////////////////////////////////////////////////////////////////////// // IEveVolume + const char* GetName() const override; + bool IsEnabled() const override; void RenderDebugInfo( ITr2DebugRenderer2 & renderer, const Matrix& parentTransform, const Color& baseColor ) override; float GetIntensity( Vector3 position ) override; uint32_t RegisterForChanges( const std::function& callBack ) override; @@ -38,6 +40,7 @@ BLUE_CLASS( EveEllipsoidVolume ) : void Setup(); BlueSharedString m_name; + bool m_enabled; ///< Disabled volumes are ignored by their owner, e.g. to switch shapes via external parameters. Vector3 m_position; Vector3 m_shape; diff --git a/trinity/Eve/Volume/EveEllipsoidVolume_Blue.cpp b/trinity/Eve/Volume/EveEllipsoidVolume_Blue.cpp index ba5104e3e..8950418b0 100644 --- a/trinity/Eve/Volume/EveEllipsoidVolume_Blue.cpp +++ b/trinity/Eve/Volume/EveEllipsoidVolume_Blue.cpp @@ -13,6 +13,7 @@ const Be::ClassInfo* EveEllipsoidVolume::ExposeToBlue() MAP_ATTRIBUTE( "name", m_name, "", Be::READWRITE | Be::PERSIST ) + MAP_ATTRIBUTE( "enabled", m_enabled, "Disabled volumes are ignored by their owner, e.g. to switch shapes via external parameters", Be::READWRITE | Be::PERSIST ) MAP_ATTRIBUTE( "position", m_position, "The position of the volume", Be::READWRITE | Be::PERSIST | Be::NOTIFY ) MAP_ATTRIBUTE( "shape", m_shape, "The shape of the outer ellipsoid", Be::READWRITE | Be::PERSIST | Be::NOTIFY ) MAP_ATTRIBUTE( "innerShape", m_innerShape, "The shape of the inner ellipsoid", Be::READWRITE | Be::PERSIST | Be::NOTIFY ) diff --git a/trinity/Eve/Volume/EveSphereVolume.cpp b/trinity/Eve/Volume/EveSphereVolume.cpp index e0f9c8e9d..5258efca2 100644 --- a/trinity/Eve/Volume/EveSphereVolume.cpp +++ b/trinity/Eve/Volume/EveSphereVolume.cpp @@ -7,6 +7,7 @@ #include "include/TriMath.h" EveSphereVolume::EveSphereVolume( IRoot* lockobj ) : + m_enabled( true ), m_innerSphere( Vector3( 0.0f, 0.0f, 0.0f ), 1.0f ), m_outerSphere( Vector3( 0.0f, 0.0f, 0.0f ), 1.0f ), m_nextCallbackID( 1 ) @@ -17,6 +18,16 @@ EveSphereVolume::~EveSphereVolume() { } +const char* EveSphereVolume::GetName() const +{ + return m_name.c_str(); +} + +bool EveSphereVolume::IsEnabled() const +{ + return m_enabled; +} + void EveSphereVolume::RenderDebugInfo( ITr2DebugRenderer2& renderer, const Matrix& parentTransform, const Color& baseColor ) { renderer.DrawSphere( this, TranslationMatrix( m_outerSphere.center ) * parentTransform, m_outerSphere.radius, 20, Tr2DebugRenderer::Wireframe, baseColor * 0.5f ); diff --git a/trinity/Eve/Volume/EveSphereVolume.h b/trinity/Eve/Volume/EveSphereVolume.h index 03e61dd31..f4e634b16 100644 --- a/trinity/Eve/Volume/EveSphereVolume.h +++ b/trinity/Eve/Volume/EveSphereVolume.h @@ -18,6 +18,8 @@ BLUE_CLASS( EveSphereVolume ) : ///////////////////////////////////////////////////////////////////////////////////// // IEveVolume + const char* GetName() const override; + bool IsEnabled() const override; void RenderDebugInfo( ITr2DebugRenderer2 & renderer, const Matrix& parentTransform, const Color& baseColor ) override; float GetIntensity( Vector3 position ) override; uint32_t RegisterForChanges( const std::function& callBack ) override; @@ -31,6 +33,7 @@ BLUE_CLASS( EveSphereVolume ) : private: BlueSharedString m_name; + bool m_enabled; ///< Disabled volumes are ignored by their owner, e.g. to switch shapes via external parameters. std::map> m_onChangeCallbacks; uint32_t m_nextCallbackID; diff --git a/trinity/Eve/Volume/EveSphereVolume_Blue.cpp b/trinity/Eve/Volume/EveSphereVolume_Blue.cpp index 0d3bb8b7b..b7dabb439 100644 --- a/trinity/Eve/Volume/EveSphereVolume_Blue.cpp +++ b/trinity/Eve/Volume/EveSphereVolume_Blue.cpp @@ -13,6 +13,7 @@ const Be::ClassInfo* EveSphereVolume::ExposeToBlue() MAP_ATTRIBUTE( "name", m_name, "", Be::READWRITE | Be::PERSIST ) + MAP_ATTRIBUTE( "enabled", m_enabled, "Disabled volumes are ignored by their owner, e.g. to switch shapes via external parameters", Be::READWRITE | Be::PERSIST ) MAP_ATTRIBUTE( "position", m_outerSphere.center, "", Be::READWRITE | Be::PERSIST | Be::NOTIFY ) MAP_ATTRIBUTE( "radius", m_outerSphere.radius, "", Be::READWRITE | Be::PERSIST | Be::NOTIFY ) MAP_ATTRIBUTE( "innerRadius", m_innerSphere.radius, "", Be::READWRITE | Be::PERSIST | Be::NOTIFY ) diff --git a/trinity/Eve/Volume/IEveVolume.h b/trinity/Eve/Volume/IEveVolume.h index d46188bb7..434c0e797 100644 --- a/trinity/Eve/Volume/IEveVolume.h +++ b/trinity/Eve/Volume/IEveVolume.h @@ -10,6 +10,8 @@ BLUE_DECLARE_INTERFACE( IEveVolume ); BLUE_INTERFACE( IEveVolume ) : public IRoot { + virtual const char* GetName() const = 0; + virtual bool IsEnabled() const = 0; virtual float GetIntensity( Vector3 position ) = 0; virtual uint32_t RegisterForChanges( const std::function& callBack ) = 0; // returns the callbackID virtual void UnregisterForChanges( uint32_t callbackID ) = 0; From 6940c4279fe819bf2cc4876fffb2f85653611b81 Mon Sep 17 00:00:00 2001 From: phevosccp Date: Thu, 20 Aug 2026 10:08:39 +0000 Subject: [PATCH 03/14] Add EveTriggerVolume: a standalone spatial trigger space object A top-level scene object whose trigger region is a list of IEveVolume shapes placed relative to its own translation and rotation, editable in Graphite like any other space object. Each synchronous update it evaluates the tracked position against the enabled volumes and keeps the inside/outside state, exposed read-only as isInside and intensity. A local bounding sphere over the enabled volumes acts as the broad phase for the point test and provides the bounds for picking, falling back to a unit radius so an object with no volumes set up yet stays selectable. --- trinity/CMakeLists.txt | 3 + trinity/Eve/EveTriggerVolume.cpp | 193 ++++++++++++++++++++++++++ trinity/Eve/EveTriggerVolume.h | 111 +++++++++++++++ trinity/Eve/EveTriggerVolume_Blue.cpp | 70 ++++++++++ 4 files changed, 377 insertions(+) create mode 100644 trinity/Eve/EveTriggerVolume.cpp create mode 100644 trinity/Eve/EveTriggerVolume.h create mode 100644 trinity/Eve/EveTriggerVolume_Blue.cpp diff --git a/trinity/CMakeLists.txt b/trinity/CMakeLists.txt index cbcebdd1b..5fd21e5d5 100644 --- a/trinity/CMakeLists.txt +++ b/trinity/CMakeLists.txt @@ -770,6 +770,9 @@ set(_SOURCES Eve/AudioGameObject.cpp Eve/AudioGameObject.h Eve/AudioGameObject_Blue.cpp + Eve/EveTriggerVolume.cpp + Eve/EveTriggerVolume.h + Eve/EveTriggerVolume_Blue.cpp Eve/EveEffectRoot2.cpp Eve/EveEffectRoot2.h Eve/EveEffectRoot2_Blue.cpp diff --git a/trinity/Eve/EveTriggerVolume.cpp b/trinity/Eve/EveTriggerVolume.cpp new file mode 100644 index 000000000..d8684c7e3 --- /dev/null +++ b/trinity/Eve/EveTriggerVolume.cpp @@ -0,0 +1,193 @@ +// Copyright © 2026 CCP ehf. + +#include "StdAfx.h" +#include "EveTriggerVolume.h" +#include "TriDevice.h" +#include "TriUtil.h" + +EveTriggerVolume::EveTriggerVolume( IRoot* lockobj ) : + PARENTLOCK( m_volumes ), + m_rotation( 0.0f, 0.0f, 0.0f, 1.0f ), + m_translation( 0.0f, 0.0f, 0.0f ), + m_worldTransform( IdentityMatrix() ), + m_enterThreshold( 0.5f ), + m_isInside( false ), + m_currentIntensity( 0.0f ), + m_display( true ) +{ +} + +EveTriggerVolume::~EveTriggerVolume() +{ +} + +void EveTriggerVolume::RebuildBoundingSphere() +{ + CCP_STATS_ZONE( __FUNCTION__ ); + + // Reset to the uninitialized sentinel (radius -1); a zero-radius reset reads as + // initialized, making the first merge below blend in a phantom sphere at the origin. + // Not CcpMath::Sphere::IncludeSphere, which fails to grow when the included sphere + // fully contains the current one. + m_boundingSphere = CcpMath::Sphere(); + + for( auto volume = m_volumes.begin(); volume != m_volumes.end(); ++volume ) + { + if( !( *volume )->IsEnabled() ) + { + continue; + } + + auto volumeSphere = ( *volume )->GetBoundingSphere(); + + if( !volumeSphere.IsInitialized() ) + { + continue; + } + // if sphere is not initialized, just copy it + // also if the sphere we are including in this sphere, then also copy it + if( !m_boundingSphere.IsInitialized() || volumeSphere.IsSphereInside( m_boundingSphere ) ) + { + m_boundingSphere = volumeSphere; + continue; + } + // do not update if is inside + if( m_boundingSphere.IsSphereInside( volumeSphere ) ) + { + continue; + } + + // extend sphere + Vector3 delta = volumeSphere.center - m_boundingSphere.center; + float deltaLen = Length( delta ); + + m_boundingSphere.center += 0.5f * ( 1.f + ( volumeSphere.radius - m_boundingSphere.radius ) / deltaLen ) * delta; + m_boundingSphere.radius = 0.5f * ( m_boundingSphere.radius + volumeSphere.radius + deltaLen ); + } +} + +void EveTriggerVolume::UpdateWorldTransform() +{ + m_worldTransform = RotationMatrix( m_rotation ) * TranslationMatrix( m_translation ); +} + +///////////////////////////////////////////////////////////////////////////////////// +// IEveSpaceObject2 +void EveTriggerVolume::UpdateSyncronous( const EveUpdateContext& updateContext ) +{ + CCP_STATS_ZONE( __FUNCTION__ ); + + UpdateWorldTransform(); + + RebuildBoundingSphere(); + + // The tracked position function may thunk into Python, so it must be evaluated on the + // synchronous update path rather than in UpdateAsyncronous. + UpdateTriggerState( updateContext ); +} + +void EveTriggerVolume::UpdateTriggerState( const EveUpdateContext& updateContext ) +{ + m_currentIntensity = 0.0f; + + bool inside = false; + if( m_trackedPosition && m_volumes.size() > 0 ) + { + Vector3 trackedPosition; + m_trackedPosition->Update( &trackedPosition, updateContext.GetTime() ); + + Matrix inverseWorldTransform = Inverse( m_worldTransform ); + Vector3 positionInObjectSpace = Transform( trackedPosition, inverseWorldTransform ).GetXYZ(); + + // check first if the tracked position is within the bounding sphere + if( m_boundingSphere.IsPointInside( positionInObjectSpace ) ) + { + // Now find the intensity within the volumes + for( const auto& volume : m_volumes ) + { + if( !volume->IsEnabled() ) + { + continue; + } + m_currentIntensity = std::max( m_currentIntensity, volume->GetIntensity( positionInObjectSpace ) ); + if( m_currentIntensity == 1.0f ) + { + // early exit + break; + } + } + } + + inside = m_currentIntensity >= m_enterThreshold; + } + + if( inside != m_isInside ) + { + m_isInside = inside; + } +} + +void EveTriggerVolume::UpdateAsyncronous( const EveUpdateContext& updateContext ) +{ +} + +void EveTriggerVolume::UpdateVisibility( const EveUpdateContext& updateContext, const Matrix& parentTransform ) +{ +} + +void EveTriggerVolume::GetRenderables( std::vector& renderables, Tr2ImpostorManager* impostors ) +{ +} + +bool EveTriggerVolume::GetBoundingSphere( Vector4& sphere, BoundingSphereQuery query ) const +{ + Vector3 worldCenter = Transform( m_boundingSphere.center, m_worldTransform ).GetXYZ(); + sphere = Vector4( worldCenter.x, worldCenter.y, worldCenter.z, std::max( m_boundingSphere.radius, 1.0f ) ); + return true; +} + +void EveTriggerVolume::UpdateModelCenterWorldPosition( Vector3& position, Be::Time t ) +{ + UpdateWorldTransform(); + GetModelCenterWorldPosition( position ); +} + +void EveTriggerVolume::GetModelCenterWorldPosition( Vector3& position ) const +{ + position = Transform( m_boundingSphere.center, m_worldTransform ).GetXYZ(); +} + +bool EveTriggerVolume::GetLocalBoundingBox( Vector3& min, Vector3& max ) +{ + // Fall back to a unit box when no volumes are set up yet, so the object stays pickable in Graphite. + float radius = std::max( m_boundingSphere.radius, 1.0f ); + min = m_boundingSphere.center - Vector3( radius, radius, radius ); + max = m_boundingSphere.center + Vector3( radius, radius, radius ); + return true; +} + +void EveTriggerVolume::GetLocalToWorldTransform( Matrix& transform ) const +{ + transform = m_worldTransform; +} + +///////////////////////////////////////////////////////////////////////////////////// +// IWorldPosition +Vector3 EveTriggerVolume::GetWorldPosition() +{ + return m_worldTransform.GetTranslation(); +} + +Quaternion EveTriggerVolume::GetWorldRotation() +{ + return Normalize( RotationQuaternion( m_worldTransform ) ); +} + +///////////////////////////////////////////////////////////////////////////////////// +// IInitialize +bool EveTriggerVolume::Initialize() +{ + UpdateWorldTransform(); + RebuildBoundingSphere(); + return true; +} diff --git a/trinity/Eve/EveTriggerVolume.h b/trinity/Eve/EveTriggerVolume.h new file mode 100644 index 000000000..2cf1f2042 --- /dev/null +++ b/trinity/Eve/EveTriggerVolume.h @@ -0,0 +1,111 @@ +// Copyright © 2026 CCP ehf. + +#pragma once + +#ifndef EveTriggerVolume_h +#define EveTriggerVolume_h + +#include "IWorldPosition.h" +#include "IEveSpaceObject2.h" +#include "Tr2DebugRenderer.h" +#include "Eve/Volume/IEveVolume.h" +#include "Utilities/BoundingSphere.h" + +#ifdef BLUE_USE_LOCAL_ITr2DebugRenderer2 +// This is only needed for py2 as the file now belongs in blue. +// Unfortunatly the blue py2 branch cannot be updated at present due to security vulnerability work. +// The file version in the older blue versions had diverged from this one is incompatible. +#include "Include/ITr2DebugRenderer2.h" +#else +#include +#endif + +#include + +BLUE_DECLARE_INTERFACE( IEveVolume ); +BLUE_DECLARE_IVECTOR( IEveVolume ); +BLUE_DECLARE( EveTriggerVolume ); + +/** + * @class EveTriggerVolume + * @brief A standalone spatial trigger that tracks whether a tracked position is inside its volumes. + * + * The trigger region is defined by a list of IEveVolume shapes (box/sphere/ellipsoid), placed relative + * to the object's translation/rotation and editable in Graphite like any other top-level scene object. + * The tracked position (typically the player ship's destiny ball) is attached from Python via the + * trackedPositionCurve slot. The isInside attribute reflects whether it is past the + * enterThreshold intensity boundary. + */ +BLUE_CLASS( EveTriggerVolume ) : + public IWorldPosition, + public IEveSpaceObject2, + public IInitialize +{ +public: + EXPOSE_TO_BLUE(); + + EveTriggerVolume( IRoot* lockobj = NULL ); + ~EveTriggerVolume(); + + /** + * @brief Recomputes the broad-phase bounding sphere from the volume list. + */ + void RebuildBoundingSphere(); + + ///////////////////////////////////////////////////////////////////////////////////// + // IEveSpaceObject2 + void UpdateSyncronous( const EveUpdateContext& updateContext ); + void UpdateAsyncronous( const EveUpdateContext& updateContext ); + void UpdateVisibility( const EveUpdateContext& updateContext, const Matrix& parentTransform ); + void GetRenderables( std::vector & renderables, Tr2ImpostorManager * impostors ); + bool GetBoundingSphere( Vector4 & sphere, BoundingSphereQuery query = EVE_BOUNDS_NORMAL ) const; + void UpdateModelCenterWorldPosition( Vector3 & position, Be::Time t ); + void GetModelCenterWorldPosition( Vector3 & position ) const; + bool GetLocalBoundingBox( Vector3 & min, Vector3 & max ); + void GetLocalToWorldTransform( Matrix & transform ) const; + + ///////////////////////////////////////////////////////////////////////////////////// + // IWorldPosition + virtual Vector3 GetWorldPosition(); + virtual Quaternion GetWorldRotation(); + + ///////////////////////////////////////////////////////////////////////////////////// + // IInitialize + bool Initialize() override; + + Quaternion m_rotation; ///< Local rotation of the trigger volume, editable in Graphite. + Vector3 m_translation; ///< Local translation of the trigger volume, editable in Graphite. + +private: + /** + * @brief Rebuilds the world transform from the translation/rotation attributes. + */ + void UpdateWorldTransform(); + + /** + * @brief Evaluates whether the tracked position is inside the volumes. + */ + void UpdateTriggerState( const EveUpdateContext& updateContext ); + + std::string m_name; ///< The name identifier, so one handler can serve many trigger volumes. + PIEveVolumeVector m_volumes; ///< The volumes defining the trigger region. + + CcpMath::Sphere m_boundingSphere; ///< Broad-phase bounding sphere around all volumes, in local space. + + // TODO: derive the tracked position from the EveSpace scene instead of attaching it from Python. + ITriVectorFunctionPtr m_trackedPosition; ///< Vector function slot for attaching a destiny ball as the tracked position. + + Matrix m_worldTransform; ///< World transform built from the translation/rotation attributes. + + float m_enterThreshold; ///< Volume intensity at which the tracked position counts as inside (0..1). + bool m_isInside; ///< Current inside/outside state of the tracked position. + float m_currentIntensity; ///< Most recent evaluated intensity, for debugging. + bool m_display; ///< Not really used for trigger volumes, but here for consistency with the EveSpaceObject interface. +}; + +/** + * @brief Macro that creates container typedefs for EveTriggerVolume. + */ +TYPEDEF_BLUECLASS( EveTriggerVolume ); + +#endif diff --git a/trinity/Eve/EveTriggerVolume_Blue.cpp b/trinity/Eve/EveTriggerVolume_Blue.cpp new file mode 100644 index 000000000..08f5c7dcf --- /dev/null +++ b/trinity/Eve/EveTriggerVolume_Blue.cpp @@ -0,0 +1,70 @@ +// Copyright © 2026 CCP ehf. + +#include "StdAfx.h" +#include "EveTriggerVolume.h" + +BLUE_DEFINE( EveTriggerVolume ); + +const Be::ClassInfo* EveTriggerVolume::ExposeToBlue() +{ + EXPOSURE_BEGIN( EveTriggerVolume, "A standalone spatial trigger that fires a Python callback when a tracked position enters or exits its volumes" ) + MAP_INTERFACE( IEveSpaceObject2 ) + MAP_INTERFACE( IInitialize ) + MAP_INTERFACE( IWorldPosition ) + + MAP_ATTRIBUTE( + "name", + m_name, + "Name identifier, so one handler can serve many trigger volumes", + Be::READWRITE | Be::PERSIST ) + + MAP_ATTRIBUTE( + "translation", + m_translation, + "Local translation of the trigger volume", + Be::READWRITE | Be::PERSIST ) + + MAP_ATTRIBUTE( + "rotation", + m_rotation, + "Local rotation of the trigger volume", + Be::READWRITE | Be::PERSIST ) + + MAP_ATTRIBUTE( + "volumes", + m_volumes, + "The volumes defining the trigger region", + Be::READ | Be::PERSIST ) + + MAP_ATTRIBUTE( + "enterThreshold", + m_enterThreshold, + "Volume intensity (0..1) at which the tracked position counts as inside", + Be::READWRITE | Be::PERSIST ) + + MAP_ATTRIBUTE( + "trackedPositionCurve", + m_trackedPosition, + "Vector function slot for attaching a destiny ball as the tracked position", + Be::READWRITE ) + + MAP_ATTRIBUTE( + "isInside", + m_isInside, + "Whether the tracked position is currently inside the trigger region", + Be::READ ) + + MAP_ATTRIBUTE( + "intensity", + m_currentIntensity, + "Most recent evaluated volume intensity of the tracked position", + Be::READ ) + + MAP_ATTRIBUTE( + "display", + m_display, + "Not really used for trigger volumes, but here for consistency with the EveSpaceObject interface", + Be::READWRITE ) + + EXPOSURE_END() +} From 1c8b356ff4496827ddc2ca397af6209eb58a7e1f Mon Sep 17 00:00:00 2001 From: phevosccp Date: Thu, 20 Aug 2026 10:08:39 +0000 Subject: [PATCH 04/14] Fire a Python callback on trigger enter/exit transitions SetCallback stores a Python callable that is invoked as callback( name, entered ) whenever the tracked position crosses the threshold. Transitions are detected during update, so the call is deferred to the post-update point on the main thread; the object is locked while the callback is queued and unlocked once it has run, so it cannot be destroyed in between. --- trinity/Eve/EveTriggerVolume.cpp | 95 +++++++++++++++++++++++++++ trinity/Eve/EveTriggerVolume.h | 42 ++++++++++-- trinity/Eve/EveTriggerVolume_Blue.cpp | 12 +++- 3 files changed, 143 insertions(+), 6 deletions(-) diff --git a/trinity/Eve/EveTriggerVolume.cpp b/trinity/Eve/EveTriggerVolume.cpp index d8684c7e3..ad4ad4678 100644 --- a/trinity/Eve/EveTriggerVolume.cpp +++ b/trinity/Eve/EveTriggerVolume.cpp @@ -5,6 +5,31 @@ #include "TriDevice.h" #include "TriUtil.h" +#if BLUE_WITH_PYTHON +namespace +{ +void InvokeTriggerCallback( void* context, bool entered ) +{ + EveTriggerVolume* triggerVolume = reinterpret_cast( context ); + + triggerVolume->InvokeCallback( entered ); + + // A reference was added when the callback was queued - release it here. + triggerVolume->GetRawRoot()->Unlock(); +} + +void TriggerEnterCallback( void* context ) +{ + InvokeTriggerCallback( context, true ); +} + +void TriggerExitCallback( void* context ) +{ + InvokeTriggerCallback( context, false ); +} +} +#endif + EveTriggerVolume::EveTriggerVolume( IRoot* lockobj ) : PARENTLOCK( m_volumes ), m_rotation( 0.0f, 0.0f, 0.0f, 1.0f ), @@ -14,11 +39,18 @@ EveTriggerVolume::EveTriggerVolume( IRoot* lockobj ) : m_isInside( false ), m_currentIntensity( 0.0f ), m_display( true ) +#if BLUE_WITH_PYTHON + , + m_callable( NULL ) +#endif { } EveTriggerVolume::~EveTriggerVolume() { +#if BLUE_WITH_PYTHON + Py_XDECREF( m_callable ); +#endif } void EveTriggerVolume::RebuildBoundingSphere() @@ -66,6 +98,68 @@ void EveTriggerVolume::RebuildBoundingSphere() } } +#if BLUE_WITH_PYTHON +void EveTriggerVolume::SetCallback( PyObject* callable ) +{ + Py_XDECREF( m_callable ); + + if( callable == NULL || callable == Py_None ) + { + m_callable = NULL; + } + else + { + m_callable = callable; + Py_XINCREF( m_callable ); + } +} + +void EveTriggerVolume::InvokeCallback( bool entered ) +{ + if( !m_callable ) + { + return; + } + + PyObject* args = Py_BuildValue( "(sO)", m_name.c_str(), entered ? Py_True : Py_False ); + if( !args ) + { + return; + } + + PyObject* result = PyObject_CallObject( m_callable, args ); + Py_DECREF( args ); + if( result ) + { + Py_DECREF( result ); + } + else + { + CCP_LOGWARN( "EveTriggerVolume: Callback raised an exception" ); + } +} +#endif + +void EveTriggerVolume::QueueCallback( bool entered ) +{ +#if BLUE_WITH_PYTHON + if( !m_callable ) + { + return; + } + + if( !PyCallable_Check( m_callable ) ) + { + CCP_LOGWARN( "EveTriggerVolume: Callback is not a callable object" ); + return; + } + + // Defer the actual Python call to a well defined point on the main thread. + GetRawRoot()->Lock(); + gTriDev->AddPostUpdateCallback( entered ? TriggerEnterCallback : TriggerExitCallback, reinterpret_cast( this ) ); +#endif +} + void EveTriggerVolume::UpdateWorldTransform() { m_worldTransform = RotationMatrix( m_rotation ) * TranslationMatrix( m_translation ); @@ -124,6 +218,7 @@ void EveTriggerVolume::UpdateTriggerState( const EveUpdateContext& updateContext if( inside != m_isInside ) { m_isInside = inside; + QueueCallback( inside ); } } diff --git a/trinity/Eve/EveTriggerVolume.h b/trinity/Eve/EveTriggerVolume.h index 2cf1f2042..2054d6ae8 100644 --- a/trinity/Eve/EveTriggerVolume.h +++ b/trinity/Eve/EveTriggerVolume.h @@ -28,13 +28,13 @@ BLUE_DECLARE( EveTriggerVolume ); /** * @class EveTriggerVolume - * @brief A standalone spatial trigger that tracks whether a tracked position is inside its volumes. + * @brief A standalone spatial trigger that fires a Python callback when a tracked position enters or exits its volumes. * * The trigger region is defined by a list of IEveVolume shapes (box/sphere/ellipsoid), placed relative * to the object's translation/rotation and editable in Graphite like any other top-level scene object. * The tracked position (typically the player ship's destiny ball) is attached from Python via the - * trackedPositionCurve slot. The isInside attribute reflects whether it is past the - * enterThreshold intensity boundary. + * trackedPositionCurve slot. When the tracked position crosses the enterThreshold intensity boundary, + * the registered callback is invoked as callback( name, entered ) at a safe point after update. */ BLUE_CLASS( EveTriggerVolume ) : public IWorldPosition, @@ -52,6 +52,24 @@ BLUE_CLASS( EveTriggerVolume ) : */ void RebuildBoundingSphere(); +#if BLUE_WITH_PYTHON + /** + * @brief Sets the Python callable invoked on enter/exit transitions. + * + * The callable is invoked as callback( name, entered ) where entered is True on entry + * and False on exit. Pass None to clear the callback. + * + * @param callable Python callable or None. + */ + void SetCallback( PyObject* callable ); + + /** + * @brief Invokes the stored callback. Called from the post-update callback on the main thread. + * @param entered True if the tracked position entered the volume, false if it exited. + */ + void InvokeCallback( bool entered ); +#endif + ///////////////////////////////////////////////////////////////////////////////////// // IEveSpaceObject2 void UpdateSyncronous( const EveUpdateContext& updateContext ); @@ -83,11 +101,17 @@ BLUE_CLASS( EveTriggerVolume ) : void UpdateWorldTransform(); /** - * @brief Evaluates whether the tracked position is inside the volumes. + * @brief Evaluates whether the tracked position is inside the volumes and fires the callback on transitions. */ void UpdateTriggerState( const EveUpdateContext& updateContext ); - std::string m_name; ///< The name identifier, so one handler can serve many trigger volumes. + /** + * @brief Queues the callback for invocation at the post-update point on the main thread. + * @param entered True if the tracked position entered the volume, false if it exited. + */ + void QueueCallback( bool entered ); + + std::string m_name; ///< The name identifier, passed to the callback so one handler can serve many volumes. PIEveVolumeVector m_volumes; ///< The volumes defining the trigger region. CcpMath::Sphere m_boundingSphere; ///< Broad-phase bounding sphere around all volumes, in local space. @@ -101,6 +125,14 @@ BLUE_CLASS( EveTriggerVolume ) : bool m_isInside; ///< Current inside/outside state of the tracked position. float m_currentIntensity; ///< Most recent evaluated intensity, for debugging. bool m_display; ///< Not really used for trigger volumes, but here for consistency with the EveSpaceObject interface. + +#if BLUE_WITH_PYTHON + + // TODO: replace the raw PyObject callback with BLUESCRIPTCALLBACK. + PyObject* m_callable; ///< Python callable invoked on enter/exit transitions. + + // TODO: bind controllers to the trigger volume for VFX. +#endif }; /** diff --git a/trinity/Eve/EveTriggerVolume_Blue.cpp b/trinity/Eve/EveTriggerVolume_Blue.cpp index 08f5c7dcf..8783f3648 100644 --- a/trinity/Eve/EveTriggerVolume_Blue.cpp +++ b/trinity/Eve/EveTriggerVolume_Blue.cpp @@ -15,7 +15,7 @@ const Be::ClassInfo* EveTriggerVolume::ExposeToBlue() MAP_ATTRIBUTE( "name", m_name, - "Name identifier, so one handler can serve many trigger volumes", + "Name identifier, passed to the callback so one handler can serve many trigger volumes", Be::READWRITE | Be::PERSIST ) MAP_ATTRIBUTE( @@ -66,5 +66,15 @@ const Be::ClassInfo* EveTriggerVolume::ExposeToBlue() "Not really used for trigger volumes, but here for consistency with the EveSpaceObject interface", Be::READWRITE ) +#if BLUE_WITH_PYTHON + MAP_METHOD_AND_WRAP( + "SetCallback", + SetCallback, + "Sets the Python callable invoked on enter/exit transitions.\n" + "The callable is invoked as callback( name, entered ) where entered is\n" + "True on entry and False on exit. Pass None to clear the callback.\n" + ":param callable: callback callable or None" ) +#endif + EXPOSURE_END() } From 064ac92aac1160d6ebbdd3836244599de807175f Mon Sep 17 00:00:00 2001 From: phevosccp Date: Thu, 20 Aug 2026 10:08:39 +0000 Subject: [PATCH 05/14] Subtract exclusion volumes from the trigger region The highest intensity among the exclusion volumes is subtracted from the trigger intensity and clamped at zero, so a region can have holes in it without modelling the remainder as separate shapes. --- trinity/Eve/EveTriggerVolume.cpp | 21 +++++++++++++++++++++ trinity/Eve/EveTriggerVolume.h | 1 + trinity/Eve/EveTriggerVolume_Blue.cpp | 6 ++++++ 3 files changed, 28 insertions(+) diff --git a/trinity/Eve/EveTriggerVolume.cpp b/trinity/Eve/EveTriggerVolume.cpp index ad4ad4678..2e2fa2967 100644 --- a/trinity/Eve/EveTriggerVolume.cpp +++ b/trinity/Eve/EveTriggerVolume.cpp @@ -32,6 +32,7 @@ void TriggerExitCallback( void* context ) EveTriggerVolume::EveTriggerVolume( IRoot* lockobj ) : PARENTLOCK( m_volumes ), + PARENTLOCK( m_exclusionVolumes ), m_rotation( 0.0f, 0.0f, 0.0f, 1.0f ), m_translation( 0.0f, 0.0f, 0.0f ), m_worldTransform( IdentityMatrix() ), @@ -210,6 +211,26 @@ void EveTriggerVolume::UpdateTriggerState( const EveUpdateContext& updateContext break; } } + + if( m_currentIntensity != 0.0f ) + { + // check if the tracked position is within an exclusion volume + float negativeIntensity = 0.0f; + for( const auto& volume : m_exclusionVolumes ) + { + if( !volume->IsEnabled() ) + { + continue; + } + negativeIntensity = std::max( negativeIntensity, volume->GetIntensity( positionInObjectSpace ) ); + if( negativeIntensity == 1.0f ) + { + // early exit + break; + } + } + m_currentIntensity = std::max( 0.0f, m_currentIntensity - negativeIntensity ); + } } inside = m_currentIntensity >= m_enterThreshold; diff --git a/trinity/Eve/EveTriggerVolume.h b/trinity/Eve/EveTriggerVolume.h index 2054d6ae8..40010f878 100644 --- a/trinity/Eve/EveTriggerVolume.h +++ b/trinity/Eve/EveTriggerVolume.h @@ -113,6 +113,7 @@ BLUE_CLASS( EveTriggerVolume ) : std::string m_name; ///< The name identifier, passed to the callback so one handler can serve many volumes. PIEveVolumeVector m_volumes; ///< The volumes defining the trigger region. + PIEveVolumeVector m_exclusionVolumes; ///< Volumes subtracted from the trigger region. CcpMath::Sphere m_boundingSphere; ///< Broad-phase bounding sphere around all volumes, in local space. diff --git a/trinity/Eve/EveTriggerVolume_Blue.cpp b/trinity/Eve/EveTriggerVolume_Blue.cpp index 8783f3648..ea9a117c9 100644 --- a/trinity/Eve/EveTriggerVolume_Blue.cpp +++ b/trinity/Eve/EveTriggerVolume_Blue.cpp @@ -36,6 +36,12 @@ const Be::ClassInfo* EveTriggerVolume::ExposeToBlue() "The volumes defining the trigger region", Be::READ | Be::PERSIST ) + MAP_ATTRIBUTE( + "exclusionVolumes", + m_exclusionVolumes, + "Volumes subtracted from the trigger region", + Be::READ | Be::PERSIST ) + MAP_ATTRIBUTE( "enterThreshold", m_enterThreshold, From e29e84d9728f3255ac1d1afe149644da8cd747f8 Mon Sep 17 00:00:00 2001 From: phevosccp Date: Thu, 20 Aug 2026 10:08:40 +0000 Subject: [PATCH 06/14] Add debug rendering and forceTriggered for Graphite Draws the trigger volumes - green while the tracked position is inside, white otherwise - the exclusion volumes in red, and the broad-phase bounding sphere, each under its own debug option. forceTriggered pins the trigger into the entered state so a setup can be exercised in Graphite with no ball attached. --- trinity/Eve/EveTriggerVolume.cpp | 49 ++++++++++++++++++++++++++- trinity/Eve/EveTriggerVolume.h | 11 +++++- trinity/Eve/EveTriggerVolume_Blue.cpp | 7 ++++ 3 files changed, 65 insertions(+), 2 deletions(-) diff --git a/trinity/Eve/EveTriggerVolume.cpp b/trinity/Eve/EveTriggerVolume.cpp index 2e2fa2967..78d5c79bb 100644 --- a/trinity/Eve/EveTriggerVolume.cpp +++ b/trinity/Eve/EveTriggerVolume.cpp @@ -37,6 +37,7 @@ EveTriggerVolume::EveTriggerVolume( IRoot* lockobj ) : m_translation( 0.0f, 0.0f, 0.0f ), m_worldTransform( IdentityMatrix() ), m_enterThreshold( 0.5f ), + m_forceTriggered( false ), m_isInside( false ), m_currentIntensity( 0.0f ), m_display( true ) @@ -186,7 +187,12 @@ void EveTriggerVolume::UpdateTriggerState( const EveUpdateContext& updateContext m_currentIntensity = 0.0f; bool inside = false; - if( m_trackedPosition && m_volumes.size() > 0 ) + if( m_forceTriggered ) + { + m_currentIntensity = 1.0f; + inside = true; + } + else if( m_trackedPosition && m_volumes.size() > 0 ) { Vector3 trackedPosition; m_trackedPosition->Update( &trackedPosition, updateContext.GetTime() ); @@ -307,3 +313,44 @@ bool EveTriggerVolume::Initialize() RebuildBoundingSphere(); return true; } + +///////////////////////////////////////////////////////////////////////////////////// +// ITr2DebugRenderable +void EveTriggerVolume::GetDebugOptions( Tr2DebugRendererOptions& options ) +{ + options.insert( "Trigger Volumes" ); + options.insert( "Trigger Exclusion Volumes" ); + options.insert( "Trigger Bounding Sphere" ); +} + +void EveTriggerVolume::RenderDebugInfo( ITr2DebugRenderer2& renderer ) +{ + if( renderer.HasOption( GetRawRoot(), "Trigger Volumes" ) ) + { + // green when the tracked position is inside, white otherwise + Color color = m_isInside ? 0xFF33FF33 : 0xFFFFFFFF; + for( auto volume = m_volumes.begin(); volume != m_volumes.end(); ++volume ) + { + if( ( *volume )->IsEnabled() ) + { + ( *volume )->RenderDebugInfo( renderer, m_worldTransform, color ); + } + } + } + + if( renderer.HasOption( GetRawRoot(), "Trigger Exclusion Volumes" ) ) + { + for( auto volume = m_exclusionVolumes.begin(); volume != m_exclusionVolumes.end(); ++volume ) + { + if( ( *volume )->IsEnabled() ) + { + ( *volume )->RenderDebugInfo( renderer, m_worldTransform, 0xFFFF3333 ); + } + } + } + + if( renderer.HasOption( GetRawRoot(), "Trigger Bounding Sphere" ) ) + { + renderer.DrawSphere( this, TranslationMatrix( m_boundingSphere.center ) * m_worldTransform, m_boundingSphere.radius, 10, Tr2DebugRenderer::Wireframe, 0xff333333 ); + } +} diff --git a/trinity/Eve/EveTriggerVolume.h b/trinity/Eve/EveTriggerVolume.h index 40010f878..efe424dd5 100644 --- a/trinity/Eve/EveTriggerVolume.h +++ b/trinity/Eve/EveTriggerVolume.h @@ -35,11 +35,14 @@ BLUE_DECLARE( EveTriggerVolume ); * The tracked position (typically the player ship's destiny ball) is attached from Python via the * trackedPositionCurve slot. When the tracked position crosses the enterThreshold intensity boundary, * the registered callback is invoked as callback( name, entered ) at a safe point after update. + * + * For testing in Graphite without an attached ball, set the forceTriggered attribute to simulate entry/exit. */ BLUE_CLASS( EveTriggerVolume ) : public IWorldPosition, public IEveSpaceObject2, - public IInitialize + public IInitialize, + public ITr2DebugRenderable { public: EXPOSE_TO_BLUE(); @@ -91,6 +94,11 @@ BLUE_CLASS( EveTriggerVolume ) : // IInitialize bool Initialize() override; + ///////////////////////////////////////////////////////////////////////////////////// + // ITr2DebugRenderable + void GetDebugOptions( Tr2DebugRendererOptions & options ) override; + void RenderDebugInfo( ITr2DebugRenderer2 & renderer ) override; + Quaternion m_rotation; ///< Local rotation of the trigger volume, editable in Graphite. Vector3 m_translation; ///< Local translation of the trigger volume, editable in Graphite. @@ -123,6 +131,7 @@ BLUE_CLASS( EveTriggerVolume ) : Matrix m_worldTransform; ///< World transform built from the translation/rotation attributes. float m_enterThreshold; ///< Volume intensity at which the tracked position counts as inside (0..1). + bool m_forceTriggered; ///< Debug: force the trigger into the entered state, e.g. for testing in Graphite. bool m_isInside; ///< Current inside/outside state of the tracked position. float m_currentIntensity; ///< Most recent evaluated intensity, for debugging. bool m_display; ///< Not really used for trigger volumes, but here for consistency with the EveSpaceObject interface. diff --git a/trinity/Eve/EveTriggerVolume_Blue.cpp b/trinity/Eve/EveTriggerVolume_Blue.cpp index ea9a117c9..24f53f8cb 100644 --- a/trinity/Eve/EveTriggerVolume_Blue.cpp +++ b/trinity/Eve/EveTriggerVolume_Blue.cpp @@ -11,6 +11,7 @@ const Be::ClassInfo* EveTriggerVolume::ExposeToBlue() MAP_INTERFACE( IEveSpaceObject2 ) MAP_INTERFACE( IInitialize ) MAP_INTERFACE( IWorldPosition ) + MAP_INTERFACE( ITr2DebugRenderable ) MAP_ATTRIBUTE( "name", @@ -54,6 +55,12 @@ const Be::ClassInfo* EveTriggerVolume::ExposeToBlue() "Vector function slot for attaching a destiny ball as the tracked position", Be::READWRITE ) + MAP_ATTRIBUTE( + "forceTriggered", + m_forceTriggered, + "Debug: force the trigger into the entered state, e.g. for testing in Graphite", + Be::READWRITE ) + MAP_ATTRIBUTE( "isInside", m_isInside, From 2c5450cf39d3195913964caaa9da9c44dc936b13 Mon Sep 17 00:00:00 2001 From: phevosccp Date: Thu, 20 Aug 2026 10:08:40 +0000 Subject: [PATCH 07/14] Support dungeon placement: external parameters and ball curves External parameters expose per-placement values for dungeon asset manipulations, and the translation/rotation curve slots let the client attach the object's own destiny ball instead of driving the object from the static translation and rotation attributes. The callback name now prefers the first enabled volume's name: external parameters in a .red file cannot reference the root object, so per-placement names are bound to a volume, and the client overwrites the root name attribute with the destiny ball ID when adding the object to the scene. --- trinity/Eve/EveTriggerVolume.cpp | 53 ++++++++++++++++++++++++--- trinity/Eve/EveTriggerVolume.h | 23 ++++++++++-- trinity/Eve/EveTriggerVolume_Blue.cpp | 18 +++++++++ 3 files changed, 85 insertions(+), 9 deletions(-) diff --git a/trinity/Eve/EveTriggerVolume.cpp b/trinity/Eve/EveTriggerVolume.cpp index 78d5c79bb..dbb0dffce 100644 --- a/trinity/Eve/EveTriggerVolume.cpp +++ b/trinity/Eve/EveTriggerVolume.cpp @@ -33,6 +33,7 @@ void TriggerExitCallback( void* context ) EveTriggerVolume::EveTriggerVolume( IRoot* lockobj ) : PARENTLOCK( m_volumes ), PARENTLOCK( m_exclusionVolumes ), + PARENTLOCK( m_externalParameters ), m_rotation( 0.0f, 0.0f, 0.0f, 1.0f ), m_translation( 0.0f, 0.0f, 0.0f ), m_worldTransform( IdentityMatrix() ), @@ -100,6 +101,25 @@ void EveTriggerVolume::RebuildBoundingSphere() } } +const char* EveTriggerVolume::GetEffectiveName() const +{ + // Prefer enabled volume names: per-placement names from dungeon asset manipulations are + // bound to the volumes, while the client overwrites the root name with the destiny ball ID. + for( auto volume = m_volumes.begin(); volume != m_volumes.end(); ++volume ) + { + if( !( *volume )->IsEnabled() ) + { + continue; + } + const char* volumeName = ( *volume )->GetName(); + if( volumeName && volumeName[0] != '\0' ) + { + return volumeName; + } + } + return m_name.c_str(); +} + #if BLUE_WITH_PYTHON void EveTriggerVolume::SetCallback( PyObject* callable ) { @@ -123,7 +143,7 @@ void EveTriggerVolume::InvokeCallback( bool entered ) return; } - PyObject* args = Py_BuildValue( "(sO)", m_name.c_str(), entered ? Py_True : Py_False ); + PyObject* args = Py_BuildValue( "(sO)", GetEffectiveName(), entered ? Py_True : Py_False ); if( !args ) { return; @@ -162,9 +182,30 @@ void EveTriggerVolume::QueueCallback( bool entered ) #endif } -void EveTriggerVolume::UpdateWorldTransform() +void EveTriggerVolume::UpdateWorldTransform( Be::Time time ) { - m_worldTransform = RotationMatrix( m_rotation ) * TranslationMatrix( m_translation ); + Quaternion rotation; + Vector3 translation; + + if( m_ballPosition ) + { + m_ballPosition->Update( &translation, time ); + } + else + { + translation = m_translation; + } + + if( m_ballRotation ) + { + m_ballRotation->Update( &rotation, time ); + } + else + { + rotation = m_rotation; + } + + m_worldTransform = RotationMatrix( rotation ) * TranslationMatrix( translation ); } ///////////////////////////////////////////////////////////////////////////////////// @@ -173,7 +214,7 @@ void EveTriggerVolume::UpdateSyncronous( const EveUpdateContext& updateContext ) { CCP_STATS_ZONE( __FUNCTION__ ); - UpdateWorldTransform(); + UpdateWorldTransform( updateContext.GetTime() ); RebuildBoundingSphere(); @@ -270,7 +311,7 @@ bool EveTriggerVolume::GetBoundingSphere( Vector4& sphere, BoundingSphereQuery q void EveTriggerVolume::UpdateModelCenterWorldPosition( Vector3& position, Be::Time t ) { - UpdateWorldTransform(); + UpdateWorldTransform( t ); GetModelCenterWorldPosition( position ); } @@ -309,7 +350,7 @@ Quaternion EveTriggerVolume::GetWorldRotation() // IInitialize bool EveTriggerVolume::Initialize() { - UpdateWorldTransform(); + UpdateWorldTransform( Be::Time( 0.0 ) ); RebuildBoundingSphere(); return true; } diff --git a/trinity/Eve/EveTriggerVolume.h b/trinity/Eve/EveTriggerVolume.h index efe424dd5..53517619a 100644 --- a/trinity/Eve/EveTriggerVolume.h +++ b/trinity/Eve/EveTriggerVolume.h @@ -24,6 +24,8 @@ BLUE_DECLARE_INTERFACE( IEveVolume ); BLUE_DECLARE_IVECTOR( IEveVolume ); +BLUE_DECLARE( Tr2ExternalParameter ); +BLUE_DECLARE_VECTOR( Tr2ExternalParameter ); BLUE_DECLARE( EveTriggerVolume ); /** @@ -104,9 +106,10 @@ BLUE_CLASS( EveTriggerVolume ) : private: /** - * @brief Rebuilds the world transform from the translation/rotation attributes. + * @brief Rebuilds the world transform from the position/rotation curves when attached + * (e.g. a destiny ball in the client), otherwise from the translation/rotation attributes. */ - void UpdateWorldTransform(); + void UpdateWorldTransform( Be::Time time ); /** * @brief Evaluates whether the tracked position is inside the volumes and fires the callback on transitions. @@ -119,16 +122,30 @@ BLUE_CLASS( EveTriggerVolume ) : */ void QueueCallback( bool entered ); + /** + * @brief Returns the name passed to the callback. + * + * Prefers the first non-empty volume name over the name attribute: external parameters + * in a .red file cannot reference the root object, so per-placement names (e.g. dungeon + * asset manipulations) are bound to the first volume, and the client overwrites the root + * name attribute with the destiny ball ID when adding the object to the scene. + */ + const char* GetEffectiveName() const; + std::string m_name; ///< The name identifier, passed to the callback so one handler can serve many volumes. PIEveVolumeVector m_volumes; ///< The volumes defining the trigger region. PIEveVolumeVector m_exclusionVolumes; ///< Volumes subtracted from the trigger region. + PTr2ExternalParameterVector m_externalParameters; ///< External parameters exposing per-placement values, e.g. for dungeon asset manipulations. CcpMath::Sphere m_boundingSphere; ///< Broad-phase bounding sphere around all volumes, in local space. // TODO: derive the tracked position from the EveSpace scene instead of attaching it from Python. ITriVectorFunctionPtr m_trackedPosition; ///< Vector function slot for attaching a destiny ball as the tracked position. - Matrix m_worldTransform; ///< World transform built from the translation/rotation attributes. + ITriVectorFunctionPtr m_ballPosition; ///< Position curve slot; the client attaches the object's own destiny ball here. + ITriQuaternionFunctionPtr m_ballRotation; ///< Rotation curve slot; the client attaches the object's own destiny ball here. + + Matrix m_worldTransform; ///< World transform built from the position/rotation curves or the translation/rotation attributes. float m_enterThreshold; ///< Volume intensity at which the tracked position counts as inside (0..1). bool m_forceTriggered; ///< Debug: force the trigger into the entered state, e.g. for testing in Graphite. diff --git a/trinity/Eve/EveTriggerVolume_Blue.cpp b/trinity/Eve/EveTriggerVolume_Blue.cpp index 24f53f8cb..500a55915 100644 --- a/trinity/Eve/EveTriggerVolume_Blue.cpp +++ b/trinity/Eve/EveTriggerVolume_Blue.cpp @@ -49,6 +49,24 @@ const Be::ClassInfo* EveTriggerVolume::ExposeToBlue() "Volume intensity (0..1) at which the tracked position counts as inside", Be::READWRITE | Be::PERSIST ) + MAP_ATTRIBUTE( + "externalParameters", + m_externalParameters, + "List of external parameters exposing per-placement values, e.g. for dungeon asset manipulations", + Be::READ | Be::PERSIST ) + + MAP_ATTRIBUTE( + "translationCurve", + m_ballPosition, + "Function for animated position updates, e.g. the object's own destiny ball in the client", + Be::READWRITE | Be::PERSIST ) + + MAP_ATTRIBUTE( + "rotationCurve", + m_ballRotation, + "Function for animated rotation updates, e.g. the object's own destiny ball in the client", + Be::READWRITE | Be::PERSIST ) + MAP_ATTRIBUTE( "trackedPositionCurve", m_trackedPosition, From 7d9718a0d3f142694f50cc6d05fb3ad1b7c1ab2d Mon Sep 17 00:00:00 2001 From: phevosccp Date: Fri, 21 Aug 2026 10:46:29 +0000 Subject: [PATCH 08/14] - use BlueScriptCallback instead of PyObject - some docs fixes --- trinity/Eve/EveTriggerVolume.cpp | 61 +++------------------------ trinity/Eve/EveTriggerVolume.h | 23 +++------- trinity/Eve/EveTriggerVolume_Blue.cpp | 6 +-- 3 files changed, 14 insertions(+), 76 deletions(-) diff --git a/trinity/Eve/EveTriggerVolume.cpp b/trinity/Eve/EveTriggerVolume.cpp index dbb0dffce..ee23b8d5f 100644 --- a/trinity/Eve/EveTriggerVolume.cpp +++ b/trinity/Eve/EveTriggerVolume.cpp @@ -5,7 +5,6 @@ #include "TriDevice.h" #include "TriUtil.h" -#if BLUE_WITH_PYTHON namespace { void InvokeTriggerCallback( void* context, bool entered ) @@ -28,7 +27,6 @@ void TriggerExitCallback( void* context ) InvokeTriggerCallback( context, false ); } } -#endif EveTriggerVolume::EveTriggerVolume( IRoot* lockobj ) : PARENTLOCK( m_volumes ), @@ -42,18 +40,11 @@ EveTriggerVolume::EveTriggerVolume( IRoot* lockobj ) : m_isInside( false ), m_currentIntensity( 0.0f ), m_display( true ) -#if BLUE_WITH_PYTHON - , - m_callable( NULL ) -#endif { } EveTriggerVolume::~EveTriggerVolume() { -#if BLUE_WITH_PYTHON - Py_XDECREF( m_callable ); -#endif } void EveTriggerVolume::RebuildBoundingSphere() @@ -120,66 +111,28 @@ const char* EveTriggerVolume::GetEffectiveName() const return m_name.c_str(); } -#if BLUE_WITH_PYTHON -void EveTriggerVolume::SetCallback( PyObject* callable ) +void EveTriggerVolume::SetCallback( const BlueScriptCallback& callback ) { - Py_XDECREF( m_callable ); - - if( callable == NULL || callable == Py_None ) - { - m_callable = NULL; - } - else - { - m_callable = callable; - Py_XINCREF( m_callable ); - } + m_callback = callback; } void EveTriggerVolume::InvokeCallback( bool entered ) { - if( !m_callable ) - { - return; - } - - PyObject* args = Py_BuildValue( "(sO)", GetEffectiveName(), entered ? Py_True : Py_False ); - if( !args ) - { - return; - } - - PyObject* result = PyObject_CallObject( m_callable, args ); - Py_DECREF( args ); - if( result ) - { - Py_DECREF( result ); - } - else - { - CCP_LOGWARN( "EveTriggerVolume: Callback raised an exception" ); - } + // The status object logs the traceback of an escaping exception as it goes out of scope. + m_callback.CallVoid( GetEffectiveName(), entered ).ReportException(); } -#endif void EveTriggerVolume::QueueCallback( bool entered ) { -#if BLUE_WITH_PYTHON - if( !m_callable ) - { - return; - } - - if( !PyCallable_Check( m_callable ) ) + if( !m_callback ) { - CCP_LOGWARN( "EveTriggerVolume: Callback is not a callable object" ); return; } - // Defer the actual Python call to a well defined point on the main thread. + // Defer the actual script call to a well defined point on the main thread: the handler + // runs game script that may add to or remove from the scene, including this object. GetRawRoot()->Lock(); gTriDev->AddPostUpdateCallback( entered ? TriggerEnterCallback : TriggerExitCallback, reinterpret_cast( this ) ); -#endif } void EveTriggerVolume::UpdateWorldTransform( Be::Time time ) diff --git a/trinity/Eve/EveTriggerVolume.h b/trinity/Eve/EveTriggerVolume.h index 53517619a..a0e8399c7 100644 --- a/trinity/Eve/EveTriggerVolume.h +++ b/trinity/Eve/EveTriggerVolume.h @@ -30,15 +30,8 @@ BLUE_DECLARE( EveTriggerVolume ); /** * @class EveTriggerVolume - * @brief A standalone spatial trigger that fires a Python callback when a tracked position enters or exits its volumes. + * @brief A volume that triggers a Python callback when a tracked position enters or exits it. * - * The trigger region is defined by a list of IEveVolume shapes (box/sphere/ellipsoid), placed relative - * to the object's translation/rotation and editable in Graphite like any other top-level scene object. - * The tracked position (typically the player ship's destiny ball) is attached from Python via the - * trackedPositionCurve slot. When the tracked position crosses the enterThreshold intensity boundary, - * the registered callback is invoked as callback( name, entered ) at a safe point after update. - * - * For testing in Graphite without an attached ball, set the forceTriggered attribute to simulate entry/exit. */ BLUE_CLASS( EveTriggerVolume ) : public IWorldPosition, @@ -57,23 +50,21 @@ BLUE_CLASS( EveTriggerVolume ) : */ void RebuildBoundingSphere(); -#if BLUE_WITH_PYTHON /** - * @brief Sets the Python callable invoked on enter/exit transitions. + * @brief Sets the callable invoked on enter/exit transitions. * * The callable is invoked as callback( name, entered ) where entered is True on entry * and False on exit. Pass None to clear the callback. * - * @param callable Python callable or None. + * @param callback Callable or None. */ - void SetCallback( PyObject* callable ); + void SetCallback( const BlueScriptCallback& callback ); /** * @brief Invokes the stored callback. Called from the post-update callback on the main thread. * @param entered True if the tracked position entered the volume, false if it exited. */ void InvokeCallback( bool entered ); -#endif ///////////////////////////////////////////////////////////////////////////////////// // IEveSpaceObject2 @@ -153,13 +144,9 @@ BLUE_CLASS( EveTriggerVolume ) : float m_currentIntensity; ///< Most recent evaluated intensity, for debugging. bool m_display; ///< Not really used for trigger volumes, but here for consistency with the EveSpaceObject interface. -#if BLUE_WITH_PYTHON - - // TODO: replace the raw PyObject callback with BLUESCRIPTCALLBACK. - PyObject* m_callable; ///< Python callable invoked on enter/exit transitions. + BlueScriptCallback m_callback; ///< Script callable invoked on enter/exit transitions. // TODO: bind controllers to the trigger volume for VFX. -#endif }; /** diff --git a/trinity/Eve/EveTriggerVolume_Blue.cpp b/trinity/Eve/EveTriggerVolume_Blue.cpp index 500a55915..c05a8867c 100644 --- a/trinity/Eve/EveTriggerVolume_Blue.cpp +++ b/trinity/Eve/EveTriggerVolume_Blue.cpp @@ -97,15 +97,13 @@ const Be::ClassInfo* EveTriggerVolume::ExposeToBlue() "Not really used for trigger volumes, but here for consistency with the EveSpaceObject interface", Be::READWRITE ) -#if BLUE_WITH_PYTHON MAP_METHOD_AND_WRAP( "SetCallback", SetCallback, - "Sets the Python callable invoked on enter/exit transitions.\n" + "Sets the callable invoked on enter/exit transitions.\n" "The callable is invoked as callback( name, entered ) where entered is\n" "True on entry and False on exit. Pass None to clear the callback.\n" - ":param callable: callback callable or None" ) -#endif + ":param callback: callable or None" ) EXPOSURE_END() } From feffadd0f0c7f95c9f1512a44802d4ee1ebd0798 Mon Sep 17 00:00:00 2001 From: phevosccp Date: Fri, 21 Aug 2026 11:16:44 +0000 Subject: [PATCH 09/14] code clean up and simplifications --- trinity/Eve/EveTriggerVolume.cpp | 128 +++++++++++++------------- trinity/Eve/EveTriggerVolume.h | 7 ++ trinity/Eve/EveTriggerVolume_Blue.cpp | 2 + 3 files changed, 72 insertions(+), 65 deletions(-) diff --git a/trinity/Eve/EveTriggerVolume.cpp b/trinity/Eve/EveTriggerVolume.cpp index ee23b8d5f..23d9a7159 100644 --- a/trinity/Eve/EveTriggerVolume.cpp +++ b/trinity/Eve/EveTriggerVolume.cpp @@ -12,8 +12,6 @@ void InvokeTriggerCallback( void* context, bool entered ) EveTriggerVolume* triggerVolume = reinterpret_cast( context ); triggerVolume->InvokeCallback( entered ); - - // A reference was added when the callback was queued - release it here. triggerVolume->GetRawRoot()->Unlock(); } @@ -51,39 +49,33 @@ void EveTriggerVolume::RebuildBoundingSphere() { CCP_STATS_ZONE( __FUNCTION__ ); - // Reset to the uninitialized sentinel (radius -1); a zero-radius reset reads as - // initialized, making the first merge below blend in a phantom sphere at the origin. - // Not CcpMath::Sphere::IncludeSphere, which fails to grow when the included sphere - // fully contains the current one. m_boundingSphere = CcpMath::Sphere(); - for( auto volume = m_volumes.begin(); volume != m_volumes.end(); ++volume ) + for( const auto& volume : m_volumes ) { - if( !( *volume )->IsEnabled() ) + if( !volume->IsEnabled() ) { continue; } - auto volumeSphere = ( *volume )->GetBoundingSphere(); + auto volumeSphere = volume->GetBoundingSphere(); if( !volumeSphere.IsInitialized() ) { continue; } - // if sphere is not initialized, just copy it - // also if the sphere we are including in this sphere, then also copy it + if( !m_boundingSphere.IsInitialized() || volumeSphere.IsSphereInside( m_boundingSphere ) ) { m_boundingSphere = volumeSphere; continue; } - // do not update if is inside + if( m_boundingSphere.IsSphereInside( volumeSphere ) ) { continue; } - // extend sphere Vector3 delta = volumeSphere.center - m_boundingSphere.center; float deltaLen = Length( delta ); @@ -94,15 +86,13 @@ void EveTriggerVolume::RebuildBoundingSphere() const char* EveTriggerVolume::GetEffectiveName() const { - // Prefer enabled volume names: per-placement names from dungeon asset manipulations are - // bound to the volumes, while the client overwrites the root name with the destiny ball ID. - for( auto volume = m_volumes.begin(); volume != m_volumes.end(); ++volume ) + for( const auto& volume : m_volumes ) { - if( !( *volume )->IsEnabled() ) + if( !volume->IsEnabled() ) { continue; } - const char* volumeName = ( *volume )->GetName(); + const char* volumeName = volume->GetName(); if( volumeName && volumeName[0] != '\0' ) { return volumeName; @@ -118,8 +108,13 @@ void EveTriggerVolume::SetCallback( const BlueScriptCallback& callback ) void EveTriggerVolume::InvokeCallback( bool entered ) { - // The status object logs the traceback of an escaping exception as it goes out of scope. - m_callback.CallVoid( GetEffectiveName(), entered ).ReportException(); + BlueScriptCallback callback = m_callback; + if( !callback ) + { + return; + } + + callback.CallVoid( GetEffectiveName(), entered ).ReportException(); } void EveTriggerVolume::QueueCallback( bool entered ) @@ -128,11 +123,17 @@ void EveTriggerVolume::QueueCallback( bool entered ) { return; } - - // Defer the actual script call to a well defined point on the main thread: the handler - // runs game script that may add to or remove from the scene, including this object. + // Keeps the object alive until the queued callback runs. GetRawRoot()->Lock(); - gTriDev->AddPostUpdateCallback( entered ? TriggerEnterCallback : TriggerExitCallback, reinterpret_cast( this ) ); + + if( entered ) + { + gTriDev->AddPostUpdateCallback( TriggerEnterCallback, reinterpret_cast( this ) ); + } + else + { + gTriDev->AddPostUpdateCallback( TriggerExitCallback, reinterpret_cast( this ) ); + } } void EveTriggerVolume::UpdateWorldTransform( Be::Time time ) @@ -161,7 +162,6 @@ void EveTriggerVolume::UpdateWorldTransform( Be::Time time ) m_worldTransform = RotationMatrix( rotation ) * TranslationMatrix( translation ); } -///////////////////////////////////////////////////////////////////////////////////// // IEveSpaceObject2 void EveTriggerVolume::UpdateSyncronous( const EveUpdateContext& updateContext ) { @@ -171,11 +171,28 @@ void EveTriggerVolume::UpdateSyncronous( const EveUpdateContext& updateContext ) RebuildBoundingSphere(); - // The tracked position function may thunk into Python, so it must be evaluated on the - // synchronous update path rather than in UpdateAsyncronous. UpdateTriggerState( updateContext ); } +float EveTriggerVolume::GetMaxIntensity( const PIEveVolumeVector& volumes, const Vector3& position ) +{ + float intensity = 0.0f; + for( const auto& volume : volumes ) + { + if( !volume->IsEnabled() ) + { + continue; + } + intensity = std::max( intensity, volume->GetIntensity( position ) ); + if( intensity == 1.0f ) + { + // early exit + break; + } + } + return intensity; +} + void EveTriggerVolume::UpdateTriggerState( const EveUpdateContext& updateContext ) { m_currentIntensity = 0.0f; @@ -186,7 +203,7 @@ void EveTriggerVolume::UpdateTriggerState( const EveUpdateContext& updateContext m_currentIntensity = 1.0f; inside = true; } - else if( m_trackedPosition && m_volumes.size() > 0 ) + else if( m_trackedPosition && !m_volumes.empty() ) { Vector3 trackedPosition; m_trackedPosition->Update( &trackedPosition, updateContext.GetTime() ); @@ -197,38 +214,12 @@ void EveTriggerVolume::UpdateTriggerState( const EveUpdateContext& updateContext // check first if the tracked position is within the bounding sphere if( m_boundingSphere.IsPointInside( positionInObjectSpace ) ) { - // Now find the intensity within the volumes - for( const auto& volume : m_volumes ) - { - if( !volume->IsEnabled() ) - { - continue; - } - m_currentIntensity = std::max( m_currentIntensity, volume->GetIntensity( positionInObjectSpace ) ); - if( m_currentIntensity == 1.0f ) - { - // early exit - break; - } - } + m_currentIntensity = GetMaxIntensity( m_volumes, positionInObjectSpace ); if( m_currentIntensity != 0.0f ) { // check if the tracked position is within an exclusion volume - float negativeIntensity = 0.0f; - for( const auto& volume : m_exclusionVolumes ) - { - if( !volume->IsEnabled() ) - { - continue; - } - negativeIntensity = std::max( negativeIntensity, volume->GetIntensity( positionInObjectSpace ) ); - if( negativeIntensity == 1.0f ) - { - // early exit - break; - } - } + float negativeIntensity = GetMaxIntensity( m_exclusionVolumes, positionInObjectSpace ); m_currentIntensity = std::max( 0.0f, m_currentIntensity - negativeIntensity ); } } @@ -277,8 +268,10 @@ bool EveTriggerVolume::GetLocalBoundingBox( Vector3& min, Vector3& max ) { // Fall back to a unit box when no volumes are set up yet, so the object stays pickable in Graphite. float radius = std::max( m_boundingSphere.radius, 1.0f ); - min = m_boundingSphere.center - Vector3( radius, radius, radius ); - max = m_boundingSphere.center + Vector3( radius, radius, radius ); + Vector3 extent( radius, radius, radius ); + + min = m_boundingSphere.center - extent; + max = m_boundingSphere.center + extent; return true; } @@ -322,23 +315,28 @@ void EveTriggerVolume::RenderDebugInfo( ITr2DebugRenderer2& renderer ) if( renderer.HasOption( GetRawRoot(), "Trigger Volumes" ) ) { // green when the tracked position is inside, white otherwise - Color color = m_isInside ? 0xFF33FF33 : 0xFFFFFFFF; - for( auto volume = m_volumes.begin(); volume != m_volumes.end(); ++volume ) + Color color = 0xFFFFFFFF; + if( m_isInside ) + { + color = 0xFF33FF33; + } + + for( const auto& volume : m_volumes ) { - if( ( *volume )->IsEnabled() ) + if( volume->IsEnabled() ) { - ( *volume )->RenderDebugInfo( renderer, m_worldTransform, color ); + volume->RenderDebugInfo( renderer, m_worldTransform, color ); } } } if( renderer.HasOption( GetRawRoot(), "Trigger Exclusion Volumes" ) ) { - for( auto volume = m_exclusionVolumes.begin(); volume != m_exclusionVolumes.end(); ++volume ) + for( const auto& volume : m_exclusionVolumes ) { - if( ( *volume )->IsEnabled() ) + if( volume->IsEnabled() ) { - ( *volume )->RenderDebugInfo( renderer, m_worldTransform, 0xFFFF3333 ); + volume->RenderDebugInfo( renderer, m_worldTransform, 0xFFFF3333 ); } } } diff --git a/trinity/Eve/EveTriggerVolume.h b/trinity/Eve/EveTriggerVolume.h index a0e8399c7..cbd0badb8 100644 --- a/trinity/Eve/EveTriggerVolume.h +++ b/trinity/Eve/EveTriggerVolume.h @@ -102,6 +102,13 @@ BLUE_CLASS( EveTriggerVolume ) : */ void UpdateWorldTransform( Be::Time time ); + /** + * @brief Returns the highest intensity any enabled volume in the list gives the position. + * @param volumes The volumes to evaluate. + * @param position The position to evaluate, in object space. + */ + static float GetMaxIntensity( const PIEveVolumeVector& volumes, const Vector3& position ); + /** * @brief Evaluates whether the tracked position is inside the volumes and fires the callback on transitions. */ diff --git a/trinity/Eve/EveTriggerVolume_Blue.cpp b/trinity/Eve/EveTriggerVolume_Blue.cpp index c05a8867c..26c582c6a 100644 --- a/trinity/Eve/EveTriggerVolume_Blue.cpp +++ b/trinity/Eve/EveTriggerVolume_Blue.cpp @@ -97,6 +97,7 @@ const Be::ClassInfo* EveTriggerVolume::ExposeToBlue() "Not really used for trigger volumes, but here for consistency with the EveSpaceObject interface", Be::READWRITE ) +#if BLUE_WITH_PYTHON MAP_METHOD_AND_WRAP( "SetCallback", SetCallback, @@ -104,6 +105,7 @@ const Be::ClassInfo* EveTriggerVolume::ExposeToBlue() "The callable is invoked as callback( name, entered ) where entered is\n" "True on entry and False on exit. Pass None to clear the callback.\n" ":param callback: callable or None" ) +#endif EXPOSURE_END() } From df7dad7092fc1085dbf96c030e8e51b7fe3434e1 Mon Sep 17 00:00:00 2001 From: phevosccp Date: Fri, 21 Aug 2026 11:32:09 +0000 Subject: [PATCH 10/14] override methods --- trinity/Eve/EveTriggerVolume.cpp | 6 ------ trinity/Eve/EveTriggerVolume.h | 22 +++++++++++----------- 2 files changed, 11 insertions(+), 17 deletions(-) diff --git a/trinity/Eve/EveTriggerVolume.cpp b/trinity/Eve/EveTriggerVolume.cpp index 23d9a7159..32967194f 100644 --- a/trinity/Eve/EveTriggerVolume.cpp +++ b/trinity/Eve/EveTriggerVolume.cpp @@ -280,8 +280,6 @@ void EveTriggerVolume::GetLocalToWorldTransform( Matrix& transform ) const transform = m_worldTransform; } -///////////////////////////////////////////////////////////////////////////////////// -// IWorldPosition Vector3 EveTriggerVolume::GetWorldPosition() { return m_worldTransform.GetTranslation(); @@ -292,8 +290,6 @@ Quaternion EveTriggerVolume::GetWorldRotation() return Normalize( RotationQuaternion( m_worldTransform ) ); } -///////////////////////////////////////////////////////////////////////////////////// -// IInitialize bool EveTriggerVolume::Initialize() { UpdateWorldTransform( Be::Time( 0.0 ) ); @@ -301,8 +297,6 @@ bool EveTriggerVolume::Initialize() return true; } -///////////////////////////////////////////////////////////////////////////////////// -// ITr2DebugRenderable void EveTriggerVolume::GetDebugOptions( Tr2DebugRendererOptions& options ) { options.insert( "Trigger Volumes" ); diff --git a/trinity/Eve/EveTriggerVolume.h b/trinity/Eve/EveTriggerVolume.h index cbd0badb8..9eeab8307 100644 --- a/trinity/Eve/EveTriggerVolume.h +++ b/trinity/Eve/EveTriggerVolume.h @@ -68,20 +68,20 @@ BLUE_CLASS( EveTriggerVolume ) : ///////////////////////////////////////////////////////////////////////////////////// // IEveSpaceObject2 - void UpdateSyncronous( const EveUpdateContext& updateContext ); - void UpdateAsyncronous( const EveUpdateContext& updateContext ); - void UpdateVisibility( const EveUpdateContext& updateContext, const Matrix& parentTransform ); - void GetRenderables( std::vector & renderables, Tr2ImpostorManager * impostors ); - bool GetBoundingSphere( Vector4 & sphere, BoundingSphereQuery query = EVE_BOUNDS_NORMAL ) const; - void UpdateModelCenterWorldPosition( Vector3 & position, Be::Time t ); - void GetModelCenterWorldPosition( Vector3 & position ) const; - bool GetLocalBoundingBox( Vector3 & min, Vector3 & max ); - void GetLocalToWorldTransform( Matrix & transform ) const; + void UpdateSyncronous( const EveUpdateContext& updateContext ) override; + void UpdateAsyncronous( const EveUpdateContext& updateContext ) override; + void UpdateVisibility( const EveUpdateContext& updateContext, const Matrix& parentTransform ) override; + void GetRenderables( std::vector & renderables, Tr2ImpostorManager * impostors ) override; + bool GetBoundingSphere( Vector4 & sphere, BoundingSphereQuery query = EVE_BOUNDS_NORMAL ) const override; + void UpdateModelCenterWorldPosition( Vector3 & position, Be::Time t ) override; + void GetModelCenterWorldPosition( Vector3 & position ) const override; + bool GetLocalBoundingBox( Vector3 & min, Vector3 & max ) override; + void GetLocalToWorldTransform( Matrix & transform ) const override; ///////////////////////////////////////////////////////////////////////////////////// // IWorldPosition - virtual Vector3 GetWorldPosition(); - virtual Quaternion GetWorldRotation(); + Vector3 GetWorldPosition() override; + Quaternion GetWorldRotation() override; ///////////////////////////////////////////////////////////////////////////////////// // IInitialize From c6768cd7a41229aea0bcfc7a46806d34f842fe8e Mon Sep 17 00:00:00 2001 From: phevosccp Date: Fri, 21 Aug 2026 11:41:12 +0000 Subject: [PATCH 11/14] delete not used param --- trinity/Eve/EveTriggerVolume.cpp | 4 +--- trinity/Eve/EveTriggerVolume.h | 8 +------- trinity/Eve/EveTriggerVolume_Blue.cpp | 6 ------ 3 files changed, 2 insertions(+), 16 deletions(-) diff --git a/trinity/Eve/EveTriggerVolume.cpp b/trinity/Eve/EveTriggerVolume.cpp index 32967194f..32382e202 100644 --- a/trinity/Eve/EveTriggerVolume.cpp +++ b/trinity/Eve/EveTriggerVolume.cpp @@ -3,7 +3,6 @@ #include "StdAfx.h" #include "EveTriggerVolume.h" #include "TriDevice.h" -#include "TriUtil.h" namespace { @@ -36,8 +35,7 @@ EveTriggerVolume::EveTriggerVolume( IRoot* lockobj ) : m_enterThreshold( 0.5f ), m_forceTriggered( false ), m_isInside( false ), - m_currentIntensity( 0.0f ), - m_display( true ) + m_currentIntensity( 0.0f ) { } diff --git a/trinity/Eve/EveTriggerVolume.h b/trinity/Eve/EveTriggerVolume.h index 9eeab8307..80a2eb71c 100644 --- a/trinity/Eve/EveTriggerVolume.h +++ b/trinity/Eve/EveTriggerVolume.h @@ -9,7 +9,6 @@ #include "IEveSpaceObject2.h" #include "Tr2DebugRenderer.h" #include "Eve/Volume/IEveVolume.h" -#include "Utilities/BoundingSphere.h" #ifdef BLUE_USE_LOCAL_ITr2DebugRenderer2 // This is only needed for py2 as the file now belongs in blue. @@ -53,9 +52,6 @@ BLUE_CLASS( EveTriggerVolume ) : /** * @brief Sets the callable invoked on enter/exit transitions. * - * The callable is invoked as callback( name, entered ) where entered is True on entry - * and False on exit. Pass None to clear the callback. - * * @param callback Callable or None. */ void SetCallback( const BlueScriptCallback& callback ); @@ -98,7 +94,7 @@ BLUE_CLASS( EveTriggerVolume ) : private: /** * @brief Rebuilds the world transform from the position/rotation curves when attached - * (e.g. a destiny ball in the client), otherwise from the translation/rotation attributes. + * otherwise from the translation/rotation attributes. */ void UpdateWorldTransform( Be::Time time ); @@ -137,7 +133,6 @@ BLUE_CLASS( EveTriggerVolume ) : CcpMath::Sphere m_boundingSphere; ///< Broad-phase bounding sphere around all volumes, in local space. - // TODO: derive the tracked position from the EveSpace scene instead of attaching it from Python. ITriVectorFunctionPtr m_trackedPosition; ///< Vector function slot for attaching a destiny ball as the tracked position. ITriVectorFunctionPtr m_ballPosition; ///< Position curve slot; the client attaches the object's own destiny ball here. @@ -149,7 +144,6 @@ BLUE_CLASS( EveTriggerVolume ) : bool m_forceTriggered; ///< Debug: force the trigger into the entered state, e.g. for testing in Graphite. bool m_isInside; ///< Current inside/outside state of the tracked position. float m_currentIntensity; ///< Most recent evaluated intensity, for debugging. - bool m_display; ///< Not really used for trigger volumes, but here for consistency with the EveSpaceObject interface. BlueScriptCallback m_callback; ///< Script callable invoked on enter/exit transitions. diff --git a/trinity/Eve/EveTriggerVolume_Blue.cpp b/trinity/Eve/EveTriggerVolume_Blue.cpp index 26c582c6a..5eb809cab 100644 --- a/trinity/Eve/EveTriggerVolume_Blue.cpp +++ b/trinity/Eve/EveTriggerVolume_Blue.cpp @@ -91,12 +91,6 @@ const Be::ClassInfo* EveTriggerVolume::ExposeToBlue() "Most recent evaluated volume intensity of the tracked position", Be::READ ) - MAP_ATTRIBUTE( - "display", - m_display, - "Not really used for trigger volumes, but here for consistency with the EveSpaceObject interface", - Be::READWRITE ) - #if BLUE_WITH_PYTHON MAP_METHOD_AND_WRAP( "SetCallback", From 8bfa77ae7efe23a4e2094a43d0b38130005d87de Mon Sep 17 00:00:00 2001 From: phevosccp Date: Fri, 21 Aug 2026 13:51:44 +0000 Subject: [PATCH 12/14] - remove debug parameter - documentation fixes --- trinity/Eve/EveTriggerVolume.cpp | 20 +--------- trinity/Eve/EveTriggerVolume.h | 57 ++++++++++----------------- trinity/Eve/EveTriggerVolume_Blue.cpp | 12 ------ 3 files changed, 23 insertions(+), 66 deletions(-) diff --git a/trinity/Eve/EveTriggerVolume.cpp b/trinity/Eve/EveTriggerVolume.cpp index 32382e202..1483587f3 100644 --- a/trinity/Eve/EveTriggerVolume.cpp +++ b/trinity/Eve/EveTriggerVolume.cpp @@ -33,7 +33,6 @@ EveTriggerVolume::EveTriggerVolume( IRoot* lockobj ) : m_translation( 0.0f, 0.0f, 0.0f ), m_worldTransform( IdentityMatrix() ), m_enterThreshold( 0.5f ), - m_forceTriggered( false ), m_isInside( false ), m_currentIntensity( 0.0f ) { @@ -136,7 +135,6 @@ void EveTriggerVolume::QueueCallback( bool entered ) void EveTriggerVolume::UpdateWorldTransform( Be::Time time ) { - Quaternion rotation; Vector3 translation; if( m_ballPosition ) @@ -148,16 +146,7 @@ void EveTriggerVolume::UpdateWorldTransform( Be::Time time ) translation = m_translation; } - if( m_ballRotation ) - { - m_ballRotation->Update( &rotation, time ); - } - else - { - rotation = m_rotation; - } - - m_worldTransform = RotationMatrix( rotation ) * TranslationMatrix( translation ); + m_worldTransform = RotationMatrix( m_rotation ) * TranslationMatrix( translation ); } // IEveSpaceObject2 @@ -196,12 +185,7 @@ void EveTriggerVolume::UpdateTriggerState( const EveUpdateContext& updateContext m_currentIntensity = 0.0f; bool inside = false; - if( m_forceTriggered ) - { - m_currentIntensity = 1.0f; - inside = true; - } - else if( m_trackedPosition && !m_volumes.empty() ) + if( m_trackedPosition && !m_volumes.empty() ) { Vector3 trackedPosition; m_trackedPosition->Update( &trackedPosition, updateContext.GetTime() ); diff --git a/trinity/Eve/EveTriggerVolume.h b/trinity/Eve/EveTriggerVolume.h index 80a2eb71c..e4f392d9f 100644 --- a/trinity/Eve/EveTriggerVolume.h +++ b/trinity/Eve/EveTriggerVolume.h @@ -44,11 +44,6 @@ BLUE_CLASS( EveTriggerVolume ) : EveTriggerVolume( IRoot* lockobj = NULL ); ~EveTriggerVolume(); - /** - * @brief Recomputes the broad-phase bounding sphere from the volume list. - */ - void RebuildBoundingSphere(); - /** * @brief Sets the callable invoked on enter/exit transitions. * @@ -62,7 +57,6 @@ BLUE_CLASS( EveTriggerVolume ) : */ void InvokeCallback( bool entered ); - ///////////////////////////////////////////////////////////////////////////////////// // IEveSpaceObject2 void UpdateSyncronous( const EveUpdateContext& updateContext ) override; void UpdateAsyncronous( const EveUpdateContext& updateContext ) override; @@ -74,27 +68,26 @@ BLUE_CLASS( EveTriggerVolume ) : bool GetLocalBoundingBox( Vector3 & min, Vector3 & max ) override; void GetLocalToWorldTransform( Matrix & transform ) const override; - ///////////////////////////////////////////////////////////////////////////////////// // IWorldPosition Vector3 GetWorldPosition() override; Quaternion GetWorldRotation() override; - ///////////////////////////////////////////////////////////////////////////////////// // IInitialize bool Initialize() override; - ///////////////////////////////////////////////////////////////////////////////////// // ITr2DebugRenderable void GetDebugOptions( Tr2DebugRendererOptions & options ) override; void RenderDebugInfo( ITr2DebugRenderer2 & renderer ) override; - Quaternion m_rotation; ///< Local rotation of the trigger volume, editable in Graphite. - Vector3 m_translation; ///< Local translation of the trigger volume, editable in Graphite. - private: /** - * @brief Rebuilds the world transform from the position/rotation curves when attached - * otherwise from the translation/rotation attributes. + * @brief Recomputes the broad-phase bounding sphere from the volume list. + */ + void RebuildBoundingSphere(); + + /** + * @brief Rebuilds the world transform from the position curve when attached, + * otherwise from the translation attribute. */ void UpdateWorldTransform( Be::Time time ); @@ -119,40 +112,32 @@ BLUE_CLASS( EveTriggerVolume ) : /** * @brief Returns the name passed to the callback. * - * Prefers the first non-empty volume name over the name attribute: external parameters - * in a .red file cannot reference the root object, so per-placement names (e.g. dungeon - * asset manipulations) are bound to the first volume, and the client overwrites the root - * name attribute with the destiny ball ID when adding the object to the scene. */ const char* GetEffectiveName() const; - std::string m_name; ///< The name identifier, passed to the callback so one handler can serve many volumes. - PIEveVolumeVector m_volumes; ///< The volumes defining the trigger region. - PIEveVolumeVector m_exclusionVolumes; ///< Volumes subtracted from the trigger region. - PTr2ExternalParameterVector m_externalParameters; ///< External parameters exposing per-placement values, e.g. for dungeon asset manipulations. + Quaternion m_rotation; + Vector3 m_translation; - CcpMath::Sphere m_boundingSphere; ///< Broad-phase bounding sphere around all volumes, in local space. + std::string m_name; + PIEveVolumeVector m_volumes; + PIEveVolumeVector m_exclusionVolumes; + PTr2ExternalParameterVector m_externalParameters; - ITriVectorFunctionPtr m_trackedPosition; ///< Vector function slot for attaching a destiny ball as the tracked position. + CcpMath::Sphere m_boundingSphere; - ITriVectorFunctionPtr m_ballPosition; ///< Position curve slot; the client attaches the object's own destiny ball here. - ITriQuaternionFunctionPtr m_ballRotation; ///< Rotation curve slot; the client attaches the object's own destiny ball here. + ITriVectorFunctionPtr m_trackedPosition; - Matrix m_worldTransform; ///< World transform built from the position/rotation curves or the translation/rotation attributes. + ITriVectorFunctionPtr m_ballPosition; - float m_enterThreshold; ///< Volume intensity at which the tracked position counts as inside (0..1). - bool m_forceTriggered; ///< Debug: force the trigger into the entered state, e.g. for testing in Graphite. - bool m_isInside; ///< Current inside/outside state of the tracked position. - float m_currentIntensity; ///< Most recent evaluated intensity, for debugging. + Matrix m_worldTransform; - BlueScriptCallback m_callback; ///< Script callable invoked on enter/exit transitions. + float m_enterThreshold; + bool m_isInside; + float m_currentIntensity; - // TODO: bind controllers to the trigger volume for VFX. + BlueScriptCallback m_callback; }; -/** - * @brief Macro that creates container typedefs for EveTriggerVolume. - */ TYPEDEF_BLUECLASS( EveTriggerVolume ); #endif diff --git a/trinity/Eve/EveTriggerVolume_Blue.cpp b/trinity/Eve/EveTriggerVolume_Blue.cpp index 5eb809cab..564eadd84 100644 --- a/trinity/Eve/EveTriggerVolume_Blue.cpp +++ b/trinity/Eve/EveTriggerVolume_Blue.cpp @@ -61,24 +61,12 @@ const Be::ClassInfo* EveTriggerVolume::ExposeToBlue() "Function for animated position updates, e.g. the object's own destiny ball in the client", Be::READWRITE | Be::PERSIST ) - MAP_ATTRIBUTE( - "rotationCurve", - m_ballRotation, - "Function for animated rotation updates, e.g. the object's own destiny ball in the client", - Be::READWRITE | Be::PERSIST ) - MAP_ATTRIBUTE( "trackedPositionCurve", m_trackedPosition, "Vector function slot for attaching a destiny ball as the tracked position", Be::READWRITE ) - MAP_ATTRIBUTE( - "forceTriggered", - m_forceTriggered, - "Debug: force the trigger into the entered state, e.g. for testing in Graphite", - Be::READWRITE ) - MAP_ATTRIBUTE( "isInside", m_isInside, From 3611e351e66a0f6d9f70a2065b173e8d00536746 Mon Sep 17 00:00:00 2001 From: phevosccp Date: Fri, 21 Aug 2026 15:13:44 +0000 Subject: [PATCH 13/14] remove not used methods --- trinity/Eve/Volume/EveBoxVolume.cpp | 11 ----------- trinity/Eve/Volume/EveBoxVolume.h | 3 --- trinity/Eve/Volume/EveBoxVolume_Blue.cpp | 1 - trinity/Eve/Volume/EveEllipsoidVolume.cpp | 11 ----------- trinity/Eve/Volume/EveEllipsoidVolume.h | 3 --- trinity/Eve/Volume/EveEllipsoidVolume_Blue.cpp | 1 - trinity/Eve/Volume/EveSphereVolume.cpp | 11 ----------- trinity/Eve/Volume/EveSphereVolume.h | 3 --- trinity/Eve/Volume/EveSphereVolume_Blue.cpp | 1 - trinity/Eve/Volume/IEveVolume.h | 2 -- 10 files changed, 47 deletions(-) diff --git a/trinity/Eve/Volume/EveBoxVolume.cpp b/trinity/Eve/Volume/EveBoxVolume.cpp index 3e15f3c70..1bdf2a8ac 100644 --- a/trinity/Eve/Volume/EveBoxVolume.cpp +++ b/trinity/Eve/Volume/EveBoxVolume.cpp @@ -12,7 +12,6 @@ Vector3 const EveBoxVolume::MAX_AABB = Vector3( 0.5, 0.5, 0.5 ); Vector3 const EveBoxVolume::MIN_AABB = Vector3( -0.5, -0.5, -0.5 ); EveBoxVolume::EveBoxVolume( IRoot* lockobj ) : - m_enabled( true ), m_position( 0, 0, 0 ), m_scaling( 0, 0, 0 ), m_innerScaling( 0, 0, 0 ), @@ -39,16 +38,6 @@ bool EveBoxVolume::Initialize() return true; } -const char* EveBoxVolume::GetName() const -{ - return m_name.c_str(); -} - -bool EveBoxVolume::IsEnabled() const -{ - return m_enabled; -} - void EveBoxVolume::RenderDebugInfo( ITr2DebugRenderer2& renderer, const Matrix& parentTransform, const Color& baseColor ) { renderer.DrawBox( this, m_boxTransform * parentTransform, MIN_AABB, MAX_AABB, Tr2DebugRenderer::Wireframe, baseColor * 0.5f ); diff --git a/trinity/Eve/Volume/EveBoxVolume.h b/trinity/Eve/Volume/EveBoxVolume.h index 3312a5765..4afa5d7ea 100644 --- a/trinity/Eve/Volume/EveBoxVolume.h +++ b/trinity/Eve/Volume/EveBoxVolume.h @@ -25,8 +25,6 @@ BLUE_CLASS( EveBoxVolume ) : ///////////////////////////////////////////////////////////////////////////////////// // IEveVolume - const char* GetName() const override; - bool IsEnabled() const override; void RenderDebugInfo( ITr2DebugRenderer2 & renderer, const Matrix& parentTransform, const Color& baseColor ) override; float GetIntensity( Vector3 position ) override; const CcpMath::Sphere GetBoundingSphere() const override; @@ -41,7 +39,6 @@ BLUE_CLASS( EveBoxVolume ) : private: void Setup(); BlueSharedString m_name; - bool m_enabled; ///< Disabled volumes are ignored by their owner, e.g. to switch shapes via external parameters. Vector3 m_position; Vector3 m_scaling; diff --git a/trinity/Eve/Volume/EveBoxVolume_Blue.cpp b/trinity/Eve/Volume/EveBoxVolume_Blue.cpp index 0f8e62521..6afd4b048 100644 --- a/trinity/Eve/Volume/EveBoxVolume_Blue.cpp +++ b/trinity/Eve/Volume/EveBoxVolume_Blue.cpp @@ -15,7 +15,6 @@ const Be::ClassInfo* EveBoxVolume::ExposeToBlue() MAP_INTERFACE( IInitialize ) MAP_ATTRIBUTE( "name", m_name, "", Be::READWRITE | Be::PERSIST ) - MAP_ATTRIBUTE( "enabled", m_enabled, "Disabled volumes are ignored by their owner, e.g. to switch shapes via external parameters", Be::READWRITE | Be::PERSIST ) MAP_ATTRIBUTE( "position", m_position, "", Be::READWRITE | Be::PERSIST | Be::NOTIFY ) MAP_ATTRIBUTE( "scaling", m_scaling, "", Be::READWRITE | Be::PERSIST | Be::NOTIFY ) MAP_ATTRIBUTE( "innerScaling", m_innerScaling, "", Be::READWRITE | Be::PERSIST | Be::NOTIFY ) diff --git a/trinity/Eve/Volume/EveEllipsoidVolume.cpp b/trinity/Eve/Volume/EveEllipsoidVolume.cpp index 2a24186e1..b0d26afd9 100644 --- a/trinity/Eve/Volume/EveEllipsoidVolume.cpp +++ b/trinity/Eve/Volume/EveEllipsoidVolume.cpp @@ -8,7 +8,6 @@ #include "include/TriMath.h" EveEllipsoidVolume::EveEllipsoidVolume( IRoot* lockobj ) : - m_enabled( true ), m_position( 0, 0, 0 ), m_shape( 0, 0, 0 ), m_innerShape( 0, 0, 0 ), @@ -70,16 +69,6 @@ void EveEllipsoidVolume::RenderDebugInfo( ITr2DebugRenderer2& renderer, const Ma } } -const char* EveEllipsoidVolume::GetName() const -{ - return m_name.c_str(); -} - -bool EveEllipsoidVolume::IsEnabled() const -{ - return m_enabled; -} - const CcpMath::Sphere EveEllipsoidVolume::GetBoundingSphere() const { return m_boundingSphere; diff --git a/trinity/Eve/Volume/EveEllipsoidVolume.h b/trinity/Eve/Volume/EveEllipsoidVolume.h index 48997e800..855d1cc47 100644 --- a/trinity/Eve/Volume/EveEllipsoidVolume.h +++ b/trinity/Eve/Volume/EveEllipsoidVolume.h @@ -19,8 +19,6 @@ BLUE_CLASS( EveEllipsoidVolume ) : ///////////////////////////////////////////////////////////////////////////////////// // IEveVolume - const char* GetName() const override; - bool IsEnabled() const override; void RenderDebugInfo( ITr2DebugRenderer2 & renderer, const Matrix& parentTransform, const Color& baseColor ) override; float GetIntensity( Vector3 position ) override; uint32_t RegisterForChanges( const std::function& callBack ) override; @@ -40,7 +38,6 @@ BLUE_CLASS( EveEllipsoidVolume ) : void Setup(); BlueSharedString m_name; - bool m_enabled; ///< Disabled volumes are ignored by their owner, e.g. to switch shapes via external parameters. Vector3 m_position; Vector3 m_shape; diff --git a/trinity/Eve/Volume/EveEllipsoidVolume_Blue.cpp b/trinity/Eve/Volume/EveEllipsoidVolume_Blue.cpp index 8950418b0..ba5104e3e 100644 --- a/trinity/Eve/Volume/EveEllipsoidVolume_Blue.cpp +++ b/trinity/Eve/Volume/EveEllipsoidVolume_Blue.cpp @@ -13,7 +13,6 @@ const Be::ClassInfo* EveEllipsoidVolume::ExposeToBlue() MAP_ATTRIBUTE( "name", m_name, "", Be::READWRITE | Be::PERSIST ) - MAP_ATTRIBUTE( "enabled", m_enabled, "Disabled volumes are ignored by their owner, e.g. to switch shapes via external parameters", Be::READWRITE | Be::PERSIST ) MAP_ATTRIBUTE( "position", m_position, "The position of the volume", Be::READWRITE | Be::PERSIST | Be::NOTIFY ) MAP_ATTRIBUTE( "shape", m_shape, "The shape of the outer ellipsoid", Be::READWRITE | Be::PERSIST | Be::NOTIFY ) MAP_ATTRIBUTE( "innerShape", m_innerShape, "The shape of the inner ellipsoid", Be::READWRITE | Be::PERSIST | Be::NOTIFY ) diff --git a/trinity/Eve/Volume/EveSphereVolume.cpp b/trinity/Eve/Volume/EveSphereVolume.cpp index 5258efca2..e0f9c8e9d 100644 --- a/trinity/Eve/Volume/EveSphereVolume.cpp +++ b/trinity/Eve/Volume/EveSphereVolume.cpp @@ -7,7 +7,6 @@ #include "include/TriMath.h" EveSphereVolume::EveSphereVolume( IRoot* lockobj ) : - m_enabled( true ), m_innerSphere( Vector3( 0.0f, 0.0f, 0.0f ), 1.0f ), m_outerSphere( Vector3( 0.0f, 0.0f, 0.0f ), 1.0f ), m_nextCallbackID( 1 ) @@ -18,16 +17,6 @@ EveSphereVolume::~EveSphereVolume() { } -const char* EveSphereVolume::GetName() const -{ - return m_name.c_str(); -} - -bool EveSphereVolume::IsEnabled() const -{ - return m_enabled; -} - void EveSphereVolume::RenderDebugInfo( ITr2DebugRenderer2& renderer, const Matrix& parentTransform, const Color& baseColor ) { renderer.DrawSphere( this, TranslationMatrix( m_outerSphere.center ) * parentTransform, m_outerSphere.radius, 20, Tr2DebugRenderer::Wireframe, baseColor * 0.5f ); diff --git a/trinity/Eve/Volume/EveSphereVolume.h b/trinity/Eve/Volume/EveSphereVolume.h index f4e634b16..03e61dd31 100644 --- a/trinity/Eve/Volume/EveSphereVolume.h +++ b/trinity/Eve/Volume/EveSphereVolume.h @@ -18,8 +18,6 @@ BLUE_CLASS( EveSphereVolume ) : ///////////////////////////////////////////////////////////////////////////////////// // IEveVolume - const char* GetName() const override; - bool IsEnabled() const override; void RenderDebugInfo( ITr2DebugRenderer2 & renderer, const Matrix& parentTransform, const Color& baseColor ) override; float GetIntensity( Vector3 position ) override; uint32_t RegisterForChanges( const std::function& callBack ) override; @@ -33,7 +31,6 @@ BLUE_CLASS( EveSphereVolume ) : private: BlueSharedString m_name; - bool m_enabled; ///< Disabled volumes are ignored by their owner, e.g. to switch shapes via external parameters. std::map> m_onChangeCallbacks; uint32_t m_nextCallbackID; diff --git a/trinity/Eve/Volume/EveSphereVolume_Blue.cpp b/trinity/Eve/Volume/EveSphereVolume_Blue.cpp index b7dabb439..0d3bb8b7b 100644 --- a/trinity/Eve/Volume/EveSphereVolume_Blue.cpp +++ b/trinity/Eve/Volume/EveSphereVolume_Blue.cpp @@ -13,7 +13,6 @@ const Be::ClassInfo* EveSphereVolume::ExposeToBlue() MAP_ATTRIBUTE( "name", m_name, "", Be::READWRITE | Be::PERSIST ) - MAP_ATTRIBUTE( "enabled", m_enabled, "Disabled volumes are ignored by their owner, e.g. to switch shapes via external parameters", Be::READWRITE | Be::PERSIST ) MAP_ATTRIBUTE( "position", m_outerSphere.center, "", Be::READWRITE | Be::PERSIST | Be::NOTIFY ) MAP_ATTRIBUTE( "radius", m_outerSphere.radius, "", Be::READWRITE | Be::PERSIST | Be::NOTIFY ) MAP_ATTRIBUTE( "innerRadius", m_innerSphere.radius, "", Be::READWRITE | Be::PERSIST | Be::NOTIFY ) diff --git a/trinity/Eve/Volume/IEveVolume.h b/trinity/Eve/Volume/IEveVolume.h index 434c0e797..d46188bb7 100644 --- a/trinity/Eve/Volume/IEveVolume.h +++ b/trinity/Eve/Volume/IEveVolume.h @@ -10,8 +10,6 @@ BLUE_DECLARE_INTERFACE( IEveVolume ); BLUE_INTERFACE( IEveVolume ) : public IRoot { - virtual const char* GetName() const = 0; - virtual bool IsEnabled() const = 0; virtual float GetIntensity( Vector3 position ) = 0; virtual uint32_t RegisterForChanges( const std::function& callBack ) = 0; // returns the callbackID virtual void UnregisterForChanges( uint32_t callbackID ) = 0; From 041aeb937c17d824b87f93c1c6632fbd2faca5dc Mon Sep 17 00:00:00 2001 From: phevosccp Date: Fri, 21 Aug 2026 15:14:18 +0000 Subject: [PATCH 14/14] remove GetEffectiveName --- trinity/Eve/EveTriggerVolume.cpp | 38 +++----------------------------- trinity/Eve/EveTriggerVolume.h | 6 ----- 2 files changed, 3 insertions(+), 41 deletions(-) diff --git a/trinity/Eve/EveTriggerVolume.cpp b/trinity/Eve/EveTriggerVolume.cpp index 1483587f3..f14ac8405 100644 --- a/trinity/Eve/EveTriggerVolume.cpp +++ b/trinity/Eve/EveTriggerVolume.cpp @@ -50,11 +50,6 @@ void EveTriggerVolume::RebuildBoundingSphere() for( const auto& volume : m_volumes ) { - if( !volume->IsEnabled() ) - { - continue; - } - auto volumeSphere = volume->GetBoundingSphere(); if( !volumeSphere.IsInitialized() ) @@ -81,23 +76,6 @@ void EveTriggerVolume::RebuildBoundingSphere() } } -const char* EveTriggerVolume::GetEffectiveName() const -{ - for( const auto& volume : m_volumes ) - { - if( !volume->IsEnabled() ) - { - continue; - } - const char* volumeName = volume->GetName(); - if( volumeName && volumeName[0] != '\0' ) - { - return volumeName; - } - } - return m_name.c_str(); -} - void EveTriggerVolume::SetCallback( const BlueScriptCallback& callback ) { m_callback = callback; @@ -111,7 +89,7 @@ void EveTriggerVolume::InvokeCallback( bool entered ) return; } - callback.CallVoid( GetEffectiveName(), entered ).ReportException(); + callback.CallVoid( m_name.c_str(), entered ).ReportException(); } void EveTriggerVolume::QueueCallback( bool entered ) @@ -166,10 +144,6 @@ float EveTriggerVolume::GetMaxIntensity( const PIEveVolumeVector& volumes, const float intensity = 0.0f; for( const auto& volume : volumes ) { - if( !volume->IsEnabled() ) - { - continue; - } intensity = std::max( intensity, volume->GetIntensity( position ) ); if( intensity == 1.0f ) { @@ -299,10 +273,7 @@ void EveTriggerVolume::RenderDebugInfo( ITr2DebugRenderer2& renderer ) for( const auto& volume : m_volumes ) { - if( volume->IsEnabled() ) - { - volume->RenderDebugInfo( renderer, m_worldTransform, color ); - } + volume->RenderDebugInfo( renderer, m_worldTransform, color ); } } @@ -310,10 +281,7 @@ void EveTriggerVolume::RenderDebugInfo( ITr2DebugRenderer2& renderer ) { for( const auto& volume : m_exclusionVolumes ) { - if( volume->IsEnabled() ) - { - volume->RenderDebugInfo( renderer, m_worldTransform, 0xFFFF3333 ); - } + volume->RenderDebugInfo( renderer, m_worldTransform, 0xFFFF3333 ); } } diff --git a/trinity/Eve/EveTriggerVolume.h b/trinity/Eve/EveTriggerVolume.h index e4f392d9f..01f9a28c1 100644 --- a/trinity/Eve/EveTriggerVolume.h +++ b/trinity/Eve/EveTriggerVolume.h @@ -109,12 +109,6 @@ BLUE_CLASS( EveTriggerVolume ) : */ void QueueCallback( bool entered ); - /** - * @brief Returns the name passed to the callback. - * - */ - const char* GetEffectiveName() const; - Quaternion m_rotation; Vector3 m_translation;