Photon Engine 2.0.0-beta
A physically based renderer.
Loading...
Searching...
No Matches
TSdlOwnerClass.ipp
Go to the documentation of this file.
1#pragma once
2
9#include "SDL/sdl_helpers.h"
10#include "SDL/sdl_traits.h"
11
12#include <Common/assertion.h>
13
14#include <type_traits>
15#include <format>
16
17namespace ph
18{
19
20template<typename Owner, typename FieldSet>
22
23 : SdlClass(sdl::category_of<Owner>(), std::move(displayName))
24
25 , m_fields()
26 , m_functions()
27{
28 setIsBlueprint(std::is_abstract_v<Owner>);
29}
30
31template<typename Owner, typename FieldSet>
32inline std::shared_ptr<ISdlResource> TSdlOwnerClass<Owner, FieldSet>::createResource() const
33{
34 if constexpr(!std::is_abstract_v<Owner> && std::is_default_constructible_v<Owner>)
35 {
36 if(!isBlueprint() && allowCreateFromClass())
37 {
38 return std::make_shared<Owner>();
39 }
40 else
41 {
42 return nullptr;
43 }
44 }
45 else
46 {
47 // The resource is abstract and/or not default-constructible, make sure this is intended
48 PH_ASSERT_MSG(isBlueprint() || !allowCreateFromClass(),
49 std::format("Cannot create resource while the SDL definition permits it (is blueprint: {}, "
50 "allow create from class: {})", isBlueprint(), allowCreateFromClass()));
51
52 return nullptr;
53 }
54}
55
56template<typename Owner, typename FieldSet>
58 ISdlResource& resource,
59 SdlInputClauses& clauses,
60 const SdlInputContext& ctx) const
61{
62 // Init base first just like how standard C++ does
63 if(isDerived())
64 {
65 PH_ASSERT(getBase());
66 getBase()->initResource(resource, clauses, ctx);
67 }
68
69 Owner* const ownerResource = castTo<Owner>(&resource);
70 loadFieldsFromSdl(*ownerResource, clauses, ctx);
71}
72
73template<typename Owner, typename FieldSet>
75{
76 // Init base first just like how standard C++ does
77 if(isDerived())
78 {
79 PH_ASSERT(getBase());
80 getBase()->initDefaultResource(resource);
81 }
82
83 Owner* const ownerResource = castTo<Owner>(&resource);
84 setFieldsToDefaults(*ownerResource);
85}
86
87template<typename Owner, typename FieldSet>
89 const ISdlResource& resource,
90 SdlOutputClauses& clauses,
91 const SdlOutputContext& ctx) const
92{
93 // No specific ordering is required here. We save base class first just like how
94 // the loading process is.
95 if(isDerived())
96 {
97 PH_ASSERT(getBase());
98 getBase()->saveResource(resource, clauses, ctx);
99 }
100
101 const Owner* const ownerResource = castTo<const Owner>(&resource);
102 saveFieldsToSdl(*ownerResource, clauses, ctx);
103}
104
105template<typename Owner, typename FieldSet>
107 const std::string_view funcName,
108 ISdlResource* const resource,
109 SdlInputClauses& clauses,
110 const SdlInputContext& ctx) const
111{
112 // Find SDL function by name
113 const SdlFunction* func = nullptr;
114 for(std::size_t funcIdx = 0; funcIdx < m_functions.size(); ++funcIdx)
115 {
116 PH_ASSERT(m_functions[funcIdx]);
117 const SdlFunction& funcI = *(m_functions[funcIdx]);
118 if(funcI.getName() == funcName)
119 {
120 func = &funcI;
121 break;
122 }
123 }
124
125 // If found the function in this class, call it
126 if(func)
127 {
128 func->call(resource, clauses, ctx);
129 }
130 // If not found in this class, call on base class instead
131 else if(getBase())
132 {
133 getBase()->call(funcName, resource, clauses, ctx);
134 }
135 else
136 {
137 throw SdlLoadError(
138 "cannot find SDL function named <" + std::string(funcName) + "> in "
139 "SDL class <" + genPrettyName() + ">");
140 }
141}
142
143template<typename Owner, typename FieldSet>
145 const ISdlResource* const targetResource,
146 std::vector<const ISdlResource*>& out_resources) const
147{
148 static_assert(std::is_base_of_v<ISdlResource, Owner>,
149 "Owner class must derive from ISdlResource.");
150
151 const Owner& owner = *(castTo<const Owner>(targetResource));
152 for(std::size_t fieldIdx = 0; fieldIdx < m_fields.numFields(); ++fieldIdx)
153 {
154 m_fields[fieldIdx].ownedResources(owner, out_resources);
155 }
156
157 // Find more references in base class
158 if(isDerived())
159 {
160 PH_ASSERT(getBase());
161 getBase()->referencedResources(targetResource, out_resources);
162 }
163}
164
165template<typename Owner, typename FieldSet>
167{
168 return m_fields.numFields();
169}
170
171template<typename Owner, typename FieldSet>
172inline const SdlField* TSdlOwnerClass<Owner, FieldSet>::getField(const std::size_t index) const
173{
174 return getOwnedField(index);
175}
176
177template<typename Owner, typename FieldSet>
179{
180 return m_functions.size();
181}
182
183template<typename Owner, typename FieldSet>
184inline const SdlFunction* TSdlOwnerClass<Owner, FieldSet>::getFunction(const std::size_t index) const
185{
186 return index < m_functions.size() ? m_functions[index] : nullptr;
187}
188
189template<typename Owner, typename FieldSet>
191{
192 return m_fields.getField(index);
193}
194
195template<typename Owner, typename FieldSet>
196template<typename SdlFieldType>
197inline auto TSdlOwnerClass<Owner, FieldSet>::addField(SdlFieldType sdlField)
199{
200 // More restrictions on the type of SdlFieldType may be imposed by FieldSet
201 static_assert(std::is_base_of_v<SdlField, SdlFieldType>,
202 "Provided SdlFieldType is not a SdlField thus cannot be added.");
203
204 m_fields.addField(std::move(sdlField));
205
206 return *this;
207}
208
209template<typename Owner, typename FieldSet>
210template<typename StructType>
211inline auto TSdlOwnerClass<Owner, FieldSet>::addStruct(StructType Owner::* const structObjPtr)
213{
214 return addStruct(structObjPtr, SdlStructFieldStump());
215}
216
217template<typename Owner, typename FieldSet>
218template<typename StructType>
220 StructType Owner::* const structObjPtr,
221 const SdlStructFieldStump& structFieldStump)
222
224{
226 "SDL struct definition not found.");
227
228 PH_ASSERT(structObjPtr);
229
230 m_fields.addFields(structFieldStump.genFieldSet(structObjPtr));
231
232 return *this;
233}
234
235template<typename Owner, typename FieldSet>
236template<typename T>
239{
240 static_assert(CHasSdlFunctionDefinition<T>,
241 "SDL function definition not found.");
242
243 m_functions.pushBack(T::getSdlFunction());
244
245 return *this;
246}
247
248template<typename Owner, typename FieldSet>
250 Owner& owner,
251 SdlInputClauses& clauses,
252 const SdlInputContext& ctx) const
253{
254 constexpr auto noticeReceiver = [](std::string noticeMsg, EFieldImportance importance)
255 {
256 if(importance == EFieldImportance::Optional || importance == EFieldImportance::NiceToHave)
257 {
258 PH_LOG_STRING(SdlClass, Note, noticeMsg);
259 }
260 else
261 {
262 PH_LOG_STRING(SdlClass, Warning, noticeMsg);
263 }
264 };
265
266 // If this class is the source class, it should be the most derived class of the current
267 // input process and consume all remaining clauses. Otherwise, redundant clauses are
268 // allowed as subsequent (derived) classes would consume them.
269 //
270 if(ctx.getSrcClass() == this)
271 {
273 owner,
274 m_fields,
275 clauses,
276 ctx,
277 noticeReceiver);
278 }
279 else
280 {
282 owner,
283 m_fields,
284 clauses,
285 ctx,
286 noticeReceiver);
287 }
288}
289
290template<typename Owner, typename FieldSet>
291inline void TSdlOwnerClass<Owner, FieldSet>::setFieldsToDefaults(Owner& owner) const
292{
293 for(std::size_t fieldIdx = 0; fieldIdx < m_fields.numFields(); ++fieldIdx)
294 {
295 const auto& field = m_fields[fieldIdx];
296
297 // Set field to default value regardless of its importance (field importance is for import/export)
298 field.ownedValueToDefault(owner);
299 }
300}
301
302template<typename Owner, typename FieldSet>
304 const Owner& owner,
305 SdlOutputClauses& clauses,
306 const SdlOutputContext& ctx) const
307{
308 for(std::size_t fieldIdx = 0; fieldIdx < m_fields.numFields(); ++fieldIdx)
309 {
310 const TSdlOwnedField<Owner>& field = m_fields[fieldIdx];
311
312 SdlOutputClause& clause = clauses.createClause();
313 sdl::save_field_id(&field, clause);
314 field.toSdl(owner, clause, ctx);
315 }
316}
317
318template<typename Owner, typename FieldSet>
319inline auto TSdlOwnerClass<Owner, FieldSet>::description(std::string descriptionStr)
321{
322 setDescription(std::move(descriptionStr));
323 return *this;
324}
325
326template<typename Owner, typename FieldSet>
327inline auto TSdlOwnerClass<Owner, FieldSet>::docName(std::string docName)
329{
330 setDocName(std::move(docName));
331 return *this;
332}
333
334template<typename Owner, typename FieldSet>
335template<typename T>
338{
339 static_assert(!std::is_same_v<T, Owner>,
340 "A SDL class cannot base on itself.");
341
342 setBase<T>();
343
344 // If base cannot be created from class, the derived should be the same
345 if(getBase() && !getBase()->allowCreateFromClass())
346 {
347 allowCreateFromClass(false);
348 }
349
350 return *this;
351}
352
353template<typename Owner, typename FieldSet>
354auto TSdlOwnerClass<Owner, FieldSet>::allowCreateFromClass(const bool allowCreateFromClass)
356{
357 setAllowCreateFromClass(allowCreateFromClass);
358 return *this;
359}
360
361template<typename Owner, typename FieldSet>
362template<typename DstType, typename SrcType>
363inline DstType* TSdlOwnerClass<Owner, FieldSet>::castTo(SrcType* const srcInstance) const
364{
365 try
366 {
367 return sdl::cast_to<DstType>(srcInstance);
368 }
369 catch(const SdlException& e)
370 {
371 throw_formatted<SdlException>(
372 "input resource is not owned by this class <{}> ({})",
373 genPrettyName(), e.whatStr());
374 }
375}
376
377}// end namespace ph
Interface for all SDL resource.
Definition ISdlResource.h:22
Definition SdlClass.h:25
SdlClass & setIsBlueprint(bool isBlueprint)
Definition SdlClass.cpp:49
Definition SdlField.h:19
Definition SdlFunction.h:18
virtual void call(ISdlResource *resource, SdlInputClauses &clauses, const SdlInputContext &ctx) const =0
std::string_view getName() const
Definition SdlFunction.h:76
const SdlClass * getSrcClass() const
The SDL class that is involved in the I/O process.
Definition SdlIOContext.h:90
Container for input clauses.
Definition SdlInputClauses.h:18
Data that SDL input process can rely on.
Definition SdlInputContext.h:19
Error on the SDL input process.
Definition sdl_exceptions.h:22
Carries SDL representation of various data during the output process. Helps to write output data such...
Definition SdlOutputClause.h:14
Definition SdlOutputClauses.h:14
SdlOutputClause & createClause()
Definition SdlOutputClauses.h:34
Data that SDL output process can rely on.
Definition SdlOutputContext.h:19
Definition SdlStructFieldStump.h:12
Abstraction for a value that is owned by some owner type. Governs how a field should be initialized o...
Definition TSdlOwnedField.h:15
void toSdl(const Owner &owner, SdlOutputClause &out_clause, const SdlOutputContext &ctx) const
Definition TSdlOwnedField.ipp:101
SDL binding type for a canonical SDL resource class.
Definition TSdlOwnerClass.h:23
void initDefaultResource(ISdlResource &resource) const override
Initialize a resource to default values. Default values are defined by the resource class's SDL defin...
Definition TSdlOwnerClass.ipp:74
const TSdlOwnedField< Owner > * getOwnedField(std::size_t index) const
Definition TSdlOwnerClass.ipp:190
void referencedResources(const ISdlResource *targetResource, std::vector< const ISdlResource * > &out_resources) const override
Get all SDL resources referenced by targetResource.
Definition TSdlOwnerClass.ipp:144
auto docName(std::string docName) -> TSdlOwnerClass &
Definition TSdlOwnerClass.ipp:327
std::shared_ptr< ISdlResource > createResource() const override
Definition TSdlOwnerClass.ipp:32
TSdlOwnerClass & addStruct(StructType Owner::*structObjPtr)
void saveFieldsToSdl(const Owner &owner, SdlOutputClauses &clauses, const SdlOutputContext &ctx) const
Definition TSdlOwnerClass.ipp:303
void loadFieldsFromSdl(Owner &owner, SdlInputClauses &clauses, const SdlInputContext &ctx) const
Definition TSdlOwnerClass.ipp:249
void initResource(ISdlResource &resource, SdlInputClauses &clauses, const SdlInputContext &ctx) const override
Initialize a resource from value clauses. How the resource will be initialized depends on the resourc...
Definition TSdlOwnerClass.ipp:57
TSdlOwnerClass(std::string displayName)
Definition TSdlOwnerClass.ipp:21
bool allowCreateFromClass() const
Whether a resource can be created by calling createResource(). This attribute is useful to decide whe...
Definition SdlClass.h:138
const SdlField * getField(std::size_t index) const override
Definition TSdlOwnerClass.ipp:172
void call(std::string_view funcName, ISdlResource *resource, SdlInputClauses &clauses, const SdlInputContext &ctx) const override
Definition TSdlOwnerClass.ipp:106
auto description(std::string descriptionStr) -> TSdlOwnerClass &
Definition TSdlOwnerClass.ipp:319
TSdlOwnerClass & addField(SdlFieldType sdlField)
auto baseOn() -> TSdlOwnerClass &
Set another SDL class as the base of this class.
Definition TSdlOwnerClass.ipp:336
TSdlOwnerClass & addFunction()
Adds a function that can later be called.
std::size_t numFields() const override
Definition TSdlOwnerClass.ipp:166
void saveResource(const ISdlResource &resource, SdlOutputClauses &clauses, const SdlOutputContext &ctx) const override
Definition TSdlOwnerClass.ipp:88
const SdlFunction * getFunction(std::size_t index) const override
Definition TSdlOwnerClass.ipp:184
std::size_t numFunctions() const override
Definition TSdlOwnerClass.ipp:178
Whether T is a well-defined SDL function.
Definition sdl_traits.h:42
Whether T is a well-defined SDL struct.
Definition sdl_traits.h:36
void load_fields_from_sdl(Owner &owner, FieldSet &fieldSet, SdlInputClauses &clauses, const SdlInputContext &ctx, NoticeReceiver noticeReceiver=NoOpNoticeReceiver())
Definition field_set_op.ipp:21
void load_fields_from_sdl_with_redundant_clauses(Owner &owner, FieldSet &fieldSet, SdlInputClauses &clauses, const SdlInputContext &ctx, NoticeReceiver noticeReceiver=NoOpNoticeReceiver())
Definition field_set_op.ipp:110
DstType * cast_to(SrcType *srcResource)
Cast between SDL resource types. Cast the input SDL resource instance of SrcType to an instance of Ds...
Definition sdl_helpers.ipp:549
void save_field_id(const SdlField *const sdlField, SdlOutputClause &clause)
Save the identity of the field to output clause.
Definition sdl_helpers.cpp:16
The root for all renderer implementations.
Definition EEngineProject.h:6
EFieldImportance
Definition EFieldImportance.h:7
Definition TAABB2D.h:96
Low-level helpers for SDL. Helpers are in an additional sdl namespace.