1//************************************ bs::framework - Copyright 2018 Marko Pintera **************************************//
2//*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********//
3#include "Utility/BsUtility.h"
4#include "Reflection/BsRTTIType.h"
5#include "Scene/BsSceneObject.h"
6
7namespace bs
8{
9 /**
10 * Checks if the specified type (or any of its derived classes) have any IReflectable pointer or value types as
11 * their fields.
12 */
13 bool hasReflectableChildren(RTTITypeBase* type)
14 {
15 UINT32 numFields = type->getNumFields();
16 for (UINT32 i = 0; i < numFields; i++)
17 {
18 RTTIField* field = type->getField(i);
19 if (field->isReflectableType() || field->isReflectablePtrType())
20 return true;
21 }
22
23 const Vector<RTTITypeBase*>& derivedClasses = type->getDerivedClasses();
24 for (auto& derivedClass : derivedClasses)
25 {
26 numFields = derivedClass->getNumFields();
27 for (UINT32 i = 0; i < numFields; i++)
28 {
29 RTTIField* field = derivedClass->getField(i);
30 if (field->isReflectableType() || field->isReflectablePtrType())
31 return true;
32 }
33 }
34
35 return false;
36 }
37
38 void findResourceDependenciesInternal(IReflectable& obj, FrameAlloc& alloc, bool recursive,
39 Map<UUID, ResourceDependency>& dependencies)
40 {
41 RTTITypeBase* rtti = obj.getRTTI();
42 do {
43 RTTITypeBase* rttiInstance = rtti->_clone(alloc);
44 rttiInstance->onSerializationStarted(&obj, nullptr);
45
46 const UINT32 numFields = rtti->getNumFields();
47 for (UINT32 i = 0; i < numFields; i++)
48 {
49 RTTIField* field = rtti->getField(i);
50 if (field->getInfo().flags.isSet(RTTIFieldFlag::SkipInReferenceSearch))
51 continue;
52
53 if (field->isReflectableType())
54 {
55 auto reflectableField = static_cast<RTTIReflectableFieldBase*>(field);
56
57 if (reflectableField->getType()->getRTTIId() == TID_ResourceHandle)
58 {
59 if (reflectableField->isArray())
60 {
61 const UINT32 numElements = reflectableField->getArraySize(rttiInstance, &obj);
62 for (UINT32 j = 0; j < numElements; j++)
63 {
64 HResource resource = (HResource&)reflectableField->getArrayValue(rttiInstance, &obj, j);
65 if (!resource.getUUID().empty())
66 {
67 ResourceDependency& dependency = dependencies[resource.getUUID()];
68 dependency.resource = resource;
69 dependency.numReferences++;
70 }
71 }
72 }
73 else
74 {
75 HResource resource = (HResource&)reflectableField->getValue(rttiInstance, &obj);
76 if (!resource.getUUID().empty())
77 {
78 ResourceDependency& dependency = dependencies[resource.getUUID()];
79 dependency.resource = resource;
80 dependency.numReferences++;
81 }
82 }
83 }
84 else if (recursive)
85 {
86 // Optimization, no need to retrieve its value and go deeper if it has no
87 // reflectable children that may hold the reference.
88 if (hasReflectableChildren(reflectableField->getType()))
89 {
90 if (reflectableField->isArray())
91 {
92 const UINT32 numElements = reflectableField->getArraySize(rttiInstance, &obj);
93 for (UINT32 j = 0; j < numElements; j++)
94 {
95 IReflectable& childObj = reflectableField->getArrayValue(rttiInstance, &obj, j);
96 findResourceDependenciesInternal(childObj, alloc, true, dependencies);
97 }
98 }
99 else
100 {
101 IReflectable& childObj = reflectableField->getValue(rttiInstance, &obj);
102 findResourceDependenciesInternal(childObj, alloc, true, dependencies);
103 }
104 }
105 }
106 }
107 else if (field->isReflectablePtrType() && recursive)
108 {
109 auto reflectablePtrField = static_cast<RTTIReflectablePtrFieldBase*>(field);
110
111 // Optimization, no need to retrieve its value and go deeper if it has no
112 // reflectable children that may hold the reference.
113 if (hasReflectableChildren(reflectablePtrField->getType()))
114 {
115 if (reflectablePtrField->isArray())
116 {
117 const UINT32 numElements = reflectablePtrField->getArraySize(rttiInstance, &obj);
118 for (UINT32 j = 0; j < numElements; j++)
119 {
120 const SPtr<IReflectable>& childObj =
121 reflectablePtrField->getArrayValue(rttiInstance, &obj, j);
122
123 if (childObj != nullptr)
124 findResourceDependenciesInternal(*childObj, alloc, true, dependencies);
125 }
126 }
127 else
128 {
129 const SPtr<IReflectable>& childObj = reflectablePtrField->getValue(rttiInstance, &obj);
130
131 if (childObj != nullptr)
132 findResourceDependenciesInternal(*childObj, alloc, true, dependencies);
133 }
134 }
135 }
136 }
137
138 rttiInstance->onSerializationEnded(&obj, nullptr);
139 alloc.destruct(rttiInstance);
140
141 rtti = rtti->getBaseClass();
142 } while(rtti != nullptr);
143 }
144
145 Vector<ResourceDependency> Utility::findResourceDependencies(IReflectable& obj, bool recursive)
146 {
147 gFrameAlloc().markFrame();
148
149 Map<UUID, ResourceDependency> dependencies;
150 findResourceDependenciesInternal(obj, gFrameAlloc(), recursive, dependencies);
151
152 gFrameAlloc().clear();
153
154 Vector<ResourceDependency> dependencyList(dependencies.size());
155 UINT32 i = 0;
156 for (auto& entry : dependencies)
157 {
158 dependencyList[i] = entry.second;
159 i++;
160 }
161
162 return dependencyList;
163 }
164
165 UINT32 Utility::getSceneObjectDepth(const HSceneObject& so)
166 {
167 HSceneObject parent = so->getParent();
168
169 UINT32 depth = 0;
170 while (parent != nullptr)
171 {
172 depth++;
173 parent = parent->getParent();
174 }
175
176 return depth;
177 }
178
179 Vector<HComponent> Utility::findComponents(const HSceneObject& object, UINT32 typeId)
180 {
181 Vector<HComponent> output;
182
183 Stack<HSceneObject> todo;
184 todo.push(object);
185
186 while(!todo.empty())
187 {
188 HSceneObject curSO = todo.top();
189 todo.pop();
190
191 const Vector<HComponent>& components = curSO->getComponents();
192 for(auto& entry : components)
193 {
194 if (entry->getRTTI()->getRTTIId() == typeId)
195 output.push_back(entry);
196 }
197
198 UINT32 numChildren = curSO->getNumChildren();
199 for (UINT32 i = 0; i < numChildren; i++)
200 todo.push(curSO->getChild(i));
201 }
202
203 return output;
204 }
205
206 class CoreSerializationContextRTTI :
207 public RTTIType<CoreSerializationContext, SerializationContext, CoreSerializationContextRTTI>
208 {
209 const String& getRTTIName() override
210 {
211 static String name = "CoreSerializationContext";
212 return name;
213 }
214
215 UINT32 getRTTIId() override
216 {
217 return TID_CoreSerializationContext;
218 }
219
220 SPtr<IReflectable> newRTTIObject() override
221 {
222 BS_EXCEPT(InternalErrorException, "Cannot instantiate an abstract class.");
223 return nullptr;
224 }
225 };
226
227 RTTITypeBase* CoreSerializationContext::getRTTIStatic()
228 {
229 return CoreSerializationContextRTTI::instance();
230 }
231
232 RTTITypeBase* CoreSerializationContext::getRTTI() const
233 {
234 return getRTTIStatic();
235 }
236
237}