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 "Scene/BsPrefab.h" |
4 | #include "Private/RTTI/BsPrefabRTTI.h" |
5 | #include "Resources/BsResources.h" |
6 | #include "Scene/BsSceneObject.h" |
7 | #include "Scene/BsPrefabUtility.h" |
8 | #include "BsCoreApplication.h" |
9 | |
10 | namespace bs |
11 | { |
12 | Prefab::Prefab() |
13 | :Resource(false) |
14 | { |
15 | |
16 | } |
17 | |
18 | Prefab::~Prefab() |
19 | { |
20 | if (mRoot != nullptr) |
21 | mRoot->destroy(true); |
22 | } |
23 | |
24 | HPrefab Prefab::create(const HSceneObject& sceneObject, bool isScene) |
25 | { |
26 | SPtr<Prefab> newPrefab = createEmpty(); |
27 | newPrefab->mIsScene = isScene; |
28 | |
29 | PrefabUtility::clearPrefabIds(sceneObject, true, false); |
30 | newPrefab->initialize(sceneObject); |
31 | |
32 | HPrefab handle = static_resource_cast<Prefab>(gResources()._createResourceHandle(newPrefab)); |
33 | newPrefab->mUUID = handle.getUUID(); |
34 | sceneObject->mPrefabLinkUUID = newPrefab->mUUID; |
35 | newPrefab->_getRoot()->mPrefabLinkUUID = newPrefab->mUUID; |
36 | |
37 | return handle; |
38 | } |
39 | |
40 | SPtr<Prefab> Prefab::createEmpty() |
41 | { |
42 | SPtr<Prefab> newPrefab = bs_core_ptr<Prefab>(new (bs_alloc<Prefab>()) Prefab()); |
43 | newPrefab->_setThisPtr(newPrefab); |
44 | |
45 | return newPrefab; |
46 | } |
47 | |
48 | void Prefab::initialize(const HSceneObject& sceneObject) |
49 | { |
50 | sceneObject->mPrefabDiff = nullptr; |
51 | PrefabUtility::generatePrefabIds(sceneObject); |
52 | |
53 | // If there are any child prefab instances, make sure to update their diffs so they are saved with this prefab |
54 | Stack<HSceneObject> todo; |
55 | todo.push(sceneObject); |
56 | |
57 | while (!todo.empty()) |
58 | { |
59 | HSceneObject current = todo.top(); |
60 | todo.pop(); |
61 | |
62 | UINT32 childCount = current->getNumChildren(); |
63 | for (UINT32 i = 0; i < childCount; i++) |
64 | { |
65 | HSceneObject child = current->getChild(i); |
66 | |
67 | if (!child->mPrefabLinkUUID.empty()) |
68 | PrefabUtility::recordPrefabDiff(child); |
69 | else |
70 | todo.push(child); |
71 | } |
72 | } |
73 | |
74 | // Clone the hierarchy for internal storage |
75 | if (mRoot != nullptr) |
76 | mRoot->destroy(true); |
77 | |
78 | mRoot = sceneObject->clone(false, true); |
79 | mRoot->mParent = nullptr; |
80 | mRoot->mLinkId = -1; |
81 | |
82 | // Remove objects with "dont save" flag |
83 | todo.push(mRoot); |
84 | |
85 | while (!todo.empty()) |
86 | { |
87 | HSceneObject current = todo.top(); |
88 | todo.pop(); |
89 | |
90 | if (current->hasFlag(SOF_DontSave)) |
91 | current->destroy(); |
92 | else |
93 | { |
94 | UINT32 numChildren = current->getNumChildren(); |
95 | for (UINT32 i = 0; i < numChildren; i++) |
96 | todo.push(current->getChild(i)); |
97 | } |
98 | } |
99 | } |
100 | |
101 | void Prefab::update(const HSceneObject& sceneObject) |
102 | { |
103 | initialize(sceneObject); |
104 | sceneObject->mPrefabLinkUUID = mUUID; |
105 | mRoot->mPrefabLinkUUID = mUUID; |
106 | |
107 | mHash++; |
108 | } |
109 | |
110 | void Prefab::_updateChildInstances() const |
111 | { |
112 | Stack<HSceneObject> todo; |
113 | todo.push(mRoot); |
114 | |
115 | while (!todo.empty()) |
116 | { |
117 | HSceneObject current = todo.top(); |
118 | todo.pop(); |
119 | |
120 | UINT32 childCount = current->getNumChildren(); |
121 | for (UINT32 i = 0; i < childCount; i++) |
122 | { |
123 | HSceneObject child = current->getChild(i); |
124 | |
125 | if (!child->mPrefabLinkUUID.empty()) |
126 | PrefabUtility::updateFromPrefab(child); |
127 | else |
128 | todo.push(child); |
129 | } |
130 | } |
131 | } |
132 | |
133 | HSceneObject Prefab::_instantiate(bool preserveUUIDs) const |
134 | { |
135 | if (mRoot == nullptr) |
136 | return HSceneObject(); |
137 | |
138 | #if BS_IS_BANSHEE3D |
139 | if (gCoreApplication().isEditor()) |
140 | { |
141 | // Update any child prefab instances in case their prefabs changed |
142 | _updateChildInstances(); |
143 | } |
144 | #endif |
145 | |
146 | HSceneObject clone = _clone(preserveUUIDs); |
147 | clone->_instantiate(); |
148 | |
149 | return clone; |
150 | } |
151 | |
152 | HSceneObject Prefab::_clone(bool preserveUUIDs) const |
153 | { |
154 | if (mRoot == nullptr) |
155 | return HSceneObject(); |
156 | |
157 | mRoot->mPrefabHash = mHash; |
158 | mRoot->mLinkId = -1; |
159 | |
160 | return mRoot->clone(false, preserveUUIDs); |
161 | } |
162 | |
163 | RTTITypeBase* Prefab::getRTTIStatic() |
164 | { |
165 | return PrefabRTTI::instance(); |
166 | } |
167 | |
168 | RTTITypeBase* Prefab::getRTTI() const |
169 | { |
170 | return Prefab::getRTTIStatic(); |
171 | } |
172 | } |