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 | |
7 | namespace 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 | } |