@@ -24,6 +24,18 @@ FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
2424ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
2525DEALINGS IN THE SOFTWARE.
2626*/
27+
28+ /**
29+ * GLTF 2.0 animation.
30+ *
31+ * The `dagon.resource.gltf.animation` module defines classes for representing
32+ * and evaluating GLTF animation samplers, channels, and animation clips.
33+ * Animation playback, blending, and update logic are included.
34+ *
35+ * Copyright: Denis Feklushkin, Timur Gafarov 2025
36+ * License: $(LINK2 https://boost.org/LICENSE_1_0.txt, Boost License 1.0).
37+ * Authors: Denis Feklushkin, Timur Gafarov
38+ */
2739module dagon.resource.gltf.animation ;
2840
2941import std.stdio ;
@@ -45,31 +57,49 @@ import dagon.resource.gltf.accessor;
4557import dagon.resource.gltf.node;
4658import dagon.resource.gltf.skin;
4759
60+ /**
61+ * Interpolation types supported by GLTF animation samplers.
62+ */
4863enum InterpolationType: string
4964{
5065 Linear = " LINEAR" ,
5166 Step = " STEP" ,
5267 CubicSpline = " CUBICSPLINE"
5368}
5469
70+ /**
71+ * Animation target property types (translation, rotation, scale).
72+ */
5573enum TRSType: string
5674{
5775 Translation = " translation" ,
5876 Rotation = " rotation" ,
5977 Scale = " scale" ,
6078}
6179
80+ /**
81+ * Represents a GLTF animation sampler, which defines keyframe times,
82+ * values, and interpolation.
83+ */
6284class GLTFAnimationSampler : Owner
6385{
64- InterpolationType interpolation; // optional, LINEAR by default
65- GLTFAccessor input; // required, contains times (in seconds) for each keyframe.
66- GLTFAccessor output; // required, contains values (of any Accessor.Type) for the animated property at each keyframe.
86+ // / Interpolation type (linear, step, cubic spline). Only LINEAR is supported at the moment
87+ InterpolationType interpolation;
88+
89+ // / Accessor for keyframe times (in seconds).
90+ GLTFAccessor input;
91+
92+ // / Accessor for keyframe values.
93+ GLTFAccessor output;
6794
6895 this (Owner o)
6996 {
7097 super (o);
7198 }
7299
100+ /**
101+ * Returns the duration of the animation sampler in seconds.
102+ */
73103 float duration ()
74104 {
75105 const timeline = input.getSlice! float ;
@@ -79,7 +109,17 @@ class GLTFAnimationSampler: Owner
79109 return 0.0f ;
80110 }
81111
82- // / Returns: beginning translation sample number
112+ /**
113+ * Finds the keyframe sample indices and times for a given animation time.
114+ *
115+ * Params:
116+ * t = Current animation time.
117+ * previousTime = Output: previous keyframe time.
118+ * nextTime = Output: next keyframe time.
119+ * loopTime = Output: wrapped time within the animation duration.
120+ * Returns:
121+ * Index of the previous keyframe.
122+ */
83123 size_t getSampleByTime (in Time t, out float previousTime, out float nextTime, out float loopTime)
84124 {
85125 assert (input.dataType == GLTFDataType.Scalar);
@@ -122,22 +162,38 @@ class GLTFAnimationSampler: Owner
122162 }
123163}
124164
165+ /**
166+ * Represents a GLTF animation channel, which targets a node and property (TRS).
167+ */
125168class GLTFAnimationChannel : Owner
126169{
127- GLTFAnimationSampler sampler; // required
128- TRSType targetPath; // required
129- GLTFNode targetNode; // optional: When undefined, the animated object MAY be defined by an extension.
170+ // / The animation sampler for this channel.
171+ GLTFAnimationSampler sampler;
172+
173+ // / The property being animated (translation, rotation, scale).
174+ TRSType targetPath;
175+
176+ // / The node being animated.
177+ GLTFNode targetNode;
130178
131179 this (Owner o)
132180 {
133181 super (o);
134182 }
135183}
136184
185+ /**
186+ * Represents a GLTF animation clip, containing samplers and channels.
187+ */
137188class GLTFAnimation : Owner
138189{
190+ // / Animation name.
139191 string name;
192+
193+ // / Animation samplers.
140194 Array! GLTFAnimationSampler samplers;
195+
196+ // / Animation channels.
141197 Array! GLTFAnimationChannel channels;
142198
143199 this (Owner o)
@@ -151,6 +207,9 @@ class GLTFAnimation: Owner
151207 channels.free();
152208 }
153209
210+ /**
211+ * Returns the duration of the animation in seconds.
212+ */
154213 float duration ()
155214 {
156215 float d = 0.0f ;
@@ -162,10 +221,18 @@ class GLTFAnimation: Owner
162221 }
163222}
164223
224+ /**
225+ * `Entity`` component for playing a GLTF animation on an entity.
226+ */
165227class GLTFAnimationComponent : EntityComponent
166228{
229+ // / The animation to play.
167230 GLTFAnimation animation;
231+
232+ // / Current animation time.
168233 Time time;
234+
235+ // / True if the animation is playing.
169236 bool playing;
170237
171238 this (EventManager em, Entity e, GLTFAnimation animation, bool playing = false )
@@ -177,21 +244,25 @@ class GLTFAnimationComponent: EntityComponent
177244 e.transformMode = TransformMode.Matrix;
178245 }
179246
247+ // / Starts animation playback.
180248 void play ()
181249 {
182250 playing = true ;
183251 }
184252
253+ // / Pauses animation playback.
185254 void pause ()
186255 {
187256 playing = false ;
188257 }
189258
259+ // / Resets animation time to zero.
190260 void reset ()
191261 {
192262 time.elapsed = 0 ;
193263 }
194264
265+ // / Updates the animation and applies transforms to the entity.
195266 override void update (Time t)
196267 {
197268 if (playing)
@@ -246,9 +317,15 @@ class GLTFAnimationComponent: EntityComponent
246317 }
247318}
248319
320+ /**
321+ * GPU skinning pose for a GLTF skin and animation.
322+ */
249323class GLTFPose : Pose
250324{
325+ // / The GLTFSkin being posed.
251326 GLTFSkin skin;
327+
328+ // / The animation to play.
252329 GLTFAnimation animation;
253330
254331 this (GLTFSkin skin, Owner o)
@@ -270,6 +347,7 @@ class GLTFPose: Pose
270347 Delete(boneMatrices);
271348 }
272349
350+ // / Updates the pose for the current animation time.
273351 override void update (Time t)
274352 {
275353 if (playing)
@@ -350,41 +428,65 @@ class GLTFPose: Pose
350428 }
351429}
352430
431+ /**
432+ * TRS (Translation, Rotation, Scale) structure for joint transforms.
433+ */
353434struct TRS
354435{
355436 Vector3f translation;
356437 Quaternionf rotation;
357438 Vector3f scaling;
358439}
359440
441+ /**
442+ * Animation playback mode (loop or once).
443+ */
360444enum PlayMode
361445{
362446 Loop,
363447 Once
364448}
365449
366- /*
367- * A Pose that supports smooth transition between animations
450+ /**
451+ * A pose that supports smooth blending between GLTF animations.
368452 */
369453class GLTFBlendedPose : Pose
370454{
455+ // / The GLTFSkin being posed.
371456 GLTFSkin skin;
372457
458+ // / Current TRS pose for each joint.
373459 TRS [] currentPose;
460+
461+ // / Next TRS pose for blending.
374462 TRS [] nextPose;
375463
464+ // / Previous animation.
376465 GLTFAnimation previousAnimation;
466+
467+ // / Current animation.
377468 GLTFAnimation animation;
469+
470+ // / Next animation.
378471 GLTFAnimation nextAnimation;
472+
473+ // / Blend factor between animations.
379474 float blendAlpha = 0.0f ;
475+
476+ // / Blend speed.
380477 float blendSpeed = 0.0f ;
478+
381479 float previousBlendSpeed = 0.0f ;
480+
481+ // / Duration of the current animation.
382482 float animationDuration = 0.0f ;
483+
484+ // / Playback mode (loop or once).
383485 PlayMode playMode = PlayMode.Loop;
384486
385- this (GLTFSkin skin, Owner o )
487+ this (GLTFSkin skin, Owner owner )
386488 {
387- super (o );
489+ super (owner );
388490 this .skin = skin;
389491
390492 if (skin.joints.length)
@@ -408,6 +510,14 @@ class GLTFBlendedPose: Pose
408510 Delete(nextPose);
409511 }
410512
513+ /**
514+ * Applies an animation to the pose at a given time.
515+ *
516+ * Params:
517+ * anim = The animation to apply.
518+ * time = The animation time.
519+ * outPose = Output array of TRS for each joint.
520+ */
411521 void applyAnimation (GLTFAnimation anim, Time time, TRS [] outPose)
412522 {
413523 if (anim)
@@ -471,6 +581,13 @@ class GLTFBlendedPose: Pose
471581 }
472582 }
473583
584+ /**
585+ * Switches to a new animation immediately.
586+ *
587+ * Params:
588+ * anim = The new animation.
589+ * playMode = Playback mode (loop or once).
590+ */
474591 void switchToAnimation (GLTFAnimation anim, PlayMode playMode = PlayMode.Loop)
475592 {
476593 if (anim ! is animation)
@@ -483,6 +600,14 @@ class GLTFBlendedPose: Pose
483600 }
484601 }
485602
603+ /**
604+ * Switches to a new animation smoothly.
605+ *
606+ * Params:
607+ * anim = The new animation.
608+ * transitionDuration = Duration of the blend (optional).
609+ * playMode = Playback mode (loop or once).
610+ */
486611 void switchToAnimation (GLTFAnimation anim, float transitionDuration, PlayMode playMode = PlayMode.Loop)
487612 {
488613 if (anim ! is animation)
@@ -498,6 +623,7 @@ class GLTFBlendedPose: Pose
498623 }
499624 }
500625
626+ // / Updates the blended pose and applies transforms to the skin.
501627 override void update (Time t)
502628 {
503629 applyAnimation(animation, time, currentPose);
0 commit comments