1 // Copyright 2001-2018 Crytek GmbH / Crytek Group. All rights reserved.
6 #include <Preferences/ViewportPreferences.h>
7 #include "Controls/PropertiesPanel.h"
8 #include "Objects/ObjectLoader.h"
9 #include "Objects/InspectorWidgetCreator.h"
10 #include <CryEntitySystem/IEntity.h>
12 #include <Serialization/Decorators/EntityLink.h>
13 #include <Serialization/Decorators/EditorActionButton.h>
14 #include <Serialization/Decorators/EditToolButton.h>
16 #include "PickObjectTool.h"
18 REGISTER_CLASS_DESC(CAreaBoxClassDesc
);
20 class AreaTargetTool
: public CPickObjectTool
22 DECLARE_DYNCREATE(AreaTargetTool
)
24 struct SAreaTargetPicker
: IPickObjectCallback
30 void OnPick(CBaseObject
* pObj
) override
34 CUndo
undo("Add target link");
35 m_owner
->AddEntity(pObj
);
39 void OnCancelPick() override
43 CAreaObjectBase
* m_owner
;
48 : CPickObjectTool(&m_picker
)
52 virtual void SetUserData(const char* key
, void* userData
) override
54 m_picker
.m_owner
= static_cast<CAreaObjectBase
*>(userData
);
58 SAreaTargetPicker m_picker
;
61 IMPLEMENT_DYNCREATE(AreaTargetTool
, CPickObjectTool
)
63 //////////////////////////////////////////////////////////////////////////
64 CAreaObjectBase::CAreaObjectBase()
66 m_entities
.RegisterEventCallback(functor(*this, &CAreaObjectBase::OnObjectEvent
));
69 //////////////////////////////////////////////////////////////////////////
70 CAreaObjectBase::~CAreaObjectBase()
72 m_entities
.UnregisterEventCallback(functor(*this, &CAreaObjectBase::OnObjectEvent
));
75 //////////////////////////////////////////////////////////////////////////
76 void CAreaObjectBase::SerializeEntityTargets(Serialization::IArchive
& ar
, bool bMultiEdit
)
78 std::vector
<Serialization::EntityTarget
> links
;
79 for (size_t i
= 0; i
< m_entities
.GetCount(); i
++)
81 links
.emplace_back(m_entities
.Get(i
)->GetId(), (LPCTSTR
)m_entities
.Get(i
)->GetName());
84 ar(links
, "attached_entities", "!Attached Entities");
87 size_t linkCount
= links
.size();
88 bool linksChanged
= m_entities
.GetCount() != linkCount
;
92 for (size_t i
= 0; i
< m_entities
.GetCount(); i
++)
94 if (m_entities
.Get(i
)->GetId() != links
[i
].guid
)
103 while (!m_entities
.IsEmpty())
108 for (size_t i
= 0; i
< links
.size(); i
++)
110 CBaseObject
* obj
= GetIEditorImpl()->GetObjectManager()->FindObject(links
[i
].guid
);
121 if (ar
.openBlock("linktools", "Target Tools"))
123 Serialization::SEditToolButton
pickToolButton("");
124 pickToolButton
.SetToolClass(RUNTIME_CLASS(AreaTargetTool
), nullptr, this);
126 ar(pickToolButton
, "picker", "^Pick");
127 ar(Serialization::ActionButton([ = ] {
128 CUndo
undo("Clear entity links");
129 while (!m_entities
.IsEmpty())
133 }), "picker", "^Clear");
140 void CAreaObjectBase::CreateInspectorWidgets(CInspectorWidgetCreator
& creator
)
142 CEntityObject::CreateInspectorWidgets(creator
);
144 creator
.AddPropertyTree
<CAreaObjectBase
>("Area", &CAreaObjectBase::SerializeEntityTargets
);
147 //////////////////////////////////////////////////////////////////////////
148 void CAreaObjectBase::PostClone(CBaseObject
* pFromObject
, CObjectCloneContext
& ctx
)
150 __super::PostClone(pFromObject
, ctx
);
152 CAreaObjectBase
const* const pFrom
= static_cast<CAreaObjectBase
*>(pFromObject
);
153 // Clone event targets.
154 if (!pFrom
->m_entities
.IsEmpty())
156 size_t const numEntities
= pFrom
->m_entities
.GetCount();
158 for (size_t i
= 0; i
< numEntities
; i
++)
160 CBaseObject
* const __restrict pBaseObject
= pFrom
->m_entities
.Get(i
);
161 CBaseObject
* const __restrict pClonedBaseObject
= ctx
.FindClone(pBaseObject
);
163 if (pClonedBaseObject
!= nullptr)
165 m_entities
.Add(pClonedBaseObject
);
169 m_entities
.Add(pBaseObject
);
175 //////////////////////////////////////////////////////////////////////////
176 void CAreaObjectBase::OnObjectEvent(CBaseObject
* const pBaseObject
, int const event
)
178 if (event
== OBJECT_ON_PREDELETE
)
180 if (pBaseObject
->IsKindOf(RUNTIME_CLASS(CEntityObject
)))
182 CEntityObject
const* const pEntityObject
= static_cast<CEntityObject
*>(pBaseObject
);
184 if (pEntityObject
!= nullptr && pEntityObject
->GetIEntity() != nullptr)
186 OnEntityRemoved(pEntityObject
->GetIEntity());
192 //////////////////////////////////////////////////////////////////////////
193 void CAreaObjectBase::AddEntity(CBaseObject
* const pBaseObject
)
195 CRY_ASSERT(pBaseObject
!= nullptr);
196 StoreUndo("Add Entity");
197 m_entities
.Add(pBaseObject
);
199 if (pBaseObject
->IsKindOf(RUNTIME_CLASS(CEntityObject
)))
201 OnEntityAdded(static_cast<CEntityObject
*>(pBaseObject
)->GetIEntity());
207 //////////////////////////////////////////////////////////////////////////
208 void CAreaObjectBase::RemoveEntity(size_t const index
)
210 CRY_ASSERT(index
>= 0 && index
< m_entities
.GetCount());
212 if (index
< m_entities
.GetCount())
214 StoreUndo("Remove Entity");
215 CBaseObject
* const pBaseObject
= m_entities
.Get(index
);
216 CEntityObject
const* const pEntity
= GetEntity(index
);
218 if (pEntity
!= nullptr)
220 OnEntityRemoved(pEntity
->GetIEntity());
223 m_entities
.Remove(pBaseObject
);
229 //////////////////////////////////////////////////////////////////////////
230 CEntityObject
* CAreaObjectBase::GetEntity(size_t const index
)
232 CRY_ASSERT(index
>= 0 && index
< m_entities
.GetCount());
233 CBaseObject
* const pBaseObject
= m_entities
.Get(index
);
235 if (pBaseObject
!= nullptr && pBaseObject
->IsKindOf(RUNTIME_CLASS(CEntityObject
)))
237 return static_cast<CEntityObject
*>(pBaseObject
);
243 //////////////////////////////////////////////////////////////////////////
244 void CAreaObjectBase::Serialize(CObjectArchive
& ar
)
246 __super::Serialize(ar
);
248 XmlNodeRef xmlNode
= ar
.node
;
252 XmlNodeRef
const entities
= xmlNode
->findChild("Entities");
256 int const numChildren
= entities
->getChildCount();
258 for (int i
= 0; i
< numChildren
; ++i
)
260 XmlNodeRef
const ent
= entities
->getChild(i
);
263 if (ent
->getAttr("Id", entityId
))
265 ar
.SetResolveCallback(this, entityId
, functor(m_entities
, &CSafeObjectsArray::Add
));
272 if (!m_entities
.IsEmpty())
274 XmlNodeRef
const nodes
= xmlNode
->newChild("Entities");
275 size_t const numEntities
= m_entities
.GetCount();
277 for (size_t i
= 0; i
< numEntities
; i
++)
279 XmlNodeRef entNode
= nodes
->newChild("Entity");
281 if (m_entities
.Get(i
) != nullptr)
283 entNode
->setAttr("Id", m_entities
.Get(i
)->GetId());
290 //////////////////////////////////////////////////////////////////////////
291 void CAreaObjectBase::DrawEntityLinks(DisplayContext
& dc
)
293 if (!m_entities
.IsEmpty())
295 Vec3
const vcol
= Vec3(1.0f
, 1.0f
, 1.0f
);
296 size_t const numEntities
= m_entities
.GetCount();
298 for (size_t i
= 0; i
< numEntities
; ++i
)
300 CBaseObject
const* const pBaseObject
= GetEntity(i
);
302 if (pBaseObject
!= nullptr)
304 dc
.DrawLine(GetWorldPos(), pBaseObject
->GetWorldPos(), ColorF(vcol
.x
, vcol
.y
, vcol
.z
, 0.7f
), ColorF(1, 1, 1, 0.7f
));
310 //////////////////////////////////////////////////////////////////////////
311 // CBase implementation.
312 //////////////////////////////////////////////////////////////////////////
313 IMPLEMENT_DYNCREATE(CAreaBox
, CEntityObject
)
315 //////////////////////////////////////////////////////////////////////////
317 : m_innerFadeDistance(0.0f
)
327 mv_displaySoundInfo
= false;
328 m_entityClass
= "AreaBox";
330 // Resize for 6 sides
331 m_abObstructSound
.resize(6);
333 m_box
.min
= Vec3(-mv_width
/ 2, -mv_length
/ 2, 0);
334 m_box
.max
= Vec3(mv_width
/ 2, mv_length
/ 2, mv_height
);
336 m_bIgnoreGameUpdate
= 1;
338 m_pOwnSoundVarBlock
= new CVarBlock
;
341 //////////////////////////////////////////////////////////////////////////
342 void CAreaBox::InitVariables()
344 if (m_pVarObject
== nullptr)
346 m_pVarObject
= stl::make_unique
<CVarObject
>();
349 m_pVarObject
->AddVariable(m_innerFadeDistance
, "InnerFadeDistance", functor(*this, &CAreaBox::OnAreaChange
));
350 m_pVarObject
->AddVariable(m_areaId
, "AreaId", functor(*this, &CAreaBox::OnAreaChange
));
351 m_pVarObject
->AddVariable(m_edgeWidth
, "FadeInZone", functor(*this, &CAreaBox::OnSizeChange
));
352 m_pVarObject
->AddVariable(mv_width
, "Width", functor(*this, &CAreaBox::OnSizeChange
));
353 m_pVarObject
->AddVariable(mv_length
, "Length", functor(*this, &CAreaBox::OnSizeChange
));
354 m_pVarObject
->AddVariable(mv_height
, "Height", functor(*this, &CAreaBox::OnSizeChange
));
355 m_pVarObject
->AddVariable(mv_groupId
, "GroupId", functor(*this, &CAreaBox::OnAreaChange
));
356 m_pVarObject
->AddVariable(mv_priority
, "Priority", functor(*this, &CAreaBox::OnAreaChange
));
357 m_pVarObject
->AddVariable(mv_filled
, "DisplayFilled");
358 m_pVarObject
->AddVariable(mv_displaySoundInfo
, "DisplaySoundInfo", functor(*this, &CAreaBox::OnSoundParamsChange
));
361 //////////////////////////////////////////////////////////////////////////
362 void CAreaBox::Done()
364 m_pOwnSoundVarBlock
->DeleteAllVariables();
366 CEntityObject::Done();
369 //////////////////////////////////////////////////////////////////////////
370 bool CAreaBox::Init(CBaseObject
* prev
, const string
& file
)
372 m_bIgnoreGameUpdate
= 1;
374 SetColor(RGB(0, 0, 255));
375 bool res
= CEntityObject::Init(prev
, file
);
377 if (m_pEntity
!= nullptr)
379 m_pEntity
->GetOrCreateComponent
<IEntityAreaComponent
>();
384 m_abObstructSound
= ((CAreaBox
*)prev
)->m_abObstructSound
;
385 CRY_ASSERT(m_abObstructSound
.size() == 6);
388 m_bIgnoreGameUpdate
= 0;
393 //////////////////////////////////////////////////////////////////////////
394 void CAreaBox::GetLocalBounds(AABB
& box
)
399 //////////////////////////////////////////////////////////////////////////
400 bool CAreaBox::HitTest(HitContext
& hc
)
405 box.Transform( GetWorldTM() );
406 float tr = hc.distanceTollerance/2;
407 box.min -= Vec3(tr,tr,tr);
408 box.max += Vec3(tr,tr,tr);
409 if (box.IsIntersectRay(hc.raySrc,hc.rayDir,p ))
411 hc.dist = Vec3(hc.raySrc - p).Length();
414 Matrix34 invertWTM
= GetWorldTM();
415 Vec3 worldPos
= invertWTM
.GetTranslation();
418 Vec3 xformedRaySrc
= invertWTM
.TransformPoint(hc
.raySrc
);
419 Vec3 xformedRayDir
= invertWTM
.TransformVector(hc
.rayDir
).GetNormalized();
421 float epsilonDist
= max(.1f
, hc
.view
->GetScreenScaleFactor(worldPos
) * 0.01f
);
422 epsilonDist
*= max(0.0001f
, min(invertWTM
.GetColumn0().GetLength(), min(invertWTM
.GetColumn1().GetLength(), invertWTM
.GetColumn2().GetLength())));
425 float tr
= hc
.distanceTolerance
/ 2 + 1;
427 box
.min
= m_box
.min
- Vec3(tr
+ epsilonDist
, tr
+ epsilonDist
, tr
+ epsilonDist
);
428 box
.max
= m_box
.max
+ Vec3(tr
+ epsilonDist
, tr
+ epsilonDist
, tr
+ epsilonDist
);
430 if (Intersect::Ray_AABB(xformedRaySrc
, xformedRayDir
, box
, p
))
432 if (Intersect::Ray_AABBEdge(xformedRaySrc
, xformedRayDir
, m_box
, epsilonDist
, hitDist
, p
))
434 hc
.dist
= xformedRaySrc
.GetDistance(p
);
441 //////////////////////////////////////////////////////////////////////////
442 void CAreaBox::CreateInspectorWidgets(CInspectorWidgetCreator
& creator
)
444 CAreaObjectBase::CreateInspectorWidgets(creator
);
446 creator
.AddPropertyTree
<CAreaBox
>("Area Box", &CAreaBox::SerializeProperties
);
449 void CAreaBox::SerializeProperties(Serialization::IArchive
& ar
, bool bMultiEdit
)
451 m_pVarObject
->SerializeVariable(&m_innerFadeDistance
, ar
);
452 m_pVarObject
->SerializeVariable(&m_areaId
, ar
);
453 m_pVarObject
->SerializeVariable(&m_edgeWidth
, ar
);
454 m_pVarObject
->SerializeVariable(&mv_width
, ar
);
455 m_pVarObject
->SerializeVariable(&mv_length
, ar
);
456 m_pVarObject
->SerializeVariable(&mv_height
, ar
);
457 m_pVarObject
->SerializeVariable(&mv_groupId
, ar
);
458 m_pVarObject
->SerializeVariable(&mv_priority
, ar
);
459 m_pVarObject
->SerializeVariable(&mv_filled
, ar
);
460 m_pVarObject
->SerializeVariable(&mv_displaySoundInfo
, ar
);
462 if (!m_abObstructSound
.empty() && !m_bIgnoreGameUpdate
&& mv_displaySoundInfo
&& !bMultiEdit
)
464 if (!ar
.isInput() || m_pOwnSoundVarBlock
->IsEmpty())
466 if (!m_pOwnSoundVarBlock
->IsEmpty())
467 m_pOwnSoundVarBlock
->DeleteAllVariables();
468 // If the shape hasn't got a height subtract 2 for roof and floor
469 CRY_ASSERT(m_abObstructSound
.size() == 6);
470 size_t const nVarCount
= m_abObstructSound
.size() - ((mv_height
> 0.0f
) ? 0 : 2);
471 for (size_t i
= 0; i
< nVarCount
; ++i
)
473 CVariable
<bool>* const pvTemp
= new CVariable
<bool>;
474 pvTemp
->Set(m_abObstructSound
[i
]);
475 pvTemp
->AddOnSetCallback(functor(*this, &CAreaBox::OnPointChange
));
478 cTemp
.Format("Side:%d", i
+ 1);
480 pvTemp
->SetName(cTemp
);
481 m_pOwnSoundVarBlock
->AddVariable(pvTemp
);
485 ar(*m_pOwnSoundVarBlock
, "SoundObstruction", "|Sound Obstruction");
489 //////////////////////////////////////////////////////////////////////////
490 void CAreaBox::Reload(bool bReloadScript
/* = false */)
492 __super::Reload(bReloadScript
);
494 // During reloading the entity+proxies get completely removed.
495 // Hence we need to completely recreate the proxy and update all data to it.
499 //////////////////////////////////////////////////////////////////////////
500 void CAreaBox::OnAreaChange(IVariable
* pVariable
)
502 if (m_bIgnoreGameUpdate
== 0 && m_pEntity
!= nullptr)
504 IEntityAreaComponent
* pArea
= m_pEntity
->GetOrCreateComponent
<IEntityAreaComponent
>();
508 pArea
->SetID(m_areaId
);
509 pArea
->SetGroup(mv_groupId
);
510 pArea
->SetPriority(mv_priority
);
511 pArea
->SetInnerFadeDistance(m_innerFadeDistance
);
516 //////////////////////////////////////////////////////////////////////////
517 void CAreaBox::OnSizeChange(IVariable
* pVariable
)
524 m_box
.min
= -size
/ 2;
525 m_box
.max
= size
/ 2;
526 // Make volume position bottom of bounding box.
528 m_box
.max
.z
= size
.z
;
530 InvalidateWorldBox();
532 if (m_bIgnoreGameUpdate
== 0 && m_pEntity
!= nullptr)
534 IEntityAreaComponent
* pArea
= m_pEntity
->GetOrCreateComponent
<IEntityAreaComponent
>();
538 pArea
->SetBox(m_box
.min
, m_box
.max
, nullptr, 0);
539 pArea
->SetProximity(m_edgeWidth
);
544 //////////////////////////////////////////////////////////////////////////
545 void CAreaBox::Display(DisplayContext
& dc
)
547 if (!gViewportDebugPreferences
.showAreaObjectHelper
)
550 if (!mv_displaySoundInfo
)
552 COLORREF wireColor
, solidColor
;
553 float wireOffset
= 0;
557 wireColor
= dc
.GetSelectedColor();
558 solidColor
= GetColor();
563 wireColor
= GetColor();
564 solidColor
= GetColor();
567 //dc.renderer->SetCullMode( R_CULL_DISABLE );
569 dc
.PushMatrix(GetWorldTM());
572 bool bFrozen
= IsFrozen();
576 //////////////////////////////////////////////////////////////////////////
578 dc
.SetColor(solidColor
, alpha
);
583 dc
.DrawSolidBox(box
.min
, box
.max
);
588 dc
.SetColor(wireColor
, 1);
592 dc
.SetLineWidth(3.0f
);
593 dc
.DrawWireBox(box
.min
, box
.max
);
597 dc
.DrawWireBox(box
.min
, box
.max
);
600 float fFadeScale
= m_edgeWidth
/ 200.0f
;
602 Vec3 EdgeDist
= InnerBox
.max
- InnerBox
.min
;
603 InnerBox
.min
.x
+= EdgeDist
.x
* fFadeScale
;
604 InnerBox
.max
.x
-= EdgeDist
.x
* fFadeScale
;
605 InnerBox
.min
.y
+= EdgeDist
.y
* fFadeScale
;
606 InnerBox
.max
.y
-= EdgeDist
.y
* fFadeScale
;
607 InnerBox
.min
.z
+= EdgeDist
.z
* fFadeScale
;
608 InnerBox
.max
.z
-= EdgeDist
.z
* fFadeScale
;
609 dc
.DrawWireBox(InnerBox
.min
, InnerBox
.max
);
614 dc
.DrawSolidBox(box
.min
, box
.max
);
616 //////////////////////////////////////////////////////////////////////////
625 ColorB
const oObstructionFilled(255, 0, 0, 120);
626 ColorB
const oObstructionFilledNotSelected(255, 0, 0, 30);
627 ColorB
const oObstructionNotFilled(255, 0, 0, 10);
628 ColorB
const oNoObstructionFilled(0, 255, 0, 120);
629 ColorB
const oNoObstructionFilledNotSelected(0, 255, 0, 30);
630 ColorB
const oNoObstructionNotFilled(0, 255, 0, 10);
634 oWireColor
= dc
.GetSelectedColor();
636 oWireColor
= GetColor();
638 dc
.SetColor(oWireColor
);
640 dc
.PushMatrix(GetWorldTM());
642 if (mv_height
> 0.0f
)
643 dc
.DrawWireBox(m_box
.min
, m_box
.max
);
645 Vec3
const v3BoxMin
= m_box
.min
;
646 Vec3
const v3BoxMax
= m_box
.max
;
648 // Now build the 6 segments
649 float const fLength
= v3BoxMax
.x
- v3BoxMin
.x
;
650 float const fWidth
= v3BoxMax
.y
- v3BoxMin
.y
;
651 float const fHeight
= v3BoxMax
.z
- v3BoxMin
.z
;
653 Vec3
const v0(v3BoxMin
);
654 Vec3
const v1(Vec3(v3BoxMin
.x
+ fLength
, v3BoxMin
.y
, v3BoxMin
.z
));
655 Vec3
const v2(Vec3(v3BoxMin
.x
+ fLength
, v3BoxMin
.y
+ fWidth
, v3BoxMin
.z
));
656 Vec3
const v3(Vec3(v3BoxMin
.x
, v3BoxMin
.y
+ fWidth
, v3BoxMin
.z
));
657 Vec3
const v4(Vec3(v3BoxMin
.x
, v3BoxMin
.y
, v3BoxMin
.z
+ fHeight
));
658 Vec3
const v5(Vec3(v3BoxMin
.x
+ fLength
, v3BoxMin
.y
, v3BoxMin
.z
+ fHeight
));
659 Vec3
const v6(Vec3(v3BoxMin
.x
+ fLength
, v3BoxMin
.y
+ fWidth
, v3BoxMin
.z
+ fHeight
));
660 Vec3
const v7(Vec3(v3BoxMin
.x
, v3BoxMin
.y
+ fWidth
, v3BoxMin
.z
+ fHeight
));
662 // Describe the box faces
663 SBoxFace
const aoBoxFaces
[6] =
665 SBoxFace(&v0
, &v4
, &v5
, &v1
),
666 SBoxFace(&v1
, &v5
, &v6
, &v2
),
667 SBoxFace(&v2
, &v6
, &v7
, &v3
),
668 SBoxFace(&v3
, &v7
, &v4
, &v0
),
669 SBoxFace(&v4
, &v5
, &v6
, &v7
),
670 SBoxFace(&v0
, &v1
, &v2
, &v3
)
674 unsigned int const nSideCount
= ((mv_height
> 0.0f
) ? 6 : 4);
675 for (unsigned int i
= 0; i
< nSideCount
; ++i
)
677 if (mv_height
== 0.0f
)
681 if (m_abObstructSound
[i
])
682 dc
.SetColor(oObstructionFilled
);
684 dc
.SetColor(oNoObstructionFilled
);
687 dc
.SetColor(oWireColor
);
689 dc
.DrawLine(*(aoBoxFaces
[i
].pP1
), *(aoBoxFaces
[i
].pP4
));
692 if (mv_height
> 0.0f
)
694 // Manipulate the color so it looks a little thicker and redder
695 if (mv_filled
|| gViewportPreferences
.fillSelectedShapes
)
697 ColorB
const nColor
= dc
.GetColor();
699 if (m_abObstructSound
[i
])
700 dc
.SetColor(IsSelected() ? oObstructionFilled
: oObstructionFilledNotSelected
);
702 dc
.SetColor(IsSelected() ? oNoObstructionFilled
: oNoObstructionFilledNotSelected
);
707 dc
.DrawQuad(*(aoBoxFaces
[i
].pP1
), *(aoBoxFaces
[i
].pP2
), *(aoBoxFaces
[i
].pP3
), *(aoBoxFaces
[i
].pP4
));
713 else if (IsSelected())
715 ColorB
const nColor
= dc
.GetColor();
717 if (m_abObstructSound
[i
])
718 dc
.SetColor(oObstructionNotFilled
);
720 dc
.SetColor(oNoObstructionNotFilled
);
725 dc
.DrawQuad(*(aoBoxFaces
[i
].pP1
), *(aoBoxFaces
[i
].pP2
), *(aoBoxFaces
[i
].pP3
), *(aoBoxFaces
[i
].pP4
));
734 //////////////////////////////////////////////////////////////////////////
742 //////////////////////////////////////////////////////////////////////////
743 void CAreaBox::InvalidateTM(int nWhyFlags
)
745 CEntityObject::InvalidateTM(nWhyFlags
);
748 //////////////////////////////////////////////////////////////////////////
749 void CAreaBox::Serialize(CObjectArchive
& ar
)
751 m_bIgnoreGameUpdate
= 1;
752 __super::Serialize(ar
);
753 m_bIgnoreGameUpdate
= 0;
754 CVarBlockPtr soundVarBlock
= new CVarBlock
;
756 XmlNodeRef xmlNode
= ar
.node
;
760 xmlNode
->getAttr("BoxMin", box
.min
);
761 xmlNode
->getAttr("BoxMax", box
.max
);
769 // xmlNode->setAttr( "AreaId",m_areaId );
770 xmlNode
->setAttr("BoxMin", m_box
.min
);
771 xmlNode
->setAttr("BoxMax", m_box
.max
);
776 for (size_t i
= 0; i
< ((mv_height
> 0.0f
) ? 6 : 4); ++i
)
778 CVariable
<bool>* const pvTemp
= new CVariable
<bool>;
781 cTemp
.Format("Side%d", i
+ 1);
783 // And add each to the block
784 soundVarBlock
->AddVariable(pvTemp
, cTemp
);
787 // Now read in the data
788 XmlNodeRef pSoundDataNode
= xmlNode
->findChild("SoundData");
791 // Make sure we stay backwards compatible and also find the old "Side:" formatting
792 // This can go out once every level got saved with the new formatting
793 char const* const pcTemp
= pSoundDataNode
->getAttr("Side:1");
794 if (pcTemp
&& pcTemp
[0])
796 // We have the old formatting
797 soundVarBlock
->DeleteAllVariables();
799 for (size_t i
= 0; i
< ((mv_height
> 0.0f
) ? 6 : 4); ++i
)
801 CVariable
<bool>* const pvTempOld
= new CVariable
<bool>;
803 stack_string cTempOld
;
804 cTempOld
.Format("Side:%d", i
+ 1);
806 // And add each to the block
807 soundVarBlock
->AddVariable(pvTempOld
, cTempOld
);
811 soundVarBlock
->Serialize(pSoundDataNode
, true);
814 // Copy the data to the "bools" list
815 // First clear the remains out
816 m_abObstructSound
.clear();
818 unsigned int const nVarCount
= soundVarBlock
->GetNumVariables();
819 for (unsigned int i
= 0; i
< nVarCount
; ++i
)
821 IVariable
const* const pTemp
= soundVarBlock
->GetVariable(i
);
826 m_abObstructSound
.push_back(bTemp
);
828 if (i
>= nVarCount
- 2)
830 // Here check for backwards compatibility reasons if "ObstructRoof" and "ObstructFloor" still exists
832 if (i
== nVarCount
- 2)
834 if (xmlNode
->getAttr("ObstructRoof", bTemp
))
835 m_abObstructSound
[i
] = bTemp
;
839 if (xmlNode
->getAttr("ObstructFloor", bTemp
))
840 m_abObstructSound
[i
] = bTemp
;
846 // Since the var block is a static object clear it for the next object to be empty
847 soundVarBlock
->DeleteAllVariables();
851 XmlNodeRef pSoundDataNode
= xmlNode
->newChild("SoundData");
854 // TODO: What if mv_height or/and mv_width or/and mv_length == 0 ??
855 // For now just serialize all data
856 // First clear the remains out
857 soundVarBlock
->DeleteAllVariables();
859 // Create the variables
860 CRY_ASSERT(m_abObstructSound
.size() == 6);
863 tSoundObstruction::const_iterator
Iter(m_abObstructSound
.begin());
864 tSoundObstruction::const_iterator
const IterEnd(m_abObstructSound
.end());
866 for (; Iter
!= IterEnd
; ++Iter
)
868 bool const bObstructed
= (bool)(*Iter
);
870 CVariable
<bool>* const pvTemp
= new CVariable
<bool>;
871 pvTemp
->Set(bObstructed
);
873 cTemp
.Format("Side%d", ++nIndex
);
875 // And add each to the block
876 soundVarBlock
->AddVariable(pvTemp
, cTemp
);
879 soundVarBlock
->Serialize(pSoundDataNode
, false);
880 soundVarBlock
->DeleteAllVariables();
885 //////////////////////////////////////////////////////////////////////////
886 XmlNodeRef
CAreaBox::Export(const string
& levelPath
, XmlNodeRef
& xmlNode
)
888 XmlNodeRef objNode
= CEntityObject::Export(levelPath
, xmlNode
);
892 //////////////////////////////////////////////////////////////////////////
893 void CAreaBox::SetAreaId(int nAreaId
)
897 if (m_bIgnoreGameUpdate
== 0 && m_pEntity
!= nullptr)
899 IEntityAreaComponent
* pArea
= m_pEntity
->GetOrCreateComponent
<IEntityAreaComponent
>();
903 pArea
->SetID(m_areaId
);
908 //////////////////////////////////////////////////////////////////////////
909 int CAreaBox::GetAreaId()
914 //////////////////////////////////////////////////////////////////////////
915 void CAreaBox::SetBox(AABB box
)
919 if (m_bIgnoreGameUpdate
== 0 && m_pEntity
!= nullptr)
921 IEntityAreaComponent
* pArea
= m_pEntity
->GetOrCreateComponent
<IEntityAreaComponent
>();
925 pArea
->SetBox(m_box
.min
, m_box
.max
, nullptr, 0);
930 //////////////////////////////////////////////////////////////////////////
931 AABB
CAreaBox::GetBox()
936 //////////////////////////////////////////////////////////////////////////
937 void CAreaBox::PostLoad(CObjectArchive
& ar
)
939 __super::PostLoad(ar
);
941 UpdateAttachedEntities();
944 //////////////////////////////////////////////////////////////////////////
945 bool CAreaBox::CreateGameObject()
947 bool const bSuccess
= __super::CreateGameObject();
957 //////////////////////////////////////////////////////////////////////////
958 void CAreaBox::OnEntityAdded(IEntity
const* const pIEntity
)
960 if (m_bIgnoreGameUpdate
== 0 && m_pEntity
!= nullptr)
962 IEntityAreaComponent
* pArea
= m_pEntity
->GetOrCreateComponent
<IEntityAreaComponent
>();
966 pArea
->AddEntity(pIEntity
->GetId());
971 //////////////////////////////////////////////////////////////////////////
972 void CAreaBox::OnEntityRemoved(IEntity
const* const pIEntity
)
974 if (m_bIgnoreGameUpdate
== 0 && m_pEntity
!= nullptr)
976 IEntityAreaComponent
* pArea
= m_pEntity
->GetOrCreateComponent
<IEntityAreaComponent
>();
980 pArea
->RemoveEntity(pIEntity
->GetId());
985 //////////////////////////////////////////////////////////////////////////
986 void CAreaBox::UpdateGameArea()
988 if (m_bIgnoreGameUpdate
== 0 && m_pEntity
!= nullptr)
990 IEntityAreaComponent
* pArea
= m_pEntity
->GetOrCreateComponent
<IEntityAreaComponent
>();
994 bool abObstructSound
[6] = { false };
997 tSoundObstruction::const_iterator
Iter(m_abObstructSound
.begin());
998 tSoundObstruction::const_iterator
const IterEnd(m_abObstructSound
.end());
1000 for (; Iter
!= IterEnd
; ++Iter
)
1002 // Here we "unpack" the data! (1 bit*nPointsCount to 1 byte*nPointsCount)
1003 bool const bObstructed
= (bool)(*Iter
);
1004 abObstructSound
[nIndex
] = bObstructed
;
1008 UpdateSoundPanelParams();
1009 pArea
->SetBox(m_box
.min
, m_box
.max
, &abObstructSound
[0], 6);
1010 pArea
->SetProximity(m_edgeWidth
);
1011 pArea
->SetID(m_areaId
);
1012 pArea
->SetGroup(mv_groupId
);
1013 pArea
->SetPriority(mv_priority
);
1014 pArea
->SetInnerFadeDistance(m_innerFadeDistance
);
1019 //////////////////////////////////////////////////////////////////////////
1020 void CAreaBox::UpdateAttachedEntities()
1022 if (m_bIgnoreGameUpdate
== 0 && m_pEntity
!= nullptr)
1024 IEntityAreaComponent
* pArea
= m_pEntity
->GetOrCreateComponent
<IEntityAreaComponent
>();
1028 pArea
->RemoveEntities();
1029 size_t const numEntities
= GetEntityCount();
1031 for (size_t i
= 0; i
< numEntities
; ++i
)
1033 CEntityObject
* const pEntity
= GetEntity(i
);
1035 if (pEntity
!= nullptr && pEntity
->GetIEntity() != nullptr)
1037 pArea
->AddEntity(pEntity
->GetIEntity()->GetId());
1044 //////////////////////////////////////////////////////////////////////////
1045 void CAreaBox::OnSoundParamsChange(IVariable
* var
)
1047 if (!m_bIgnoreGameUpdate
&& mv_displaySoundInfo
)
1049 // Refresh inspector
1054 //////////////////////////////////////////////////////////////////////////
1055 void CAreaBox::OnPointChange(IVariable
* var
)
1057 CRY_ASSERT(m_abObstructSound
.size() == 6);
1058 size_t const numVariables
= static_cast<size_t>(m_pOwnSoundVarBlock
->GetNumVariables());
1060 for (size_t i
= 0; i
< numVariables
; ++i
)
1062 if (m_pOwnSoundVarBlock
->GetVariable(i
) == var
)
1064 if (m_pEntity
!= nullptr)
1066 IEntityAreaComponent
* const pArea
= m_pEntity
->GetOrCreateComponent
<IEntityAreaComponent
>();
1070 bool bValue
= false;
1072 pArea
->SetSoundObstructionOnAreaFace(i
, bValue
);
1073 m_abObstructSound
[i
] = bValue
;
1082 //////////////////////////////////////////////////////////////////////////
1083 void CAreaBox::UpdateSoundPanelParams()
1085 if (!m_bIgnoreGameUpdate
&& mv_displaySoundInfo
)