Photon Editor Library 2.0.0-beta
A physically based renderer.
Loading...
Searching...
No Matches
DesignerScene.ipp
Go to the documentation of this file.
1#pragma once
2
6
7#include <Utility/traits.h>
8#include <Common/assertion.h>
9#include <Common/exceptions.h>
10#include <Common/logging.h>
11#include <SDL/sdl_helpers.h>
12
13#include <utility>
14#include <type_traits>
15
16namespace ph::editor
17{
18
19namespace detail
20{
21
22template<typename ObjectType>
24{
25 inline void operator () (ObjectType* const obj) const
26 {
27 static_assert(CDerived<ObjectType, DesignerObject>,
28 "Object must be a designer object.");
29
30 if(!obj)
31 {
32 return;
33 }
34
35 obj->getScene().deleteObject(obj);
36 }
37};
38
39}// end namespace detail
40
42{
43 return "untitled scene";
44}
45
46template<typename ObjectType>
47inline ObjectType* DesignerScene::newObject(
48 const bool shouldInit,
49 const bool shouldSetToDefault)
50{
52 ObjectType::getSdlClass(),
53 shouldInit,
54 shouldSetToDefault);
55
56 // We know the exact type
57 return static_cast<ObjectType*>(obj);
58}
59
60template<typename ObjectType>
62 const bool shouldInit,
63 const bool shouldSetToDefault)
64{
66 ObjectType::getSdlClass(),
67 shouldInit,
68 shouldSetToDefault);
69
70 // We know the exact type
71 return static_cast<ObjectType*>(obj);
72}
73
74template<typename ObjectType>
75inline std::shared_ptr<ObjectType> DesignerScene::newSharedRootObject(
76 const bool shouldInit,
77 const bool shouldSetToDefault)
78{
79 std::shared_ptr<ObjectType> rootObj = newSharedRootObject(
80 ObjectType::getSdlClass(),
81 shouldInit,
82 shouldSetToDefault);
83
84 return std::static_pointer_cast<ObjectType>(std::move(rootObj));
85}
86
87template<typename ObjectType, typename... DeducedArgs>
88inline ObjectType* DesignerScene::makeObjectFromStorage(DeducedArgs&&... args)
89{
90 static_assert(CDerived<ObjectType, DesignerObject>,
91 "Object must be a designer object.");
92
93 PH_ASSERT(Threads::isOnMainThread());
94
95 if(isPaused())
96 {
97 // This is a condition that should be investigated (API misuse)
98 PH_ASSERT_MSG(false,
99 "Cannot create object when paused--this may modify object storage.");
100 return nullptr;
101 }
102
103 auto storageIndex = static_cast<uint64>(-1);
104
105 // Create new storage space
106 if(m_freeObjStorageIndices.empty())
107 {
108 m_objStorage.add<ObjectType>(nullptr);
109 storageIndex = m_objStorage.size() - 1;
110 }
111 // Use existing storage space
112 else
113 {
114 storageIndex = m_freeObjStorageIndices.back();
115 m_freeObjStorageIndices.pop_back();
116 }
117
118 auto uniqueObj = std::make_unique<ObjectType>(std::forward<DeducedArgs>(args)...);
119 ObjectType* obj = uniqueObj.get();
120 m_objStorage.getUniquePtr(storageIndex) = std::move(uniqueObj);
121
122 PH_ASSERT(obj != nullptr);
123 obj->setSceneStorageIndex(storageIndex);
124 return obj;
125}
126
127template<typename ObjectType>
129{
130 static_assert(CDerived<ObjectType, DesignerObject>,
131 "Object must be a designer object.");
132
133 const SdlClass* const clazz = ObjectType::getSdlClass();
134 if(classToObjMaker.find(clazz) != classToObjMaker.end())
135 {
136 PH_LOG(DesignerScene, Error,
137 "designer object already registered ({})",
138 sdl::gen_pretty_name(clazz));
139
140 return;
141 }
142
143 classToObjMaker[clazz] =
144 [](DesignerScene& scene) -> DesignerObject*
145 {
146 if constexpr(std::is_abstract_v<ObjectType>)
147 {
148 PH_ASSERT_MSG(false,
149 "Attempting to create object of an abstract type.");
150 return nullptr;
151 }
152 else
153 {
154 return scene.makeObjectFromStorage<ObjectType>();
155 }
156 };
157}
158
159inline bool DesignerScene::removeObjectFromStorage(DesignerObject* const obj)
160{
161 if(isPaused())
162 {
163 // This is a condition that should be investigated (API misuse)
164 PH_ASSERT_MSG(false,
165 "Cannot remove object when paused--this may modify object storage.");
166
167 return false;
168 }
169
170 if(!obj || &(obj->getScene()) != this || obj->getSceneStorageIndex() == static_cast<uint64>(-1))
171 {
172 return false;
173 }
174
175 const auto objIndex = obj->getSceneStorageIndex();
176 PH_ASSERT(obj == m_objStorage[objIndex]);
177 m_objStorage.getUniquePtr(objIndex) = nullptr;
178 m_freeObjStorageIndices.push_back(objIndex);
179
180 return true;
181}
182
188
190{
191 return obj.getState().has(EObjectState::HasInitialized) &&
193}
194
195inline bool DesignerScene::isOrphan(const DesignerObject& obj)
196{
197 const bool isChild = obj.getState().hasNo(EObjectState::Root);
198 const bool hasParent = obj.getParent() != nullptr;
199
200 return isChild && !hasParent;
201}
202
204{
205 PH_ASSERT(m_editor);
206 return *m_editor;
207}
208
209inline const Editor& DesignerScene::getEditor() const
210{
211 PH_ASSERT(m_editor);
212 return *m_editor;
213}
214
216{
217 PH_ASSERT(Threads::isOnMainThread());// do not let the word "render" fool you
218 PH_ASSERT_MSG(m_rendererScene,
219 "Please make sure you are calling from render command generating methods.");
220
221 return *m_rendererScene;
222}
223
225{
226 PH_ASSERT(Threads::isOnMainThread());// do not let the word "render" fool you
227 PH_ASSERT_MSG(m_rendererScene,
228 "Please make sure you are calling from render command generating methods.");
229
230 return *m_rendererScene;
231}
232
234{
235 return m_selectedObjs.empty() ? nullptr : m_selectedObjs.front();
236}
237
238inline TSpanView<DesignerObject*> DesignerScene::getSelection() const
239{
240 return m_selectedObjs;
241}
242
243inline bool DesignerScene::SceneAction::isDone() const
244{
245 return !updateTask && !renderTask;
246}
247
248inline const Path& DesignerScene::getWorkingDirectory() const
249{
250 return m_workingDirectory;
251}
252
253inline TSpanView<DesignerRendererBinding> DesignerScene::getRendererBindings() const
254{
255 return m_rendererBindings;
256}
257
258inline const std::string& DesignerScene::getName() const
259{
260 return m_name;
261}
262
263inline SceneDescription& DesignerScene::getRenderDescription()
264{
265 return m_renderDescription;
266}
267
268inline const SceneDescription& DesignerScene::getRenderDescription() const
269{
270 return m_renderDescription;
271}
272
273inline const ResourceIdentifier& DesignerScene::getRenderDescriptionLink() const
274{
275 return m_renderDescriptionLink;
276}
277
278inline void DesignerScene::setRenderDescriptionLink(ResourceIdentifier link)
279{
280 m_renderDescriptionLink = std::move(link);
281}
282
283inline TSpanView<DesignerObject*> DesignerScene::getRootObjects() const
284{
285 return m_rootObjs;
286}
287
288inline bool DesignerScene::isPaused() const
289{
290 return m_isPaused;
291}
292
293template<typename ObjectType>
294inline ObjectType* DesignerScene::findObjectByName(std::string_view name) const
295{
296 ObjectType* result = nullptr;
297
299 [name, &result](DesignerObject* obj) -> bool
300 {
301 // Implicit cast if `ObjectType` is a base type
302 if constexpr(CDerived<DesignerObject, ObjectType>)
303 {
304 if(obj->getName() == name)
305 {
306 result = obj;
307 return false;
308 }
309 }
310 // Otherwise explicit downcasting is required
311 else
312 {
313 static_assert(CDerived<ObjectType, DesignerObject>,
314 "Object must be a designer object.");
315
316 if(obj->getName() == name)
317 {
318 // Directly use the result of `dynamic_cast`. This can be null if the type does
319 // not match--which is fine, as the object name is unique (and we already found the
320 // object) there is no point in continuing the search.
321 result = dynamic_cast<ObjectType*>(obj);
322 return false;
323 }
324 }
325
326 return true;
327 });
328
329 return result;
330}
331
332template<typename ObjectType>
333inline void DesignerScene::findObjectsByType(std::vector<ObjectType*>& out_objs) const
334{
335 out_objs.reserve(out_objs.size() + m_objStorage.size());
336
338 [&out_objs](DesignerObject* obj) -> bool
339 {
340 // Implicit cast if `ObjectType` is a base type
341 if constexpr(CDerived<DesignerObject, ObjectType>)
342 {
343 out_objs.push_back(obj);
344 }
345 // Otherwise explicit downcasting is required
346 else
347 {
348 static_assert(CDerived<ObjectType, DesignerObject>,
349 "Object must be a designer object.");
350
351 auto const derivedObj = dynamic_cast<ObjectType*>(obj);
352 if(derivedObj)
353 {
354 out_objs.push_back(derivedObj);
355 }
356 }
357
358 // Always continue
359 return true;
360 });
361}
362
363template<typename PerObjectOperation>
364inline void DesignerScene::forEachUsableObject(PerObjectOperation op) const
365{
366 static_assert(std::is_invocable_r_v<bool, PerObjectOperation, DesignerObject*>);
367
368 PH_ASSERT(Threads::isOnMainThread());
369
370 for(auto& objRes : m_objStorage)
371 {
372 DesignerObject* const obj = objRes.get();
373
374 // Skip removed object
375 if(!obj)
376 {
377 continue;
378 }
379
380 // Skip object with incomplete initialization state (we do not care about render state here)
381 if(!isInitialized(*obj))
382 {
383 continue;
384 }
385
386 // Skip orphans
387 if(isOrphan(*obj))
388 {
389 continue;
390 }
391
392 const bool shouldContinue = op(obj);
393 if(!shouldContinue)
394 {
395 break;
396 }
397 }
398}
399
400inline std::size_t DesignerScene::numRootObjects() const
401{
402 return m_rootObjs.size();
403}
404
405inline std::size_t DesignerScene::numTickingObjects() const
406{
407 return m_tickingObjs.size();
408}
409
411{
412 return m_renderTickingObjs.size();
413}
414
415inline std::size_t DesignerScene::numAllocatedObjects() const
416{
417 return m_objStorage.size();
418}
419
420}// end namespace ph::editor
const TEnumFlags< EObjectState > & getState() const
Definition AbstractDesignerObject.ipp:10
Definition DesignerObject.h:31
DesignerScene & getScene()
Definition DesignerObject.cpp:287
DesignerObject * getParent()
Definition DesignerObject.cpp:309
const std::string & getName() const
Definition DesignerObject.ipp:66
Definition DesignerScene.h:58
void findObjectsByType(std::vector< ObjectType * > &out_objs) const
Find usable objects of a matching type.
Definition DesignerScene.ipp:333
Editor & getEditor()
Definition DesignerScene.ipp:203
static bool isInitialized(const DesignerObject &obj)
Definition DesignerScene.ipp:189
static void registerObjectType()
Definition DesignerScene.ipp:128
void setRenderDescriptionLink(ResourceIdentifier link)
Definition DesignerScene.ipp:278
const ResourceIdentifier & getRenderDescriptionLink() const
Definition DesignerScene.ipp:273
DesignerObject * getPrimarySelectedObject() const
Definition DesignerScene.ipp:233
std::size_t numRenderTickingObjects() const
Definition DesignerScene.ipp:410
ObjectType * newObject(bool shouldInit=true, bool shouldSetToDefault=true)
Create a new object.
Definition DesignerScene.ipp:47
TSpanView< DesignerRendererBinding > getRendererBindings() const
Definition DesignerScene.ipp:253
ObjectType * findObjectByName(std::string_view name) const
Find a usable object with the specified name.
Definition DesignerScene.ipp:294
render::Scene & getRendererScene()
Definition DesignerScene.ipp:215
const Path & getWorkingDirectory() const
Definition DesignerScene.ipp:248
static const char * defaultSceneName()
Definition DesignerScene.ipp:41
std::size_t numAllocatedObjects() const
Definition DesignerScene.ipp:415
std::shared_ptr< ObjectType > newSharedRootObject(bool shouldInit=true, bool shouldSetToDefault=true)
Create root object with automatic lifetime management. The root object will delete itself once the sh...
Definition DesignerScene.ipp:75
TSpanView< DesignerObject * > getSelection() const
Definition DesignerScene.ipp:238
bool isPaused() const
Whether the scene is pausing. When the scene is pausing, object and scene states should not be modifi...
Definition DesignerScene.ipp:288
std::size_t numTickingObjects() const
Definition DesignerScene.ipp:405
static bool isFullyInitialized(const DesignerObject &obj)
Definition DesignerScene.ipp:183
TSpanView< DesignerObject * > getRootObjects() const
Definition DesignerScene.ipp:283
void forEachUsableObject(PerObjectOperation op) const
Definition DesignerScene.ipp:364
std::size_t numRootObjects() const
Definition DesignerScene.ipp:400
ObjectType * newRootObject(bool shouldInit=true, bool shouldSetToDefault=true)
Create a new root object.
Definition DesignerScene.ipp:61
SceneDescription & getRenderDescription()
Definition DesignerScene.ipp:263
const std::string & getName() const
Definition DesignerScene.ipp:258
Definition Editor.h:45
static bool isOnMainThread()
Whether current thread is the thread that called main().
Definition Threads.h:47
A scene for the editor renderer only.
Definition Scene.h:34
Definition ph_editor.h:10
Definition DesignerScene.ipp:24
void operator()(ObjectType *const obj) const
Definition DesignerScene.ipp:25