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
33package jme3test.model.anim;
34
35import com.jme3.animation.Bone;
36import com.jme3.animation.Skeleton;
37import com.jme3.animation.SkeletonControl;
38import com.jme3.app.SimpleApplication;
39import com.jme3.light.AmbientLight;
40import com.jme3.light.DirectionalLight;
41import com.jme3.math.Quaternion;
42import com.jme3.math.Vector3f;
43import com.jme3.scene.Geometry;
44import com.jme3.scene.Node;
45import com.jme3.scene.VertexBuffer;
46import com.jme3.scene.VertexBuffer.Format;
47import com.jme3.scene.VertexBuffer.Type;
48import com.jme3.scene.VertexBuffer.Usage;
49import com.jme3.scene.shape.Box;
50import java.nio.ByteBuffer;
51import java.nio.FloatBuffer;
52
53public class TestCustomAnim extends SimpleApplication {
54
55    private Bone bone;
56    private Skeleton skeleton;
57    private Quaternion rotation = new Quaternion();
58
59    public static void main(String[] args) {
60        TestCustomAnim app = new TestCustomAnim();
61        app.start();
62    }
63
64    @Override
65    public void simpleInitApp() {
66
67        AmbientLight al = new AmbientLight();
68        rootNode.addLight(al);
69
70        DirectionalLight dl = new DirectionalLight();
71        dl.setDirection(Vector3f.UNIT_XYZ.negate());
72        rootNode.addLight(dl);
73
74        Box box = new Box(1, 1, 1);
75
76        // Setup bone weight buffer
77        FloatBuffer weights = FloatBuffer.allocate( box.getVertexCount() * 4 );
78        VertexBuffer weightsBuf = new VertexBuffer(Type.BoneWeight);
79        weightsBuf.setupData(Usage.CpuOnly, 4, Format.Float, weights);
80        box.setBuffer(weightsBuf);
81
82        // Setup bone index buffer
83        ByteBuffer indices = ByteBuffer.allocate( box.getVertexCount() * 4 );
84        VertexBuffer indicesBuf = new VertexBuffer(Type.BoneIndex);
85        indicesBuf.setupData(Usage.CpuOnly, 4, Format.UnsignedByte, indices);
86        box.setBuffer(indicesBuf);
87
88        // Create bind pose buffers
89        box.generateBindPose(true);
90
91        // Create skeleton
92        bone = new Bone("root");
93        bone.setBindTransforms(Vector3f.ZERO, Quaternion.IDENTITY, Vector3f.UNIT_XYZ);
94        bone.setUserControl(true);
95        skeleton = new Skeleton(new Bone[]{ bone });
96
97        // Assign all verticies to bone 0 with weight 1
98        for (int i = 0; i < box.getVertexCount() * 4; i += 4){
99            // assign vertex to bone index 0
100            indices.array()[i+0] = 0;
101            indices.array()[i+1] = 0;
102            indices.array()[i+2] = 0;
103            indices.array()[i+3] = 0;
104
105            // set weight to 1 only for first entry
106            weights.array()[i+0] = 1;
107            weights.array()[i+1] = 0;
108            weights.array()[i+2] = 0;
109            weights.array()[i+3] = 0;
110        }
111
112        // Maximum number of weights per bone is 1
113        box.setMaxNumWeights(1);
114
115        // Create model
116        Geometry geom = new Geometry("box", box);
117        geom.setMaterial(assetManager.loadMaterial("Textures/Terrain/BrickWall/BrickWall.j3m"));
118        Node model = new Node("model");
119        model.attachChild(geom);
120
121        // Create skeleton control
122        SkeletonControl skeletonControl = new SkeletonControl(skeleton);
123        model.addControl(skeletonControl);
124
125        rootNode.attachChild(model);
126    }
127
128    @Override
129    public void simpleUpdate(float tpf){
130        // Rotate around X axis
131        Quaternion rotate = new Quaternion();
132        rotate.fromAngleAxis(tpf, Vector3f.UNIT_X);
133
134        // Combine rotation with previous
135        rotation.multLocal(rotate);
136
137        // Set new rotation into bone
138        bone.setUserTransforms(Vector3f.ZERO, rotation, Vector3f.UNIT_XYZ);
139
140        // After changing skeleton transforms, must update world data
141        skeleton.updateWorldVectors();
142    }
143
144}
145