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 "Renderer/BsDecal.h"
4#include "Private/RTTI/BsDecalRTTI.h"
5#include "Scene/BsSceneObject.h"
6#include "Renderer/BsRenderer.h"
7#include "Material/BsMaterial.h"
8#include "CoreThread/BsCoreObjectSync.h"
9
10namespace bs
11{
12 DecalBase::DecalBase()
13 {
14 updateBounds();
15 }
16
17 DecalBase::DecalBase(const Vector2& size, float maxDistance)
18 : mSize(size), mMaxDistance(maxDistance)
19 {
20 updateBounds();
21 }
22
23 void DecalBase::setLayer(UINT64 layer)
24 {
25 const bool isPow2 = layer && !((layer - 1) & layer);
26
27 if (!isPow2)
28 {
29 LOGWRN("Invalid layer provided. Only one layer bit may be set. Ignoring.");
30 return;
31 }
32
33 mLayer = layer;
34 _markCoreDirty();
35 }
36
37 void DecalBase::setTransform(const Transform& transform)
38 {
39 if (mMobility != ObjectMobility::Movable)
40 return;
41
42 mTransform = transform;
43 mTfrmMatrix = transform.getMatrix();
44 mTfrmMatrixNoScale = Matrix4::TRS(transform.getPosition(), transform.getRotation(), Vector3::ONE);
45
46 _markCoreDirty(ActorDirtyFlag::Transform);
47 }
48
49 void DecalBase::updateBounds()
50 {
51 const Vector2& extents = mSize * 0.5f;
52
53 AABox localAABB(
54 Vector3(-extents.x, -extents.y, -mMaxDistance),
55 Vector3(extents.x, extents.y, 0.0f)
56 );
57
58 localAABB.transformAffine(mTfrmMatrix);
59
60 mBounds = Bounds(localAABB, Sphere(localAABB.getCenter(), localAABB.getRadius()));
61 }
62
63 template <bool Core>
64 template <class P>
65 void TDecal<Core>::rttiEnumFields(P p)
66 {
67 p(mSize);
68 p(mMaxDistance);
69 p(mMaterial);
70 p(mBounds);
71 p(mLayer);
72 p(mLayerMask);
73 }
74
75 Decal::Decal(const HMaterial& material, const Vector2& size, float maxDistance)
76 :TDecal(material, size, maxDistance)
77 {
78 // Calling virtual method is okay here because this is the most derived type
79 updateBounds();
80 }
81
82 SPtr<ct::Decal> Decal::getCore() const
83 {
84 return std::static_pointer_cast<ct::Decal>(mCoreSpecific);
85 }
86
87 SPtr<Decal> Decal::create(const HMaterial& material, const Vector2& size, float maxDistance)
88 {
89 Decal* decal = new (bs_alloc<Decal>()) Decal(material, size, maxDistance);
90 SPtr<Decal> decalPtr = bs_core_ptr<Decal>(decal);
91 decalPtr->_setThisPtr(decalPtr);
92 decalPtr->initialize();
93
94 return decalPtr;
95 }
96
97 SPtr<Decal> Decal::createEmpty()
98 {
99 Decal* decal = new (bs_alloc<Decal>()) Decal();
100 SPtr<Decal> decalPtr = bs_core_ptr<Decal>(decal);
101 decalPtr->_setThisPtr(decalPtr);
102
103 return decalPtr;
104 }
105
106 SPtr<ct::CoreObject> Decal::createCore() const
107 {
108 SPtr<ct::Material> material;
109 if(mMaterial.isLoaded(false))
110 material = mMaterial->getCore();
111
112 ct::Decal* decal = new (bs_alloc<ct::Decal>()) ct::Decal(material, mSize, mMaxDistance);
113 SPtr<ct::Decal> decalPtr = bs_shared_ptr<ct::Decal>(decal);
114 decalPtr->_setThisPtr(decalPtr);
115
116 return decalPtr;
117 }
118
119 void Decal::getCoreDependencies(Vector<CoreObject*>& dependencies)
120 {
121 if (mMaterial.isLoaded())
122 dependencies.push_back(mMaterial.get());
123 }
124
125 CoreSyncData Decal::syncToCore(FrameAlloc* allocator)
126 {
127 UINT32 size = 0;
128 size += rttiGetElemSize(getCoreDirtyFlags());
129 size += coreSyncGetElemSize((SceneActor&)*this);
130 size += coreSyncGetElemSize(*this);
131
132 UINT8* buffer = allocator->alloc(size);
133
134 char* dataPtr = (char*)buffer;
135 dataPtr = rttiWriteElem(getCoreDirtyFlags(), dataPtr);
136 dataPtr = coreSyncWriteElem((SceneActor&)*this, dataPtr);
137 dataPtr = coreSyncWriteElem(*this, dataPtr);
138
139 return CoreSyncData(buffer, size);
140 }
141
142 void Decal::_markCoreDirty(ActorDirtyFlag flags)
143 {
144 markCoreDirty((UINT32)flags);
145 }
146
147 RTTITypeBase* Decal::getRTTIStatic()
148 {
149 return DecalRTTI::instance();
150 }
151
152 RTTITypeBase* Decal::getRTTI() const
153 {
154 return Decal::getRTTIStatic();
155 }
156
157 template class TDecal<true>;
158 template class TDecal<false>;
159
160 namespace ct
161 {
162 Decal::Decal(const SPtr<Material>& material, const Vector2& size, float maxDistance)
163 : TDecal(material, size, maxDistance)
164 { }
165
166 Decal::~Decal()
167 {
168 gRenderer()->notifyDecalRemoved(this);
169 }
170
171 void Decal::initialize()
172 {
173 updateBounds();
174 gRenderer()->notifyDecalAdded(this);
175
176 CoreObject::initialize();
177 }
178
179 void Decal::syncToCore(const CoreSyncData& data)
180 {
181 char* dataPtr = (char*)data.getBuffer();
182
183 UINT32 dirtyFlags = 0;
184 bool oldIsActive = mActive;
185
186 dataPtr = rttiReadElem(dirtyFlags, dataPtr);
187 dataPtr = coreSyncReadElem((SceneActor&)*this, dataPtr);
188 dataPtr = coreSyncReadElem(*this, dataPtr);
189
190 mTfrmMatrix = mTransform.getMatrix();
191 mTfrmMatrixNoScale = Matrix4::TRS(mTransform.getPosition(), mTransform.getRotation(), Vector3::ONE);
192
193 updateBounds();
194
195 if (dirtyFlags == (UINT32)ActorDirtyFlag::Transform)
196 {
197 if (mActive)
198 gRenderer()->notifyDecalUpdated(this);
199 }
200 else
201 {
202 if (oldIsActive != mActive)
203 {
204 if (mActive)
205 gRenderer()->notifyDecalAdded(this);
206 else
207 gRenderer()->notifyDecalRemoved(this);
208 }
209 else
210 {
211 gRenderer()->notifyDecalRemoved(this);
212 gRenderer()->notifyDecalAdded(this);
213 }
214 }
215 }
216}}
217