1 // Copyright 2001-2019 Crytek GmbH / Crytek Group. All rights reserved.
4 #include "BaseEnv/Components/BaseEnv_EntityDetectionVolumeComponent.h"
6 #include <CryAnimation/ICryAnimation.h>
7 #include <CryRenderer/IRenderer.h>
8 #include <CryRenderer/IRenderAuxGeom.h>
10 #include "BaseEnv/BaseEnv_AutoRegistrar.h"
11 #include "BaseEnv/BaseEnv_BaseEnv.h"
12 #include "BaseEnv/Components/BaseEnv_EntityGeomComponent.h"
14 namespace SchematycBaseEnv
16 namespace EntityDetectionVolumeComponentUtils
18 struct SPreviewProperties
: public Schematyc2::IComponentPreviewProperties
26 // Schematyc2::IComponentPreviewProperties
28 virtual void Serialize(Serialization::IArchive
& archive
) override
30 archive(bShowGizmos
, "bShowGizmos", "Show Gizmos");
31 archive(gizmoLength
, "gizmoLength", "Gizmo Length");
32 archive(bShowVolumes
, "bShowVolumes", "Show Volumes");
35 // ~Schematyc2::IComponentPreviewProperties
43 const Schematyc2::SGUID
CEntityDetectionVolumeComponent::s_componentGUID
= "5F0322C0-2EB0-46C7-B3E3-56AB5F200E74";
44 const Schematyc2::SGUID
CEntityDetectionVolumeComponent::s_enterSignalGUID
= "FBCA030D-7122-41B0-A3AE-BD9EA9E8965E";
45 const Schematyc2::SGUID
CEntityDetectionVolumeComponent::s_leaveSignalGUID
= "8F2FFE6D-8E74-4B82-B045-051230027AA9";
47 CEntityDetectionVolumeComponent::SVolumeProperties::SVolumeProperties()
50 , shape(ESpatialVolumeShape::Box
)
53 void CEntityDetectionVolumeComponent::SVolumeProperties::Serialize(Serialization::IArchive
& archive
)
55 archive(shape
, "shape", "Shape");
60 case ESpatialVolumeShape::Box
:
62 archive(size
, "size", "Size");
66 case ESpatialVolumeShape::Sphere
:
68 archive(radius
, "radius", "Radius");
69 archive
.doc("Radius");
74 archive(tags
, "tags", "+Tags");
76 archive(monitorTags
, "monitorTags", "+Monitor Tags");
77 archive
.doc("Signals will be sent when volumes with one or more of these tags set enter/leave this volume.");
80 CEntityDetectionVolumeComponent::SProperties::SProperties()
84 void CEntityDetectionVolumeComponent::SProperties::Serialize(Serialization::IArchive
& archive
)
86 archive(TransformDecorator
<ETransformComponent::PositionAndRotation
>(transform
), "transform", "Transform");
87 archive
.doc("Transform");
88 archive(volume
, "volume", "Volume");
89 archive
.doc("Volumes");
92 Schematyc2::SEnvFunctionResult
CEntityDetectionVolumeComponent::SProperties::SetTransform(const Schematyc2::SEnvFunctionContext
& context
, const STransform
& _transform
)
94 transform
= _transform
;
95 return Schematyc2::SEnvFunctionResult();
98 CEntityDetectionVolumeComponent::SVolume::SVolume()
103 , shape(ESpatialVolumeShape::None
)
106 CEntityDetectionVolumeComponent::CEntityDetectionVolumeComponent()
107 : m_pProperties(nullptr)
111 bool CEntityDetectionVolumeComponent::Init(const Schematyc2::SComponentParams
& params
)
113 if(CEntityTransformComponentBase::Init(params
))
115 m_pProperties
= params
.properties
.ToPtr
<SProperties
>();
116 m_bEnabled
= m_pProperties
->bEnabled
;
118 const EntityId entityId
= CEntityComponentBase::GetEntityId();
119 const Matrix34 worldTM
= CEntityComponentBase::GetEntity().GetWorldTM();
121 CSpatialIndex
& spatialIndex
= CBaseEnv::GetInstance().GetSpatialIndex();
122 const SVolumeProperties
& volumeProperties
= m_pProperties
->volume
;
124 m_volume
.shape
= m_pProperties
->volume
.shape
;
125 m_volume
.rot
= Matrix33::CreateRotationXYZ(m_pProperties
->transform
.rot
);
126 m_volume
.size
= volumeProperties
.size
;
127 m_volume
.pos
= m_pProperties
->transform
.pos
;
128 m_volume
.radius
= volumeProperties
.radius
;
130 SSpatialVolumeParams volumeParams
;
131 volumeParams
.tags
= spatialIndex
.CreateTags(volumeProperties
.tags
);
132 volumeParams
.monitorTags
= spatialIndex
.CreateTags(volumeProperties
.monitorTags
);
133 volumeParams
.entityId
= entityId
;
135 switch(m_volume
.shape
)
137 case ESpatialVolumeShape::Box
:
139 volumeParams
.bounds
= CSpatialVolumeBounds::CreateOBB(worldTM
, m_volume
.pos
, m_volume
.size
, m_volume
.rot
);
142 case ESpatialVolumeShape::Sphere
:
144 volumeParams
.bounds
= CSpatialVolumeBounds::CreateSphere(worldTM
, m_volume
.pos
, m_volume
.radius
);
147 case ESpatialVolumeShape::Point
:
149 volumeParams
.bounds
= CSpatialVolumeBounds::CreatePoint(worldTM
, m_volume
.pos
);
154 m_volume
.volumeId
= spatialIndex
.CreateVolume(volumeParams
, SpatialIndexEventCallback::FromMemberFunction
<CEntityDetectionVolumeComponent
, &CEntityDetectionVolumeComponent::VolumeEventCallback
>(*this));
160 void CEntityDetectionVolumeComponent::Run(Schematyc2::ESimulationMode simulationMode
)
162 switch(simulationMode
)
164 case Schematyc2::ESimulationMode::Game
:
166 gEnv
->pSchematyc2
->GetUpdateScheduler().Connect(m_updateScope
, Schematyc2::UpdateCallback::FromMemberFunction
<CEntityDetectionVolumeComponent
, &CEntityDetectionVolumeComponent::Update
>(*this), Schematyc2::EUpdateFrequency::EveryFrame
, Schematyc2::EUpdatePriority::Default
, m_updateFilter
.Init(&CEntityComponentBase::GetEntity()));
167 g_entityEventSignal
.Select(CEntityComponentBase::GetEntityId()).Connect(EntityEventSignal::Delegate::FromMemberFunction
<CEntityDetectionVolumeComponent
, &CEntityDetectionVolumeComponent::OnEvent
>(*this), m_connectionScope
);
172 if(m_pProperties
->bEnabled
)
178 Schematyc2::IComponentPreviewPropertiesPtr
CEntityDetectionVolumeComponent::GetPreviewProperties() const
180 static Schematyc2::IComponentPreviewPropertiesPtr previewProperties
= std::make_shared
<EntityDetectionVolumeComponentUtils::SPreviewProperties
>();
181 return previewProperties
;
184 void CEntityDetectionVolumeComponent::Preview(const SRendParams
& params
, const SRenderingPassInfo
& passInfo
, const Schematyc2::IComponentPreviewProperties
& previewProperties
) const
186 const EntityDetectionVolumeComponentUtils::SPreviewProperties
& previewPropertiesImpl
= static_cast<const EntityDetectionVolumeComponentUtils::SPreviewProperties
&>(previewProperties
);
188 if(previewPropertiesImpl
.bShowGizmos
)
190 if(CEntityTransformComponentBase::SlotIsValid())
192 IRenderAuxGeom
& renderAuxGeom
= *gEnv
->pRenderer
->GetIRenderAuxGeom();
193 const Matrix34 worldTM
= CEntityTransformComponentBase::GetWorldTM();
194 const float lineThickness
= 4.0f
;
196 renderAuxGeom
.DrawLine(worldTM
.GetTranslation(), ColorB(255, 0, 0, 255), worldTM
.GetTranslation() + (worldTM
.GetColumn0().GetNormalized() * previewPropertiesImpl
.gizmoLength
), ColorB(255, 0, 0, 255), lineThickness
);
197 renderAuxGeom
.DrawLine(worldTM
.GetTranslation(), ColorB(0, 255, 0, 255), worldTM
.GetTranslation() + (worldTM
.GetColumn1().GetNormalized() * previewPropertiesImpl
.gizmoLength
), ColorB(0, 255, 0, 255), lineThickness
);
198 renderAuxGeom
.DrawLine(worldTM
.GetTranslation(), ColorB(0, 0, 255, 255), worldTM
.GetTranslation() + (worldTM
.GetColumn2().GetNormalized() * previewPropertiesImpl
.gizmoLength
), ColorB(0, 0, 255, 255), lineThickness
);
202 if(previewPropertiesImpl
.bShowVolumes
)
204 IRenderAuxGeom
& renderAuxGeom
= *gEnv
->pRenderer
->GetIRenderAuxGeom();
205 IEntity
& entity
= CEntityComponentBase::GetEntity();
206 const Matrix34 worldTM
= entity
.GetWorldTM();
208 switch(m_volume
.shape
)
210 case ESpatialVolumeShape::Box
:
212 const CSpatialVolumeBounds bounds
= CSpatialVolumeBounds::CreateOBB(worldTM
, m_volume
.pos
, m_volume
.size
, m_volume
.rot
);
213 renderAuxGeom
.DrawOBB(bounds
.AsBox(), Matrix34(IDENTITY
), false, ColorB(0, 150, 0, 255), eBBD_Faceted
);
216 case ESpatialVolumeShape::Sphere
:
218 SAuxGeomRenderFlags prevRenderFlags
= renderAuxGeom
.GetRenderFlags();
219 renderAuxGeom
.SetRenderFlags(e_Mode3D
| e_FillModeWireframe
| e_CullModeNone
| e_DepthWriteOff
| e_DepthTestOn
);
220 renderAuxGeom
.DrawSphere(worldTM
.TransformPoint(m_volume
.pos
), m_volume
.radius
, ColorB(0, 150, 0, 64), false);
221 renderAuxGeom
.SetRenderFlags(prevRenderFlags
);
224 case ESpatialVolumeShape::Point
:
226 renderAuxGeom
.DrawSphere(worldTM
.TransformPoint(m_volume
.pos
), 0.1f
, ColorB(0, 150, 0, 64), false);
233 void CEntityDetectionVolumeComponent::Shutdown()
235 CSpatialIndex
& spatialIndex
= CBaseEnv::GetInstance().GetSpatialIndex();
236 spatialIndex
.DestroyVolume(m_volume
.volumeId
);
238 CEntityTransformComponentBase::Shutdown();
241 Schematyc2::INetworkSpawnParamsPtr
CEntityDetectionVolumeComponent::GetNetworkSpawnParams() const
243 return Schematyc2::INetworkSpawnParamsPtr();
246 void CEntityDetectionVolumeComponent::Register()
248 Schematyc2::IEnvRegistry
& envRegistry
= gEnv
->pSchematyc2
->GetEnvRegistry();
251 Schematyc2::IComponentFactoryPtr pComponentFactory
= SCHEMATYC2_MAKE_COMPONENT_FACTORY_SHARED(CEntityDetectionVolumeComponent
, SProperties
, CEntityDetectionVolumeComponent::s_componentGUID
);
252 pComponentFactory
->SetName("DetectionVolume");
253 pComponentFactory
->SetNamespace("Base");
254 pComponentFactory
->SetAuthor("Crytek");
255 pComponentFactory
->SetDescription("Entity detection volume component");
256 pComponentFactory
->SetFlags(Schematyc2::EComponentFlags::CreatePropertyGraph
);
257 pComponentFactory
->SetAttachmentType(Schematyc2::EComponentSocket::Parent
, g_tranformAttachmentGUID
);
258 pComponentFactory
->SetAttachmentType(Schematyc2::EComponentSocket::Child
, g_tranformAttachmentGUID
);
259 envRegistry
.RegisterComponentFactory(pComponentFactory
);
265 Schematyc2::CEnvFunctionDescriptorPtr pFunctionDescriptor
= Schematyc2::MakeEnvFunctionDescriptorShared(&CEntityDetectionVolumeComponent::SProperties::SetTransform
);
266 pFunctionDescriptor
->SetGUID("D363B5BC-75BD-4582-8BD8-AA6EC1CD8DAE");
267 pFunctionDescriptor
->SetName("SetTransform");
268 pFunctionDescriptor
->BindInput(0, 0, "Transform", "");
269 envRegistry
.RegisterFunction(pFunctionDescriptor
);
273 Schematyc2::IComponentMemberFunctionPtr pFunction
= SCHEMATYC2_MAKE_COMPONENT_MEMBER_FUNCTION_SHARED(CEntityDetectionVolumeComponent::SetVolumeSize
, "C926DA55-97A2-4C97-A7E6-C1416DD6284A", CEntityDetectionVolumeComponent::s_componentGUID
);
274 pFunction
->SetAuthor("Crytek");
275 pFunction
->SetDescription("Sets the size of the volume.");
276 pFunction
->BindInput(0, "X", "Size X", .0f
);
277 pFunction
->BindInput(1, "Y", "Size Y", .0f
);
278 pFunction
->BindInput(2, "Z", "Size Z", .0f
);
279 envRegistry
.RegisterComponentMemberFunction(pFunction
);
283 Schematyc2::IComponentMemberFunctionPtr pFunction
= SCHEMATYC2_MAKE_COMPONENT_MEMBER_FUNCTION_SHARED(CEntityDetectionVolumeComponent::GetVolumeSize
, "E8E87E86-C96B-4948-A298-0FE010E04F2E", CEntityDetectionVolumeComponent::s_componentGUID
);
284 pFunction
->SetAuthor("Crytek");
285 pFunction
->SetDescription("Gets the size of the volume.");
286 pFunction
->BindOutput(0, "X", "Size X");
287 pFunction
->BindOutput(1, "Y", "Size Y");
288 pFunction
->BindOutput(2, "Z", "Size Z");
289 envRegistry
.RegisterComponentMemberFunction(pFunction
);
293 Schematyc2::IComponentMemberFunctionPtr pFunction
= SCHEMATYC2_MAKE_COMPONENT_MEMBER_FUNCTION_SHARED(CEntityDetectionVolumeComponent::SetVolumeRadius
, "17FB678F-2256-4F7B-AB46-E8EAACD2497C", CEntityDetectionVolumeComponent::s_componentGUID
);
294 pFunction
->SetAuthor("Crytek");
295 pFunction
->SetDescription("Sets the radius of the volume.");
296 pFunction
->BindInput(0, "Radius", "Radius", .0f
);
297 envRegistry
.RegisterComponentMemberFunction(pFunction
);
301 Schematyc2::IComponentMemberFunctionPtr pFunction
= SCHEMATYC2_MAKE_COMPONENT_MEMBER_FUNCTION_SHARED(CEntityDetectionVolumeComponent::GetVolumeRadius
, "3950621F-8D47-4BE7-836C-35F211B41FBB", CEntityDetectionVolumeComponent::s_componentGUID
);
302 pFunction
->SetAuthor("Crytek");
303 pFunction
->SetDescription("Gets the radius of the volume.");
304 pFunction
->BindOutput(0, "Radius", "Radius");
305 envRegistry
.RegisterComponentMemberFunction(pFunction
);
311 Schematyc2::ISignalPtr pSignal
= envRegistry
.CreateSignal(CEntityDetectionVolumeComponent::s_enterSignalGUID
);
312 pSignal
->SetSenderGUID(CEntityDetectionVolumeComponent::s_componentGUID
);
313 pSignal
->SetName("EnterVolume");
314 pSignal
->SetFileName(SCHEMATYC2_FILE_NAME
, "Code");
315 pSignal
->SetAuthor("Crytek");
316 pSignal
->SetDescription("Sent when an entity enters the volume.");
317 pSignal
->AddInput("Volume", "Name of the volume", Schematyc2::CPoolString());
318 pSignal
->AddInput("Entity", "Entity entering volume", Schematyc2::ExplicitEntityId());
322 Schematyc2::ISignalPtr pSignal
= envRegistry
.CreateSignal(CEntityDetectionVolumeComponent::s_leaveSignalGUID
);
323 pSignal
->SetSenderGUID(CEntityDetectionVolumeComponent::s_componentGUID
);
324 pSignal
->SetName("LeaveVolume");
325 pSignal
->SetFileName(SCHEMATYC2_FILE_NAME
, "Code");
326 pSignal
->SetAuthor("Crytek");
327 pSignal
->SetDescription("Sent when an entity leaves the volume.");
328 pSignal
->AddInput("Volume", "Name of the volume", Schematyc2::CPoolString());
329 pSignal
->AddInput("Entity", "Entity leaving volume", Schematyc2::ExplicitEntityId());
333 void CEntityDetectionVolumeComponent::SetVolumeSize(float sizeX
, float sizeY
, float sizeZ
)
335 if(m_volume
.shape
== ESpatialVolumeShape::Box
)
337 m_volume
.size
.x
= sizeX
;
338 m_volume
.size
.y
= sizeY
;
339 m_volume
.size
.z
= sizeZ
;
343 void CEntityDetectionVolumeComponent::GetVolumeSize(float& sizeX
, float& sizeY
, float& sizeZ
) const
345 if(m_volume
.shape
== ESpatialVolumeShape::Box
)
347 sizeX
= m_volume
.size
.x
;
348 sizeY
= m_volume
.size
.y
;
349 sizeZ
= m_volume
.size
.z
;
353 sizeX
= sizeY
= sizeZ
= .0f
;
357 void CEntityDetectionVolumeComponent::SetVolumeRadius(float radius
)
359 if(m_volume
.shape
== ESpatialVolumeShape::Sphere
)
361 m_volume
.radius
= radius
;
365 float CEntityDetectionVolumeComponent::GetVolumeRadius() const
367 if(m_volume
.shape
== ESpatialVolumeShape::Sphere
)
369 return m_volume
.radius
;
374 void CEntityDetectionVolumeComponent::VolumeEventCallback(const SSpatialIndexEvent
& event
)
376 const SSpatialVolumeParams eventVolumeParams
= CBaseEnv::GetInstance().GetSpatialIndex().GetVolumeParams(event
.volumeIds
[1]);
377 if(eventVolumeParams
.entityId
!= CEntityComponentBase::GetEntityId())
379 const char* szVolumeName
= GetVolumeName(event
.volumeIds
[0]);
384 case ESpatialIndexEventId::Entering
:
386 const IEntity
* pEntity
= gEnv
->pEntitySystem
->GetEntity(eventVolumeParams
.entityId
);
390 EntityIds::iterator itEntityInArea
= std::find(m_entityIds
.begin(), m_entityIds
.end(), eventVolumeParams
.entityId
);
391 if(itEntityInArea
== m_entityIds
.end())
393 m_entityIds
.push_back(eventVolumeParams
.entityId
);
395 Schematyc2::CInPlaceStack stack
;
396 Schematyc2::Push(stack
, szVolumeName
);
397 Schematyc2::Push(stack
, Schematyc2::ExplicitEntityId(eventVolumeParams
.entityId
));
398 CEntityComponentBase::GetObject().ProcessSignal(s_enterSignalGUID
, stack
);
403 case ESpatialIndexEventId::Leaving
:
405 EntityIds::iterator itEntityInArea
= std::find(m_entityIds
.begin(), m_entityIds
.end(), eventVolumeParams
.entityId
);
406 if(itEntityInArea
!= m_entityIds
.end())
408 Schematyc2::CInPlaceStack stack
;
409 Schematyc2::Push(stack
, szVolumeName
);
410 Schematyc2::Push(stack
, Schematyc2::ExplicitEntityId(eventVolumeParams
.entityId
));
411 CEntityComponentBase::GetObject().ProcessSignal(s_leaveSignalGUID
, stack
);
413 m_entityIds
.erase(itEntityInArea
);
422 void CEntityDetectionVolumeComponent::OnEvent(const SEntityEvent
& event
)
426 case ENTITY_EVENT_XFORM
:
428 IEntity
& entity
= CEntityComponentBase::GetEntity();
429 const Matrix34 worldTM
= entity
.GetWorldTM();
431 CSpatialVolumeBounds bounds
;
432 switch(m_volume
.shape
)
434 case ESpatialVolumeShape::Box
:
436 bounds
= CSpatialVolumeBounds::CreateOBB(worldTM
, m_volume
.pos
, m_volume
.size
, m_volume
.rot
);
439 case ESpatialVolumeShape::Sphere
:
441 bounds
= CSpatialVolumeBounds::CreateSphere(worldTM
, m_volume
.pos
, m_volume
.radius
);
444 case ESpatialVolumeShape::Point
:
446 bounds
= CSpatialVolumeBounds::CreatePoint(worldTM
, m_volume
.pos
);
451 CSpatialIndex
& spatialIndex
= CBaseEnv::GetInstance().GetSpatialIndex();
452 spatialIndex
.UpdateVolumeBounds(m_volume
.volumeId
, bounds
);
458 void CEntityDetectionVolumeComponent::Update(const Schematyc2::SUpdateContext
& updateContext
)
460 CRY_PROFILE_FUNCTION_ARG(PROFILE_GAME
, GetEntity().GetName());
462 IEntity
& entity
= CEntityComponentBase::GetEntity();
463 const Matrix34 worldTM
= entity
.GetWorldTM();
465 CSpatialVolumeBounds bounds
;
466 switch(m_volume
.shape
)
468 case ESpatialVolumeShape::Box
:
470 bounds
= CSpatialVolumeBounds::CreateOBB(worldTM
, m_volume
.pos
, m_volume
.size
, m_volume
.rot
);
473 case ESpatialVolumeShape::Sphere
:
475 bounds
= CSpatialVolumeBounds::CreateSphere(worldTM
, m_volume
.pos
, m_volume
.radius
);
478 case ESpatialVolumeShape::Point
:
480 bounds
= CSpatialVolumeBounds::CreatePoint(worldTM
, m_volume
.pos
);
485 CSpatialIndex
& spatialIndex
= CBaseEnv::GetInstance().GetSpatialIndex();
486 spatialIndex
.UpdateVolumeBounds(m_volume
.volumeId
, bounds
);
489 const char* CEntityDetectionVolumeComponent::GetVolumeName(SpatialVolumeId volumeId
) const
491 // TODO: Retrieve and return the name of the component instance.
495 bool CEntityDetectionVolumeComponent::SetEnabled(bool bEnable
)
497 if(bEnable
!= m_bEnabled
)
511 void CEntityDetectionVolumeComponent::Enable()
516 void CEntityDetectionVolumeComponent::Disable()
522 SCHEMATYC2_GAME_ENV_AUTO_REGISTER(&SchematycBaseEnv::CEntityDetectionVolumeComponent::Register
)