Coverage Report

Created: 2026-05-24 07:02

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ogre/OgreMain/src/OgreEntity.cpp
Line
Count
Source
1
/*
2
  -----------------------------------------------------------------------------
3
  This source file is part of OGRE
4
  (Object-oriented Graphics Rendering Engine)
5
  For the latest info, see http://www.ogre3d.org
6
7
Copyright (c) 2000-2014 Torus Knot Software Ltd
8
9
  Permission is hereby granted, free of charge, to any person obtaining a copy
10
  of this software and associated documentation files (the "Software"), to deal
11
  in the Software without restriction, including without limitation the rights
12
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
  copies of the Software, and to permit persons to whom the Software is
14
  furnished to do so, subject to the following conditions:
15
16
  The above copyright notice and this permission notice shall be included in
17
  all copies or substantial portions of the Software.
18
19
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25
  THE SOFTWARE.
26
  -----------------------------------------------------------------------------
27
*/
28
#include "OgreStableHeaders.h"
29
#include "OgreTagPoint.h"
30
#include "OgreSkeletonInstance.h"
31
#include "OgreOptimisedUtil.h"
32
#include "OgreLodStrategy.h"
33
#include "OgreLodListener.h"
34
35
36
namespace Ogre {
37
    //-----------------------------------------------------------------------
38
    Entity::Entity ()
39
0
        : mAnimationState(NULL),
40
0
          mTempSkelAnimInfo(),
41
0
          mTempVertexAnimInfo(),
42
0
          mVertexAnimationAppliedThisFrame(false),
43
0
          mPreparedForShadowVolumes(false),
44
0
          mDisplaySkeleton(false),
45
0
          mShowBoundingSphere(false),
46
0
          mCurrentHWAnimationState(false),
47
0
          mSkipAnimStateUpdates(false),
48
0
          mAlwaysUpdateMainSkeleton(false),
49
0
          mUpdateBoundingBoxFromSkeleton(false),
50
0
          mVertexProgramInUse(false),
51
0
          mInitialised(false),
52
0
          mHardwarePoseCount(0),
53
0
          mNumBoneMatrices(0),
54
0
          mBoneWorldMatrices(NULL),
55
0
          mBoneMatrices(NULL),
56
0
          mFrameAnimationLastUpdated(std::numeric_limits<unsigned long>::max()),
57
0
          mFrameBonesLastUpdated(NULL),
58
0
          mSharedSkeletonEntities(NULL),
59
0
        mSoftwareAnimationRequests(0),
60
0
        mSoftwareAnimationNormalsRequests(0),
61
0
        mMeshLodIndex(0),
62
0
        mMeshLodFactorTransformed(1.0f),
63
0
        mMinMeshLodIndex(99),
64
0
        mMaxMeshLodIndex(0),        // Backwards, remember low value = high detail
65
0
        mMaterialLodFactor(1.0f),
66
0
        mMinMaterialLodIndex(99),
67
0
        mMaxMaterialLodIndex(0),        // Backwards, remember low value = high detail
68
0
        mSkeletonInstance(0),
69
0
        mLastParentXform(Affine3::ZERO),
70
0
        mMeshStateCount(0),
71
0
        mFullBoundingBox()
72
0
    {
73
0
    }
74
    //-----------------------------------------------------------------------
75
0
    Entity::Entity( const String& name, const MeshPtr& mesh) : Entity()
76
0
    {
77
0
        mName = name;
78
0
        mMesh = mesh;
79
0
        _initialise();
80
0
    }
81
    //-----------------------------------------------------------------------
82
    void Entity::loadingComplete(Resource* res)
83
0
    {
84
0
        if (res == mMesh.get())
85
0
        {
86
            // mesh loading has finished, we can construct ourselves now
87
0
            _initialise();
88
0
        }
89
0
    }
90
    //-----------------------------------------------------------------------
91
    void Entity::_initialise(bool forceReinitialise)
92
0
    {
93
0
        if (forceReinitialise)
94
0
            _deinitialise();
95
96
0
        if (mInitialised)
97
0
            return;
98
99
0
        if (mMesh->isBackgroundLoaded() && !mMesh->isLoaded())
100
0
        {
101
            // register for a callback when mesh is finished loading
102
            // do this before asking for load to happen to avoid race
103
0
            mMesh->addListener(this);
104
0
        }
105
106
        // On-demand load
107
0
        mMesh->load();
108
        // If loading failed, or deferred loading isn't done yet, defer
109
        // Will get a callback in the case of deferred loading
110
        // Skeletons are cascade-loaded so no issues there
111
0
        if (!mMesh->isLoaded())
112
0
            return;
113
114
        // Is mesh skeletally animated?
115
0
        if (mMesh->hasSkeleton() && mMesh->getSkeleton())
116
0
        {
117
0
            mSkeletonInstance = OGRE_NEW SkeletonInstance(mMesh->getSkeleton());
118
0
            mSkeletonInstance->load();
119
            // if mUpdateBoundingBoxFromSkeleton was turned on before the mesh was loaded, and mesh hasn't computed the boneBoundingRadius yet,
120
0
            if ( mUpdateBoundingBoxFromSkeleton && mMesh->getBoneBoundingRadius() == Real(0))
121
0
            {
122
0
                mMesh->_computeBoneBoundingRadius();
123
0
            }
124
0
        }
125
126
        // Build main subentity list
127
0
        buildSubEntityList(mMesh, &mSubEntityList);
128
0
#if !OGRE_NO_MESHLOD
129
        // Check if mesh is using manual LOD
130
0
        if (mMesh->hasManualLodLevel())
131
0
        {
132
0
            ushort i, numLod;
133
0
            numLod = mMesh->getNumLodLevels();
134
            // NB skip LOD 0 which is the original
135
0
            for (i = 1; i < numLod; ++i)
136
0
            {
137
0
                const MeshLodUsage& usage = mMesh->getLodLevel(i);
138
0
                Entity* lodEnt;
139
0
                if(!usage.manualName.empty()){
140
                    // Disabled to prevent recursion when a.mesh has manualLod to b.mesh and b.mesh has manualLod to a.mesh.
141
0
                    OgreAssert(usage.manualMesh->getNumLodLevels() == 1, "Manual Lod Mesh can't have Lod levels!");
142
143
0
                    if(usage.manualMesh->getNumLodLevels() != 1) {
144
                        // To prevent crash in release builds, we will remove Lod levels.
145
0
                        usage.manualMesh->removeLodLevels();
146
0
                    }
147
148
                    // Manually create entity
149
0
                    lodEnt = OGRE_NEW Entity(mName + "Lod" + StringConverter::toString(i),
150
0
                        usage.manualMesh);
151
0
                } else {
152
                    // Autogenerated lod uses original entity
153
0
                    lodEnt = this;
154
0
                }
155
0
                mLodEntityList.push_back(lodEnt);
156
0
            }
157
0
        }
158
0
#endif
159
160
        // Initialise the AnimationState, if Mesh has animation
161
0
        if (hasSkeleton())
162
0
        {
163
0
            mFrameBonesLastUpdated = OGRE_ALLOC_T(unsigned long, 1, MEMCATEGORY_ANIMATION);
164
0
            *mFrameBonesLastUpdated = std::numeric_limits<unsigned long>::max();
165
0
            mNumBoneMatrices = mSkeletonInstance->getNumBones();
166
0
            mBoneMatrices = static_cast<Affine3*>(OGRE_MALLOC_SIMD(sizeof(Affine3) * mNumBoneMatrices, MEMCATEGORY_ANIMATION));
167
0
        }
168
0
        if (hasSkeleton() || hasVertexAnimation())
169
0
        {
170
0
            mAnimationState = OGRE_NEW AnimationStateSet();
171
0
            mMesh->_initAnimationState(mAnimationState);
172
0
            prepareTempBlendBuffers();
173
0
        }
174
175
0
        reevaluateVertexProcessing();
176
177
        // Update of bounds of the parent SceneNode, if Entity already attached
178
        // this can happen if Mesh is loaded in background or after reinitialisation
179
0
        if( mParentNode )
180
0
        {
181
0
            getParentSceneNode()->needUpdate();
182
0
        }
183
184
0
        mInitialised = true;
185
0
        mMeshStateCount = mMesh->getStateCount();
186
0
    }
187
    //-----------------------------------------------------------------------
188
    void Entity::_deinitialise(void)
189
0
    {
190
0
        if (!mInitialised)
191
0
            return;
192
193
        // Delete submeshes
194
0
        for (auto *s : mSubEntityList)
195
0
        {
196
            // Delete SubEntity
197
0
            OGRE_DELETE s;
198
0
            s = nullptr;
199
0
        }
200
0
        mSubEntityList.clear();
201
202
0
#if !OGRE_NO_MESHLOD
203
        // Delete LOD entities
204
0
        for (auto *li : mLodEntityList)
205
0
        {
206
0
            if(li != this) {
207
0
                li->mParentNode = NULL; // prevent LODs from unregistering themselves
208
0
                OGRE_DELETE li;
209
0
            }
210
0
        }
211
0
        mLodEntityList.clear();
212
0
#endif
213
        // Delete shadow renderables
214
0
        clearShadowRenderableList(mShadowRenderables);
215
216
        // Detach all child objects, do this manually to avoid needUpdate() call
217
        // which can fail because of deleted items
218
0
        detachAllObjectsImpl();
219
220
0
        if (mSkeletonInstance) {
221
0
            OGRE_FREE_SIMD(mBoneWorldMatrices, MEMCATEGORY_ANIMATION);
222
0
            mBoneWorldMatrices = 0;
223
224
0
            if (mSharedSkeletonEntities) {
225
0
                mSharedSkeletonEntities->erase(this);
226
0
                if (mSharedSkeletonEntities->size() == 1)
227
0
                {
228
0
                    (*mSharedSkeletonEntities->begin())->stopSharingSkeletonInstance();
229
0
                }
230
                // Should never occur, just in case
231
0
                else if (mSharedSkeletonEntities->empty())
232
0
                {
233
0
                    OGRE_DELETE_T(mSharedSkeletonEntities, EntitySet, MEMCATEGORY_ANIMATION); mSharedSkeletonEntities = 0;
234
                    // using OGRE_FREE since unsigned long is not a destructor
235
0
                    OGRE_FREE(mFrameBonesLastUpdated, MEMCATEGORY_ANIMATION); mFrameBonesLastUpdated = 0;
236
0
                    OGRE_DELETE mSkeletonInstance; mSkeletonInstance = 0;
237
0
                    OGRE_FREE_SIMD(mBoneMatrices, MEMCATEGORY_ANIMATION); mBoneMatrices = 0;
238
0
                    OGRE_DELETE mAnimationState; mAnimationState = 0;
239
0
                }
240
0
            } else {
241
                // using OGRE_FREE since unsigned long is not a destructor
242
0
                OGRE_FREE(mFrameBonesLastUpdated, MEMCATEGORY_ANIMATION); mFrameBonesLastUpdated = 0;
243
0
                OGRE_DELETE mSkeletonInstance; mSkeletonInstance = 0;
244
0
                OGRE_FREE_SIMD(mBoneMatrices, MEMCATEGORY_ANIMATION); mBoneMatrices = 0;
245
0
                OGRE_DELETE mAnimationState; mAnimationState = 0;
246
0
            }
247
0
        }
248
0
        else
249
0
        {
250
            //Non-skeletally animated objects don't share the mAnimationState. Always delete.
251
            //See https://ogre3d.atlassian.net/browse/OGRE-504
252
0
            OGRE_DELETE mAnimationState;
253
0
            mAnimationState = 0;
254
0
        }
255
256
0
        mSkelAnimVertexData.reset();
257
0
        mSoftwareVertexAnimVertexData.reset();
258
0
        mHardwareVertexAnimVertexData.reset();
259
260
0
        mInitialised = false;
261
0
    }
262
    //-----------------------------------------------------------------------
263
    Entity::~Entity()
264
0
    {
265
0
        _deinitialise();
266
        // Unregister our listener
267
0
        mMesh->removeListener(this);
268
0
    }
269
    //-----------------------------------------------------------------------
270
    void Entity::_releaseManualHardwareResources()
271
0
    {
272
0
        clearShadowRenderableList(mShadowRenderables);
273
0
    }
274
    //-----------------------------------------------------------------------
275
    void Entity::_restoreManualHardwareResources()
276
0
    {
277
        // mShadowRenderables are lazy initialized
278
0
    }
279
    //-----------------------------------------------------------------------
280
    bool Entity::hasVertexAnimation(void) const
281
0
    {
282
0
        return mMesh->hasVertexAnimation();
283
0
    }
284
    //-----------------------------------------------------------------------
285
    const MeshPtr& Entity::getMesh(void) const
286
0
    {
287
0
        return mMesh;
288
0
    }
289
    //-----------------------------------------------------------------------
290
    SubEntity* Entity::getSubEntity(const String& name) const
291
0
    {
292
0
        ushort index = mMesh->_getSubMeshIndex(name);
293
0
        return getSubEntity(index);
294
0
    }
295
    //-----------------------------------------------------------------------
296
    Entity* Entity::clone( const String& newName) const
297
0
    {
298
0
        OgreAssert(mManager, "Cannot clone an Entity that wasn't created through a SceneManager");
299
0
        Entity* newEnt = mManager->createEntity(newName, getMesh()->getName() );
300
301
0
        if (mInitialised)
302
0
        {
303
            // Copy material settings
304
0
            unsigned int n = 0;
305
0
            for (const auto *e : mSubEntityList)
306
0
            {
307
0
                newEnt->getSubEntities()[n++]->setMaterialName(e->getMaterialName());
308
0
            }
309
0
            if (mAnimationState)
310
0
            {
311
0
                OGRE_DELETE newEnt->mAnimationState;
312
0
                newEnt->mAnimationState = OGRE_NEW AnimationStateSet(*mAnimationState);
313
0
            }
314
0
        }
315
316
0
        return newEnt;
317
0
    }
318
    //-----------------------------------------------------------------------
319
    void Entity::setMaterialName( const String& name, const String& groupName /* = ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME */)
320
0
    {
321
        // Set for all subentities
322
0
        for (auto *s : mSubEntityList)
323
0
        {
324
0
            s->setMaterialName(name, groupName);
325
0
        }
326
327
0
    }
328
    //-----------------------------------------------------------------------
329
    void Entity::setMaterial( const MaterialPtr& material )
330
0
    {
331
        // Set for all subentities
332
0
        for (auto *s : mSubEntityList)
333
0
        {
334
0
            s->setMaterial(material);
335
0
        }
336
0
    }
337
    //-----------------------------------------------------------------------
338
    void Entity::_notifyCurrentCamera(Camera* cam)
339
0
    {
340
0
        MovableObject::_notifyCurrentCamera(cam);
341
342
        // Calculate the LOD
343
0
        if (mParentNode)
344
0
        {
345
0
#if !OGRE_NO_MESHLOD
346
            // Get mesh lod strategy
347
0
            const LodStrategy *meshStrategy = mMesh->getLodStrategy();
348
            // Get the appropriate LOD value
349
0
            Real lodValue = meshStrategy->getValue(this, cam);
350
            // Bias the LOD value
351
0
            Real biasedMeshLodValue = lodValue * mMeshLodFactorTransformed;
352
353
354
            // Get the index at this biased depth
355
0
            ushort newMeshLodIndex = mMesh->getLodIndex(biasedMeshLodValue);
356
            // Apply maximum detail restriction (remember lower = higher detail, higher = lower detail)
357
0
            newMeshLodIndex = Math::Clamp(newMeshLodIndex, mMaxMeshLodIndex, mMinMeshLodIndex);
358
359
            // Construct event object
360
0
            EntityMeshLodChangedEvent evt;
361
0
            evt.entity = this;
362
0
            evt.camera = cam;
363
0
            evt.lodValue = biasedMeshLodValue;
364
0
            evt.previousLodIndex = mMeshLodIndex;
365
0
            evt.newLodIndex = newMeshLodIndex;
366
367
            // Notify LOD event listeners
368
0
            cam->getSceneManager()->_notifyEntityMeshLodChanged(evt);
369
370
            // Change LOD index
371
0
            mMeshLodIndex = evt.newLodIndex;
372
0
#endif
373
374
375
0
            for (auto *s : mSubEntityList)
376
0
            {
377
                // Get sub-entity material
378
0
                const MaterialPtr& material = s->getMaterial();
379
380
                // Get material LOD strategy
381
0
                const LodStrategy *materialStrategy = material->getLodStrategy();
382
383
                // Recalculate LOD value if strategies do not match
384
0
                Real biasedMaterialLodValue;
385
0
#if !OGRE_NO_MESHLOD
386
0
                if (meshStrategy == materialStrategy)
387
0
                    biasedMaterialLodValue = biasedMeshLodValue;
388
0
                else
389
0
#endif
390
0
                    biasedMaterialLodValue = materialStrategy->getValue(this, cam) * materialStrategy->transformBias(mMaterialLodFactor);
391
392
                // Get the index at this biased depth
393
0
                unsigned short idx = material->getLodIndex(biasedMaterialLodValue);
394
                // Apply maximum detail restriction (remember lower = higher detail, higher = lower detail)
395
0
                idx = Math::Clamp(idx, mMaxMaterialLodIndex, mMinMaterialLodIndex);
396
397
                // Construct event object
398
0
                EntityMaterialLodChangedEvent subEntEvt;
399
0
                subEntEvt.subEntity = s;
400
0
                subEntEvt.camera = cam;
401
0
                subEntEvt.lodValue = biasedMaterialLodValue;
402
0
                subEntEvt.previousLodIndex = s->mMaterialLodIndex;
403
0
                subEntEvt.newLodIndex = idx;
404
405
                // Notify LOD event listeners
406
0
                cam->getSceneManager()->_notifyEntityMaterialLodChanged(subEntEvt);
407
408
                // Change LOD index
409
0
                s->mMaterialLodIndex = subEntEvt.newLodIndex;
410
                // Also invalidate any camera distance cache
411
0
                s->_invalidateCameraCache ();
412
0
            }
413
414
415
0
        }
416
        // Notify any child objects
417
0
        for(auto child : mChildObjectList)
418
0
        {
419
0
            child->_notifyCurrentCamera(cam);
420
0
        }
421
0
    }
422
    //-----------------------------------------------------------------------
423
    void Entity::setUpdateBoundingBoxFromSkeleton(bool update)
424
0
    {
425
0
        mUpdateBoundingBoxFromSkeleton = update;
426
0
        if (mUpdateBoundingBoxFromSkeleton && mMesh->isLoaded() && mMesh->getBoneBoundingRadius() == Real(0))
427
0
        {
428
0
            mMesh->_computeBoneBoundingRadius();
429
0
        }
430
0
    }
431
    //-----------------------------------------------------------------------
432
    const AxisAlignedBox& Entity::getBoundingBox(void) const
433
0
    {
434
        // Get from Mesh
435
0
        if (mMesh->isLoaded())
436
0
        {
437
0
            if ( mUpdateBoundingBoxFromSkeleton && hasSkeleton() )
438
0
            {
439
                // get from skeleton
440
                // self bounding box without children
441
0
                AxisAlignedBox bbox;
442
0
                bbox.setNull();
443
0
                Real maxScale = Real(0);
444
0
                bool boneHasVerts[ OGRE_MAX_NUM_BONES ] = { false };
445
                // for each bone that has vertices weighted to it,
446
0
                for (uint16 iBone : mMesh->sharedBlendIndexToBoneIndexMap)
447
0
                {
448
                    // record which bones have vertices assigned
449
0
                    boneHasVerts[ iBone ] = true;
450
0
                }
451
                // for each submesh,
452
0
                for (uint16 iSubMesh = 0; iSubMesh < mMesh->getNumSubMeshes(); ++iSubMesh)
453
0
                {
454
0
                    SubMesh* submesh = mMesh->getSubMesh( iSubMesh );
455
                    // if the submesh has own vertices,
456
0
                    if ( ! submesh->useSharedVertices )
457
0
                    {
458
                        // record which bones have vertices assigned
459
0
                        for (uint16 iBone : submesh->blendIndexToBoneIndexMap)
460
0
                        {
461
0
                            boneHasVerts[ iBone ] = true;
462
0
                        }
463
0
                    }
464
0
                }
465
                // for each bone that has vertices weighted to it,
466
0
                for (const Bone* bone : mSkeletonInstance->getBones())
467
0
                {
468
0
                    if ( boneHasVerts[ bone->getHandle() ] )
469
0
                    {
470
0
                        Vector3 scaleVec = bone->_getDerivedScale();
471
0
                        Real scale = std::max( std::max( Math::Abs(scaleVec.x), Math::Abs(scaleVec.y)), Math::Abs(scaleVec.z) );
472
0
                        maxScale = std::max( maxScale, scale );
473
                        // only include bones that aren't scaled to zero
474
0
                        if (scale > Real(0))
475
0
                        {
476
0
                            bbox.merge( bone->_getDerivedPosition() );
477
0
                        }
478
0
                    }
479
0
                }
480
                // unless all bones were scaled to zero,
481
0
                if (! bbox.isNull())
482
0
                {
483
                    // inflate the bounding box
484
0
                    float r = mMesh->getBoneBoundingRadius() * maxScale;  // adjust bone bounding radius by max scale of any bone
485
0
                    Vector3 expansion(r, r, r);
486
0
                    bbox.setExtents( bbox.getMinimum() - expansion, bbox.getMaximum() + expansion );
487
0
                }
488
0
                bbox.merge(getChildObjectsBoundingBox());
489
                // if bounding box has changed,
490
0
                if (bbox != mFullBoundingBox)
491
0
                {
492
0
                    mFullBoundingBox = bbox;
493
0
                    Node::queueNeedUpdate( mParentNode );  // inform the parent node to update its AABB (without this, changes to the bbox won't propagate to the scene node)
494
0
                }
495
0
            }
496
0
            else
497
0
            {
498
                // Get from Mesh
499
0
                mFullBoundingBox = mMesh->getBounds();
500
0
                mFullBoundingBox.merge(getChildObjectsBoundingBox());
501
0
            }
502
            // Don't scale here, this is taken into account when world BBox calculation is done
503
0
        }
504
0
        else
505
0
        {
506
0
            mFullBoundingBox.setNull();
507
0
        }
508
509
0
        return mFullBoundingBox;
510
0
    }
511
    //-----------------------------------------------------------------------
512
    AxisAlignedBox Entity::getChildObjectsBoundingBox(void) const
513
0
    {
514
0
        AxisAlignedBox aa_box;
515
0
        AxisAlignedBox full_aa_box;
516
0
        full_aa_box.setNull();
517
518
0
        for(auto child : mChildObjectList)
519
0
        {
520
0
            aa_box = child->getBoundingBox();
521
0
            TagPoint* tp = static_cast<TagPoint*>(child->getParentNode());
522
            // Use transform local to skeleton since world xform comes later
523
0
            aa_box.transform(tp->_getFullLocalTransform());
524
525
0
            full_aa_box.merge(aa_box);
526
0
        }
527
528
0
        return full_aa_box;
529
0
    }
530
    //-----------------------------------------------------------------------
531
    const AxisAlignedBox& Entity::getWorldBoundingBox(bool derive) const
532
0
    {
533
0
        if (derive)
534
0
        {
535
            // derive child bounding boxes
536
0
            for(auto child : mChildObjectList)
537
0
            {
538
0
                child->getWorldBoundingBox(true);
539
0
            }
540
0
        }
541
0
        return MovableObject::getWorldBoundingBox(derive);
542
0
    }
543
    //-----------------------------------------------------------------------
544
    const Sphere& Entity::getWorldBoundingSphere(bool derive) const
545
0
    {
546
0
        if (derive)
547
0
        {
548
            // derive child bounding boxes
549
0
            for(auto child : mChildObjectList)
550
0
            {
551
0
                child->getWorldBoundingSphere(true);
552
0
            }
553
0
        }
554
0
        return MovableObject::getWorldBoundingSphere(derive);
555
556
0
    }
557
    //-----------------------------------------------------------------------
558
    void Entity::_updateRenderQueue(RenderQueue* queue)
559
0
    {
560
        // Do nothing if not initialised yet
561
0
        if (!mInitialised)
562
0
            return;
563
564
        // Check mesh state count, will be incremented if reloaded
565
0
        if (mMesh->getStateCount() != mMeshStateCount)
566
0
        {
567
            // force reinitialise
568
0
            _initialise(true);
569
0
        }
570
571
0
        Entity* displayEntity = this;
572
0
#if !OGRE_NO_MESHLOD
573
        // Check we're not using a manual LOD
574
0
        if (mMeshLodIndex > 0 && mMesh->hasManualLodLevel())
575
0
        {
576
            // Use alternate entity
577
0
            assert( static_cast< size_t >( mMeshLodIndex - 1 ) < mLodEntityList.size() &&
578
0
                    "No LOD EntityList - did you build the manual LODs after creating the entity?");
579
            // index - 1 as we skip index 0 (original LOD)
580
0
            displayEntity = mLodEntityList[mMeshLodIndex-1];
581
582
0
            if (displayEntity != this && hasSkeleton() && displayEntity->hasSkeleton())
583
0
            {
584
                // Copy the animation state set to lod entity, we assume the lod
585
                // entity only has a subset animation states
586
0
                AnimationStateSet* targetState = displayEntity->mAnimationState;
587
0
                if (mAnimationState != targetState) // only copy if LODs use different skeleton instances
588
0
                {
589
0
                    if (mAnimationState->getDirtyFrameNumber() != targetState->getDirtyFrameNumber()) // only copy if animation was updated
590
0
                        mAnimationState->copyMatchingState(targetState);
591
0
                }
592
0
            }
593
0
        }
594
0
#endif
595
596
        // Add each visible SubEntity to the queue
597
0
        for (auto *s : displayEntity->mSubEntityList)
598
0
        {
599
0
            if(s->isVisible())
600
0
            {
601
                // Order: first use subentity queue settings, if available
602
                //        if not then use entity queue settings, if available
603
                //        finally fall back on default queue settings
604
0
                if(s->isRenderQueuePrioritySet())
605
0
                {
606
0
                    assert(s->isRenderQueueGroupSet() == true);
607
0
                    queue->addRenderable(s, s->getRenderQueueGroup(), s->getRenderQueuePriority());
608
0
                }
609
0
                else if(s->isRenderQueueGroupSet())
610
0
                {
611
0
                    queue->addRenderable(s, s->getRenderQueueGroup());
612
0
                }
613
0
                else if (mRenderQueuePrioritySet)
614
0
                {
615
0
                    assert(mRenderQueueIDSet == true);
616
0
                    queue->addRenderable(s, mRenderQueueID, mRenderQueuePriority);
617
0
                }
618
0
                else if(mRenderQueueIDSet)
619
0
                {
620
0
                    queue->addRenderable(s, mRenderQueueID);
621
0
                }
622
0
                else
623
0
                {
624
0
                    queue->addRenderable(s);
625
0
                }
626
0
            }
627
0
        }
628
0
#if !OGRE_NO_MESHLOD
629
0
        if (getAlwaysUpdateMainSkeleton() && hasSkeleton() && (mMeshLodIndex > 0))
630
0
        {
631
            //check if an update was made
632
0
            if (cacheBoneMatrices())
633
0
            {
634
0
                getSkeleton()->_updateTransforms();
635
                //We will mark the skeleton as dirty. Otherwise, if in the same frame the entity will
636
                //be rendered first with a low LOD and then with a high LOD the system wont know that
637
                //the bone matrices has changed and there for will not update the vertex buffers
638
0
                getSkeleton()->_notifyManualBonesDirty();
639
0
            }
640
0
        }
641
0
#endif
642
        // Since we know we're going to be rendered, take this opportunity to
643
        // update the animation
644
0
        if (displayEntity->hasSkeleton() || displayEntity->hasVertexAnimation())
645
0
        {
646
0
            displayEntity->updateAnimation();
647
648
            //--- pass this point,  we are sure that the transformation matrix of each bone and tagPoint have been updated
649
0
            for(auto child : mChildObjectList)
650
0
            {
651
0
                bool visible = child->isVisible();
652
0
                if (visible && (displayEntity != this))
653
0
                {
654
                    //Check if the bone exists in the current LOD
655
656
                    //The child is connected to a tagpoint which is connected to a bone
657
0
                    Bone* bone = static_cast<Bone*>(child->getParentNode()->getParent());
658
0
                    if (!displayEntity->getSkeleton()->hasBone(bone->getName()))
659
0
                    {
660
                        //Current LOD entity does not have the bone that the
661
                        //child is connected to. Do not display.
662
0
                        visible = false;
663
0
                    }
664
0
                }
665
0
                if (visible)
666
0
                {
667
0
                    child->_updateRenderQueue(queue);
668
0
                }
669
0
            }
670
0
        }
671
672
        // HACK to display bones
673
0
        if (mDisplaySkeleton && hasSkeleton() && mManager && mManager->getDebugDrawer())
674
0
        {
675
0
            for (Bone* bone : mSkeletonInstance->getBones())
676
0
            {
677
0
                mManager->getDebugDrawer()->drawBone(bone, mParentNode->_getFullTransform());
678
0
            }
679
0
        }
680
        // HACK to display bounding sphere
681
0
        if (mShowBoundingSphere && mManager && mManager->getDebugDrawer())
682
0
        {
683
0
            mManager->getDebugDrawer()->drawSphere(getWorldBoundingSphere());
684
0
        }
685
0
    }
686
    //-----------------------------------------------------------------------
687
    AnimationState* Entity::getAnimationState(const String& name) const
688
0
    {
689
0
        OgreAssert(mAnimationState, "Entity is not animated");
690
0
        return mAnimationState->getAnimationState(name);
691
0
    }
692
    //-----------------------------------------------------------------------
693
    bool Entity::hasAnimationState(const String& name) const
694
0
    {
695
0
        return mAnimationState && mAnimationState->hasAnimationState(name);
696
0
    }
697
    //-----------------------------------------------------------------------
698
    AnimationStateSet* Entity::getAllAnimationStates(void) const
699
0
    {
700
0
        return mAnimationState;
701
0
    }
702
    //-----------------------------------------------------------------------
703
    const String& Entity::getMovableType(void) const
704
0
    {
705
0
        return MOT_ENTITY;
706
0
    }
707
    //-----------------------------------------------------------------------
708
    bool Entity::tempVertexAnimBuffersBound(void) const
709
0
    {
710
        // Do we still have temp buffers for software vertex animation bound?
711
0
        bool ret = true;
712
0
        if (mMesh->sharedVertexData && mMesh->getSharedVertexDataAnimationType() != VAT_NONE)
713
0
        {
714
0
            ret = ret && mTempVertexAnimInfo.buffersCheckedOut(true, mMesh->getSharedVertexDataAnimationIncludesNormals());
715
0
        }
716
0
        for (auto sub : mSubEntityList)
717
0
        {
718
0
            if (!sub->getSubMesh()->useSharedVertices
719
0
                && sub->getSubMesh()->getVertexAnimationType() != VAT_NONE)
720
0
            {
721
0
                ret = ret && sub->mTempVertexAnimInfo.buffersCheckedOut(
722
0
                    true, sub->getSubMesh()->getVertexAnimationIncludesNormals());
723
0
            }
724
0
        }
725
0
        return ret;
726
0
    }
727
    //-----------------------------------------------------------------------
728
    bool Entity::tempSkelAnimBuffersBound(bool requestNormals) const
729
0
    {
730
        // Do we still have temp buffers for software skeleton animation bound?
731
0
        if (mSkelAnimVertexData)
732
0
        {
733
0
            if (!mTempSkelAnimInfo.buffersCheckedOut(true, requestNormals))
734
0
                return false;
735
0
        }
736
0
        for (auto sub : mSubEntityList)
737
0
        {
738
0
            if (sub->isVisible() && sub->mSkelAnimVertexData)
739
0
            {
740
0
                if (!sub->mTempSkelAnimInfo.buffersCheckedOut(true, requestNormals))
741
0
                    return false;
742
0
            }
743
0
        }
744
0
        return true;
745
0
    }
746
    //-----------------------------------------------------------------------
747
    void Entity::updateAnimation(void)
748
0
    {
749
        // Do nothing if not initialised yet
750
0
        if (!mInitialised)
751
0
            return;
752
753
0
        Root& root = Root::getSingleton();
754
0
        bool hwAnimation = isHardwareAnimationEnabled();
755
0
        bool isNeedUpdateHardwareAnim = hwAnimation && !mCurrentHWAnimationState;
756
0
        bool forcedSwAnimation = getSoftwareAnimationRequests()>0;
757
0
        bool forcedNormals = getSoftwareAnimationNormalsRequests()>0;
758
0
        bool stencilShadows = false;
759
0
        if (getCastShadows() && hasEdgeList() && root._getCurrentSceneManager())
760
0
            stencilShadows =  root._getCurrentSceneManager()->isShadowTechniqueStencilBased();
761
0
        bool softwareAnimation = !hwAnimation || stencilShadows || forcedSwAnimation;
762
        // Blend normals in s/w only if we're not using h/w animation,
763
        // since shadows only require positions
764
0
        bool blendNormals = !hwAnimation || forcedNormals;
765
        // Animation dirty if animation state modified or manual bones modified
766
0
        bool animationDirty =
767
0
            (mFrameAnimationLastUpdated != mAnimationState->getDirtyFrameNumber()) ||
768
0
            (hasSkeleton() && getSkeleton()->getManualBonesDirty());
769
770
        //update the current hardware animation state
771
0
        mCurrentHWAnimationState = hwAnimation;
772
773
        // We only do these tasks if animation is dirty
774
        // Or, if we're using a skeleton and manual bones have been moved
775
        // Or, if we're using software animation and temp buffers are unbound
776
0
        if (animationDirty ||
777
0
            (softwareAnimation && hasVertexAnimation() && !tempVertexAnimBuffersBound()) ||
778
0
            (softwareAnimation && hasSkeleton() && !tempSkelAnimBuffersBound(blendNormals)))
779
0
        {
780
0
            if (hasVertexAnimation())
781
0
            {
782
0
                if (softwareAnimation)
783
0
                {
784
                    // grab & bind temporary buffer for positions (& normals if they are included)
785
0
                    if (mSoftwareVertexAnimVertexData
786
0
                        && mMesh->getSharedVertexDataAnimationType() != VAT_NONE)
787
0
                    {
788
0
                        bool useNormals = mMesh->getSharedVertexDataAnimationIncludesNormals();
789
0
                        mTempVertexAnimInfo.checkoutTempCopies(true, useNormals);
790
                        // NB we suppress hardware upload while doing blend if we're
791
                        // hardware animation, because the only reason for doing this
792
                        // is for shadow, which need only be uploaded then
793
0
                        mTempVertexAnimInfo.bindTempCopies(mSoftwareVertexAnimVertexData.get(),
794
0
                                                           hwAnimation);
795
0
                    }
796
0
                    for (auto *se : mSubEntityList)
797
0
                    {
798
                        // Blend dedicated geometry
799
0
                        if (se->isVisible() && se->mSoftwareVertexAnimVertexData
800
0
                            && se->getSubMesh()->getVertexAnimationType() != VAT_NONE)
801
0
                        {
802
0
                            bool useNormals = se->getSubMesh()->getVertexAnimationIncludesNormals();
803
0
                            se->mTempVertexAnimInfo.checkoutTempCopies(true, useNormals);
804
0
                            se->mTempVertexAnimInfo.bindTempCopies(se->mSoftwareVertexAnimVertexData.get(),
805
0
                                                                   hwAnimation);
806
0
                        }
807
0
                    }
808
0
                }
809
0
                applyVertexAnimation(hwAnimation, stencilShadows);
810
0
            }
811
812
0
            if (hasSkeleton())
813
0
            {
814
0
                cacheBoneMatrices();
815
816
                // Software blend?
817
0
                if (softwareAnimation)
818
0
                {
819
0
                    const Affine3* blendMatrices[OGRE_MAX_NUM_BONES];
820
821
                    // Ok, we need to do a software blend
822
                    // Firstly, check out working vertex buffers
823
0
                    if (mSkelAnimVertexData)
824
0
                    {
825
                        // Blend shared geometry
826
                        // NB we suppress hardware upload while doing blend if we're
827
                        // hardware animation, because the only reason for doing this
828
                        // is for shadow, which need only be uploaded then
829
0
                        mTempSkelAnimInfo.checkoutTempCopies(true, blendNormals);
830
0
                        mTempSkelAnimInfo.bindTempCopies(mSkelAnimVertexData.get(),
831
0
                                                         hwAnimation);
832
                        // Prepare blend matrices, TODO: Move out of here
833
0
                        Mesh::prepareMatricesForVertexBlend(blendMatrices,
834
0
                                                            mBoneMatrices, mMesh->sharedBlendIndexToBoneIndexMap);
835
                        // Blend, taking source from either mesh data or morph data
836
0
                        Mesh::softwareVertexBlend(
837
0
                            (mMesh->getSharedVertexDataAnimationType() != VAT_NONE) ?
838
0
                            mSoftwareVertexAnimVertexData.get() : mMesh->sharedVertexData,
839
0
                            mSkelAnimVertexData.get(),
840
0
                            blendMatrices, mMesh->sharedBlendIndexToBoneIndexMap.size(),
841
0
                            blendNormals);
842
0
                    }
843
844
0
                    for (auto *se : mSubEntityList)
845
0
                    {
846
                        // Blend dedicated geometry
847
0
                        if (se->isVisible() && se->mSkelAnimVertexData)
848
0
                        {
849
0
                            se->mTempSkelAnimInfo.checkoutTempCopies(true, blendNormals);
850
0
                            se->mTempSkelAnimInfo.bindTempCopies(se->mSkelAnimVertexData.get(),
851
0
                                                                 hwAnimation);
852
                            // Prepare blend matrices, TODO: Move out of here
853
0
                            Mesh::prepareMatricesForVertexBlend(blendMatrices,
854
0
                                                                mBoneMatrices, se->mSubMesh->blendIndexToBoneIndexMap);
855
                            // Blend, taking source from either mesh data or morph data
856
0
                            Mesh::softwareVertexBlend(
857
0
                                (se->getSubMesh()->getVertexAnimationType() != VAT_NONE)?
858
0
                                se->mSoftwareVertexAnimVertexData.get() : se->mSubMesh->vertexData,
859
0
                                se->mSkelAnimVertexData.get(),
860
0
                                blendMatrices, se->mSubMesh->blendIndexToBoneIndexMap.size(),
861
0
                                blendNormals);
862
0
                        }
863
864
0
                    }
865
866
0
                }
867
0
            }
868
869
            // Trigger update of bounding box if necessary
870
0
            if (!mChildObjectList.empty())
871
0
                mParentNode->needUpdate();
872
873
0
            mFrameAnimationLastUpdated = mAnimationState->getDirtyFrameNumber();
874
0
        }
875
876
        // Need to update the child object's transforms when animation dirty
877
        // or parent node transform has altered.
878
0
        if (hasSkeleton() &&
879
0
            (isNeedUpdateHardwareAnim ||
880
0
             animationDirty || mLastParentXform != _getParentNodeFullTransform()))
881
0
        {
882
            // Cache last parent transform for next frame use too.
883
0
            mLastParentXform = _getParentNodeFullTransform();
884
885
            //--- Update the child object's transforms
886
0
            for(auto child : mChildObjectList)
887
0
            {
888
0
                child->getParentNode()->_update(true, true);
889
0
            }
890
891
            // Also calculate bone world matrices, since are used as replacement world matrices,
892
            // but only if it's used (when using hardware animation and skeleton animated).
893
0
            if (hwAnimation && _isSkeletonAnimated() && !MeshManager::getBonesUseObjectSpace())
894
0
            {
895
                // Allocate bone world matrices on demand, for better memory footprint
896
                // when using software animation.
897
0
                if (!mBoneWorldMatrices)
898
0
                {
899
0
                    mBoneWorldMatrices =
900
0
                        static_cast<Affine3*>(OGRE_MALLOC_SIMD(sizeof(Affine3) * mNumBoneMatrices, MEMCATEGORY_ANIMATION));
901
0
                    std::fill(mBoneWorldMatrices, mBoneWorldMatrices + mNumBoneMatrices, Affine3::IDENTITY);
902
0
                }
903
904
0
                OptimisedUtil::getImplementation()->concatenateAffineMatrices(
905
0
                    mLastParentXform,
906
0
                    mBoneMatrices,
907
0
                    mBoneWorldMatrices,
908
0
                    mNumBoneMatrices);
909
0
            }
910
0
        }
911
0
    }
912
    //-----------------------------------------------------------------------
913
    ushort Entity::initHardwareAnimationElements(VertexData* vdata,
914
                                                 ushort numberOfElements, bool animateNormals)
915
0
    {
916
0
        ushort elemsSupported = numberOfElements;
917
0
        if (vdata->hwAnimationDataList.size() < numberOfElements)
918
0
        {
919
0
            elemsSupported =
920
0
                vdata->allocateHardwareAnimationElements(numberOfElements, animateNormals);
921
0
        }
922
        // Initialise parametrics in case we don't use all of them
923
0
        for (auto & i : vdata->hwAnimationDataList)
924
0
        {
925
0
            i.parametric = 0.0f;
926
0
        }
927
        // reset used count
928
0
        vdata->hwAnimDataItemsUsed = 0;
929
930
0
        return elemsSupported;
931
932
0
    }
933
    //-----------------------------------------------------------------------
934
    void Entity::applyVertexAnimation(bool hardwareAnimation, bool stencilShadows)
935
0
    {
936
0
        const MeshPtr& msh = getMesh();
937
0
        bool swAnim = !hardwareAnimation || stencilShadows || (mSoftwareAnimationRequests>0);
938
939
        // make sure we have enough hardware animation elements to play with
940
0
        if (hardwareAnimation)
941
0
        {
942
0
            if (mHardwareVertexAnimVertexData
943
0
                && msh->getSharedVertexDataAnimationType() != VAT_NONE)
944
0
            {
945
0
                ushort supportedCount =
946
0
                    initHardwareAnimationElements(mHardwareVertexAnimVertexData.get(),
947
0
                                                  (msh->getSharedVertexDataAnimationType() == VAT_POSE)
948
0
                                                  ? mHardwarePoseCount : 1,
949
0
                                                  msh->getSharedVertexDataAnimationIncludesNormals());
950
951
0
                if (msh->getSharedVertexDataAnimationType() == VAT_POSE &&
952
0
                    supportedCount < mHardwarePoseCount)
953
0
                {
954
0
                    LogManager::getSingleton().stream() <<
955
0
                        "Vertex program assigned to Entity '" << mName <<
956
0
                        "' claimed to support " << mHardwarePoseCount <<
957
0
                        " morph/pose vertex sets, but in fact only " << supportedCount <<
958
0
                        " were able to be supported in the shared mesh data.";
959
0
                    mHardwarePoseCount = supportedCount;
960
0
                }
961
962
0
}
963
0
            for (auto sub : mSubEntityList)
964
0
            {
965
0
                if (sub->getSubMesh()->getVertexAnimationType() != VAT_NONE &&
966
0
                    !sub->getSubMesh()->useSharedVertices)
967
0
                {
968
0
                    ushort supportedCount = initHardwareAnimationElements(
969
0
                        sub->_getHardwareVertexAnimVertexData(),
970
0
                        (sub->getSubMesh()->getVertexAnimationType() == VAT_POSE)
971
0
                        ? sub->mHardwarePoseCount : 1,
972
0
                        sub->getSubMesh()->getVertexAnimationIncludesNormals());
973
974
0
                    if (sub->getSubMesh()->getVertexAnimationType() == VAT_POSE &&
975
0
                        supportedCount < sub->mHardwarePoseCount)
976
0
                    {
977
0
                        LogManager::getSingleton().stream() <<
978
0
                        "Vertex program assigned to SubEntity of '" << mName <<
979
0
                        "' claimed to support " << sub->mHardwarePoseCount <<
980
0
                        " morph/pose vertex sets, but in fact only " << supportedCount <<
981
0
                        " were able to be supported in the mesh data.";
982
0
                        sub->mHardwarePoseCount = supportedCount;
983
0
                    }
984
985
0
                }
986
0
            }
987
988
0
        }
989
0
        else
990
0
        {
991
            // May be blending multiple poses in software
992
            // Suppress hardware upload of buffers
993
            // Note, we query position buffer here but it may also include normals
994
0
            if (mSoftwareVertexAnimVertexData &&
995
0
                mMesh->getSharedVertexDataAnimationType() == VAT_POSE)
996
0
            {
997
0
                const VertexElement* elem = mSoftwareVertexAnimVertexData
998
0
                    ->vertexDeclaration->findElementBySemantic(VES_POSITION);
999
0
                HardwareVertexBufferSharedPtr buf = mSoftwareVertexAnimVertexData
1000
0
                    ->vertexBufferBinding->getBuffer(elem->getSource());
1001
0
                buf->suppressHardwareUpdate(true);
1002
1003
0
                initialisePoseVertexData(mMesh->sharedVertexData, mSoftwareVertexAnimVertexData.get(),
1004
0
                    mMesh->getSharedVertexDataAnimationIncludesNormals());
1005
0
            }
1006
0
            for (auto sub : mSubEntityList)
1007
0
            {
1008
0
                if (!sub->getSubMesh()->useSharedVertices &&
1009
0
                    sub->getSubMesh()->getVertexAnimationType() == VAT_POSE)
1010
0
                {
1011
0
                    VertexData* data = sub->_getSoftwareVertexAnimVertexData();
1012
0
                    const VertexElement* elem = data->vertexDeclaration
1013
0
                        ->findElementBySemantic(VES_POSITION);
1014
0
                    HardwareVertexBufferSharedPtr buf = data
1015
0
                        ->vertexBufferBinding->getBuffer(elem->getSource());
1016
0
                    buf->suppressHardwareUpdate(true);
1017
                    // if we're animating normals, we need to start with zeros
1018
0
                    initialisePoseVertexData(sub->getSubMesh()->vertexData, data,
1019
0
                        sub->getSubMesh()->getVertexAnimationIncludesNormals());
1020
0
                }
1021
0
            }
1022
0
        }
1023
1024
1025
        // Now apply the animation(s)
1026
        // Note - you should only apply one morph animation to each set of vertex data
1027
        // at once; if you do more, only the last one will actually apply
1028
0
        markBuffersUnusedForAnimation();
1029
0
        EnabledAnimationStateList::const_iterator animIt;
1030
0
        for(auto *state : mAnimationState->getEnabledAnimationStates())
1031
0
        {
1032
0
            Animation* anim = msh->_getAnimationImpl(state->getAnimationName());
1033
0
            if (anim)
1034
0
            {
1035
0
                anim->apply(this, state->getTimePosition(), state->getWeight(),
1036
0
                    swAnim, hardwareAnimation);
1037
0
            }
1038
0
        }
1039
        // Deal with cases where no animation applied
1040
0
        restoreBuffersForUnusedAnimation(hardwareAnimation);
1041
1042
        // Unsuppress hardware upload if we suppressed it
1043
0
        if (!hardwareAnimation)
1044
0
        {
1045
0
            if (mSoftwareVertexAnimVertexData &&
1046
0
                msh->getSharedVertexDataAnimationType() == VAT_POSE)
1047
0
            {
1048
                // if we're animating normals, if pose influence < 1 need to use the base mesh
1049
0
                if (mMesh->getSharedVertexDataAnimationIncludesNormals())
1050
0
                    finalisePoseNormals(mMesh->sharedVertexData, mSoftwareVertexAnimVertexData.get());
1051
1052
0
                const VertexElement* elem = mSoftwareVertexAnimVertexData
1053
0
                    ->vertexDeclaration->findElementBySemantic(VES_POSITION);
1054
0
                HardwareVertexBufferSharedPtr buf = mSoftwareVertexAnimVertexData
1055
0
                    ->vertexBufferBinding->getBuffer(elem->getSource());
1056
0
                buf->suppressHardwareUpdate(false);
1057
0
            }
1058
0
            for (auto sub : mSubEntityList)
1059
0
            {
1060
0
                if (!sub->getSubMesh()->useSharedVertices &&
1061
0
                    sub->getSubMesh()->getVertexAnimationType() == VAT_POSE)
1062
0
                {
1063
0
                    VertexData* data = sub->_getSoftwareVertexAnimVertexData();
1064
                    // if we're animating normals, if pose influence < 1 need to use the base mesh
1065
0
                    if (sub->getSubMesh()->getVertexAnimationIncludesNormals())
1066
0
                        finalisePoseNormals(sub->getSubMesh()->vertexData, data);
1067
1068
0
                    const VertexElement* elem = data->vertexDeclaration
1069
0
                        ->findElementBySemantic(VES_POSITION);
1070
0
                    HardwareVertexBufferSharedPtr buf = data
1071
0
                        ->vertexBufferBinding->getBuffer(elem->getSource());
1072
0
                    buf->suppressHardwareUpdate(false);
1073
0
                }
1074
0
            }
1075
0
        }
1076
1077
0
    }
1078
    //-----------------------------------------------------------------------------
1079
    void Entity::markBuffersUnusedForAnimation(void)
1080
0
    {
1081
0
        mVertexAnimationAppliedThisFrame = false;
1082
0
        for (auto & i : mSubEntityList)
1083
0
        {
1084
0
            i->_markBuffersUnusedForAnimation();
1085
0
        }
1086
0
    }
1087
    //-----------------------------------------------------------------------------
1088
    void Entity::_markBuffersUsedForAnimation(void)
1089
0
    {
1090
0
        mVertexAnimationAppliedThisFrame = true;
1091
        // no cascade
1092
0
    }
1093
    //-----------------------------------------------------------------------------
1094
    void Entity::restoreBuffersForUnusedAnimation(bool hardwareAnimation)
1095
0
    {
1096
        // Rebind original positions if:
1097
        //  We didn't apply any animation and
1098
        //    We're morph animated (hardware binds keyframe, software is missing)
1099
        //    or we're pose animated and software (hardware is fine, still bound)
1100
0
        if (mMesh->sharedVertexData &&
1101
0
            !mVertexAnimationAppliedThisFrame &&
1102
0
            (!hardwareAnimation || mMesh->getSharedVertexDataAnimationType() == VAT_MORPH))
1103
0
        {
1104
            // Note, VES_POSITION is specified here but if normals are included in animation
1105
            // then these will be re-bound too (buffers must be shared)
1106
0
            const VertexElement* srcPosElem =
1107
0
                mMesh->sharedVertexData->vertexDeclaration->findElementBySemantic(VES_POSITION);
1108
0
            HardwareVertexBufferSharedPtr srcBuf =
1109
0
                mMesh->sharedVertexData->vertexBufferBinding->getBuffer(
1110
0
                    srcPosElem->getSource());
1111
1112
            // Bind to software
1113
0
            const VertexElement* destPosElem =
1114
0
                mSoftwareVertexAnimVertexData->vertexDeclaration->findElementBySemantic(VES_POSITION);
1115
0
            mSoftwareVertexAnimVertexData->vertexBufferBinding->setBinding(
1116
0
                destPosElem->getSource(), srcBuf);
1117
1118
0
        }
1119
1120
        // rebind any missing hardware pose buffers
1121
        // Caused by not having any animations enabled, or keyframes which reference
1122
        // no poses
1123
0
        if (mMesh->sharedVertexData && hardwareAnimation
1124
0
            && mMesh->getSharedVertexDataAnimationType() == VAT_POSE)
1125
0
        {
1126
0
            bindMissingHardwarePoseBuffers(mMesh->sharedVertexData, mHardwareVertexAnimVertexData.get());
1127
0
        }
1128
1129
1130
0
        for (auto & i : mSubEntityList)
1131
0
        {
1132
0
            i->_restoreBuffersForUnusedAnimation(hardwareAnimation);
1133
0
        }
1134
1135
0
    }
1136
    //---------------------------------------------------------------------
1137
    void Entity::bindMissingHardwarePoseBuffers(const VertexData* srcData,
1138
        VertexData* destData)
1139
0
    {
1140
        // For hardware pose animation, also make sure we've bound buffers to all the elements
1141
        // required - if there are missing bindings for elements in use,
1142
        // some rendersystems can complain because elements refer
1143
        // to an unbound source.
1144
        // Get the original position source, we'll use this to fill gaps
1145
0
        const VertexElement* srcPosElem =
1146
0
            srcData->vertexDeclaration->findElementBySemantic(VES_POSITION);
1147
0
        HardwareVertexBufferSharedPtr srcBuf =
1148
0
            srcData->vertexBufferBinding->getBuffer(
1149
0
                srcPosElem->getSource());
1150
1151
0
        for (auto animData : destData->hwAnimationDataList)
1152
0
        {
1153
0
            if (!destData->vertexBufferBinding->isBufferBound(
1154
0
                animData.targetBufferIndex))
1155
0
            {
1156
                // Bind to a safe default
1157
0
                destData->vertexBufferBinding->setBinding(
1158
0
                    animData.targetBufferIndex, srcBuf);
1159
0
            }
1160
0
        }
1161
1162
0
    }
1163
    //-----------------------------------------------------------------------
1164
    void Entity::initialisePoseVertexData(const VertexData* srcData,
1165
        VertexData* destData, bool animateNormals)
1166
0
    {
1167
1168
        // First time through for a piece of pose animated vertex data
1169
        // We need to copy the original position values to the temp accumulator
1170
0
        const VertexElement* origelem =
1171
0
            srcData->vertexDeclaration->findElementBySemantic(VES_POSITION);
1172
0
        const VertexElement* destelem =
1173
0
            destData->vertexDeclaration->findElementBySemantic(VES_POSITION);
1174
0
        HardwareVertexBufferSharedPtr origBuffer =
1175
0
            srcData->vertexBufferBinding->getBuffer(origelem->getSource());
1176
0
        HardwareVertexBufferSharedPtr destBuffer =
1177
0
            destData->vertexBufferBinding->getBuffer(destelem->getSource());
1178
0
        destBuffer->copyData(*origBuffer.get(), 0, 0, destBuffer->getSizeInBytes(), true);
1179
1180
        // If normals are included in animation, we want to reset the normals to zero
1181
0
        if (animateNormals)
1182
0
        {
1183
0
            const VertexElement* normElem =
1184
0
                destData->vertexDeclaration->findElementBySemantic(VES_NORMAL);
1185
1186
0
            if (normElem)
1187
0
            {
1188
0
                HardwareVertexBufferSharedPtr buf =
1189
0
                    destData->vertexBufferBinding->getBuffer(normElem->getSource());
1190
0
                HardwareBufferLockGuard vertexLock(buf, HardwareBuffer::HBL_NORMAL);
1191
0
                char* pBase = static_cast<char*>(vertexLock.pData) + destData->vertexStart * buf->getVertexSize();
1192
1193
0
                for (size_t v = 0; v < destData->vertexCount; ++v)
1194
0
                {
1195
0
                    float* pNorm;
1196
0
                    normElem->baseVertexPointerToElement(pBase, &pNorm);
1197
0
                    *pNorm++ = 0.0f;
1198
0
                    *pNorm++ = 0.0f;
1199
0
                    *pNorm++ = 0.0f;
1200
1201
0
                    pBase += buf->getVertexSize();
1202
0
                }
1203
0
            }
1204
0
        }
1205
0
    }
1206
    //-----------------------------------------------------------------------
1207
    void Entity::finalisePoseNormals(const VertexData* srcData, VertexData* destData)
1208
0
    {
1209
0
        const VertexElement* destNormElem =
1210
0
            destData->vertexDeclaration->findElementBySemantic(VES_NORMAL);
1211
0
        const VertexElement* srcNormElem =
1212
0
            srcData->vertexDeclaration->findElementBySemantic(VES_NORMAL);
1213
1214
0
        if (destNormElem && srcNormElem)
1215
0
        {
1216
0
            auto srcbuf = srcData->vertexBufferBinding->getBuffer(srcNormElem->getSource());
1217
0
            auto dstbuf = destData->vertexBufferBinding->getBuffer(destNormElem->getSource());
1218
1219
0
            HardwareBufferLockGuard dstLock(dstbuf, HardwareBuffer::HBL_NORMAL);
1220
0
            char* pDstBase = static_cast<char*>(dstLock.pData) + destData->vertexStart * dstbuf->getVertexSize();
1221
0
            char* pSrcBase = pDstBase;
1222
1223
0
            HardwareBufferLockGuard srcLock;
1224
0
            if (srcbuf != dstbuf)
1225
0
            {
1226
0
                srcLock.lock(srcbuf, HardwareBuffer::HBL_READ_ONLY);
1227
0
                pSrcBase = static_cast<char*>(srcLock.pData) + srcData->vertexStart * srcbuf->getVertexSize();
1228
0
            }
1229
            // The goal here is to detect the length of the vertices, and to apply
1230
            // the base mesh vertex normal at one minus that length; this deals with
1231
            // any individual vertices which were either not affected by any pose, or
1232
            // were not affected to a complete extent
1233
            // We also normalise every normal to deal with over-weighting
1234
0
            for (size_t v = 0; v < destData->vertexCount; ++v)
1235
0
            {
1236
0
                float* pDstNorm;
1237
0
                destNormElem->baseVertexPointerToElement(pDstBase, &pDstNorm);
1238
0
                Vector3 norm(pDstNorm[0], pDstNorm[1], pDstNorm[2]);
1239
0
                Real len = norm.length();
1240
0
                if (len + 1e-4f < 1.0f)
1241
0
                {
1242
                    // Poses did not completely fill in this normal
1243
                    // Apply base mesh
1244
0
                    float baseWeight = 1.0f - (float)len;
1245
0
                    float* pSrcNorm;
1246
0
                    srcNormElem->baseVertexPointerToElement(pSrcBase, &pSrcNorm);
1247
0
                    norm.x += *pSrcNorm++ * baseWeight;
1248
0
                    norm.y += *pSrcNorm++ * baseWeight;
1249
0
                    norm.z += *pSrcNorm++ * baseWeight;
1250
0
                }
1251
0
                norm.normalise();
1252
1253
0
                *pDstNorm++ = (float)norm.x;
1254
0
                *pDstNorm++ = (float)norm.y;
1255
0
                *pDstNorm++ = (float)norm.z;
1256
1257
0
                pDstBase += dstbuf->getVertexSize();
1258
0
                pSrcBase += dstbuf->getVertexSize();
1259
0
            }
1260
0
        }
1261
0
    }
1262
    //-----------------------------------------------------------------------
1263
    void Entity::_updateAnimation(void)
1264
0
    {
1265
        // Externally visible method
1266
0
        if (hasSkeleton() || hasVertexAnimation())
1267
0
        {
1268
0
            updateAnimation();
1269
0
        }
1270
0
    }
1271
    //-----------------------------------------------------------------------
1272
    void Entity::_updateSkeleton(void)
1273
0
    {
1274
0
        mSkeletonInstance->setAnimationState(*mAnimationState);
1275
0
    }
1276
    //-----------------------------------------------------------------------
1277
    bool Entity::_isAnimated(void) const
1278
0
    {
1279
0
        return (mAnimationState && mAnimationState->hasEnabledAnimationState()) ||
1280
0
               (getSkeleton() && getSkeleton()->hasManualBones());
1281
0
    }
1282
    //-----------------------------------------------------------------------
1283
    bool Entity::_isSkeletonAnimated(void) const
1284
0
    {
1285
0
        return getSkeleton() &&
1286
0
            (mAnimationState->hasEnabledAnimationState() || getSkeleton()->hasManualBones());
1287
0
    }
1288
    //-----------------------------------------------------------------------
1289
    VertexData* Entity::_getSkelAnimVertexData(void) const
1290
0
    {
1291
0
        assert (mSkelAnimVertexData && "Not software skinned or has no shared vertex data!");
1292
0
        return mSkelAnimVertexData.get();
1293
0
    }
1294
    //-----------------------------------------------------------------------
1295
    VertexData* Entity::_getSoftwareVertexAnimVertexData(void) const
1296
0
    {
1297
0
        assert (mSoftwareVertexAnimVertexData && "Not vertex animated or has no shared vertex data!");
1298
0
        return mSoftwareVertexAnimVertexData.get();
1299
0
    }
1300
    //-----------------------------------------------------------------------
1301
    VertexData* Entity::_getHardwareVertexAnimVertexData(void) const
1302
0
    {
1303
0
        assert (mHardwareVertexAnimVertexData && "Not vertex animated or has no shared vertex data!");
1304
0
        return mHardwareVertexAnimVertexData.get();
1305
0
    }
1306
    //-----------------------------------------------------------------------
1307
    bool Entity::cacheBoneMatrices(void)
1308
0
    {
1309
0
        Root& root = Root::getSingleton();
1310
0
        unsigned long currentFrameNumber = root.getNextFrameNumber();
1311
0
        if ((*mFrameBonesLastUpdated != currentFrameNumber) ||
1312
0
            (hasSkeleton() && getSkeleton()->getManualBonesDirty()))
1313
0
        {
1314
0
            if ((!mSkipAnimStateUpdates) && (*mFrameBonesLastUpdated != currentFrameNumber))
1315
0
                mSkeletonInstance->setAnimationState(*mAnimationState);
1316
0
            mSkeletonInstance->_getBoneMatrices(mBoneMatrices);
1317
0
            *mFrameBonesLastUpdated  = currentFrameNumber;
1318
1319
0
            return true;
1320
0
        }
1321
0
        return false;
1322
0
    }
1323
    //-----------------------------------------------------------------------
1324
    void Entity::setDisplaySkeleton(bool display)
1325
0
    {
1326
0
        mDisplaySkeleton = display;
1327
0
    }
1328
    //-----------------------------------------------------------------------
1329
    bool Entity::getDisplaySkeleton(void) const
1330
0
    {
1331
0
        return mDisplaySkeleton;
1332
0
    }
1333
    //-----------------------------------------------------------------------
1334
    void Entity::showBoundingSphere(bool show)
1335
0
    {
1336
0
        mShowBoundingSphere = show;
1337
0
    }
1338
    //-----------------------------------------------------------------------
1339
    bool Entity::getShowBoundingSphere(void) const
1340
0
    {
1341
0
        return mShowBoundingSphere;
1342
0
    }
1343
    //-----------------------------------------------------------------------
1344
    size_t Entity::getNumManualLodLevels(void) const
1345
0
    {
1346
0
#if !OGRE_NO_MESHLOD
1347
0
        return mLodEntityList.size();
1348
#else
1349
        return 0;
1350
#endif
1351
0
    }
1352
1353
    //-----------------------------------------------------------------------
1354
    Entity* Entity::getManualLodLevel(size_t index) const
1355
0
    {
1356
0
#if !OGRE_NO_MESHLOD
1357
0
        assert(index < mLodEntityList.size());
1358
1359
0
        return mLodEntityList[index];
1360
#else
1361
        OgreAssert(0, "This feature is disabled in ogre configuration!");
1362
        return NULL;
1363
#endif
1364
0
    }
1365
#if !OGRE_NO_MESHLOD
1366
    //-----------------------------------------------------------------------
1367
    void Entity::setMeshLodBias(Real factor, ushort maxDetailIndex, ushort minDetailIndex)
1368
0
    {
1369
0
        mMeshLodFactorTransformed = mMesh->getLodStrategy()->transformBias(factor);
1370
0
        mMaxMeshLodIndex = maxDetailIndex;
1371
0
        mMinMeshLodIndex = minDetailIndex;
1372
0
    }
1373
#endif
1374
    //-----------------------------------------------------------------------
1375
    void Entity::setMaterialLodBias(Real factor, ushort maxDetailIndex, ushort minDetailIndex)
1376
0
    {
1377
0
        mMaterialLodFactor = factor;
1378
0
        mMaxMaterialLodIndex = maxDetailIndex;
1379
0
        mMinMaterialLodIndex = minDetailIndex;
1380
0
    }
1381
1382
    //-----------------------------------------------------------------------
1383
    void Entity::buildSubEntityList(MeshPtr& mesh, SubEntityList* sublist)
1384
0
    {
1385
        // Create SubEntities
1386
0
        size_t i, numSubMeshes;
1387
1388
0
        numSubMeshes = mesh->getNumSubMeshes();
1389
0
        for (i = 0; i < numSubMeshes; ++i)
1390
0
        {
1391
0
            SubMesh* subMesh = mesh->getSubMesh(i);
1392
0
            SubEntity* subEnt = OGRE_NEW SubEntity(this, subMesh);
1393
0
            if (subMesh->getMaterial())
1394
0
                subEnt->setMaterial(subMesh->getMaterial());
1395
0
            sublist->push_back(subEnt);
1396
0
        }
1397
0
    }
1398
    //-----------------------------------------------------------------------
1399
    void Entity::setPolygonModeOverrideable(bool overrideable)
1400
0
    {
1401
0
        for(auto *s : mSubEntityList)
1402
0
        {
1403
0
            s->setPolygonModeOverrideable(overrideable);
1404
0
        }
1405
0
    }
1406
1407
    //-----------------------------------------------------------------------
1408
1409
    struct MovableObjectNameExists {
1410
        const String& name;
1411
        bool operator()(const MovableObject* mo) {
1412
            return mo->getName() == name;
1413
        }
1414
    };
1415
1416
    TagPoint* Entity::attachObjectToBone(const String &boneName, MovableObject *pMovable, const Quaternion &offsetOrientation, const Vector3 &offsetPosition)
1417
0
    {
1418
0
        MovableObjectNameExists pred = {pMovable->getName()};
1419
0
        auto it = std::find_if(mChildObjectList.begin(), mChildObjectList.end(), pred);
1420
0
        if (it != mChildObjectList.end())
1421
0
        {
1422
0
            OGRE_EXCEPT(Exception::ERR_DUPLICATE_ITEM,
1423
0
                "An object with the name " + pMovable->getName() + " already attached",
1424
0
                "Entity::attachObjectToBone");
1425
0
        }
1426
0
        OgreAssert(!pMovable->isAttached(), "Object already attached to a sceneNode or a Bone");
1427
0
        OgreAssert(hasSkeleton(), "This entity's mesh has no skeleton to attach object to");
1428
0
        Bone* bone = mSkeletonInstance->getBone(boneName);
1429
0
        if (!bone)
1430
0
        {
1431
0
            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Cannot locate bone named " + boneName,
1432
0
                "Entity::attachObjectToBone");
1433
0
        }
1434
1435
0
        TagPoint *tp = mSkeletonInstance->createTagPointOnBone(
1436
0
            bone, offsetOrientation, offsetPosition);
1437
0
        tp->setParentEntity(this);
1438
0
        tp->setChildObject(pMovable);
1439
1440
0
        attachObjectImpl(pMovable, tp);
1441
1442
        // Trigger update of bounding box if necessary
1443
0
        if (mParentNode)
1444
0
            mParentNode->needUpdate();
1445
1446
0
        return tp;
1447
0
    }
1448
1449
    //-----------------------------------------------------------------------
1450
    void Entity::attachObjectImpl(MovableObject *pObject, TagPoint *pAttachingPoint)
1451
0
    {
1452
0
        assert(std::find_if(mChildObjectList.begin(), mChildObjectList.end(),
1453
0
                            MovableObjectNameExists{pObject->getName()}) == mChildObjectList.end());
1454
1455
0
        mChildObjectList.push_back(pObject);
1456
0
        pObject->_notifyAttached(pAttachingPoint, true);
1457
0
    }
1458
1459
    //-----------------------------------------------------------------------
1460
    MovableObject* Entity::detachObjectFromBone(const String &name)
1461
0
    {
1462
0
        MovableObjectNameExists pred = {name};
1463
0
        auto it = std::find_if(mChildObjectList.begin(), mChildObjectList.end(), pred);
1464
1465
0
        if (it == mChildObjectList.end())
1466
0
        {
1467
0
            OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "No child object entry found named " + name,
1468
0
                "Entity::detachObjectFromBone");
1469
0
        }
1470
0
        detachObjectImpl(*it);
1471
0
        std::swap(*it, mChildObjectList.back());
1472
0
        mChildObjectList.pop_back();
1473
1474
        // Trigger update of bounding box if necessary
1475
0
        if (mParentNode)
1476
0
            mParentNode->needUpdate();
1477
1478
0
        return *it;
1479
0
    }
1480
    //-----------------------------------------------------------------------
1481
    void Entity::detachObjectFromBone(MovableObject* obj)
1482
0
    {
1483
0
        auto it = std::find(mChildObjectList.begin(), mChildObjectList.end(), obj);
1484
0
        OgreAssert(it != mChildObjectList.end(), "Object not attached to this entity");
1485
0
        detachObjectImpl(*it);
1486
0
        std::swap(*it, mChildObjectList.back());
1487
0
        mChildObjectList.pop_back();
1488
1489
        // Trigger update of bounding box if necessary
1490
0
        if (mParentNode)
1491
0
            mParentNode->needUpdate();
1492
0
    }
1493
    //-----------------------------------------------------------------------
1494
    void Entity::detachAllObjectsFromBone(void)
1495
0
    {
1496
0
        detachAllObjectsImpl();
1497
1498
        // Trigger update of bounding box if necessary
1499
0
        if (mParentNode)
1500
0
            mParentNode->needUpdate();
1501
0
    }
1502
    //-----------------------------------------------------------------------
1503
    void Entity::detachObjectImpl(MovableObject* pObject)
1504
0
    {
1505
0
        TagPoint* tp = static_cast<TagPoint*>(pObject->getParentNode());
1506
1507
        // free the TagPoint so we can reuse it later
1508
0
        mSkeletonInstance->freeTagPoint(tp);
1509
1510
0
        pObject->_notifyAttached((TagPoint*)0);
1511
0
    }
1512
    //-----------------------------------------------------------------------
1513
    void Entity::detachAllObjectsImpl(void)
1514
0
    {
1515
0
        for (auto child : mChildObjectList)
1516
0
        {
1517
0
            detachObjectImpl(child);
1518
0
        }
1519
0
        mChildObjectList.clear();
1520
0
    }
1521
1522
    //-----------------------------------------------------------------------
1523
    Entity::ChildObjectListIterator Entity::getAttachedObjectIterator()
1524
0
    {
1525
0
        return ChildObjectListIterator(mChildObjectList.begin(), mChildObjectList.end());
1526
0
    }
1527
    //-----------------------------------------------------------------------
1528
    Real Entity::getBoundingRadius(void) const
1529
0
    {
1530
0
        return mMesh->getBoundingSphereRadius();
1531
0
    }
1532
    //-----------------------------------------------------------------------
1533
    void Entity::prepareTempBlendBuffers(void)
1534
0
    {
1535
0
        mSkelAnimVertexData.reset();
1536
0
        mSoftwareVertexAnimVertexData.reset();
1537
0
        mHardwareVertexAnimVertexData.reset();
1538
1539
0
        if (hasVertexAnimation())
1540
0
        {
1541
            // Shared data
1542
0
            if (mMesh->sharedVertexData
1543
0
                && mMesh->getSharedVertexDataAnimationType() != VAT_NONE)
1544
0
            {
1545
                // Create temporary vertex blend info
1546
                // Prepare temp vertex data if needed
1547
                // Clone without copying data, don't remove any blending info
1548
                // (since if we skeletally animate too, we need it)
1549
0
                mSoftwareVertexAnimVertexData.reset(mMesh->sharedVertexData->clone(false));
1550
0
                mTempVertexAnimInfo.extractFrom(mSoftwareVertexAnimVertexData.get());
1551
1552
                // Also clone for hardware usage, don't remove blend info since we'll
1553
                // need it if we also hardware skeletally animate
1554
0
                mHardwareVertexAnimVertexData.reset(mMesh->sharedVertexData->clone(false));
1555
0
            }
1556
0
        }
1557
1558
0
        if (hasSkeleton())
1559
0
        {
1560
            // Shared data
1561
0
            if (mMesh->sharedVertexData)
1562
0
            {
1563
                // Create temporary vertex blend info
1564
                // Prepare temp vertex data if needed
1565
                // Clone without copying data, remove blending info
1566
                // (since blend is performed in software)
1567
0
                mSkelAnimVertexData.reset(mMesh->sharedVertexData->_cloneRemovingBlendData());
1568
0
                mTempSkelAnimInfo.extractFrom(mSkelAnimVertexData.get());
1569
0
            }
1570
1571
0
        }
1572
1573
        // Do SubEntities
1574
0
        for (auto *s : mSubEntityList)
1575
0
        {
1576
0
            s->prepareTempBlendBuffers();
1577
0
        }
1578
1579
        // It's prepared for shadow volumes only if mesh has been prepared for shadow volumes.
1580
0
        mPreparedForShadowVolumes = mMesh->isPreparedForShadowVolumes();
1581
0
    }
1582
    //-----------------------------------------------------------------------
1583
    EdgeData* Entity::getEdgeList(void)
1584
0
    {
1585
        // Get from Mesh
1586
0
        return mMesh->getEdgeList(mMeshLodIndex);
1587
0
    }
1588
    //-----------------------------------------------------------------------
1589
    bool Entity::isHardwareAnimationEnabled(void)
1590
0
    {
1591
        //find whether the entity has hardware animation for the current active sceme
1592
0
        unsigned short schemeIndex = MaterialManager::getSingleton()._getActiveSchemeIndex();
1593
0
        for(const auto& p : mSchemeHardwareAnim)
1594
0
        {
1595
0
            if(p.first == schemeIndex) return p.second;
1596
0
        }
1597
0
        bool ret = calcVertexProcessing();
1598
0
        mSchemeHardwareAnim.emplace_back(schemeIndex, ret);
1599
0
        return ret;
1600
0
    }
1601
1602
    //-----------------------------------------------------------------------
1603
    void Entity::reevaluateVertexProcessing(void)
1604
0
    {
1605
        //clear the cache so that the values will be reevaluated
1606
0
        mSchemeHardwareAnim.clear();
1607
0
    }
1608
    //-----------------------------------------------------------------------
1609
    bool Entity::calcVertexProcessing(void)
1610
0
    {
1611
        // init
1612
0
        bool hasHardwareAnimation = false;
1613
0
        bool firstPass = true;
1614
1615
0
        for (auto *sub : mSubEntityList)
1616
0
        {
1617
0
            const MaterialPtr& m = sub->getMaterial();
1618
            // Make sure it's loaded
1619
0
            m->load();
1620
0
            Technique* t = m->getBestTechnique(0, sub);
1621
0
            if (!t)
1622
0
            {
1623
                // No supported techniques
1624
0
                continue;
1625
0
            }
1626
0
            if (t->getNumPasses() == 0)
1627
0
            {
1628
                // No passes, invalid
1629
0
                continue;
1630
0
            }
1631
0
            Pass* p = t->getPass(0);
1632
0
            if (p->hasVertexProgram())
1633
0
            {
1634
0
                if (mVertexProgramInUse == false)
1635
0
                {
1636
                    // If one material uses a vertex program, set this flag
1637
                    // Causes some special processing like forcing a separate light cap
1638
0
                    mVertexProgramInUse = true;
1639
1640
                    // If shadow renderables already created create their light caps
1641
0
                    ShadowRenderableList::iterator si = mShadowRenderables.begin();
1642
0
                    ShadowRenderableList::iterator siend = mShadowRenderables.end();
1643
0
                    for (si = mShadowRenderables.begin(); si != siend; ++si)
1644
0
                    {
1645
0
                        static_cast<EntityShadowRenderable*>(*si)->_createSeparateLightCap();
1646
0
                    }
1647
0
                }
1648
1649
0
                if (hasSkeleton())
1650
0
                {
1651
                    // All materials must support skinning for us to consider using
1652
                    // hardware animation - if one fails we use software
1653
0
                    if (firstPass)
1654
0
                    {
1655
0
                        hasHardwareAnimation = p->getVertexProgram()->isSkeletalAnimationIncluded();
1656
0
                        firstPass = false;
1657
0
                    }
1658
0
                    else
1659
0
                    {
1660
0
                        hasHardwareAnimation = hasHardwareAnimation &&
1661
0
                            p->getVertexProgram()->isSkeletalAnimationIncluded();
1662
0
                    }
1663
0
                }
1664
1665
0
                VertexAnimationType animType = VAT_NONE;
1666
0
                if (sub->getSubMesh()->useSharedVertices)
1667
0
                {
1668
0
                    animType = mMesh->getSharedVertexDataAnimationType();
1669
0
                }
1670
0
                else
1671
0
                {
1672
0
                    animType = sub->getSubMesh()->getVertexAnimationType();
1673
0
                }
1674
0
                if (animType == VAT_MORPH)
1675
0
                {
1676
                    // All materials must support morph animation for us to consider using
1677
                    // hardware animation - if one fails we use software
1678
0
                    if (firstPass)
1679
0
                    {
1680
0
                        hasHardwareAnimation = p->getVertexProgram()->isMorphAnimationIncluded();
1681
0
                        firstPass = false;
1682
0
                    }
1683
0
                    else
1684
0
                    {
1685
0
                        hasHardwareAnimation = hasHardwareAnimation &&
1686
0
                            p->getVertexProgram()->isMorphAnimationIncluded();
1687
0
                    }
1688
0
                }
1689
0
                else if (animType == VAT_POSE)
1690
0
                {
1691
                    // All materials must support pose animation for us to consider using
1692
                    // hardware animation - if one fails we use software
1693
0
                    if (firstPass)
1694
0
                    {
1695
0
                        hasHardwareAnimation = p->getVertexProgram()->isPoseAnimationIncluded();
1696
0
                        if (sub->getSubMesh()->useSharedVertices)
1697
0
                            mHardwarePoseCount = p->getVertexProgram()->getNumberOfPosesIncluded();
1698
0
                        else
1699
0
                            sub->mHardwarePoseCount = p->getVertexProgram()->getNumberOfPosesIncluded();
1700
0
                        firstPass = false;
1701
0
                    }
1702
0
                    else
1703
0
                    {
1704
0
                        hasHardwareAnimation = hasHardwareAnimation &&
1705
0
                            p->getVertexProgram()->isPoseAnimationIncluded();
1706
0
                        if (sub->getSubMesh()->useSharedVertices)
1707
0
                            mHardwarePoseCount = std::max(mHardwarePoseCount,
1708
0
                                p->getVertexProgram()->getNumberOfPosesIncluded());
1709
0
                        else
1710
0
                            sub->mHardwarePoseCount = std::max(sub->mHardwarePoseCount,
1711
0
                                p->getVertexProgram()->getNumberOfPosesIncluded());
1712
0
                    }
1713
0
                }
1714
1715
0
            }
1716
0
        }
1717
1718
        // Should be force update of animation if they exists, due reevaluate
1719
        // vertex processing might switchs between hardware/software animation,
1720
        // and then we'll end with NULL or incorrect mBoneWorldMatrices, or
1721
        // incorrect blended software animation buffers.
1722
0
        if (mAnimationState)
1723
0
        {
1724
0
            mFrameAnimationLastUpdated = mAnimationState->getDirtyFrameNumber() - 1;
1725
0
        }
1726
1727
0
        return hasHardwareAnimation;
1728
0
    }
1729
1730
    //-----------------------------------------------------------------------
1731
    Real Entity::_getMeshLodFactorTransformed() const
1732
0
    {
1733
0
        return mMeshLodFactorTransformed;
1734
0
    }
1735
    //-----------------------------------------------------------------------
1736
    const ShadowRenderableList&
1737
    Entity::getShadowVolumeRenderableList(const Light* light, const HardwareIndexBufferPtr& indexBuffer,
1738
                                          size_t& indexBufferUsedSize, float extrusionDistance, int flags)
1739
0
    {
1740
0
        assert(indexBuffer->getType() == HardwareIndexBuffer::IT_16BIT &&
1741
0
               "Only 16-bit indexes supported for now");
1742
1743
        // Check mesh state count, will be incremented if reloaded
1744
0
        if (mMesh->getStateCount() != mMeshStateCount)
1745
0
        {
1746
            // force reinitialise
1747
0
            _initialise(true);
1748
0
        }
1749
1750
0
#if !OGRE_NO_MESHLOD
1751
        // Potentially delegate to LOD entity
1752
0
        if (mMesh->hasManualLodLevel() && mMeshLodIndex > 0)
1753
0
        {
1754
            // Use alternate entity
1755
0
            assert( static_cast< size_t >( mMeshLodIndex - 1 ) < mLodEntityList.size() &&
1756
0
                "No LOD EntityList - did you build the manual LODs after creating the entity?");
1757
1758
0
            Entity* requiredEntity = mLodEntityList[mMeshLodIndex-1];
1759
0
            if (requiredEntity != this) {
1760
                // delegate, we're using manual LOD and not the top lod index
1761
0
                if (hasSkeleton() && mLodEntityList[mMeshLodIndex-1]->hasSkeleton())
1762
0
                {
1763
                    // Copy the animation state set to lod entity, we assume the lod
1764
                    // entity only has a subset animation states
1765
0
                    AnimationStateSet* targetState = mLodEntityList[mMeshLodIndex-1]->mAnimationState;
1766
0
                    if (mAnimationState != targetState) // only copy if lods have different skeleton instances
1767
0
                    {
1768
0
                        if (mAnimationState && mAnimationState->getDirtyFrameNumber() != targetState->getDirtyFrameNumber()) // only copy if animation was updated
1769
0
                            mAnimationState->copyMatchingState(targetState);
1770
0
                    }
1771
0
                }
1772
0
                return mLodEntityList[mMeshLodIndex - 1]->getShadowVolumeRenderableList(
1773
0
                    light, indexBuffer, indexBufferUsedSize, extrusionDistance, flags);
1774
0
            }
1775
0
        }
1776
0
#endif
1777
1778
        // Prepare temp buffers if required
1779
0
        if (!mPreparedForShadowVolumes)
1780
0
        {
1781
0
            mMesh->prepareForShadowVolume();
1782
            // reset frame last updated to force update of animations if they exist
1783
0
            if (mAnimationState)
1784
0
                mFrameAnimationLastUpdated = mAnimationState->getDirtyFrameNumber() - 1;
1785
            // re-prepare buffers
1786
0
            prepareTempBlendBuffers();
1787
0
        }
1788
1789
1790
0
        bool hasAnimation = (hasSkeleton() || hasVertexAnimation());
1791
1792
        // Update any animation
1793
0
        if (hasAnimation)
1794
0
        {
1795
0
            updateAnimation();
1796
0
        }
1797
1798
        // Calculate the object space light details
1799
0
        Vector4 lightPos = light->getAs4DVector();
1800
0
        Affine3 world2Obj = mParentNode->_getFullTransform().inverse();
1801
0
        lightPos = world2Obj * lightPos;
1802
0
        Matrix3 world2Obj3x3 = world2Obj.linear();
1803
0
        extrusionDistance *= Math::Sqrt(std::min(std::min(world2Obj3x3.GetColumn(0).squaredLength(), world2Obj3x3.GetColumn(1).squaredLength()), world2Obj3x3.GetColumn(2).squaredLength()));
1804
1805
        // We need to search the edge list for silhouette edges
1806
0
        EdgeData* edgeList = getEdgeList();
1807
1808
0
        if (!edgeList)
1809
0
        {
1810
            // we can't get an edge list for some reason, return blank
1811
            // really we shouldn't be able to get here, but this is a safeguard
1812
0
            return mShadowRenderables;
1813
0
        }
1814
1815
        // Init shadow renderable list if required
1816
0
        bool init = mShadowRenderables.empty();
1817
1818
0
        EdgeData::EdgeGroupList::iterator egi;
1819
0
        ShadowRenderableList::iterator si, siend;
1820
0
        if (init)
1821
0
            mShadowRenderables.resize(edgeList->edgeGroups.size());
1822
1823
0
        bool isAnimated = hasAnimation;
1824
0
        bool updatedSharedGeomNormals = false;
1825
0
        bool extrude = flags & SRF_EXTRUDE_IN_SOFTWARE;
1826
0
        siend = mShadowRenderables.end();
1827
0
        egi = edgeList->edgeGroups.begin();
1828
0
        for (si = mShadowRenderables.begin(); si != siend; ++si, ++egi)
1829
0
        {
1830
0
            const VertexData *pVertData;
1831
0
            if (isAnimated)
1832
0
            {
1833
                // Use temp buffers
1834
0
                pVertData = findBlendedVertexData(egi->vertexData);
1835
0
            }
1836
0
            else
1837
0
            {
1838
0
                pVertData = egi->vertexData;
1839
0
            }
1840
0
            if (init)
1841
0
            {
1842
                // Try to find corresponding SubEntity; this allows the
1843
                // linkage of visibility between ShadowRenderable and SubEntity
1844
0
                SubEntity* subent = findSubEntityForVertexData(egi->vertexData);
1845
                // Create a new renderable, create a separate light cap if
1846
                // we're using a vertex program (either for this model, or
1847
                // for extruding the shadow volume) since otherwise we can
1848
                // get depth-fighting on the light cap
1849
1850
0
                *si = OGRE_NEW EntityShadowRenderable(this, indexBuffer, pVertData,
1851
0
                                                      mVertexProgramInUse || !extrude, subent);
1852
0
            }
1853
0
            else
1854
0
            {
1855
                // If we have animation, we have no guarantee that the position
1856
                // buffer we used last frame is the same one we used last frame
1857
                // since a temporary buffer is requested each frame
1858
                // therefore, we need to update the EntityShadowRenderable
1859
                // with the current position buffer
1860
0
                static_cast<EntityShadowRenderable*>(*si)->rebindPositionBuffer(pVertData, hasAnimation);
1861
1862
0
            }
1863
            // Get shadow renderable
1864
0
            HardwareVertexBufferSharedPtr esrPositionBuffer = (*si)->getPositionBuffer();
1865
            // For animated entities we need to recalculate the face normals
1866
0
            if (hasAnimation)
1867
0
            {
1868
0
                if (egi->vertexData != mMesh->sharedVertexData || !updatedSharedGeomNormals)
1869
0
                {
1870
                    // recalculate face normals
1871
0
                    edgeList->updateFaceNormals(egi->vertexSet, esrPositionBuffer);
1872
                    // If we're not extruding in software we still need to update
1873
                    // the latter part of the buffer (the hardware extruded part)
1874
                    // with the latest animated positions
1875
0
                    if (!extrude)
1876
0
                    {
1877
                        // Lock, we'll be locking the (suppressed hardware update) shadow buffer
1878
0
                        HardwareBufferLockGuard posLock(esrPositionBuffer, HardwareBuffer::HBL_NORMAL);
1879
0
                        float* pSrc = static_cast<float*>(posLock.pData);
1880
0
                        float* pDest = pSrc + (egi->vertexData->vertexCount * 3);
1881
0
                        memcpy(pDest, pSrc, sizeof(float) * 3 * egi->vertexData->vertexCount);
1882
0
                    }
1883
0
                    if (egi->vertexData == mMesh->sharedVertexData)
1884
0
                    {
1885
0
                        updatedSharedGeomNormals = true;
1886
0
                    }
1887
0
                }
1888
0
            }
1889
            // Extrude vertices in software if required
1890
0
            if (extrude)
1891
0
            {
1892
0
                extrudeVertices(esrPositionBuffer,
1893
0
                    egi->vertexData->vertexCount,
1894
0
                    lightPos, extrusionDistance);
1895
1896
0
            }
1897
            // Stop suppressing hardware update now, if we were
1898
0
            esrPositionBuffer->suppressHardwareUpdate(false);
1899
1900
0
        }
1901
        // Calc triangle light facing
1902
0
        updateEdgeListLightFacing(edgeList, lightPos);
1903
1904
        // Generate indexes and update renderables
1905
0
        generateShadowVolume(edgeList, indexBuffer, indexBufferUsedSize, light, mShadowRenderables, flags);
1906
1907
0
        return mShadowRenderables;
1908
0
    }
1909
    //-----------------------------------------------------------------------
1910
    const VertexData* Entity::findBlendedVertexData(const VertexData* orig)
1911
0
    {
1912
0
        bool skel = hasSkeleton();
1913
1914
0
        if (orig == mMesh->sharedVertexData)
1915
0
        {
1916
0
            return skel? mSkelAnimVertexData.get() : mSoftwareVertexAnimVertexData.get();
1917
0
        }
1918
1919
0
        for (auto *se : mSubEntityList)
1920
0
        {
1921
0
            if (orig == se->getSubMesh()->vertexData)
1922
0
            {
1923
0
                return skel? se->_getSkelAnimVertexData() : se->_getSoftwareVertexAnimVertexData();
1924
0
            }
1925
0
        }
1926
        // None found
1927
0
        OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,
1928
0
            "Cannot find blended version of the vertex data specified.",
1929
0
            "Entity::findBlendedVertexData");
1930
0
    }
1931
    //-----------------------------------------------------------------------
1932
    SubEntity* Entity::findSubEntityForVertexData(const VertexData* orig)
1933
0
    {
1934
0
        if (orig == mMesh->sharedVertexData)
1935
0
        {
1936
0
            return 0;
1937
0
        }
1938
1939
0
        for (auto *se : mSubEntityList)
1940
0
        {
1941
0
            if (orig == se->getSubMesh()->vertexData)
1942
0
            {
1943
0
                return se;
1944
0
            }
1945
0
        }
1946
1947
        // None found
1948
0
        return 0;
1949
0
    }
1950
    //-----------------------------------------------------------------------
1951
    void Entity::addSoftwareAnimationRequest(bool normalsAlso)
1952
0
    {
1953
0
        mSoftwareAnimationRequests++;
1954
0
        if (normalsAlso) {
1955
0
            mSoftwareAnimationNormalsRequests++;
1956
0
        }
1957
0
    }
1958
    //-----------------------------------------------------------------------
1959
    void Entity::removeSoftwareAnimationRequest(bool normalsAlso)
1960
0
    {
1961
0
        if (mSoftwareAnimationRequests == 0 ||
1962
0
            (normalsAlso && mSoftwareAnimationNormalsRequests == 0))
1963
0
        {
1964
0
            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
1965
0
                        "Attempt to remove nonexistent request.",
1966
0
                        "Entity::removeSoftwareAnimationRequest");
1967
0
        }
1968
0
        mSoftwareAnimationRequests--;
1969
0
        if (normalsAlso) {
1970
0
            mSoftwareAnimationNormalsRequests--;
1971
0
        }
1972
0
    }
1973
    //-----------------------------------------------------------------------
1974
    void Entity::_notifyAttached(Node* parent, bool isTagPoint)
1975
0
    {
1976
0
        MovableObject::_notifyAttached(parent, isTagPoint);
1977
0
#if !OGRE_NO_MESHLOD
1978
        // Also notify LOD entities
1979
0
        for (auto *e : mLodEntityList)
1980
0
        {
1981
0
            if(e != this)
1982
0
                e->_notifyAttached(parent, isTagPoint);
1983
0
        }
1984
0
#endif
1985
0
    }
1986
    //-----------------------------------------------------------------------
1987
    //-----------------------------------------------------------------------
1988
    Entity::EntityShadowRenderable::EntityShadowRenderable(MovableObject* parent,
1989
                                                           const HardwareIndexBufferSharedPtr& indexBuffer,
1990
                                                           const VertexData* vertexData,
1991
                                                           bool createSeparateLightCap, SubEntity* subent,
1992
                                                           bool isLightCap)
1993
0
        : ShadowRenderable(parent, indexBuffer, vertexData, false, isLightCap), mSubEntity(subent)
1994
0
    {
1995
        // Save link to vertex data
1996
0
        mCurrentVertexData = vertexData;
1997
0
        mOriginalPosBufferBinding =
1998
0
            vertexData->vertexDeclaration->findElementBySemantic(VES_POSITION)->getSource();
1999
0
        if (!isLightCap && createSeparateLightCap) // we passed createSeparateLightCap=false to parent
2000
0
        {
2001
0
            _createSeparateLightCap();
2002
0
        }
2003
0
    }
2004
2005
    //-----------------------------------------------------------------------
2006
    void Entity::EntityShadowRenderable::_createSeparateLightCap()
2007
0
    {
2008
0
        if (mLightCap == NULL)
2009
0
        {
2010
            // Create child light cap
2011
0
            mLightCap = OGRE_NEW EntityShadowRenderable(mParent,
2012
0
                mRenderOp.indexData->indexBuffer, mCurrentVertexData, false, mSubEntity, true);
2013
0
        }
2014
0
    }
2015
    //-----------------------------------------------------------------------
2016
    void Entity::EntityShadowRenderable::rebindPositionBuffer(const VertexData* vertexData, bool force)
2017
0
    {
2018
0
        if (force || mCurrentVertexData != vertexData)
2019
0
        {
2020
0
            mCurrentVertexData = vertexData;
2021
0
            mPositionBuffer = mCurrentVertexData->vertexBufferBinding->getBuffer(
2022
0
                mOriginalPosBufferBinding);
2023
0
            mRenderOp.vertexData->vertexBufferBinding->setBinding(0, mPositionBuffer);
2024
0
            if (mLightCap)
2025
0
            {
2026
0
                static_cast<EntityShadowRenderable*>(mLightCap)->rebindPositionBuffer(vertexData, force);
2027
0
            }
2028
0
        }
2029
0
    }
2030
    //-----------------------------------------------------------------------
2031
    bool Entity::EntityShadowRenderable::isVisible(void) const
2032
0
    {
2033
0
        if (mSubEntity)
2034
0
        {
2035
0
            return mSubEntity->isVisible();
2036
0
        }
2037
0
        else
2038
0
        {
2039
0
            return ShadowRenderable::isVisible();
2040
0
        }
2041
0
    }
2042
    //-----------------------------------------------------------------------
2043
    void Entity::setRenderQueueGroup(uint8 queueID)
2044
0
    {
2045
0
        MovableObject::setRenderQueueGroup(queueID);
2046
0
#if !OGRE_NO_MESHLOD
2047
        // Set render queue for all manual LOD entities
2048
0
        if (mMesh->hasManualLodLevel())
2049
0
        {
2050
0
            for (auto *e : mLodEntityList)
2051
0
            {
2052
0
                if(e != this)
2053
0
                    e->setRenderQueueGroup(queueID);
2054
0
            }
2055
0
        }
2056
0
#endif
2057
0
    }
2058
    //-----------------------------------------------------------------------
2059
    void Entity::setRenderQueueGroupAndPriority(uint8 queueID, ushort priority)
2060
0
    {
2061
0
        MovableObject::setRenderQueueGroupAndPriority(queueID, priority);
2062
0
#if !OGRE_NO_MESHLOD
2063
        // Set render queue for all manual LOD entities
2064
0
        if (mMesh->hasManualLodLevel())
2065
0
        {
2066
0
            for (auto *e : mLodEntityList)
2067
0
            {
2068
0
                if(e != this)
2069
0
                    e->setRenderQueueGroupAndPriority(queueID, priority);
2070
0
            }
2071
0
        }
2072
0
#endif
2073
0
    }
2074
    //-----------------------------------------------------------------------
2075
    void Entity::shareSkeletonInstanceWith(Entity* entity)
2076
0
    {
2077
0
        OgreAssert(entity->getMesh()->getSkeleton() == getMesh()->getSkeleton(),
2078
0
                   "The supplied entity has a different skeleton");
2079
0
        OgreAssert(mSkeletonInstance, "This entity has no skeleton");
2080
0
        OgreAssert(!mSharedSkeletonEntities || !entity->mSharedSkeletonEntities,
2081
0
                   "Both entities already shares their SkeletonInstances! At least one of the instances "
2082
0
                   "must not share it's instance");
2083
2084
        //check if we already share our skeletoninstance, we don't want to delete it if so
2085
0
        if (mSharedSkeletonEntities != NULL)
2086
0
        {
2087
0
            entity->shareSkeletonInstanceWith(this);
2088
0
        }
2089
0
        else
2090
0
        {
2091
0
            OGRE_DELETE mSkeletonInstance;
2092
0
            OGRE_FREE_SIMD(mBoneMatrices, MEMCATEGORY_ANIMATION);
2093
0
            OGRE_DELETE mAnimationState;
2094
            // using OGRE_FREE since unsigned long is not a destructor
2095
0
            OGRE_FREE(mFrameBonesLastUpdated, MEMCATEGORY_ANIMATION);
2096
0
            mSkeletonInstance = entity->mSkeletonInstance;
2097
0
            mNumBoneMatrices = entity->mNumBoneMatrices;
2098
0
            mBoneMatrices = entity->mBoneMatrices;
2099
0
            mAnimationState = entity->mAnimationState;
2100
0
            mFrameBonesLastUpdated = entity->mFrameBonesLastUpdated;
2101
0
            if (entity->mSharedSkeletonEntities == NULL)
2102
0
            {
2103
0
                entity->mSharedSkeletonEntities = OGRE_NEW_T(EntitySet, MEMCATEGORY_ANIMATION)();
2104
0
                entity->mSharedSkeletonEntities->insert(entity);
2105
0
            }
2106
0
            mSharedSkeletonEntities = entity->mSharedSkeletonEntities;
2107
0
            mSharedSkeletonEntities->insert(this);
2108
0
        }
2109
0
    }
2110
    //-----------------------------------------------------------------------
2111
    void Entity::stopSharingSkeletonInstance()
2112
0
    {
2113
0
        OgreAssert(mSharedSkeletonEntities, "This entity is not sharing it's skeletoninstance");
2114
        //check if there's no other than us sharing the skeleton instance
2115
0
        if (mSharedSkeletonEntities->size() == 1)
2116
0
        {
2117
            //just reset
2118
0
            OGRE_DELETE_T(mSharedSkeletonEntities, EntitySet, MEMCATEGORY_ANIMATION);
2119
0
            mSharedSkeletonEntities = 0;
2120
0
        }
2121
0
        else
2122
0
        {
2123
0
            mSkeletonInstance = OGRE_NEW SkeletonInstance(mMesh->getSkeleton());
2124
0
            mSkeletonInstance->load();
2125
0
            mAnimationState = OGRE_NEW AnimationStateSet();
2126
0
            mMesh->_initAnimationState(mAnimationState);
2127
0
            mFrameBonesLastUpdated = OGRE_ALLOC_T(unsigned long, 1, MEMCATEGORY_ANIMATION);
2128
0
            *mFrameBonesLastUpdated = std::numeric_limits<unsigned long>::max();
2129
0
            mNumBoneMatrices = mSkeletonInstance->getNumBones();
2130
0
            mBoneMatrices = static_cast<Affine3*>(OGRE_MALLOC_SIMD(sizeof(Affine3) * mNumBoneMatrices, MEMCATEGORY_ANIMATION));
2131
2132
0
            mSharedSkeletonEntities->erase(this);
2133
0
            if (mSharedSkeletonEntities->size() == 1)
2134
0
            {
2135
0
                (*mSharedSkeletonEntities->begin())->stopSharingSkeletonInstance();
2136
0
            }
2137
0
            mSharedSkeletonEntities = 0;
2138
0
        }
2139
0
    }
2140
    //-----------------------------------------------------------------------
2141
    void Entity::refreshAvailableAnimationState(void)
2142
0
    {
2143
0
        mMesh->_refreshAnimationState(mAnimationState);
2144
0
    }
2145
    //-----------------------------------------------------------------------
2146
    uint32 Entity::getTypeFlags(void) const
2147
0
    {
2148
0
        return SceneManager::ENTITY_TYPE_MASK;
2149
0
    }
2150
    //-----------------------------------------------------------------------
2151
    VertexData* Entity::getVertexDataForBinding(void)
2152
0
    {
2153
0
        Entity::VertexDataBindChoice c =
2154
0
            chooseVertexDataForBinding(mMesh->getSharedVertexDataAnimationType() != VAT_NONE);
2155
0
        switch(c)
2156
0
        {
2157
0
        case BIND_ORIGINAL:
2158
0
            return mMesh->sharedVertexData;
2159
0
        case BIND_HARDWARE_MORPH:
2160
0
            return mHardwareVertexAnimVertexData.get();
2161
0
        case BIND_SOFTWARE_MORPH:
2162
0
            return mSoftwareVertexAnimVertexData.get();
2163
0
        case BIND_SOFTWARE_SKELETAL:
2164
0
            return mSkelAnimVertexData.get();
2165
0
        };
2166
        // keep compiler happy
2167
0
        return mMesh->sharedVertexData;
2168
0
    }
2169
    //-----------------------------------------------------------------------
2170
    Entity::VertexDataBindChoice Entity::chooseVertexDataForBinding(bool vertexAnim)
2171
0
    {
2172
0
        if (hasSkeleton())
2173
0
        {
2174
0
            if (!isHardwareAnimationEnabled())
2175
0
            {
2176
                // all software skeletal binds same vertex data
2177
                // may be a 2-stage s/w transform including morph earlier though
2178
0
                return BIND_SOFTWARE_SKELETAL;
2179
0
            }
2180
0
            else if (vertexAnim)
2181
0
            {
2182
                // hardware morph animation
2183
0
                return BIND_HARDWARE_MORPH;
2184
0
            }
2185
0
            else
2186
0
            {
2187
                // hardware skeletal, no morphing
2188
0
                return BIND_ORIGINAL;
2189
0
            }
2190
0
        }
2191
0
        else if (vertexAnim)
2192
0
        {
2193
            // morph only, no skeletal
2194
0
            if (isHardwareAnimationEnabled())
2195
0
            {
2196
0
                return BIND_HARDWARE_MORPH;
2197
0
            }
2198
0
            else
2199
0
            {
2200
0
                return BIND_SOFTWARE_MORPH;
2201
0
            }
2202
2203
0
        }
2204
0
        else
2205
0
        {
2206
0
            return BIND_ORIGINAL;
2207
0
        }
2208
2209
0
    }
2210
    //---------------------------------------------------------------------
2211
    void Entity::visitRenderables(Renderable::Visitor* visitor,
2212
        bool debugRenderables)
2213
0
    {
2214
        // Visit each SubEntity
2215
0
        for (auto& i : mSubEntityList)
2216
0
        {
2217
0
            visitor->visit(i, 0, false);
2218
0
        }
2219
0
#if !OGRE_NO_MESHLOD
2220
        // if manual LOD is in use, visit those too
2221
0
        ushort lodi = 1;
2222
0
        for (auto& e : mLodEntityList)
2223
0
        {
2224
0
            if(e != this) {
2225
0
                size_t nsub = e->getNumSubEntities();
2226
0
                for (uint s = 0; s < nsub; ++s)
2227
0
                {
2228
0
                    visitor->visit(e->getSubEntity(s), lodi, false);
2229
0
                }
2230
0
            }
2231
0
          ++lodi;
2232
0
        }
2233
0
#endif
2234
0
    }
2235
    //-----------------------------------------------------------------------
2236
    //-----------------------------------------------------------------------
2237
    const String MOT_ENTITY = "Entity";
2238
    //-----------------------------------------------------------------------
2239
    const String& EntityFactory::getType(void) const
2240
0
    {
2241
0
        return MOT_ENTITY;
2242
0
    }
2243
    //-----------------------------------------------------------------------
2244
    MovableObject* EntityFactory::createInstanceImpl( const String& name,
2245
        const NameValuePairList* params)
2246
0
    {
2247
        // must have mesh parameter
2248
0
        MeshPtr pMesh;
2249
0
        if (params != 0)
2250
0
        {
2251
0
            String groupName = ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME;
2252
2253
0
            NameValuePairList::const_iterator ni;
2254
2255
0
            ni = params->find("resourceGroup");
2256
0
            if (ni != params->end())
2257
0
            {
2258
0
                groupName = ni->second;
2259
0
            }
2260
2261
0
            ni = params->find("mesh");
2262
0
            if (ni != params->end())
2263
0
            {
2264
                // Get mesh (load if required)
2265
0
                pMesh = MeshManager::getSingleton().load(
2266
0
                    ni->second,
2267
                    // autodetect group location
2268
0
                    groupName );
2269
0
            }
2270
2271
0
        }
2272
0
        if (!pMesh)
2273
0
        {
2274
0
            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
2275
0
                "'mesh' parameter required when constructing an Entity.",
2276
0
                "EntityFactory::createInstance");
2277
0
        }
2278
2279
0
        return OGRE_NEW Entity(name, pMesh);
2280
2281
0
    }
2282
   //-----------------------------------------------------------------------------
2283
    //-----------------------------------------------------------------------------
2284
    //-----------------------------------------------------------------------------
2285
    Entity::TempBlendedBufferInfo::~TempBlendedBufferInfo(void)
2286
0
    {
2287
        // check that temp buffers have been released
2288
0
        if (destPositionBuffer)
2289
0
            destPositionBuffer->getManager()->releaseVertexBufferCopy(destPositionBuffer);
2290
0
        if (destNormalBuffer)
2291
0
            destNormalBuffer->getManager()->releaseVertexBufferCopy(destNormalBuffer);
2292
2293
0
    }
2294
    //-----------------------------------------------------------------------------
2295
    void Entity::TempBlendedBufferInfo::extractFrom(const VertexData* sourceData)
2296
0
    {
2297
        // Release old buffer copies first
2298
0
        if (destPositionBuffer)
2299
0
        {
2300
0
            destPositionBuffer->getManager()->releaseVertexBufferCopy(destPositionBuffer);
2301
0
            assert(!destPositionBuffer);
2302
0
        }
2303
0
        if (destNormalBuffer)
2304
0
        {
2305
0
            destNormalBuffer->getManager()->releaseVertexBufferCopy(destNormalBuffer);
2306
0
            assert(!destNormalBuffer);
2307
0
        }
2308
2309
0
        VertexDeclaration* decl = sourceData->vertexDeclaration;
2310
0
        VertexBufferBinding* bind = sourceData->vertexBufferBinding;
2311
0
        const VertexElement *posElem = decl->findElementBySemantic(VES_POSITION);
2312
0
        const VertexElement *normElem = decl->findElementBySemantic(VES_NORMAL);
2313
2314
0
        assert(posElem && "Positions are required");
2315
2316
0
        posBindIndex = posElem->getSource();
2317
0
        srcPositionBuffer = bind->getBuffer(posBindIndex);
2318
0
        srcNormalBuffer.reset();
2319
2320
0
        if (!normElem)
2321
0
        {
2322
0
            posNormalShareBuffer = false;
2323
0
            posNormalExtraData = posElem->getSize() != srcPositionBuffer->getVertexSize();
2324
0
        }
2325
0
        else
2326
0
        {
2327
0
            normBindIndex = normElem->getSource();
2328
0
            if (normBindIndex == posBindIndex)
2329
0
            {
2330
0
                posNormalShareBuffer = true;
2331
0
                posNormalExtraData = (posElem->getSize() + normElem->getSize()) != srcPositionBuffer->getVertexSize();
2332
0
            }
2333
0
            else
2334
0
            {
2335
0
                posNormalExtraData = false;
2336
0
                posNormalShareBuffer = false;
2337
0
                srcNormalBuffer = bind->getBuffer(normBindIndex);
2338
0
            }
2339
0
        }
2340
0
    }
2341
    //-----------------------------------------------------------------------------
2342
    void Entity::TempBlendedBufferInfo::checkoutTempCopies(bool positions, bool normals)
2343
0
    {
2344
0
        bindPositions = positions;
2345
0
        bindNormals = normals;
2346
2347
0
        if (positions && !destPositionBuffer)
2348
0
        {
2349
0
            destPositionBuffer =
2350
0
                srcPositionBuffer->getManager()->allocateVertexBufferCopy(srcPositionBuffer, this, posNormalExtraData);
2351
0
        }
2352
0
        if (normals && !posNormalShareBuffer && srcNormalBuffer && !destNormalBuffer)
2353
0
        {
2354
0
            destNormalBuffer = srcNormalBuffer->getManager()->allocateVertexBufferCopy(srcNormalBuffer, this);
2355
0
        }
2356
0
    }
2357
    //-----------------------------------------------------------------------------
2358
    bool Entity::TempBlendedBufferInfo::buffersCheckedOut(bool positions, bool normals) const
2359
0
    {
2360
0
        if (positions || (normals && posNormalShareBuffer))
2361
0
        {
2362
0
            if (!destPositionBuffer)
2363
0
                return false;
2364
2365
0
            destPositionBuffer->getManager()->touchVertexBufferCopy(destPositionBuffer);
2366
0
        }
2367
2368
0
        if (normals && !posNormalShareBuffer)
2369
0
        {
2370
0
            if (!destNormalBuffer)
2371
0
                return false;
2372
2373
0
            destNormalBuffer->getManager()->touchVertexBufferCopy(destNormalBuffer);
2374
0
        }
2375
2376
0
        return true;
2377
0
    }
2378
    //-----------------------------------------------------------------------------
2379
    void Entity::TempBlendedBufferInfo::bindTempCopies(VertexData* targetData, bool suppressHardwareUpload)
2380
0
    {
2381
0
        this->destPositionBuffer->suppressHardwareUpdate(suppressHardwareUpload);
2382
0
        targetData->vertexBufferBinding->setBinding(
2383
0
            this->posBindIndex, this->destPositionBuffer);
2384
0
        if (bindNormals && !posNormalShareBuffer && destNormalBuffer)
2385
0
        {
2386
0
            this->destNormalBuffer->suppressHardwareUpdate(suppressHardwareUpload);
2387
0
            targetData->vertexBufferBinding->setBinding(
2388
0
                this->normBindIndex, this->destNormalBuffer);
2389
0
        }
2390
0
    }
2391
    //-----------------------------------------------------------------------------
2392
    void Entity::TempBlendedBufferInfo::licenseExpired(HardwareBuffer* buffer)
2393
0
    {
2394
0
        assert(buffer == destPositionBuffer.get()
2395
0
            || buffer == destNormalBuffer.get());
2396
2397
0
        if (buffer == destPositionBuffer.get())
2398
0
            destPositionBuffer.reset();
2399
0
        if (buffer == destNormalBuffer.get())
2400
0
            destNormalBuffer.reset();
2401
0
    }
2402
}