OSDN Git Service

Add AndroidTGALoader
[mikumikustudio/MikuMikuStudio.git] / engine / src / core / com / jme3 / animation / Bone.java
1 /*
2  * Copyright (c) 2009-2010 jMonkeyEngine
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  *   notice, this list of conditions and the following disclaimer.
11  *
12  * * Redistributions in binary form must reproduce the above copyright
13  *   notice, this list of conditions and the following disclaimer in the
14  *   documentation and/or other materials provided with the distribution.
15  *
16  * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
17  *   may be used to endorse or promote products derived from this software
18  *   without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 package com.jme3.animation;
33
34 import com.jme3.export.JmeExporter;
35 import com.jme3.export.JmeImporter;
36 import com.jme3.export.InputCapsule;
37 import com.jme3.export.OutputCapsule;
38 import com.jme3.export.Savable;
39 import com.jme3.math.Matrix3f;
40 import com.jme3.math.Matrix4f;
41 import com.jme3.math.Quaternion;
42 import com.jme3.math.Transform;
43 import com.jme3.math.Vector3f;
44 import com.jme3.scene.Node;
45 import com.jme3.util.TempVars;
46 import java.io.IOException;
47 import java.util.ArrayList;
48
49 /**
50  * <code>Bone</code> describes a bone in the bone-weight skeletal animation
51  * system. A bone contains a name and an index, as well as relevant
52  * transformation data.
53  *
54  * @author Kirill Vainer
55  */
56 public final class Bone implements Savable {
57
58     private String name;
59     private Bone parent;
60     private final ArrayList<Bone> children = new ArrayList<Bone>();
61     /**
62      * If enabled, user can control bone transform with setUserTransforms.
63      * Animation transforms are not applied to this bone when enabled.
64      */
65     private boolean userControl = false;
66     private boolean useModelSpaceVectors = false;
67     /**
68      * The attachment node.
69      */
70     private Node attachNode;
71     /**
72      * Initial transform is the local bind transform of this bone.
73      * PARENT SPACE -> BONE SPACE
74      */
75     private Vector3f initialPos;
76     private Quaternion initialRot;
77     private Vector3f initialScale;
78     /**
79      * The inverse world bind transform.
80      * BONE SPACE -> MODEL SPACE
81      */
82     private Vector3f worldBindInversePos;
83     private Quaternion worldBindInverseRot;
84     private Vector3f worldBindInverseScale;
85     /**
86      * The local animated transform combined with the local bind transform and parent world transform
87      */
88     private Vector3f localPos = new Vector3f();
89     private Quaternion localRot = new Quaternion();
90     private Vector3f localScale = new Vector3f(1.0f, 1.0f, 1.0f);
91     /**
92      * MODEL SPACE -> BONE SPACE (in animated state)
93      */
94     private Vector3f worldPos = new Vector3f();
95     private Quaternion worldRot = new Quaternion();
96     private Vector3f worldScale = new Vector3f();
97     //used for getCombinedTransform 
98     private Transform tmpTransform = new Transform();
99
100     /**
101      * Creates a new bone with the given name.
102      * 
103      * @param name Name to give to this bone
104      */
105     public Bone(String name) {
106         if (name == null)
107             throw new IllegalArgumentException("Name cannot be null");
108         
109         this.name = name;
110
111         initialPos = new Vector3f();
112         initialRot = new Quaternion();
113         initialScale = new Vector3f(1, 1, 1);
114
115         worldBindInversePos = new Vector3f();
116         worldBindInverseRot = new Quaternion();
117         worldBindInverseScale = new Vector3f();
118     }
119
120     /**
121      * Special-purpose copy constructor. 
122      * <p>
123      * Only copies the name and bind pose from the original.
124      * <p>
125      * WARNING: Local bind pose and world inverse bind pose transforms shallow 
126      * copied. Modifying that data on the original bone will cause it to
127      * be recomputed on any cloned bones.
128      * <p>
129      * The rest of the data is <em>NOT</em> copied, as it will be
130      * generated automatically when the bone is animated.
131      * 
132      * @param source The bone from which to copy the data.
133      */
134     Bone(Bone source) {
135         this.name = source.name;
136
137         userControl = source.userControl;
138
139         initialPos = source.initialPos;
140         initialRot = source.initialRot;
141         initialScale = source.initialScale;
142
143         worldBindInversePos = source.worldBindInversePos;
144         worldBindInverseRot = source.worldBindInverseRot;
145         worldBindInverseScale = source.worldBindInverseScale;
146
147         // parent and children will be assigned manually..
148     }
149
150     /**
151      * Serialization only. Do not use.
152      */
153     public Bone() {
154     }
155
156     /**
157      * Returns the name of the bone, set in the constructor.
158      * 
159      * @return The name of the bone, set in the constructor.
160      */
161     public String getName() {
162         return name;
163     }
164
165     /**
166      * Returns parent bone of this bone, or null if it is a root bone.
167      * @return The parent bone of this bone, or null if it is a root bone.
168      */
169     public Bone getParent() {
170         return parent;
171     }
172
173     /**
174      * Returns all the children bones of this bone.
175      * 
176      * @return All the children bones of this bone.
177      */
178     public ArrayList<Bone> getChildren() {
179         return children;
180     }
181
182     /**
183      * Returns the local position of the bone, relative to the parent bone.
184      * 
185      * @return The local position of the bone, relative to the parent bone.
186      */
187     public Vector3f getLocalPosition() {
188         return localPos;
189     }
190
191     /**
192      * Returns the local rotation of the bone, relative to the parent bone.
193      * 
194      * @return The local rotation of the bone, relative to the parent bone.
195      */
196     public Quaternion getLocalRotation() {
197         return localRot;
198     }
199
200     /**
201      * Returns the local scale of the bone, relative to the parent bone.
202      * 
203      * @return The local scale of the bone, relative to the parent bone.
204      */
205     public Vector3f getLocalScale() {
206         return localScale;
207     }
208
209     /**
210      * Returns the position of the bone in model space.
211      * 
212      * @return The position of the bone in model space.
213      */
214     public Vector3f getModelSpacePosition() {
215         return worldPos;
216     }
217
218     /**
219      * Returns the rotation of the bone in model space.
220      * 
221      * @return The rotation of the bone in model space.
222      */
223     public Quaternion getModelSpaceRotation() {
224         return worldRot;
225     }
226
227     /**
228      * Returns the scale of the bone in model space.
229      * 
230      * @return The scale of the bone in model space.
231      */
232     public Vector3f getModelSpaceScale() {
233         return worldScale;
234     }
235
236     /**
237      * Returns the inverse world bind pose position.
238      * <p>
239      * The bind pose transform of the bone is its "default"
240      * transform with no animation applied.
241      * 
242      * @return the inverse world bind pose position.
243      */
244     public Vector3f getWorldBindInversePosition() {
245         return worldBindInversePos;
246     }
247
248     /**
249      * Returns the inverse world bind pose rotation.
250      * <p>
251      * The bind pose transform of the bone is its "default"
252      * transform with no animation applied.
253      * 
254      * @return the inverse world bind pose rotation.
255      */
256     public Quaternion getWorldBindInverseRotation() {
257         return worldBindInverseRot;
258     }
259
260     /**
261      * Returns the inverse world bind pose scale.
262      * <p>
263      * The bind pose transform of the bone is its "default"
264      * transform with no animation applied.
265      * 
266      * @return the inverse world bind pose scale.
267      */
268     public Vector3f getWorldBindInverseScale() {
269         return worldBindInverseScale;
270     }
271
272     /**
273      * Returns the world bind pose position.
274      * <p>
275      * The bind pose transform of the bone is its "default"
276      * transform with no animation applied.
277      * 
278      * @return the world bind pose position.
279      */
280     public Vector3f getWorldBindPosition() {
281         return initialPos;
282     }
283
284     /**
285      * Returns the world bind pose rotation.
286      * <p>
287      * The bind pose transform of the bone is its "default"
288      * transform with no animation applied.
289      * 
290      * @return the world bind pose rotation.
291      */
292     public Quaternion getWorldBindRotation() {
293         return initialRot;
294     }
295
296     /**
297      * Returns the world bind pose scale.
298      * <p>
299      * The bind pose transform of the bone is its "default"
300      * transform with no animation applied.
301      * 
302      * @return the world bind pose scale.
303      */
304     public Vector3f getWorldBindScale() {
305         return initialScale;
306     }
307
308     /**
309      * If enabled, user can control bone transform with setUserTransforms.
310      * Animation transforms are not applied to this bone when enabled.
311      */
312     public void setUserControl(boolean enable) {
313         userControl = enable;
314     }
315
316     /**
317      * Add a new child to this bone. Shouldn't be used by user code.
318      * Can corrupt skeleton.
319      * 
320      * @param bone The bone to add
321      */
322     public void addChild(Bone bone) {
323         children.add(bone);
324         bone.parent = this;
325     }
326
327     /**
328      * Updates the world transforms for this bone, and, possibly the attach node
329      * if not null.
330      * <p>
331      * The world transform of this bone is computed by combining the parent's
332      * world transform with this bones' local transform.
333      */
334     public final void updateWorldVectors() {
335         if (true || !useModelSpaceVectors) {
336             if (parent != null) {
337                 //rotation
338                 parent.worldRot.mult(localRot, worldRot);
339
340                 //scale
341                 //For scale parent scale is not taken into account!
342                 // worldScale.set(localScale);
343                 parent.worldScale.mult(localScale, worldScale);
344
345                 //translation
346                 //scale and rotation of parent affect bone position            
347                 parent.worldRot.mult(localPos, worldPos);
348                 worldPos.multLocal(parent.worldScale);
349                 worldPos.addLocal(parent.worldPos);
350             } else {
351                 worldRot.set(localRot);
352                 worldPos.set(localPos);
353                 worldScale.set(localScale);
354             }
355         }
356         if (attachNode != null) {
357             attachNode.setLocalTranslation(worldPos);
358             attachNode.setLocalRotation(worldRot);
359             attachNode.setLocalScale(worldScale);
360         }
361     }
362
363     /**
364      * Updates world transforms for this bone and it's children.
365      */
366     final void update() {
367         this.updateWorldVectors();
368
369         for (int i = children.size() - 1; i >= 0; i--) {
370             children.get(i).update();
371         }
372     }
373
374     /**
375      * Saves the current bone state as its binding pose, including its children.
376      */
377     void setBindingPose() {
378         initialPos.set(localPos);
379         initialRot.set(localRot);
380         initialScale.set(localScale);
381
382         if (worldBindInversePos == null) {
383             worldBindInversePos = new Vector3f();
384             worldBindInverseRot = new Quaternion();
385             worldBindInverseScale = new Vector3f();
386         }
387
388         // Save inverse derived position/scale/orientation, used for calculate offset transform later
389         worldBindInversePos.set(worldPos);
390         worldBindInversePos.negateLocal();
391
392         worldBindInverseRot.set(worldRot);
393         worldBindInverseRot.inverseLocal();
394
395         worldBindInverseScale.set(Vector3f.UNIT_XYZ);
396         worldBindInverseScale.divideLocal(worldScale);
397
398         for (Bone b : children) {
399             b.setBindingPose();
400         }
401     }
402
403     /**
404      * Reset the bone and it's children to bind pose.
405      */
406     final void reset() {
407         if (!userControl) {
408             localPos.set(initialPos);
409             localRot.set(initialRot);
410             localScale.set(initialScale);
411         }
412
413         for (int i = children.size() - 1; i >= 0; i--) {
414             children.get(i).reset();
415         }
416     }
417
418      /**
419      * Stores the skinning transform in the specified Matrix4f.
420      * The skinning transform applies the animation of the bone to a vertex.
421      * 
422      * This assumes that the world transforms for the entire bone hierarchy
423      * have already been computed, otherwise this method will return undefined
424      * results.
425      * 
426      * @param outTransform
427      */
428     void getOffsetTransform(Matrix4f outTransform, Quaternion tmp1, Vector3f tmp2, Vector3f tmp3, Matrix3f tmp4) {
429         // Computing scale
430         Vector3f scale = worldScale.mult(worldBindInverseScale, tmp3);
431
432         // Computing rotation
433         Quaternion rotate = worldRot.mult(worldBindInverseRot, tmp1);
434
435         // Computing translation
436         // Translation depend on rotation and scale
437         Vector3f translate = worldPos.add(rotate.mult(scale.mult(worldBindInversePos, tmp2), tmp2), tmp2);
438
439         // Populating the matrix
440         outTransform.loadIdentity();
441         outTransform.setTransform(translate, scale, rotate.toRotationMatrix(tmp4));
442     }
443
444     /**
445      * Sets user transform.
446      */
447     public void setUserTransforms(Vector3f translation, Quaternion rotation, Vector3f scale) {
448         if (!userControl) {
449             throw new IllegalStateException("User control must be on bone to allow user transforms");
450         }
451
452         localPos.set(initialPos);
453         localRot.set(initialRot);
454         localScale.set(initialScale);
455
456         localPos.addLocal(translation);
457         localRot = localRot.mult(rotation);
458         localScale.multLocal(scale);
459     }
460
461     /**
462      * Must update all bones in skeleton for this to work.
463      * @param translation
464      * @param rotation
465      */
466     public void setUserTransformsWorld(Vector3f translation, Quaternion rotation) {
467         if (!userControl) {
468             throw new IllegalStateException("User control must be on bone to allow user transforms");
469         }
470
471         // TODO: add scale here ???
472         worldPos.set(translation);
473         worldRot.set(rotation);
474     }
475
476     /**
477      * Returns the local transform of this bone combined with the given position and rotation
478      * @param position a position
479      * @param rotation a rotation
480      */
481     public Transform getCombinedTransform(Vector3f position, Quaternion rotation) {
482         rotation.mult(localPos, tmpTransform.getTranslation()).addLocal(position);
483         tmpTransform.setRotation(rotation).getRotation().multLocal(localRot);
484         return tmpTransform;
485     }
486
487     /**
488      * Returns the attachment node.
489      * Attach models and effects to this node to make
490      * them follow this bone's motions.
491      */
492     public Node getAttachmentsNode() {
493         if (attachNode == null) {
494             attachNode = new Node(name + "_attachnode");
495             attachNode.setUserData("AttachedBone", this);
496         }
497         return attachNode;
498     }
499
500     /**
501      * Used internally after model cloning.
502      * @param attachNode
503      */
504     void setAttachmentsNode(Node attachNode) {
505         this.attachNode = attachNode;
506     }
507
508     /**
509      * Sets the local animation transform of this bone.
510      * Bone is assumed to be in bind pose when this is called.
511      */
512     void setAnimTransforms(Vector3f translation, Quaternion rotation, Vector3f scale) {
513         if (userControl) {
514             return;
515         }
516
517 //        localPos.addLocal(translation);
518 //        localRot.multLocal(rotation);
519         //localRot = localRot.mult(rotation);
520
521         localPos.set(initialPos).addLocal(translation);
522         localRot.set(initialRot).multLocal(rotation);
523
524         if (scale != null) {
525             localScale.set(initialScale).multLocal(scale);
526         }
527     }
528
529     void blendAnimTransforms(Vector3f translation, Quaternion rotation, Vector3f scale, float weight) {
530         if (userControl) {
531             return;
532         }
533
534         TempVars vars = TempVars.get();
535 //        assert vars.lock();
536
537         Vector3f tmpV = vars.vect1;
538         Vector3f tmpV2 = vars.vect2;
539         Quaternion tmpQ = vars.quat1;
540
541         //location
542         tmpV.set(initialPos).addLocal(translation);
543         localPos.interpolate(tmpV, weight);
544
545         //rotation
546         tmpQ.set(initialRot).multLocal(rotation);
547         localRot.nlerp(tmpQ, weight);
548
549         //scale
550         if (scale != null) {
551             tmpV2.set(initialScale).multLocal(scale);
552             localScale.interpolate(tmpV2, weight);
553         }
554
555
556         vars.release();
557     }
558
559     /**
560      * Sets local bind transform for bone.
561      * Call setBindingPose() after all of the skeleton bones' bind transforms are set to save them.
562      */
563     public void setBindTransforms(Vector3f translation, Quaternion rotation, Vector3f scale) {
564         initialPos.set(translation);
565         initialRot.set(rotation);
566         //ogre.xml can have null scale values breaking this if the check is removed
567         if (scale != null) {
568             initialScale.set(scale);
569         }
570
571         localPos.set(translation);
572         localRot.set(rotation);
573         if (scale != null) {
574             localScale.set(scale);
575         }
576     }
577
578     private String toString(int depth) {
579         StringBuilder sb = new StringBuilder();
580         for (int i = 0; i < depth; i++) {
581             sb.append('-');
582         }
583
584         sb.append(name).append(" bone\n");
585         for (Bone child : children) {
586             sb.append(child.toString(depth + 1));
587         }
588         return sb.toString();
589     }
590
591     @Override
592     public String toString() {
593         return this.toString(0);
594     }
595
596     public boolean isUseModelSpaceVectors() {
597         return useModelSpaceVectors;
598     }
599
600     public void setUseModelSpaceVectors(boolean useModelSpaceVectors) {
601         this.useModelSpaceVectors = useModelSpaceVectors;
602     }
603
604     @Override
605     @SuppressWarnings("unchecked")
606     public void read(JmeImporter im) throws IOException {
607         InputCapsule input = im.getCapsule(this);
608
609         name = input.readString("name", null);
610         initialPos = (Vector3f) input.readSavable("initialPos", null);
611         initialRot = (Quaternion) input.readSavable("initialRot", null);
612         initialScale = (Vector3f) input.readSavable("initialScale", new Vector3f(1.0f, 1.0f, 1.0f));
613         attachNode = (Node) input.readSavable("attachNode", null);
614
615         localPos.set(initialPos);
616         localRot.set(initialRot);
617
618         ArrayList<Bone> childList = input.readSavableArrayList("children", null);
619         for (int i = childList.size() - 1; i >= 0; i--) {
620             this.addChild(childList.get(i));
621         }
622
623         // NOTE: Parent skeleton will call update() then setBindingPose()
624         // after Skeleton has been de-serialized.
625         // Therefore, worldBindInversePos and worldBindInverseRot
626         // will be reconstructed based on that information.
627     }
628
629     @Override
630     public void write(JmeExporter ex) throws IOException {
631         OutputCapsule output = ex.getCapsule(this);
632
633         output.write(name, "name", null);
634         output.write(attachNode, "attachNode", null);
635         output.write(initialPos, "initialPos", null);
636         output.write(initialRot, "initialRot", null);
637         output.write(initialScale, "initialScale", new Vector3f(1.0f, 1.0f, 1.0f));
638         output.writeSavableArrayList(children, "children", null);
639     }
640 }