1 // Copyright 2001-2019 Crytek GmbH / Crytek Group. All rights reserved.
4 #include "DesignerObject.h"
6 #include "Util/Converter.h"
7 #include "Util/Display.h"
8 #include "Util/PrimitiveShape.h"
10 #include "DesignerEditor.h"
12 #include <IAIManager.h>
13 #include <Material/MaterialManager.h>
14 #include <GameEngine.h>
16 #include <Controls/DynamicPopupMenu.h>
17 #include <Objects/ObjectLoader.h>
18 #include <Objects/InspectorWidgetCreator.h>
19 #include <Preferences/ViewportPreferences.h>
20 #include <Serialization/Decorators/EditorActionButton.h>
22 #include <CryCore/Base64.h>
26 IMPLEMENT_DYNCREATE(DesignerObject
, CBaseObject
)
28 REGISTER_CLASS_DESC(BoxObjectClassDesc
)
29 REGISTER_CLASS_DESC(SphereObjectClassDesc
)
30 REGISTER_CLASS_DESC(ConeObjectClassDesc
)
31 REGISTER_CLASS_DESC(CylinderObjectClassDesc
)
33 REGISTER_CLASS_DESC(DesignerObjectClassDesc
)
35 REGISTER_CLASS_DESC(SolidObjectClassDesc
)
37 DesignerObject::DesignerObject()
39 m_pCompiler
= new ModelCompiler(eCompiler_General
);
40 m_nBrushUniqFileId
= s_nGlobalBrushDesignerFileId
;
41 m_EngineFlags
.m_pObj
= this;
42 ++s_nGlobalBrushDesignerFileId
;
43 m_bSupportsBoxHighlight
= false;
46 void GeneratePrimitiveShape(PolygonList
& polygonList
, string primitiveType
)
50 BrushVec3
min(0.0, 0.0, 0.0);
51 BrushVec3
max(1.0, 1.0, 1.0);
53 if (primitiveType
== "DesignerSphere")
55 min
-= BrushVec3(0.0, 0.0, 0.5);
56 max
-= BrushVec3(0.0, 0.0, 0.5);
64 else if (primitiveType
== "DesignerBox")
71 else if (primitiveType
== "DesignerCylinder")
79 else if (primitiveType
== "DesignerCone")
89 bool DesignerObject::Init(CBaseObject
* prev
, const string
& file
)
91 SetMaterial(BrushDesignerDefaultMaterial
);
95 DesignerObject
* pGeomObj
= static_cast<DesignerObject
*>(prev
);
97 Model
* pModel
= pGeomObj
->GetModel();
100 Model
* pClonedModel
= new Model(*pModel
);
101 SetModel(pClonedModel
);
104 ModelCompiler
* pFrontBrush
= pGeomObj
->GetCompiler();
107 ModelCompiler
* pClonedCompilier
= new ModelCompiler(*pFrontBrush
);
108 SetCompiler(pClonedCompilier
);
109 ApplyPostProcess(GetMainContext(), ePostProcess_Mesh
);
113 bool ret
= CBaseObject::Init(prev
, file
);
115 // Finished initialization, now generate geometry for this object type.
116 // Do this only for new objects, or we risk duplicating lots of cubes
117 if (ret
&& !prev
&& (!file
.IsEmpty()))
119 PolygonList polygonList
;
123 GeneratePrimitiveShape(polygonList
, file
);
125 MODEL_SHELF_RECONSTRUCTOR(GetModel());
127 GetModel()->SetShelf(eShelf_Base
);
129 for (int i
= 0, iPolygonCount(polygonList
.size()); i
< iPolygonCount
; ++i
)
131 polygonList
[i
]->SetSubMatID(0);
132 GetModel()->AddUnionPolygon(polygonList
[i
]);
135 ApplyPostProcess(GetMainContext(), ePostProcess_Mesh
);
141 void DesignerObject::Display(CObjectRenderHelper
& objRenderHelper
)
143 SDisplayContext
& dc
= objRenderHelper
.GetDisplayContextRef();
147 dc
.PushMatrix(GetWorldTM());
148 Display::DisplayModel(dc
, GetModel(), NULL
, eShelf_Any
, 2, IsSelected() ? kSelectedColor
: ColorB(0, 0, 0));
154 DrawOpenPolygons(dc
);
158 const ColorB
& DesignerObject::GetSelectionPreviewHighlightColor()
160 return gViewportSelectionPreferences
.solidBrushGeometryColor
;
163 void DesignerObject::DrawOpenPolygons(SDisplayContext
& dc
)
165 dc
.PushMatrix(GetWorldTM());
167 ColorB oldColor
= dc
.GetColor();
168 int oldLineWidth
= dc
.GetLineWidth();
170 dc
.SetColor(ColorB(0, 0, 2));
172 for (int i
= 0, iPolygonCount(GetModel()->GetPolygonCount()); i
< iPolygonCount
; ++i
)
174 PolygonPtr pPolygon
= GetModel()->GetPolygon(i
);
175 if (!pPolygon
->IsOpen())
177 Display::DisplayPolygon(dc
, pPolygon
);
179 dc
.SetColor(oldColor
);
180 dc
.SetLineWidth(oldLineWidth
);
185 void DesignerObject::GetBoundBox(AABB
& box
)
189 for (int i
= eShelf_Base
; i
< cShelfMax
; ++i
)
191 if (!GetModel()->IsEmpty(static_cast<ShelfID
>(i
)))
193 box
.SetTransformedAABB(GetWorldTM(), GetModel()->GetBoundBox(static_cast<ShelfID
>(i
)));
199 BrushVec3 vWorldPos
= GetWorldTM().GetTranslation();
200 box
= AABB(vWorldPos
, vWorldPos
);
203 void DesignerObject::GetLocalBounds(AABB
& box
)
207 box
= GetModel()->GetBoundBox(eShelf_Base
);
211 box
= AABB(Vec3(0, 0, 0), Vec3(0, 0, 0));
215 bool DesignerObject::HitTest(HitContext
& hc
)
218 GetLocalViewRay(GetWorldTM(), hc
.view
, hc
.point2d
, ray
);
220 if (Designer::HitTest(ray
, GetMainContext(), hc
))
227 BrushMatrix34 invMat
= GetWorldTM().GetInverted();
228 for (int i
= 0, iPolygonCount(GetModel()->GetPolygonCount()); i
< iPolygonCount
; ++i
)
230 PolygonPtr pPolygon
= GetModel()->GetPolygon(i
);
231 if (!pPolygon
->IsOpen())
233 for (int k
= 0, iEdgeCount(pPolygon
->GetEdgeCount()); k
< iEdgeCount
; ++k
)
235 BrushEdge3D edge
= pPolygon
->GetEdge(k
);
236 if (HitTestEdge(ray
, pPolygon
->GetPlane().Normal(), edge
, hc
.view
))
247 IPhysicalEntity
* DesignerObject::GetCollisionEntity() const
249 if (GetCompiler() == NULL
)
251 if (GetCompiler()->GetRenderNode())
252 return GetCompiler()->GetRenderNode()->GetPhysics();
256 void DesignerObject::OnContextMenu(CPopupMenuItem
* menu
)
258 // Add button to enter edit mode
259 menu
->Add("Edit", [=]()
261 BeginUndoAndEnsureSelection();
262 GetIEditor()->GetIUndoManager()->Accept("Select Object");
263 GetIEditor()->ExecuteCommand("general.open_pane 'Modeling'");
265 // then show the rest of object properties
266 CBaseObject::OnContextMenu(menu
);
269 void DesignerObject::Serialize(CObjectArchive
& ar
)
271 CBaseObject::Serialize(ar
);
273 XmlNodeRef xmlNode
= ar
.node
;
277 string
typeName("Designer");
278 xmlNode
->getAttr("Type", typeName
);
280 bool bDesignerBinary
= false;
281 xmlNode
->getAttr("DesignerBinary", bDesignerBinary
);
283 XmlNodeRef brushNode
= xmlNode
->findChild("Brush");
286 bool bDesignerObject
= true;
287 if (!brushNode
->haveAttr("DesignerModeFlags"))
288 bDesignerObject
= false;
291 SetCompiler(new ModelCompiler(eCompiler_General
));
298 if (ar
.bUndo
|| !bDesignerBinary
)
299 GetModel()->Serialize(brushNode
, ar
.bLoading
, ar
.bUndo
);
303 bool bConvertSuccess
= Converter::ConvertSolidXMLToDesignerObject(brushNode
, this);
304 CRY_ASSERT(bConvertSuccess
);
311 GetCompiler()->DeleteAllRenderNodes();
316 uint64 nRenderFlag
= ERF_HAS_CASTSHADOWMAPS
| ERF_CASTSHADOWMAPS
;
317 ar
.node
->getAttr("RndFlags", nRenderFlag
, false);
318 if (nRenderFlag
& ERF_CASTSHADOWMAPS
)
319 nRenderFlag
|= ERF_HAS_CASTSHADOWMAPS
;
320 GetCompiler()->SetRenderFlags(nRenderFlag
);
321 int nStatObjFlag
= 0;
322 if (ar
.node
->getAttr("StaticObjFlags", nStatObjFlag
))
323 GetCompiler()->SetStaticObjFlags(nStatObjFlag
);
324 int nViewDistRadio
= kDefaultViewDist
;
325 ar
.node
->getAttr("ViewDistRatio", nViewDistRadio
);
326 GetCompiler()->SetViewDistRatio(nViewDistRadio
);
328 XmlNodeRef meshNode
= ar
.node
->findChild("Mesh");
331 const char* encodedStr
;
333 meshNode
->getAttr("Version", nVersion
);
334 if (meshNode
->getAttr("BinaryData", &encodedStr
))
336 int nLength
= strlen(encodedStr
);
339 int nDestBufferLen
= Base64::decodedsize_base64(nLength
);
340 std::vector
<char> buffer
;
341 buffer
.resize(nDestBufferLen
, 0);
342 Base64::decode_base64(&buffer
[0], encodedStr
, nLength
, false);
343 GetCompiler()->LoadMesh(nVersion
, buffer
, this, GetModel());
344 bDesignerBinary
= true;
352 if (ar
.bUndo
|| !bDesignerBinary
)
354 if (GetModel()->GetSubdivisionLevel() > 0)
355 GetModel()->ResetDB(eDBRF_Vertex
);
356 ApplyPostProcess(GetMainContext(), ePostProcess_Mesh
);
363 XmlNodeRef brushNode
= xmlNode
->newChild("Brush");
364 GetModel()->Serialize(brushNode
, ar
.bLoading
, ar
.bUndo
);
368 ar
.node
->setAttr("RndFlags", ERF_GET_WRITABLE(GetCompiler()->GetRenderFlags()), false);
369 ar
.node
->setAttr("StaticObjFlags", ERF_GET_WRITABLE(GetCompiler()->GetStaticObjFlags()));
370 ar
.node
->setAttr("ViewDistRatio", GetCompiler()->GetViewDistRatio());
371 if (!GetCompiler()->IsValid())
372 GetCompiler()->Compile(this, GetModel());
374 if (GetCompiler()->IsValid() && !ar
.bUndo
)
376 XmlNodeRef meshNode
= xmlNode
->newChild("Mesh");
377 std::vector
<char> meshBuffer
;
378 const int nMeshVersion
= 2;
379 if (GetCompiler()->SaveMesh(nMeshVersion
, meshBuffer
, this, GetModel()))
381 unsigned int meshBufferSize
= meshBuffer
.size();
382 std::vector
<char> encodedStr(Base64::encodedsize_base64(meshBufferSize
) + 1);
383 Base64::encode_base64(&encodedStr
[0], &meshBuffer
[0], meshBufferSize
, true);
384 meshNode
->setAttr("Version", nMeshVersion
);
385 meshNode
->setAttr("BinaryData", &encodedStr
[0]);
392 // Get a list of incompatible subtools with current Designer Object type
393 std::vector
<EDesignerTool
> DesignerObject::GetIncompatibleSubtools()
395 return std::vector
<EDesignerTool
>();
398 void DesignerObject::CreateInspectorWidgets(CInspectorWidgetCreator
& creator
)
400 CBaseObject::CreateInspectorWidgets(creator
);
402 creator
.AddPropertyTree
<DesignerObject
>("Designer", [](DesignerObject
* pObject
, Serialization::IArchive
& ar
, bool bMultiEdit
)
404 pObject
->m_EngineFlags
.Serialize(ar
);
406 if (ar
.openBlock("Edit", "<Edit"))
408 ar(Serialization::ActionButton([=]
410 GetIEditor()->ExecuteCommand("general.open_pane 'Modeling'");
418 pObject
->UpdateGameResource();
423 void DesignerObject::SetMaterial(IEditorMaterial
* mtl
)
425 bool bAssignedSubmaterial
= false;
428 mtl
= GetIEditor()->GetMaterialManager()->LoadMaterial(BrushDesignerDefaultMaterial
);
430 CMaterial
* pParentMat
= mtl
? ((CMaterial
*)mtl
)->GetParent() : NULL
;
431 if (pParentMat
&& pParentMat
== GetMaterial())
433 DesignerSession
* pSession
= DesignerSession::GetInstance();
434 Model
* pModel
= GetModel();
436 for (int i
= 0, iSubMatCount(pParentMat
->GetSubMaterialCount()); i
< iSubMatCount
; ++i
)
438 if (pParentMat
->GetSubMaterial(i
) != mtl
)
441 if (pSession
->GetIsActive())
443 CBaseObject
* pObject
= pSession
->GetBaseObject();
445 if (CUndo::IsRecording() && pObject
)
446 CUndo::Record(new UndoTextureMapping(pObject
, "Designer : SetSubMatID"));
448 ElementSet
* pSelected
= pSession
->GetSelectedElements();
449 if (pSelected
->IsEmpty())
450 pModel
->SetSubMatID(i
);
452 AssignMatIDToSelectedPolygons(i
);
454 pSession
->SetCurrentSubMatID(i
);
457 pModel
->SetSubMatID(i
);
459 GetCompiler()->Compile(this, GetModel());
460 bAssignedSubmaterial
= true;
465 if (!bAssignedSubmaterial
)
469 CBaseObject::SetMaterial(mtl
);
471 else if (pParentMat
!= GetMaterial())
473 CBaseObject::SetMaterial(pParentMat
);
481 void DesignerObject::SetMaterial(const string
& materialName
)
483 CMaterial
* pMaterial
= NULL
;
484 pMaterial
= GetIEditor()->GetMaterialManager()->LoadMaterial(materialName
);
485 if (!pMaterial
|| (pMaterial
&& pMaterial
->IsDummy()))
487 IMaterial
* pMatInfo
= GetIEditor()->Get3DEngine()->GetMaterialManager()->LoadMaterial(materialName
, false);
490 GetIEditor()->GetMaterialManager()->OnCreateMaterial(pMatInfo
);
491 pMaterial
= GetIEditor()->GetMaterialManager()->FromIMaterial(pMatInfo
);
494 CBaseObject::SetMaterial(pMaterial
);
496 const string materialNameWithoutExtension
= PathUtil::RemoveExtension(materialName
);
497 if (pMaterial
->GetName() != materialNameWithoutExtension
)
498 m_materialNameOverride
= materialNameWithoutExtension
;
500 m_materialNameOverride
.Empty();
505 void DesignerObject::SetSelected(bool bSelect
)
507 CBaseObject::SetSelected(bSelect
);
508 GetCompiler()->SetSelected(bSelect
);
511 string
DesignerObject::GetMaterialName() const
513 if (!m_materialNameOverride
.IsEmpty())
514 return m_materialNameOverride
;
516 return CBaseObject::GetMaterialName();
519 void DesignerObject::SetMaterialLayersMask(uint32 nLayersMask
)
521 CBaseObject::SetMaterialLayersMask(nLayersMask
);
525 void DesignerObject::SetMinSpec(uint32 nSpec
, bool bSetChildren
)
527 __super::SetMinSpec(nSpec
, bSetChildren
);
528 if (GetCompiler() && GetCompiler()->GetRenderNode())
529 GetCompiler()->GetRenderNode()->SetMinSpec(GetMinSpec());
532 bool DesignerObject::IsSimilarObject(CBaseObject
* pObject
) const
534 if (pObject
->GetClassDesc() == GetClassDesc() && GetRuntimeClass() == pObject
->GetRuntimeClass())
539 void DesignerObject::OnEvent(ObjectEvent event
)
541 CBaseObject::OnEvent(event
);
546 if (CheckFlags(OBJFLAG_SUBOBJ_EDITING
))
547 EndSubObjectSelection();
548 DesignerEditor
* pDesignerTool
= GetDesigner();
549 if (pDesignerTool
&& !GetIEditor()->GetGameEngine()->GetSimulationMode())
550 pDesignerTool
->LeaveCurrentTool();
553 case EVENT_OUTOFGAME
:
555 DesignerEditor
* pDesignerTool
= GetDesigner();
557 pDesignerTool
->EnterCurrentTool();
563 void DesignerObject::WorldToLocalRay(Vec3
& raySrc
, Vec3
& rayDir
) const
565 raySrc
= m_invertTM
.TransformPoint(raySrc
);
566 rayDir
= m_invertTM
.TransformVector(rayDir
).GetNormalized();
569 void DesignerObject::InvalidateTM(int nWhyFlags
)
571 CBaseObject::InvalidateTM(nWhyFlags
);
573 m_invertTM
= GetWorldTM();
577 void DesignerObject::GenerateGameFilename(string
& generatedFileName
) const
579 generatedFileName
.Format("%%level%%/Brush/designer_%d.%s", m_nBrushUniqFileId
, CRY_GEOMETRY_FILE_EXT
);
582 void DesignerObject::DrawDimensions(SDisplayContext
& dc
, AABB
* pMergedBoundBox
)
584 if (!HasMeasurementAxis() || GetDesigner() || !gDesignerSettings
.bDisplayDimensionHelper
)
587 GetLocalBounds(localBoundBox
);
588 DrawDimensionsImpl(dc
, localBoundBox
, pMergedBoundBox
);
591 IRenderNode
* DesignerObject::GetEngineNode() const
593 if (!GetCompiler() || !GetCompiler()->GetRenderNode())
595 return GetCompiler()->GetRenderNode();
598 DesignerObjectFlags::DesignerObjectFlags() : m_pObj(NULL
)
603 supportSecVisArea
= false;
604 rainOccluder
= false;
607 excludeFromTriangulation
= false;
609 noStaticDecals
= false;
610 excludeCollision
= false;
612 ignoreTerrainLayerBlend
= false;
613 ignoreDecalBlend
= false;
616 void DesignerObjectFlags::Set()
618 ratioViewDist
= m_pObj
->GetCompiler()->GetViewDistRatio();
619 uint64 flags
= m_pObj
->GetCompiler()->GetRenderFlags();
620 int statobjFlags
= m_pObj
->GetCompiler()->GetStaticObjFlags();
621 outdoor
= (flags
& ERF_OUTDOORONLY
) != 0;
622 rainOccluder
= (flags
& ERF_RAIN_OCCLUDER
) != 0;
623 castShadows
= (flags
& ERF_CASTSHADOWMAPS
) != 0;
624 giMode
= (flags
& ERF_GI_MODE_BIT0
) != 0;
625 supportSecVisArea
= (flags
& ERF_REGISTER_BY_BBOX
) != 0;
626 occluder
= (flags
& ERF_GOOD_OCCLUDER
) != 0;
627 hideable
= (flags
& ERF_HIDABLE
) != 0;
628 noDynWater
= (flags
& ERF_NODYNWATER
) != 0;
629 noStaticDecals
= (flags
& ERF_NO_DECALNODE_DECALS
) != 0;
630 excludeFromTriangulation
= (flags
& ERF_EXCLUDE_FROM_TRIANGULATION
) != 0;
631 excludeCollision
= (statobjFlags
& STATIC_OBJECT_NO_PLAYER_COLLIDE
) != 0;
632 ignoreTerrainLayerBlend
= (flags
& ERF_FOB_ALLOW_TERRAIN_LAYER_BLEND
) == 0;
633 ignoreDecalBlend
= (flags
& ERF_FOB_ALLOW_DECAL_BLEND
) == 0;
636 void DesignerObjectFlags::Serialize(Serialization::IArchive
& ar
)
638 ar(castShadows
, "castShadows", "Cast Shadows");
639 ar(giMode
, "globalIllumination", "Global Illumination");
640 ar(supportSecVisArea
, "supportSecVisArea", "Support Second Visarea");
641 ar(outdoor
, "outdoor", "Outdoor");
642 ar(rainOccluder
, "rainOccluder", "Rain Occluder");
643 ar(ratioViewDist
, "ratioViewDist", "View Distance Ratio");
644 ar(excludeFromTriangulation
, "excludeFromTriangulation", "Exclude From Navigation");
645 ar(hideable
, "hideable", "AI Hideable");
646 ar(noDynWater
, "noDynWater", "No Dynamic Water");
647 ar(noStaticDecals
, "noStaticDecals", "No Static Decal");
648 ar(excludeCollision
, "excludeCollision", "Exclude Collision");
649 ar(occluder
, "occluder", "Occluder");
650 ar(ignoreTerrainLayerBlend
, "ignoreTerrainLayerBlend", "Ignore Terrain Layer Blending");
651 ar(ignoreDecalBlend
, "ignoreDecalBlend", "Ignore Decal Blending");
657 void ModifyFlag(T
& nFlags
, const T
& flag
, const T
& clearFlag
, bool var
)
659 nFlags
= (var
) ? (nFlags
| flag
) : (nFlags
& (~clearFlag
));
662 void ModifyFlag(T
& nFlags
, const T
& flag
, bool var
)
664 ModifyFlag(nFlags
, flag
, flag
, var
);
667 void DesignerObjectFlags::Update()
669 const uint64 nOldFlags
= m_pObj
->GetCompiler()->GetRenderFlags();
670 uint64 nFlags
= nOldFlags
;
671 int statobjFlags
= m_pObj
->GetCompiler()->GetStaticObjFlags();
673 ModifyFlag
<uint64
>(nFlags
, ERF_OUTDOORONLY
, outdoor
);
674 ModifyFlag
<uint64
>(nFlags
, ERF_RAIN_OCCLUDER
, rainOccluder
);
675 ModifyFlag
<uint64
>(nFlags
, ERF_CASTSHADOWMAPS
| ERF_HAS_CASTSHADOWMAPS
, ERF_CASTSHADOWMAPS
, castShadows
);
676 ModifyFlag
<uint64
>(nFlags
, ERF_GI_MODE_BIT0
, giMode
);
677 ModifyFlag
<uint64
>(nFlags
, ERF_REGISTER_BY_BBOX
, supportSecVisArea
);
678 ModifyFlag
<uint64
>(nFlags
, ERF_HIDABLE
, hideable
);
679 ModifyFlag
<uint64
>(nFlags
, ERF_EXCLUDE_FROM_TRIANGULATION
, excludeFromTriangulation
);
680 ModifyFlag
<uint64
>(nFlags
, ERF_NODYNWATER
, noDynWater
);
681 ModifyFlag
<uint64
>(nFlags
, ERF_NO_DECALNODE_DECALS
, noStaticDecals
);
682 ModifyFlag
<uint64
>(nFlags
, ERF_GOOD_OCCLUDER
, occluder
);
683 ModifyFlag
<uint64
>(nFlags
, ERF_FOB_ALLOW_TERRAIN_LAYER_BLEND
, !ignoreTerrainLayerBlend
);
684 ModifyFlag
<uint64
>(nFlags
, ERF_FOB_ALLOW_DECAL_BLEND
, !ignoreDecalBlend
);
685 ModifyFlag
<int>(statobjFlags
, STATIC_OBJECT_NO_PLAYER_COLLIDE
, excludeCollision
);
687 m_pObj
->GetCompiler()->SetViewDistRatio(ratioViewDist
);
688 m_pObj
->GetCompiler()->SetRenderFlags(nFlags
);
689 m_pObj
->GetCompiler()->SetStaticObjFlags(statobjFlags
);
690 m_pObj
->GetCompiler()->Compile(m_pObj
, m_pObj
->GetModel(), eShelf_Base
, true);
691 ApplyPostProcess(m_pObj
->GetMainContext(), ePostProcess_SyncPrefab
);
693 if ((nOldFlags
& ERF_EXCLUDE_FROM_TRIANGULATION
) != (nFlags
& ERF_EXCLUDE_FROM_TRIANGULATION
))
696 m_pObj
->GetBoundBox(bbox
);
697 GetIEditor()->GetAIManager()->OnAreaModified(bbox
);