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/BsRenderable.h" |
4 | #include "Private/RTTI/BsRenderableRTTI.h" |
5 | #include "Scene/BsSceneObject.h" |
6 | #include "Mesh/BsMesh.h" |
7 | #include "Material/BsMaterial.h" |
8 | #include "Math/BsBounds.h" |
9 | #include "Renderer/BsRenderer.h" |
10 | #include "Animation/BsAnimation.h" |
11 | #include "Animation/BsMorphShapes.h" |
12 | #include "RenderAPI/BsGpuBuffer.h" |
13 | #include "Animation/BsAnimationManager.h" |
14 | #include "Scene/BsSceneManager.h" |
15 | #include "CoreThread/BsCoreObjectSync.h" |
16 | |
17 | namespace bs |
18 | { |
19 | template<class T> |
20 | bool isMeshValid(const T& mesh) { return false; } |
21 | |
22 | template<> |
23 | bool isMeshValid(const HMesh& mesh) { return mesh.isLoaded(); } |
24 | |
25 | template<> |
26 | bool isMeshValid(const SPtr<ct::Mesh>& mesh) { return mesh != nullptr; } |
27 | |
28 | template<bool Core> |
29 | TRenderable<Core>::TRenderable() |
30 | { |
31 | mMaterials.resize(1); |
32 | } |
33 | |
34 | template <bool Core> |
35 | void TRenderable<Core>::setTransform(const Transform& transform) |
36 | { |
37 | if (mMobility != ObjectMobility::Movable) |
38 | return; |
39 | |
40 | mTransform = transform; |
41 | mTfrmMatrix = transform.getMatrix(); |
42 | mTfrmMatrixNoScale = Matrix4::TRS(transform.getPosition(), transform.getRotation(), Vector3::ONE); |
43 | |
44 | _markCoreDirty(ActorDirtyFlag::Transform); |
45 | } |
46 | |
47 | template<bool Core> |
48 | void TRenderable<Core>::setMesh(const MeshType& mesh) |
49 | { |
50 | mMesh = mesh; |
51 | |
52 | int numSubMeshes = 0; |
53 | if (isMeshValid(mesh)) |
54 | numSubMeshes = mesh->getProperties().getNumSubMeshes(); |
55 | |
56 | mMaterials.resize(numSubMeshes); |
57 | |
58 | onMeshChanged(); |
59 | |
60 | _markDependenciesDirty(); |
61 | _markResourcesDirty(); |
62 | _markCoreDirty(); |
63 | } |
64 | |
65 | template<bool Core> |
66 | void TRenderable<Core>::setMaterial(UINT32 idx, const MaterialType& material) |
67 | { |
68 | if (idx >= (UINT32)mMaterials.size()) |
69 | return; |
70 | |
71 | mMaterials[idx] = material; |
72 | |
73 | _markDependenciesDirty(); |
74 | _markResourcesDirty(); |
75 | _markCoreDirty(); |
76 | } |
77 | |
78 | template<bool Core> |
79 | void TRenderable<Core>::setMaterials(const Vector<MaterialType>& materials) |
80 | { |
81 | UINT32 numMaterials = (UINT32)mMaterials.size(); |
82 | UINT32 min = std::min(numMaterials, (UINT32)materials.size()); |
83 | |
84 | for (UINT32 i = 0; i < min; i++) |
85 | mMaterials[i] = materials[i]; |
86 | |
87 | for (UINT32 i = min; i < numMaterials; i++) |
88 | mMaterials[i] = nullptr; |
89 | |
90 | _markDependenciesDirty(); |
91 | _markResourcesDirty(); |
92 | _markCoreDirty(); |
93 | } |
94 | |
95 | template<bool Core> |
96 | void TRenderable<Core>::setMaterial(const MaterialType& material) |
97 | { |
98 | setMaterial(0, material); |
99 | } |
100 | |
101 | template <bool Core> |
102 | typename TRenderable<Core>::MaterialType TRenderable<Core>::getMaterial(UINT32 idx) const |
103 | { |
104 | if(idx >= (UINT32)mMaterials.size()) |
105 | return nullptr; |
106 | |
107 | return mMaterials[idx]; |
108 | } |
109 | |
110 | template<bool Core> |
111 | void TRenderable<Core>::setLayer(UINT64 layer) |
112 | { |
113 | const bool isPow2 = layer && !((layer - 1) & layer); |
114 | |
115 | if (!isPow2) |
116 | { |
117 | LOGWRN("Invalid layer provided. Only one layer bit may be set. Ignoring." ); |
118 | return; |
119 | } |
120 | |
121 | mLayer = layer; |
122 | _markCoreDirty(); |
123 | } |
124 | |
125 | template<bool Core> |
126 | void TRenderable<Core>::setOverrideBounds(const AABox& bounds) |
127 | { |
128 | mOverrideBounds = bounds; |
129 | |
130 | if(mUseOverrideBounds) |
131 | _markCoreDirty(); |
132 | } |
133 | |
134 | template<bool Core> |
135 | void TRenderable<Core>::setUseOverrideBounds(bool enable) |
136 | { |
137 | if (mUseOverrideBounds == enable) |
138 | return; |
139 | |
140 | mUseOverrideBounds = enable; |
141 | _markCoreDirty(); |
142 | } |
143 | |
144 | template<bool Core> |
145 | void TRenderable<Core>::setCullDistanceFactor(float factor) |
146 | { |
147 | mCullDistanceFactor = factor; |
148 | |
149 | _markCoreDirty(); |
150 | } |
151 | |
152 | template class TRenderable < false >; |
153 | template class TRenderable < true >; |
154 | |
155 | void Renderable::initialize() |
156 | { |
157 | CoreObject::initialize(); |
158 | |
159 | // Since we don't pass any information along to the core thread object on its construction, make sure the data |
160 | // sync executes |
161 | _markCoreDirty(); |
162 | |
163 | // If any resources were deserialized before initialization, make sure the listener is notified |
164 | _markResourcesDirty(); |
165 | } |
166 | |
167 | |
168 | void Renderable::setAnimation(const SPtr<Animation>& animation) |
169 | { |
170 | mAnimation = animation; |
171 | refreshAnimation(); |
172 | |
173 | _markCoreDirty(); |
174 | } |
175 | |
176 | Bounds Renderable::getBounds() const |
177 | { |
178 | if(mUseOverrideBounds) |
179 | { |
180 | Sphere sphere(mOverrideBounds.getCenter(), mOverrideBounds.getRadius()); |
181 | |
182 | Bounds bounds(mOverrideBounds, sphere); |
183 | bounds.transformAffine(mTfrmMatrix); |
184 | |
185 | return bounds; |
186 | } |
187 | |
188 | HMesh mesh = getMesh(); |
189 | |
190 | if (!mesh.isLoaded()) |
191 | { |
192 | const Transform& tfrm = getTransform(); |
193 | |
194 | AABox box(tfrm.getPosition(), tfrm.getPosition()); |
195 | Sphere sphere(tfrm.getPosition(), 0.0f); |
196 | |
197 | return Bounds(box, sphere); |
198 | } |
199 | else |
200 | { |
201 | Bounds bounds = mesh->getProperties().getBounds(); |
202 | bounds.transformAffine(mTfrmMatrix); |
203 | |
204 | return bounds; |
205 | } |
206 | } |
207 | |
208 | SPtr<ct::Renderable> Renderable::getCore() const |
209 | { |
210 | return std::static_pointer_cast<ct::Renderable>(mCoreSpecific); |
211 | } |
212 | |
213 | SPtr<ct::CoreObject> Renderable::createCore() const |
214 | { |
215 | ct::Renderable* handler = new (bs_alloc<ct::Renderable>()) ct::Renderable(); |
216 | SPtr<ct::Renderable> handlerPtr = bs_shared_ptr<ct::Renderable>(handler); |
217 | handlerPtr->_setThisPtr(handlerPtr); |
218 | |
219 | return handlerPtr; |
220 | } |
221 | |
222 | void Renderable::onMeshChanged() |
223 | { |
224 | refreshAnimation(); |
225 | } |
226 | |
227 | void Renderable::refreshAnimation() |
228 | { |
229 | if (mAnimation == nullptr) |
230 | { |
231 | mAnimType = RenderableAnimType::None; |
232 | return; |
233 | } |
234 | |
235 | if (mMesh.isLoaded(false)) |
236 | { |
237 | SPtr<Skeleton> skeleton = mMesh->getSkeleton(); |
238 | SPtr<MorphShapes> morphShapes = mMesh->getMorphShapes(); |
239 | |
240 | if (skeleton != nullptr && morphShapes != nullptr) |
241 | mAnimType = RenderableAnimType::SkinnedMorph; |
242 | else if (skeleton != nullptr) |
243 | mAnimType = RenderableAnimType::Skinned; |
244 | else if (morphShapes != nullptr) |
245 | mAnimType = RenderableAnimType::Morph; |
246 | else |
247 | mAnimType = RenderableAnimType::None; |
248 | |
249 | mAnimation->setSkeleton(mMesh->getSkeleton()); |
250 | mAnimation->setMorphShapes(mMesh->getMorphShapes()); |
251 | } |
252 | else |
253 | { |
254 | mAnimType = RenderableAnimType::None; |
255 | |
256 | mAnimation->setSkeleton(nullptr); |
257 | mAnimation->setMorphShapes(nullptr); |
258 | } |
259 | } |
260 | |
261 | void Renderable::_updateState(const SceneObject& so, bool force) |
262 | { |
263 | UINT32 curHash = so.getTransformHash(); |
264 | if (curHash != mHash || force) |
265 | { |
266 | // If skinned animation, don't include own transform since that will be handled by root bone animation |
267 | bool ignoreOwnTransform; |
268 | if (mAnimType == RenderableAnimType::Skinned || mAnimType == RenderableAnimType::SkinnedMorph) |
269 | ignoreOwnTransform = mAnimation->_getAnimatesRoot(); |
270 | else |
271 | ignoreOwnTransform = false; |
272 | |
273 | if (ignoreOwnTransform) |
274 | { |
275 | // Note: Technically we're checking child's hash but using parent's transform. Ideally we check the parent's |
276 | // hash to reduce the number of required updates. |
277 | HSceneObject parentSO = so.getParent(); |
278 | if (parentSO != nullptr) |
279 | setTransform(parentSO->getTransform()); |
280 | else |
281 | setTransform(Transform()); |
282 | } |
283 | else |
284 | setTransform(so.getTransform()); |
285 | |
286 | mHash = curHash; |
287 | } |
288 | |
289 | // Hash now matches so transform won't be applied twice, so we can just call base class version |
290 | SceneActor::_updateState(so, force); |
291 | } |
292 | |
293 | void Renderable::_markCoreDirty(ActorDirtyFlag flag) |
294 | { |
295 | markCoreDirty((UINT32)flag); |
296 | } |
297 | |
298 | void Renderable::_markDependenciesDirty() |
299 | { |
300 | markDependenciesDirty(); |
301 | } |
302 | |
303 | void Renderable::_markResourcesDirty() |
304 | { |
305 | markListenerResourcesDirty(); |
306 | } |
307 | |
308 | CoreSyncData Renderable::syncToCore(FrameAlloc* allocator) |
309 | { |
310 | const UINT32 dirtyFlags = getCoreDirtyFlags(); |
311 | UINT32 size = rttiGetElemSize(dirtyFlags); |
312 | SceneActor::rttiEnumFields(RttiCoreSyncSize(size), (ActorDirtyFlags)dirtyFlags); |
313 | |
314 | // The most common case if only the transform changed, so we sync only transform related options |
315 | UINT32 numMaterials = 0; |
316 | UINT64 animationId = 0; |
317 | if(dirtyFlags != (UINT32)ActorDirtyFlag::Transform) |
318 | { |
319 | numMaterials = (UINT32)mMaterials.size(); |
320 | |
321 | if (mAnimation != nullptr) |
322 | animationId = mAnimation->_getId(); |
323 | else |
324 | animationId = (UINT64)-1; |
325 | |
326 | size += |
327 | rttiGetElemSize(mLayer) + |
328 | rttiGetElemSize(mOverrideBounds) + |
329 | rttiGetElemSize(mUseOverrideBounds) + |
330 | rttiGetElemSize(numMaterials) + |
331 | rttiGetElemSize(animationId) + |
332 | rttiGetElemSize(mAnimType) + |
333 | rttiGetElemSize(mCullDistanceFactor) + |
334 | sizeof(SPtr<ct::Mesh>) + |
335 | numMaterials * sizeof(SPtr<ct::Material>); |
336 | } |
337 | |
338 | |
339 | UINT8* data = allocator->alloc(size); |
340 | char* dataPtr = (char*)data; |
341 | |
342 | dataPtr = rttiWriteElem(dirtyFlags, dataPtr); |
343 | SceneActor::rttiEnumFields(RttiCoreSyncWriter(&dataPtr), (ActorDirtyFlags)dirtyFlags); |
344 | |
345 | if(dirtyFlags != (UINT32)ActorDirtyFlag::Transform) |
346 | { |
347 | dataPtr = rttiWriteElem(mLayer, dataPtr); |
348 | dataPtr = rttiWriteElem(mOverrideBounds, dataPtr); |
349 | dataPtr = rttiWriteElem(mUseOverrideBounds, dataPtr); |
350 | dataPtr = rttiWriteElem(numMaterials, dataPtr); |
351 | dataPtr = rttiWriteElem(animationId, dataPtr); |
352 | dataPtr = rttiWriteElem(mAnimType, dataPtr); |
353 | dataPtr = rttiWriteElem(mCullDistanceFactor, dataPtr); |
354 | |
355 | SPtr<ct::Mesh>* mesh = new (dataPtr) SPtr<ct::Mesh>(); |
356 | if (mMesh.isLoaded()) |
357 | *mesh = mMesh->getCore(); |
358 | |
359 | dataPtr += sizeof(SPtr<ct::Mesh>); |
360 | |
361 | for (UINT32 i = 0; i < numMaterials; i++) |
362 | { |
363 | SPtr<ct::Material>* material = new (dataPtr)SPtr<ct::Material>(); |
364 | if (mMaterials[i].isLoaded()) |
365 | *material = mMaterials[i]->getCore(); |
366 | |
367 | dataPtr += sizeof(SPtr<ct::Material>); |
368 | } |
369 | } |
370 | |
371 | return CoreSyncData(data, size); |
372 | } |
373 | |
374 | void Renderable::getCoreDependencies(Vector<CoreObject*>& dependencies) |
375 | { |
376 | if (mMesh.isLoaded()) |
377 | dependencies.push_back(mMesh.get()); |
378 | |
379 | for (auto& material : mMaterials) |
380 | { |
381 | if (material.isLoaded()) |
382 | dependencies.push_back(material.get()); |
383 | } |
384 | } |
385 | |
386 | void Renderable::onDependencyDirty(CoreObject* dependency, UINT32 dirtyFlags) |
387 | { |
388 | if(mMesh.isLoaded(false) && mMesh.get() == dependency) |
389 | { |
390 | CoreObject::onDependencyDirty(dependency, dirtyFlags); |
391 | return; |
392 | } |
393 | |
394 | if(((UINT32)MaterialDirtyFlags::Shader & dirtyFlags) != 0) |
395 | CoreObject::onDependencyDirty(dependency, dirtyFlags); |
396 | } |
397 | |
398 | void Renderable::getListenerResources(Vector<HResource>& resources) |
399 | { |
400 | if (mMesh != nullptr) |
401 | resources.push_back(mMesh); |
402 | |
403 | for (auto& material : mMaterials) |
404 | { |
405 | if (material != nullptr) |
406 | resources.push_back(material); |
407 | } |
408 | } |
409 | |
410 | void Renderable::notifyResourceLoaded(const HResource& resource) |
411 | { |
412 | if (resource == mMesh) |
413 | onMeshChanged(); |
414 | |
415 | markDependenciesDirty(); |
416 | markCoreDirty(); |
417 | } |
418 | |
419 | void Renderable::notifyResourceChanged(const HResource& resource) |
420 | { |
421 | if(resource == mMesh) |
422 | onMeshChanged(); |
423 | |
424 | markDependenciesDirty(); |
425 | markCoreDirty(); |
426 | } |
427 | |
428 | SPtr<Renderable> Renderable::create() |
429 | { |
430 | SPtr<Renderable> handlerPtr = createEmpty(); |
431 | handlerPtr->initialize(); |
432 | |
433 | return handlerPtr; |
434 | } |
435 | |
436 | SPtr<Renderable> Renderable::createEmpty() |
437 | { |
438 | Renderable* handler = new (bs_alloc<Renderable>()) Renderable(); |
439 | SPtr<Renderable> handlerPtr = bs_core_ptr<Renderable>(handler); |
440 | handlerPtr->_setThisPtr(handlerPtr); |
441 | |
442 | return handlerPtr; |
443 | } |
444 | |
445 | RTTITypeBase* Renderable::getRTTIStatic() |
446 | { |
447 | return RenderableRTTI::instance(); |
448 | } |
449 | |
450 | RTTITypeBase* Renderable::getRTTI() const |
451 | { |
452 | return Renderable::getRTTIStatic(); |
453 | } |
454 | |
455 | namespace ct |
456 | { |
457 | Renderable::Renderable() |
458 | :mRendererId(0), mAnimationId((UINT64)-1), mMorphShapeVersion(0) |
459 | { |
460 | } |
461 | |
462 | Renderable::~Renderable() |
463 | { |
464 | if (mActive) |
465 | gRenderer()->notifyRenderableRemoved(this); |
466 | } |
467 | |
468 | void Renderable::initialize() |
469 | { |
470 | gRenderer()->notifyRenderableAdded(this); |
471 | |
472 | CoreObject::initialize(); |
473 | } |
474 | |
475 | Bounds Renderable::getBounds() const |
476 | { |
477 | if (mUseOverrideBounds) |
478 | { |
479 | Sphere sphere(mOverrideBounds.getCenter(), mOverrideBounds.getRadius()); |
480 | |
481 | Bounds bounds(mOverrideBounds, sphere); |
482 | bounds.transformAffine(mTfrmMatrix); |
483 | |
484 | return bounds; |
485 | } |
486 | |
487 | SPtr<Mesh> mesh = getMesh(); |
488 | |
489 | if (mesh == nullptr) |
490 | { |
491 | const Transform& tfrm = getTransform(); |
492 | |
493 | AABox box(tfrm.getPosition(), tfrm.getPosition()); |
494 | Sphere sphere(tfrm.getPosition(), 0.0f); |
495 | |
496 | return Bounds(box, sphere); |
497 | } |
498 | else |
499 | { |
500 | Bounds bounds = mesh->getProperties().getBounds(); |
501 | bounds.transformAffine(mTfrmMatrix); |
502 | |
503 | return bounds; |
504 | } |
505 | } |
506 | |
507 | void Renderable::createAnimationBuffers() |
508 | { |
509 | if (mAnimType == RenderableAnimType::Skinned || mAnimType == RenderableAnimType::SkinnedMorph) |
510 | { |
511 | SPtr<Skeleton> skeleton = mMesh->getSkeleton(); |
512 | UINT32 numBones = skeleton != nullptr ? skeleton->getNumBones() : 0; |
513 | |
514 | if (numBones > 0) |
515 | { |
516 | GPU_BUFFER_DESC desc; |
517 | desc.elementCount = numBones * 3; |
518 | desc.elementSize = 0; |
519 | desc.type = GBT_STANDARD; |
520 | desc.format = BF_32X4F; |
521 | desc.usage = GBU_DYNAMIC; |
522 | |
523 | SPtr<GpuBuffer> buffer = GpuBuffer::create(desc); |
524 | UINT8* dest = (UINT8*)buffer->lock(0, numBones * 3 * sizeof(Vector4), GBL_WRITE_ONLY_DISCARD); |
525 | |
526 | // Initialize bone transforms to identity, so the object renders properly even if no animation is animating it |
527 | for (UINT32 i = 0; i < numBones; i++) |
528 | { |
529 | memcpy(dest, &Matrix4::IDENTITY, 12 * sizeof(float)); // Assuming row-major format |
530 | |
531 | dest += 12 * sizeof(float); |
532 | } |
533 | |
534 | buffer->unlock(); |
535 | |
536 | mBoneMatrixBuffer = buffer; |
537 | } |
538 | else |
539 | mBoneMatrixBuffer = nullptr; |
540 | } |
541 | else |
542 | mBoneMatrixBuffer = nullptr; |
543 | |
544 | if (mAnimType == RenderableAnimType::Morph || mAnimType == RenderableAnimType::SkinnedMorph) |
545 | { |
546 | SPtr<MorphShapes> morphShapes = mMesh->getMorphShapes(); |
547 | |
548 | UINT32 vertexSize = sizeof(Vector3) + sizeof(UINT32); |
549 | UINT32 numVertices = morphShapes->getNumVertices(); |
550 | |
551 | VERTEX_BUFFER_DESC desc; |
552 | desc.vertexSize = vertexSize; |
553 | desc.numVerts = numVertices; |
554 | desc.usage = GBU_DYNAMIC; |
555 | |
556 | SPtr<VertexBuffer> vertexBuffer = VertexBuffer::create(desc); |
557 | |
558 | UINT32 totalSize = vertexSize * numVertices; |
559 | UINT8* dest = (UINT8*)vertexBuffer->lock(0, totalSize, GBL_WRITE_ONLY_DISCARD); |
560 | memset(dest, 0, totalSize); |
561 | vertexBuffer->unlock(); |
562 | |
563 | mMorphShapeBuffer = vertexBuffer; |
564 | } |
565 | else |
566 | mMorphShapeBuffer = nullptr; |
567 | |
568 | mMorphShapeVersion = 0; |
569 | } |
570 | |
571 | void Renderable::updateAnimationBuffers(const EvaluatedAnimationData& animData) |
572 | { |
573 | if (mAnimationId == (UINT64)-1) |
574 | return; |
575 | |
576 | const EvaluatedAnimationData::AnimInfo* animInfo = nullptr; |
577 | |
578 | auto iterFind = animData.infos.find(mAnimationId); |
579 | if (iterFind != animData.infos.end()) |
580 | animInfo = &iterFind->second; |
581 | |
582 | if (animInfo == nullptr) |
583 | return; |
584 | |
585 | if (mAnimType == RenderableAnimType::Skinned || mAnimType == RenderableAnimType::SkinnedMorph) |
586 | { |
587 | const EvaluatedAnimationData::PoseInfo& poseInfo = animInfo->poseInfo; |
588 | |
589 | // Note: If multiple elements are using the same animation (not possible atm), this buffer should be shared by |
590 | // all such elements |
591 | UINT8* dest = (UINT8*)mBoneMatrixBuffer->lock(0, poseInfo.numBones * 3 * sizeof(Vector4), GBL_WRITE_ONLY_DISCARD); |
592 | for (UINT32 j = 0; j < poseInfo.numBones; j++) |
593 | { |
594 | const Matrix4& transform = animData.transforms[poseInfo.startIdx + j]; |
595 | memcpy(dest, &transform, 12 * sizeof(float)); // Assuming row-major format |
596 | |
597 | dest += 12 * sizeof(float); |
598 | } |
599 | |
600 | mBoneMatrixBuffer->unlock(); |
601 | } |
602 | |
603 | if (mAnimType == RenderableAnimType::Morph || mAnimType == RenderableAnimType::SkinnedMorph) |
604 | { |
605 | if (mMorphShapeVersion != animInfo->morphShapeInfo.version) |
606 | { |
607 | SPtr<MeshData> meshData = animInfo->morphShapeInfo.meshData; |
608 | |
609 | UINT32 bufferSize = meshData->getSize(); |
610 | UINT8* data = meshData->getData(); |
611 | |
612 | mMorphShapeBuffer->writeData(0, bufferSize, data, BWT_DISCARD); |
613 | mMorphShapeVersion = animInfo->morphShapeInfo.version; |
614 | } |
615 | } |
616 | } |
617 | |
618 | void Renderable::syncToCore(const CoreSyncData& data) |
619 | { |
620 | char* dataPtr = (char*)data.getBuffer(); |
621 | |
622 | mMaterials.clear(); |
623 | |
624 | UINT32 numMaterials = 0; |
625 | UINT32 dirtyFlags = 0; |
626 | bool oldIsActive = mActive; |
627 | |
628 | dataPtr = rttiReadElem(dirtyFlags, dataPtr); |
629 | SceneActor::rttiEnumFields(RttiCoreSyncReader(&dataPtr), (ActorDirtyFlags)dirtyFlags); |
630 | |
631 | mTfrmMatrix = mTransform.getMatrix(); |
632 | mTfrmMatrixNoScale = Matrix4::TRS(mTransform.getPosition(), mTransform.getRotation(), Vector3::ONE); |
633 | |
634 | if(dirtyFlags != (UINT32)ActorDirtyFlag::Transform) |
635 | { |
636 | dataPtr = rttiReadElem(mLayer, dataPtr); |
637 | dataPtr = rttiReadElem(mOverrideBounds, dataPtr); |
638 | dataPtr = rttiReadElem(mUseOverrideBounds, dataPtr); |
639 | dataPtr = rttiReadElem(numMaterials, dataPtr); |
640 | dataPtr = rttiReadElem(mAnimationId, dataPtr); |
641 | dataPtr = rttiReadElem(mAnimType, dataPtr); |
642 | dataPtr = rttiReadElem(mCullDistanceFactor, dataPtr); |
643 | |
644 | SPtr<Mesh>* mesh = (SPtr<Mesh>*)dataPtr; |
645 | mMesh = *mesh; |
646 | mesh->~SPtr<Mesh>(); |
647 | dataPtr += sizeof(SPtr<Mesh>); |
648 | |
649 | for (UINT32 i = 0; i < numMaterials; i++) |
650 | { |
651 | SPtr<Material>* material = (SPtr<Material>*)dataPtr; |
652 | mMaterials.push_back(*material); |
653 | material->~SPtr<Material>(); |
654 | dataPtr += sizeof(SPtr<Material>); |
655 | } |
656 | } |
657 | |
658 | UINT32 updateEverythingFlag = (UINT32)ActorDirtyFlag::Everything |
659 | | (UINT32)ActorDirtyFlag::Active |
660 | | (UINT32)ActorDirtyFlag::Dependency; |
661 | |
662 | if((dirtyFlags & updateEverythingFlag) != 0) |
663 | { |
664 | createAnimationBuffers(); |
665 | |
666 | // Create special vertex declaration if using morph shapes |
667 | if (mAnimType == RenderableAnimType::Morph || mAnimType == RenderableAnimType::SkinnedMorph) |
668 | { |
669 | SPtr<VertexDataDesc> vertexDesc = VertexDataDesc::create(); |
670 | *vertexDesc = * mMesh->getVertexDesc(); |
671 | |
672 | vertexDesc->addVertElem(VET_FLOAT3, VES_POSITION, 1, 1); |
673 | vertexDesc->addVertElem(VET_UBYTE4_NORM, VES_NORMAL, 1, 1); |
674 | |
675 | mMorphVertexDeclaration = VertexDeclaration::create(vertexDesc); |
676 | } |
677 | else |
678 | mMorphVertexDeclaration = nullptr; |
679 | |
680 | if (oldIsActive != mActive) |
681 | { |
682 | if (mActive) |
683 | gRenderer()->notifyRenderableAdded(this); |
684 | else |
685 | gRenderer()->notifyRenderableRemoved(this); |
686 | } |
687 | else |
688 | { |
689 | gRenderer()->notifyRenderableRemoved(this); |
690 | gRenderer()->notifyRenderableAdded(this); |
691 | } |
692 | } |
693 | else if((dirtyFlags & (UINT32)ActorDirtyFlag::Mobility) != 0) |
694 | { |
695 | gRenderer()->notifyRenderableRemoved(this); |
696 | gRenderer()->notifyRenderableAdded(this); |
697 | } |
698 | else if ((dirtyFlags & (UINT32)ActorDirtyFlag::Transform) != 0) |
699 | { |
700 | if (mActive) |
701 | gRenderer()->notifyRenderableUpdated(this); |
702 | } |
703 | } |
704 | } |
705 | } |
706 | |