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-2005 The OGRE Team
|
---|
8 | Also see acknowledgements in Readme.html
|
---|
9 |
|
---|
10 | This program is free software; you can redistribute it and/or modify it under
|
---|
11 | the terms of the GNU Lesser General Public License as published by the Free Software
|
---|
12 | Foundation; either version 2 of the License, or (at your option) any later
|
---|
13 | version.
|
---|
14 |
|
---|
15 | This program is distributed in the hope that it will be useful, but WITHOUT
|
---|
16 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
---|
17 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
---|
18 |
|
---|
19 | You should have received a copy of the GNU Lesser General Public License along with
|
---|
20 | this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
---|
21 | Place - Suite 330, Boston, MA 02111-1307, USA, or go to
|
---|
22 | http://www.gnu.org/copyleft/lesser.txt.
|
---|
23 | -----------------------------------------------------------------------------
|
---|
24 | */
|
---|
25 |
|
---|
26 | #ifndef __Skeleton_H__
|
---|
27 | #define __Skeleton_H__
|
---|
28 |
|
---|
29 | #include "OgrePrerequisites.h"
|
---|
30 | #include "OgreResource.h"
|
---|
31 | #include "OgreQuaternion.h"
|
---|
32 | #include "OgreVector3.h"
|
---|
33 | #include "OgreIteratorWrappers.h"
|
---|
34 |
|
---|
35 | namespace Ogre {
|
---|
36 |
|
---|
37 | /** */
|
---|
38 | enum SkeletonAnimationBlendMode {
|
---|
39 | /// Animations are applied by calculating a weighted average of all animations
|
---|
40 | ANIMBLEND_AVERAGE,
|
---|
41 | /// Animations are applied by calculating a weighted cumulative total
|
---|
42 | ANIMBLEND_CUMULATIVE
|
---|
43 | };
|
---|
44 |
|
---|
45 | #define OGRE_MAX_NUM_BONES 256
|
---|
46 |
|
---|
47 |
|
---|
48 | struct LinkedSkeletonAnimationSource;
|
---|
49 |
|
---|
50 | /** A collection of Bone objects used to animate a skinned mesh.
|
---|
51 | @remarks
|
---|
52 | Skeletal animation works by having a collection of 'bones' which are
|
---|
53 | actually just joints with a position and orientation, arranged in a tree structure.
|
---|
54 | For example, the wrist joint is a child of the elbow joint, which in turn is a
|
---|
55 | child of the shoulder joint. Rotating the shoulder automatically moves the elbow
|
---|
56 | and wrist as well due to this hierarchy.
|
---|
57 | @par
|
---|
58 | So how does this animate a mesh? Well every vertex in a mesh is assigned to one or more
|
---|
59 | bones which affects it's position when the bone is moved. If a vertex is assigned to
|
---|
60 | more than one bone, then weights must be assigned to determine how much each bone affects
|
---|
61 | the vertex (actually a weight of 1.0 is used for single bone assignments).
|
---|
62 | Weighted vertex assignments are especially useful around the joints themselves
|
---|
63 | to avoid 'pinching' of the mesh in this region.
|
---|
64 | @par
|
---|
65 | Therefore by moving the skeleton using preset animations, we can animate the mesh. The
|
---|
66 | advantage of using skeletal animation is that you store less animation data, especially
|
---|
67 | as vertex counts increase. In addition, you are able to blend multiple animations together
|
---|
68 | (e.g. walking and looking around, running and shooting) and provide smooth transitions
|
---|
69 | between animations without incurring as much of an overhead as would be involved if you
|
---|
70 | did this on the core vertex data.
|
---|
71 | @par
|
---|
72 | Skeleton definitions are loaded from datafiles, namely the .skeleton file format. They
|
---|
73 | are loaded on demand, especially when referenced by a Mesh.
|
---|
74 | */
|
---|
75 | class _OgreExport Skeleton : public Resource
|
---|
76 | {
|
---|
77 | friend class SkeletonInstance;
|
---|
78 | protected:
|
---|
79 | /// Internal constructor for use by SkeletonInstance only
|
---|
80 | Skeleton();
|
---|
81 |
|
---|
82 | public:
|
---|
83 | /** Constructor, don't call directly, use SkeletonManager.
|
---|
84 | @remarks
|
---|
85 | On creation, a Skeleton has a no bones, you should create them and link
|
---|
86 | them together appropriately.
|
---|
87 | */
|
---|
88 | Skeleton(ResourceManager* creator, const String& name, ResourceHandle handle,
|
---|
89 | const String& group, bool isManual = false, ManualResourceLoader* loader = 0);
|
---|
90 | virtual ~Skeleton();
|
---|
91 |
|
---|
92 |
|
---|
93 | /** Creates a brand new Bone owned by this Skeleton.
|
---|
94 | @remarks
|
---|
95 | This method creates an unattached new Bone for this skeleton.
|
---|
96 | Unless this is to be a root bone (there may be more than one of
|
---|
97 | these), you must attach it to another Bone in the skeleton using addChild for it to be any use.
|
---|
98 | For this reason you will likely be better off creating child bones using the
|
---|
99 | Bone::createChild method instead, once you have created the root bone.
|
---|
100 | @par
|
---|
101 | Note that this method automatically generates a handle for the bone, which you
|
---|
102 | can retrieve using Bone::getHandle. If you wish the new Bone to have a specific
|
---|
103 | handle, use the alternate form of this method which takes a handle as a parameter,
|
---|
104 | although you should note the restrictions.
|
---|
105 | */
|
---|
106 | virtual Bone* createBone(void);
|
---|
107 |
|
---|
108 | /** Creates a brand new Bone owned by this Skeleton.
|
---|
109 | @remarks
|
---|
110 | This method creates an unattached new Bone for this skeleton and assigns it a
|
---|
111 | specific handle. Unless this is to be a root bone (there may be more than one of
|
---|
112 | these), you must attach it to another Bone in the skeleton using addChild for it to be any use.
|
---|
113 | For this reason you will likely be better off creating child bones using the
|
---|
114 | Bone::createChild method instead, once you have created a root bone.
|
---|
115 | @param handle The handle to give to this new bone - must be unique within this skeleton.
|
---|
116 | You should also ensure that all bone handles are eventually contiguous (this is to simplify
|
---|
117 | their compilation into an indexed array of transformation matrices). For this reason
|
---|
118 | it is advised that you use the simpler createBone method which automatically assigns a
|
---|
119 | sequential handle starting from 0.
|
---|
120 | */
|
---|
121 | virtual Bone* createBone(unsigned short handle);
|
---|
122 |
|
---|
123 | /** Creates a brand new Bone owned by this Skeleton.
|
---|
124 | @remarks
|
---|
125 | This method creates an unattached new Bone for this skeleton and assigns it a
|
---|
126 | specific name.Unless this is to be a root bone (there may be more than one of
|
---|
127 | these), you must attach it to another Bone in the skeleton using addChild for it to be any use.
|
---|
128 | For this reason you will likely be better off creating child bones using the
|
---|
129 | Bone::createChild method instead, once you have created the root bone.
|
---|
130 | @param name The name to give to this new bone - must be unique within this skeleton.
|
---|
131 | Note that the way OGRE looks up bones is via a numeric handle, so if you name a
|
---|
132 | Bone this way it will be given an automatic sequential handle. The name is just
|
---|
133 | for your convenience, although it is recommended that you only use the handle to
|
---|
134 | retrieve the bone in performance-critical code.
|
---|
135 | */
|
---|
136 | virtual Bone* createBone(const String& name);
|
---|
137 |
|
---|
138 | /** Creates a brand new Bone owned by this Skeleton.
|
---|
139 | @remarks
|
---|
140 | This method creates an unattached new Bone for this skeleton and assigns it a
|
---|
141 | specific name and handle. Unless this is to be a root bone (there may be more than one of
|
---|
142 | these), you must attach it to another Bone in the skeleton using addChild for it to be any use.
|
---|
143 | For this reason you will likely be better off creating child bones using the
|
---|
144 | Bone::createChild method instead, once you have created the root bone.
|
---|
145 | @param name The name to give to this new bone - must be unique within this skeleton.
|
---|
146 | @param handle The handle to give to this new bone - must be unique within this skeleton.
|
---|
147 | */
|
---|
148 | virtual Bone* createBone(const String& name, unsigned short handle);
|
---|
149 |
|
---|
150 | /** Returns the number of bones in this skeleton. */
|
---|
151 | virtual unsigned short getNumBones(void) const;
|
---|
152 |
|
---|
153 | /** Gets the root bone of the skeleton: deprecated in favour of getRootBoneIterator.
|
---|
154 | @remarks
|
---|
155 | The system derives the root bone the first time you ask for it. The root bone is the
|
---|
156 | only bone in the skeleton which has no parent. The system locates it by taking the
|
---|
157 | first bone in the list and going up the bone tree until there are no more parents,
|
---|
158 | and saves this top bone as the root. If you are building the skeleton manually using
|
---|
159 | createBone then you must ensure there is only one bone which is not a child of
|
---|
160 | another bone, otherwise your skeleton will not work properly. If you use createBone
|
---|
161 | only once, and then use Bone::createChild from then on, then inherently the first
|
---|
162 | bone you create will by default be the root.
|
---|
163 | */
|
---|
164 | virtual Bone* getRootBone(void) const;
|
---|
165 |
|
---|
166 | typedef std::vector<Bone*> BoneList;
|
---|
167 | typedef VectorIterator<BoneList> BoneIterator;
|
---|
168 | /// Get an iterator over the root bones in the skeleton, ie those with no parents
|
---|
169 | virtual BoneIterator getRootBoneIterator(void);
|
---|
170 | /// Get an iterator over all the bones in the skeleton
|
---|
171 | virtual BoneIterator getBoneIterator(void);
|
---|
172 |
|
---|
173 | /** Gets a bone by it's handle. */
|
---|
174 | virtual Bone* getBone(unsigned short handle) const;
|
---|
175 |
|
---|
176 | /** Gets a bone by it's name. */
|
---|
177 | virtual Bone* getBone(const String& name) const;
|
---|
178 |
|
---|
179 | /** Sets the current position / orientation to be the 'binding pose' ie the layout in which
|
---|
180 | bones were originally bound to a mesh.
|
---|
181 | */
|
---|
182 | virtual void setBindingPose(void);
|
---|
183 |
|
---|
184 | /** Resets the position and orientation of all bones in this skeleton to their original binding position.
|
---|
185 | @remarks
|
---|
186 | A skeleton is bound to a mesh in a binding pose. Bone positions are then modified from this
|
---|
187 | position during animation. This method returns all the bones to their original position and
|
---|
188 | orientation.
|
---|
189 | @param resetManualBones If set to true, causes the state of manual bones to be reset
|
---|
190 | too, which is normally not done to allow the manual state to persist even
|
---|
191 | when keyframe animation is applied.
|
---|
192 | */
|
---|
193 | virtual void reset(bool resetManualBones = false);
|
---|
194 |
|
---|
195 | /** Creates a new Animation object for animating this skeleton.
|
---|
196 | @param name The name of this animation
|
---|
197 | @param length The length of the animation in seconds
|
---|
198 | */
|
---|
199 | virtual Animation* createAnimation(const String& name, Real length);
|
---|
200 |
|
---|
201 | /** Returns the named Animation object.
|
---|
202 | @remarks
|
---|
203 | Will pick up animations in linked skeletons
|
---|
204 | (@see addLinkedSkeletonAnimationSource).
|
---|
205 | @param name The name of the animation
|
---|
206 | @param linker Optional pointer to a pointer to the linked skeleton animation
|
---|
207 | where this is coming from.
|
---|
208 | */
|
---|
209 | virtual Animation* getAnimation(const String& name,
|
---|
210 | const LinkedSkeletonAnimationSource** linker = 0) const;
|
---|
211 |
|
---|
212 | /// Internal accessor for animations (returns null if animation does not exist)
|
---|
213 | Animation* _getAnimationImpl(const String& name,
|
---|
214 | const LinkedSkeletonAnimationSource** linker = 0) const;
|
---|
215 |
|
---|
216 |
|
---|
217 | /** Returns whether this skeleton contains the named animation. */
|
---|
218 | virtual bool hasAnimation(const String& name);
|
---|
219 |
|
---|
220 | /** Removes an Animation from this skeleton. */
|
---|
221 | virtual void removeAnimation(const String& name);
|
---|
222 |
|
---|
223 | /** Changes the state of the skeleton to reflect the application of the passed in collection of animations.
|
---|
224 | @remarks
|
---|
225 | Animating a skeleton involves both interpolating between keyframes of a specific animation,
|
---|
226 | and blending between the animations themselves. Calling this method sets the state of
|
---|
227 | the skeleton so that it reflects the combination of all the passed in animations, at the
|
---|
228 | time index specified for each, using the weights specified. Note that the weights between
|
---|
229 | animations do not have to sum to 1.0, because some animations may affect only subsets
|
---|
230 | of the skeleton. If the weights exceed 1.0 for the same area of the skeleton, the
|
---|
231 | movement will just be exaggerated.
|
---|
232 | @param
|
---|
233 | */
|
---|
234 | virtual void setAnimationState(const AnimationStateSet& animSet);
|
---|
235 |
|
---|
236 |
|
---|
237 | /** Initialise an animation set suitable for use with this skeleton.
|
---|
238 | @remarks
|
---|
239 | Only recommended for use inside the engine, not by applications.
|
---|
240 | */
|
---|
241 | virtual void _initAnimationState(AnimationStateSet* animSet);
|
---|
242 |
|
---|
243 | /** Refresh an animation set suitable for use with this skeleton.
|
---|
244 | @remarks
|
---|
245 | Only recommended for use inside the engine, not by applications.
|
---|
246 | */
|
---|
247 | virtual void _refreshAnimationState(AnimationStateSet* animSet);
|
---|
248 |
|
---|
249 | /** Populates the passed in array with the bone matrices based on the current position.
|
---|
250 | @remarks
|
---|
251 | Internal use only. The array pointed to by the passed in pointer must
|
---|
252 | be at least as large as the number of bones.
|
---|
253 | Assumes animation has already been updated.
|
---|
254 | */
|
---|
255 | virtual void _getBoneMatrices(Matrix4* pMatrices);
|
---|
256 |
|
---|
257 | /** Gets the number of animations on this skeleton. */
|
---|
258 | virtual unsigned short getNumAnimations(void) const;
|
---|
259 |
|
---|
260 | /** Gets a single animation by index.
|
---|
261 | @remarks
|
---|
262 | Will NOT pick up animations in linked skeletons
|
---|
263 | (@see addLinkedSkeletonAnimationSource).
|
---|
264 | */
|
---|
265 | virtual Animation* getAnimation(unsigned short index) const;
|
---|
266 |
|
---|
267 |
|
---|
268 | /** Gets the animation blending mode which this skeleton will use. */
|
---|
269 | virtual SkeletonAnimationBlendMode getBlendMode() const;
|
---|
270 | /** Sets the animation blending mode this skeleton will use. */
|
---|
271 | virtual void setBlendMode(SkeletonAnimationBlendMode state);
|
---|
272 |
|
---|
273 | /// Updates all the derived transforms in the skeleton
|
---|
274 | virtual void _updateTransforms(void);
|
---|
275 |
|
---|
276 | /** Optimise all of this skeleton's animations.
|
---|
277 | @see Animation::optimise
|
---|
278 | */
|
---|
279 | virtual void optimiseAllAnimations(void);
|
---|
280 |
|
---|
281 | /** Allows you to use the animations from another Skeleton object to animate
|
---|
282 | this skeleton.
|
---|
283 | @remarks
|
---|
284 | If you have skeletons of identical structure (that means identically
|
---|
285 | named bones with identical handles, and with the same hierarchy), but
|
---|
286 | slightly different proportions or binding poses, you can re-use animations
|
---|
287 | from one in the other. Because animations are actually stored as
|
---|
288 | changes to bones from their bind positions, it's possible to use the
|
---|
289 | same animation data for different skeletons, provided the skeletal
|
---|
290 | structure matches and the 'deltas' stored in the keyframes apply
|
---|
291 | equally well to the other skeletons bind position (so they must be
|
---|
292 | roughly similar, but don't have to be identical). You can use the
|
---|
293 | 'scale' option to adjust the translation and scale keyframes where
|
---|
294 | there are large differences in size between the skeletons.
|
---|
295 | @note
|
---|
296 | This method takes a skeleton name, rather than a more specific
|
---|
297 | animation name, for two reasons; firstly it allows some validation
|
---|
298 | of compatibility of skeletal structure, and secondly skeletons are
|
---|
299 | the unit of loading. Linking a skeleton to another in this way means
|
---|
300 | that the linkee will be prevented from being destroyed until the
|
---|
301 | linker is destroyed.
|
---|
302 |
|
---|
303 | You cannot set up cyclic relationships, e.g. SkeletonA uses SkeletonB's
|
---|
304 | animations, and SkeletonB uses SkeletonA's animations. This is because
|
---|
305 | it would set up a circular dependency which would prevent proper
|
---|
306 | unloading - make one of the skeletons the 'master' in this case.
|
---|
307 | @param skelName Name of the skeleton to link animations from. This
|
---|
308 | skeleton will be loaded immediately if this skeleton is already
|
---|
309 | loaded, otherwise it will be loaded when this skeleton is.
|
---|
310 | @param scale A scale factor to apply to translation and scaling elements
|
---|
311 | of the keyframes in the other skeleton when applying the animations
|
---|
312 | to this one. Compensates for skeleton size differences.
|
---|
313 | */
|
---|
314 | virtual void addLinkedSkeletonAnimationSource(const String& skelName,
|
---|
315 | Real scale = 1.0f);
|
---|
316 | /// Remove all links to other skeletons for the purposes of sharing animation
|
---|
317 | virtual void removeAllLinkedSkeletonAnimationSources(void);
|
---|
318 |
|
---|
319 | typedef std::vector<LinkedSkeletonAnimationSource>
|
---|
320 | LinkedSkeletonAnimSourceList;
|
---|
321 | typedef ConstVectorIterator<LinkedSkeletonAnimSourceList>
|
---|
322 | LinkedSkeletonAnimSourceIterator;
|
---|
323 | /// Get an iterator over the linked skeletons used as animation sources
|
---|
324 | virtual LinkedSkeletonAnimSourceIterator
|
---|
325 | getLinkedSkeletonAnimationSourceIterator(void) const;
|
---|
326 |
|
---|
327 | /// Internal method for marking the manual bones as dirty
|
---|
328 | virtual void _notifyManualBonesDirty(void);
|
---|
329 | /// Internal method for notifying that a bone is manual
|
---|
330 | virtual void _notifyManualBoneStateChange(Bone* bone);
|
---|
331 |
|
---|
332 | /// Have manual bones been modified since the skeleton was last updated?
|
---|
333 | virtual bool getManualBonesDirty(void) const { return mManualBonesDirty; }
|
---|
334 | /// Are there any manually controlled bones?
|
---|
335 | virtual bool hasManualBones(void) const { return !mManualBones.empty(); }
|
---|
336 |
|
---|
337 | protected:
|
---|
338 | SkeletonAnimationBlendMode mBlendState;
|
---|
339 | /// Storage of bones, indexed by bone handle
|
---|
340 | BoneList mBoneList;
|
---|
341 | /// Lookup by bone name
|
---|
342 | typedef std::map<String, Bone*> BoneListByName;
|
---|
343 | BoneListByName mBoneListByName;
|
---|
344 |
|
---|
345 |
|
---|
346 | /// Pointer to root bones (can now have multiple roots)
|
---|
347 | mutable BoneList mRootBones;
|
---|
348 | /// Bone automatic handles
|
---|
349 | unsigned short mNextAutoHandle;
|
---|
350 | typedef std::set<Bone*> BoneSet;
|
---|
351 | /// Manual bones
|
---|
352 | BoneSet mManualBones;
|
---|
353 | /// Manual bones dirty?
|
---|
354 | bool mManualBonesDirty;
|
---|
355 |
|
---|
356 |
|
---|
357 | /// Storage of animations, lookup by name
|
---|
358 | typedef std::map<String, Animation*> AnimationList;
|
---|
359 | AnimationList mAnimationsList;
|
---|
360 |
|
---|
361 | /// List of references to other skeletons to use animations from
|
---|
362 | mutable LinkedSkeletonAnimSourceList mLinkedSkeletonAnimSourceList;
|
---|
363 |
|
---|
364 | /** Internal method which parses the bones to derive the root bone.
|
---|
365 | @remarks
|
---|
366 | Must be const because called in getRootBone but mRootBone is mutable
|
---|
367 | since lazy-updated.
|
---|
368 | */
|
---|
369 | void deriveRootBone(void) const;
|
---|
370 |
|
---|
371 | /// Debugging method
|
---|
372 | void _dumpContents(const String& filename);
|
---|
373 |
|
---|
374 | /** @copydoc Resource::loadImpl
|
---|
375 | */
|
---|
376 | void loadImpl(void);
|
---|
377 |
|
---|
378 | /** @copydoc Resource::unloadImpl
|
---|
379 | */
|
---|
380 | void unloadImpl(void);
|
---|
381 | /// @copydoc Resource::calculateSize
|
---|
382 | size_t calculateSize(void) const { return 0; } // TODO
|
---|
383 |
|
---|
384 | };
|
---|
385 |
|
---|
386 | /** Specialisation of SharedPtr to allow SharedPtr to be assigned to SkeletonPtr
|
---|
387 | @note Has to be a subclass since we need operator=.
|
---|
388 | We could templatise this instead of repeating per Resource subclass,
|
---|
389 | except to do so requires a form VC6 does not support i.e.
|
---|
390 | ResourceSubclassPtr<T> : public SharedPtr<T>
|
---|
391 | */
|
---|
392 | class _OgreExport SkeletonPtr : public SharedPtr<Skeleton>
|
---|
393 | {
|
---|
394 | public:
|
---|
395 | SkeletonPtr() : SharedPtr<Skeleton>() {}
|
---|
396 | explicit SkeletonPtr(Skeleton* rep) : SharedPtr<Skeleton>(rep) {}
|
---|
397 | SkeletonPtr(const SkeletonPtr& r) : SharedPtr<Skeleton>(r) {}
|
---|
398 | SkeletonPtr(const ResourcePtr& r) : SharedPtr<Skeleton>()
|
---|
399 | {
|
---|
400 | // lock & copy other mutex pointer
|
---|
401 | OGRE_LOCK_MUTEX(*r.OGRE_AUTO_MUTEX_NAME)
|
---|
402 | OGRE_COPY_AUTO_SHARED_MUTEX(r.OGRE_AUTO_MUTEX_NAME)
|
---|
403 | pRep = static_cast<Skeleton*>(r.getPointer());
|
---|
404 | pUseCount = r.useCountPointer();
|
---|
405 | if (pUseCount)
|
---|
406 | {
|
---|
407 | ++(*pUseCount);
|
---|
408 | }
|
---|
409 | }
|
---|
410 |
|
---|
411 | /// Operator used to convert a ResourcePtr to a SkeletonPtr
|
---|
412 | SkeletonPtr& operator=(const ResourcePtr& r)
|
---|
413 | {
|
---|
414 | if (pRep == static_cast<Skeleton*>(r.getPointer()))
|
---|
415 | return *this;
|
---|
416 | release();
|
---|
417 | // lock & copy other mutex pointer
|
---|
418 | OGRE_LOCK_MUTEX(*r.OGRE_AUTO_MUTEX_NAME)
|
---|
419 | OGRE_COPY_AUTO_SHARED_MUTEX(r.OGRE_AUTO_MUTEX_NAME)
|
---|
420 | pRep = static_cast<Skeleton*>(r.getPointer());
|
---|
421 | pUseCount = r.useCountPointer();
|
---|
422 | if (pUseCount)
|
---|
423 | {
|
---|
424 | ++(*pUseCount);
|
---|
425 | }
|
---|
426 | return *this;
|
---|
427 | }
|
---|
428 | };
|
---|
429 |
|
---|
430 | /// Link to another skeleton to share animations
|
---|
431 | struct LinkedSkeletonAnimationSource
|
---|
432 | {
|
---|
433 | String skeletonName;
|
---|
434 | SkeletonPtr pSkeleton;
|
---|
435 | Real scale;
|
---|
436 | LinkedSkeletonAnimationSource(const String& skelName, Real scl)
|
---|
437 | : skeletonName(skelName), scale(scl) {}
|
---|
438 | LinkedSkeletonAnimationSource(const String& skelName, Real scl,
|
---|
439 | SkeletonPtr skelPtr)
|
---|
440 | : skeletonName(skelName), pSkeleton(skelPtr), scale(scl) {}
|
---|
441 | };
|
---|
442 | }
|
---|
443 |
|
---|
444 |
|
---|
445 | #endif
|
---|
446 |
|
---|