瀏覽代碼

Adds an ArmatureDebugger

Nehon 7 年之前
父節點
當前提交
4904d0235e

+ 60 - 99
jme3-core/src/main/java/com/jme3/scene/debug/custom/SkeletonBone.java → jme3-core/src/main/java/com/jme3/scene/debug/custom/ArmatureBone.java

@@ -32,58 +32,51 @@ package com.jme3.scene.debug.custom;
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
  */
 
 
-import java.util.Map;
-
-import com.jme3.animation.Bone;
-import com.jme3.animation.Skeleton;
+import com.jme3.animation.Armature;
+import com.jme3.animation.Joint;
 import com.jme3.bounding.*;
 import com.jme3.bounding.*;
-import com.jme3.math.FastMath;
 import com.jme3.math.Quaternion;
 import com.jme3.math.Quaternion;
 import com.jme3.math.Vector3f;
 import com.jme3.math.Vector3f;
-import com.jme3.scene.Geometry;
-import com.jme3.scene.Mesh;
-import com.jme3.scene.Node;
-import com.jme3.scene.VertexBuffer;
+import com.jme3.scene.*;
 import com.jme3.scene.shape.Sphere;
 import com.jme3.scene.shape.Sphere;
 
 
-import static com.jme3.util.BufferUtils.createFloatBuffer;
-
 import java.nio.FloatBuffer;
 import java.nio.FloatBuffer;
 import java.util.HashMap;
 import java.util.HashMap;
+import java.util.Map;
+
+import static com.jme3.util.BufferUtils.createFloatBuffer;
 
 
 /**
 /**
  * The class that displays either wires between the bones' heads if no length
  * The class that displays either wires between the bones' heads if no length
  * data is supplied and full bones' shapes otherwise.
  * data is supplied and full bones' shapes otherwise.
  */
  */
-public class SkeletonBone extends Node {
+public class ArmatureBone extends Node {
 
 
     /**
     /**
-     * The skeleton to be displayed.
+     * The armature to be displayed.
      */
      */
-    private Skeleton skeleton;
+    private Armature armature;
     /**
     /**
      * The map between the bone index and its length.
      * The map between the bone index and its length.
      */
      */
-    private Map<Bone, Node> boneNodes = new HashMap<Bone, Node>();
-    private Map<Node, Bone> nodeBones = new HashMap<Node, Bone>();
+    private Map<Joint, Node> jointNode = new HashMap<>();
+    private Map<Node, Joint> nodeJoint = new HashMap<>();
     private Node selectedNode = null;
     private Node selectedNode = null;
-    private boolean guessBonesOrientation = false;
+    private boolean guessJointsOrientation = false;
 
 
     /**
     /**
      * Creates a wire with bone lengths data. If the data is supplied then the
      * Creates a wire with bone lengths data. If the data is supplied then the
      * wires will show each full bone (from head to tail).
      * wires will show each full bone (from head to tail).
      *
      *
-     * @param skeleton    the skeleton that will be shown
+     * @param armature    the armature that will be shown
      * @param boneLengths a map between the bone's index and the bone's length
      * @param boneLengths a map between the bone's index and the bone's length
      */
      */
-    public SkeletonBone(Skeleton skeleton, Map<Integer, Float> boneLengths, boolean guessBonesOrientation) {
-        this.skeleton = skeleton;
-        this.skeleton.reset();
-        this.skeleton.updateWorldVectors();
-        this.guessBonesOrientation = guessBonesOrientation;
-
-        BoneShape boneShape = new BoneShape(5, 12, 0.02f, 0.07f, 1f, false, false);
-        Sphere jointShape = new Sphere(10, 10, 0.1f);
+    public ArmatureBone(Armature armature, Map<Integer, Float> boneLengths, boolean guessJointsOrientation) {
+        this.armature = armature;
+        this.guessJointsOrientation = guessJointsOrientation;
+
+        BoneShape boneShape = new BoneShape();
+        Sphere jointShape = new Sphere(16, 16, 0.05f);
         jointShape.setBuffer(VertexBuffer.Type.Color, 4, createFloatBuffer(jointShape.getVertexCount() * 4));
         jointShape.setBuffer(VertexBuffer.Type.Color, 4, createFloatBuffer(jointShape.getVertexCount() * 4));
         FloatBuffer cb = jointShape.getFloatBuffer(VertexBuffer.Type.Color);
         FloatBuffer cb = jointShape.getFloatBuffer(VertexBuffer.Type.Color);
 
 
@@ -92,13 +85,13 @@ public class SkeletonBone extends Node {
             cb.put(0.05f).put(0.05f).put(0.05f).put(1f);
             cb.put(0.05f).put(0.05f).put(0.05f).put(1f);
         }
         }
 
 
-        for (Bone bone : skeleton.getRoots()) {
-            createSkeletonGeoms(bone, boneShape, jointShape, boneLengths, skeleton, this, guessBonesOrientation);
+        for (Joint joint : armature.getRoots()) {
+            createSkeletonGeoms(joint, boneShape, jointShape, boneLengths, armature, this, guessJointsOrientation);
         }
         }
         this.updateModelBound();
         this.updateModelBound();
 
 
 
 
-        Sphere originShape = new Sphere(10, 10, 0.02f);
+        Sphere originShape = new Sphere(16, 16, 0.02f);
         originShape.setBuffer(VertexBuffer.Type.Color, 4, createFloatBuffer(originShape.getVertexCount() * 4));
         originShape.setBuffer(VertexBuffer.Type.Color, 4, createFloatBuffer(originShape.getVertexCount() * 4));
         cb = originShape.getFloatBuffer(VertexBuffer.Type.Color);
         cb = originShape.getFloatBuffer(VertexBuffer.Type.Color);
         cb.rewind();
         cb.rewind();
@@ -118,91 +111,65 @@ public class SkeletonBone extends Node {
         }
         }
         origin.scale(scale);
         origin.scale(scale);
         attachChild(origin);
         attachChild(origin);
-
-
-
     }
     }
 
 
-    protected final void createSkeletonGeoms(Bone bone, Mesh boneShape, Mesh jointShape, Map<Integer, Float> boneLengths, Skeleton skeleton, Node parent, boolean guessBonesOrientation) {
+    protected final void createSkeletonGeoms(Joint joint, Mesh boneShape, Mesh jointShape, Map<Integer, Float> boneLengths, Armature armature, Node parent, boolean guessBonesOrientation) {
 
 
-        if (guessBonesOrientation && bone.getName().equalsIgnoreCase("Site")) {
-            //BVH skeleton have a useless end point bone named Site
-            return;
-        }
-        Node n = new Node(bone.getName() + "Node");
-        Geometry bGeom = new Geometry(bone.getName(), boneShape);
-        Geometry jGeom = new Geometry(bone.getName() + "Joint", jointShape);
-        n.setLocalTranslation(bone.getLocalPosition());
-        n.setLocalRotation(bone.getLocalRotation());
+        Node n = new Node(joint.getName() + "Node");
+        Geometry bGeom = new Geometry(joint.getName() + "Bone", boneShape);
+        Geometry jGeom = new Geometry(joint.getName() + "Joint", jointShape);
+        n.setLocalTransform(joint.getLocalTransform());
 
 
-        float boneLength = boneLengths.get(skeleton.getBoneIndex(bone));
-        n.setLocalScale(bone.getLocalScale());
-
-        bGeom.setLocalRotation(new Quaternion().fromAngleAxis(-FastMath.HALF_PI, Vector3f.UNIT_X).normalizeLocal());
+        float boneLength = boneLengths.get(armature.getJointIndex(joint));
 
 
         if (guessBonesOrientation) {
         if (guessBonesOrientation) {
             //One child only, the bone direction is from the parent joint to the child joint.
             //One child only, the bone direction is from the parent joint to the child joint.
-            if (bone.getChildren().size() == 1) {
-                Vector3f v = bone.getChildren().get(0).getLocalPosition();
+            if (joint.getChildren().size() == 1) {
+                Vector3f v = joint.getChildren().get(0).getLocalTranslation();
                 Quaternion q = new Quaternion();
                 Quaternion q = new Quaternion();
                 q.lookAt(v, Vector3f.UNIT_Z);
                 q.lookAt(v, Vector3f.UNIT_Z);
                 bGeom.setLocalRotation(q);
                 bGeom.setLocalRotation(q);
-                boneLength = v.length();
             }
             }
             //no child, the bone has the same direction as the parent bone.
             //no child, the bone has the same direction as the parent bone.
-            if (bone.getChildren().isEmpty()) {
-                if (parent.getChildren().size() > 0) {
-                    bGeom.setLocalRotation(parent.getChild(0).getLocalRotation());
-                } else {
-                    //no parent, let's use the bind orientation of the bone
-                    bGeom.setLocalRotation(bone.getBindRotation());
+            if (joint.getChildren().isEmpty()) {
+                //no parent, let's use the bind orientation of the bone
+                Spatial s = parent.getChild(0);
+                if (s != null) {
+                    bGeom.setLocalRotation(s.getLocalRotation());
                 }
                 }
             }
             }
         }
         }
-        bGeom.setLocalScale(boneLength);
-        jGeom.setLocalScale(boneLength);
-
-        n.attachChild(bGeom);
-        n.attachChild(jGeom);
 
 
-        //tip
-        if (bone.getChildren().size() != 1) {
-            Geometry gt = jGeom.clone();
-            gt.scale(0.8f);
-            Vector3f v = new Vector3f(0, boneLength, 0);
-            if (guessBonesOrientation) {
-                if (bone.getChildren().isEmpty()) {
-                    if (parent.getChildren().size() > 0) {
-                        gt.setLocalTranslation(bGeom.getLocalRotation().mult(parent.getChild(0).getLocalRotation()).mult(v, v));
-                    } else {
-                        gt.setLocalTranslation(bGeom.getLocalRotation().mult(bone.getBindRotation()).mult(v, v));
-                    }
-                }
-            } else {
-                gt.setLocalTranslation(v);
-            }
+        float boneScale = boneLength * 0.8f;
+        float scale = boneScale / 8f;
+        bGeom.setLocalScale(new Vector3f(scale, scale, boneScale));
+        Vector3f offset = new Vector3f(0, 0, boneLength * 0.1f);
+        bGeom.getLocalRotation().multLocal(offset);
+        bGeom.setLocalTranslation(offset);
+        jGeom.setLocalScale(boneLength);
 
 
-            n.attachChild(gt);
+        if (joint.getChildren().size() <= 1) {
+            n.attachChild(bGeom);
         }
         }
+        n.attachChild(jGeom);
 
 
-
-        boneNodes.put(bone, n);
-        nodeBones.put(n, bone);
+        jointNode.put(joint, n);
+        nodeJoint.put(n, joint);
         parent.attachChild(n);
         parent.attachChild(n);
-        for (Bone childBone : bone.getChildren()) {
-            createSkeletonGeoms(childBone, boneShape, jointShape, boneLengths, skeleton, n, guessBonesOrientation);
+        for (Joint child : joint.getChildren()) {
+            createSkeletonGeoms(child, boneShape, jointShape, boneLengths, armature, n, guessBonesOrientation);
         }
         }
     }
     }
 
 
-    protected Bone select(Geometry g) {
+    protected Joint select(Geometry g) {
         Node parentNode = g.getParent();
         Node parentNode = g.getParent();
 
 
         if (parent != null) {
         if (parent != null) {
-            Bone b = nodeBones.get(parentNode);
-            if (b != null) {
+            Joint j = nodeJoint.get(parentNode);
+            if (j != null) {
                 selectedNode = parentNode;
                 selectedNode = parentNode;
             }
             }
-            return b;
+            return j;
         }
         }
         return null;
         return null;
     }
     }
@@ -212,17 +179,12 @@ public class SkeletonBone extends Node {
     }
     }
 
 
 
 
-    protected final void updateSkeletonGeoms(Bone bone) {
-        if (guessBonesOrientation && bone.getName().equalsIgnoreCase("Site")) {
-            return;
-        }
-        Node n = boneNodes.get(bone);
-        n.setLocalTranslation(bone.getLocalPosition());
-        n.setLocalRotation(bone.getLocalRotation());
-        n.setLocalScale(bone.getLocalScale());
+    protected final void updateSkeletonGeoms(Joint joint) {
+        Node n = jointNode.get(joint);
+        n.setLocalTransform(joint.getLocalTransform());
 
 
-        for (Bone childBone : bone.getChildren()) {
-            updateSkeletonGeoms(childBone);
+        for (Joint child : joint.getChildren()) {
+            updateSkeletonGeoms(child);
         }
         }
     }
     }
 
 
@@ -230,9 +192,8 @@ public class SkeletonBone extends Node {
      * The method updates the geometry according to the positions of the bones.
      * The method updates the geometry according to the positions of the bones.
      */
      */
     public void updateGeometry() {
     public void updateGeometry() {
-
-        for (Bone bone : skeleton.getRoots()) {
-            updateSkeletonGeoms(bone);
+        for (Joint joint : armature.getRoots()) {
+            updateSkeletonGeoms(joint);
         }
         }
     }
     }
 }
 }

+ 154 - 0
jme3-core/src/main/java/com/jme3/scene/debug/custom/ArmatureDebugAppState.java

@@ -0,0 +1,154 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.jme3.scene.debug.custom;
+
+import com.jme3.animation.*;
+import com.jme3.app.Application;
+import com.jme3.app.state.AbstractAppState;
+import com.jme3.app.state.AppStateManager;
+import com.jme3.input.MouseInput;
+import com.jme3.input.controls.ActionListener;
+import com.jme3.input.controls.MouseButtonTrigger;
+import com.jme3.light.DirectionalLight;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.Vector3f;
+import com.jme3.renderer.ViewPort;
+import com.jme3.scene.*;
+
+import java.util.*;
+
+/**
+ * @author Nehon
+ */
+public class ArmatureDebugAppState extends AbstractAppState {
+
+    private Node debugNode = new Node("debugNode");
+    private Map<Armature, ArmatureDebugger> armatures = new HashMap<>();
+    private Map<Armature, Joint> selectedBones = new HashMap<>();
+    private Application app;
+
+    @Override
+    public void initialize(AppStateManager stateManager, Application app) {
+        ViewPort vp = app.getRenderManager().createMainView("debug", app.getCamera());
+        vp.attachScene(debugNode);
+        vp.setClearDepth(true);
+        this.app = app;
+        for (ArmatureDebugger armatureDebugger : armatures.values()) {
+            armatureDebugger.initialize(app.getAssetManager());
+        }
+        app.getInputManager().addListener(actionListener, "shoot");
+        app.getInputManager().addMapping("shoot", new MouseButtonTrigger(MouseInput.BUTTON_LEFT), new MouseButtonTrigger(MouseInput.BUTTON_RIGHT));
+        super.initialize(stateManager, app);
+
+
+        debugNode.addLight(new DirectionalLight(new Vector3f(-1f, -1f, -1f).normalizeLocal()));
+
+        debugNode.addLight(new DirectionalLight(new Vector3f(1f, 1f, 1f).normalizeLocal(), new ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f)));
+
+    }
+
+    @Override
+    public void update(float tpf) {
+        debugNode.updateLogicalState(tpf);
+        debugNode.updateGeometricState();
+    }
+
+    public ArmatureDebugger addArmature(ArmatureControl armatureControl, boolean guessJointsOrientation) {
+        Armature armature = armatureControl.getArmature();
+        Spatial forSpatial = armatureControl.getSpatial();
+        return addArmature(armature, forSpatial, guessJointsOrientation);
+    }
+
+    public ArmatureDebugger addArmature(Armature armature, Spatial forSpatial, boolean guessJointsOrientation) {
+
+        ArmatureDebugger ad = new ArmatureDebugger(forSpatial.getName() + "_Armature", armature, guessJointsOrientation);
+        ad.setLocalTransform(forSpatial.getWorldTransform());
+        if (forSpatial instanceof Node) {
+            List<Geometry> geoms = new ArrayList<>();
+            findGeoms((Node) forSpatial, geoms);
+            if (geoms.size() == 1) {
+                ad.setLocalTransform(geoms.get(0).getWorldTransform());
+            }
+        }
+        armatures.put(armature, ad);
+        debugNode.attachChild(ad);
+        if (isInitialized()) {
+            ad.initialize(app.getAssetManager());
+        }
+        return ad;
+    }
+
+    private void findGeoms(Node node, List<Geometry> geoms) {
+        for (Spatial spatial : node.getChildren()) {
+            if (spatial instanceof Geometry) {
+                geoms.add((Geometry) spatial);
+            } else if (spatial instanceof Node) {
+                findGeoms((Node) spatial, geoms);
+            }
+        }
+    }
+
+    /**
+     * Pick a Target Using the Mouse Pointer. <ol><li>Map "pick target" action
+     * to a MouseButtonTrigger. <li>flyCam.setEnabled(false);
+     * <li>inputManager.setCursorVisible(true); <li>Implement action in
+     * AnalogListener (TODO).</ol>
+     */
+    private ActionListener actionListener = new ActionListener() {
+        public void onAction(String name, boolean isPressed, float tpf) {
+            //if (name.equals("shoot") && isPressed) {
+//                CollisionResults results = new CollisionResults();
+//                Vector2f click2d = app.getInputManager().getCursorPosition();
+//                Vector3f click3d = app.getCamera().getWorldCoordinates(new Vector2f(click2d.x, click2d.y), 0f).clone();
+//                Vector3f dir = app.getCamera().getWorldCoordinates(new Vector2f(click2d.x, click2d.y), 1f).subtractLocal(click3d);
+//                Ray ray = new Ray(click3d, dir);
+//
+//                debugNode.collideWith(ray, results);
+//
+//                if (results.size() > 0) {
+//                    // The closest result is the target that the player picked:
+//                    Geometry target = results.getClosestCollision().getGeometry();
+//                    for (ArmatureDebugger skeleton : armatures.values()) {
+//                        Joint selectedBone = skeleton.select(target);
+//                        if (selectedBone != null) {
+//                            selectedBones.put(skeleton.getArmature(), selectedBone);
+//                            System.err.println("-----------------------");
+//                            System.err.println("Selected Bone : " + selectedBone.getName() + " in skeleton " + skeleton.getName());
+//                            System.err.println("Root Bone : " + (selectedBone.getParent() == null));
+//                            System.err.println("-----------------------");
+//                            System.err.println("Bind translation: " + selectedBone.getBindPosition());
+//                            System.err.println("Bind rotation: " + selectedBone.getBindRotation());
+//                            System.err.println("Bind scale: " + selectedBone.getBindScale());
+//                            System.err.println("---");
+//                            System.err.println("Local translation: " + selectedBone.getLocalPosition());
+//                            System.err.println("Local rotation: " + selectedBone.getLocalRotation());
+//                            System.err.println("Local scale: " + selectedBone.getLocalScale());
+//                            System.err.println("---");
+//                            System.err.println("Model translation: " + selectedBone.getModelSpacePosition());
+//                            System.err.println("Model rotation: " + selectedBone.getModelSpaceRotation());
+//                            System.err.println("Model scale: " + selectedBone.getModelSpaceScale());
+//                            System.err.println("---");
+//                            System.err.println("Bind inverse Transform: ");
+//                            System.err.println(selectedBone.getBindInverseTransform());
+//                            return;
+//                        }
+//                    }
+//                }
+//            }
+        }
+    };
+
+//    public Map<Skeleton, Bone> getSelectedBones() {
+//        return selectedBones;
+//    }
+
+    public Node getDebugNode() {
+        return debugNode;
+    }
+
+    public void setDebugNode(Node debugNode) {
+        this.debugNode = debugNode;
+    }
+}

+ 54 - 59
jme3-core/src/main/java/com/jme3/scene/debug/custom/SkeletonDebugger.java → jme3-core/src/main/java/com/jme3/scene/debug/custom/ArmatureDebugger.java

@@ -32,46 +32,37 @@ package com.jme3.scene.debug.custom;
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
  */
 
 
-import com.jme3.animation.Bone;
-
-import java.util.Map;
-
-import com.jme3.animation.Skeleton;
+import com.jme3.animation.*;
 import com.jme3.asset.AssetManager;
 import com.jme3.asset.AssetManager;
 import com.jme3.material.Material;
 import com.jme3.material.Material;
 import com.jme3.math.ColorRGBA;
 import com.jme3.math.ColorRGBA;
-import com.jme3.scene.BatchNode;
-import com.jme3.scene.Geometry;
-import com.jme3.scene.Node;
-import com.jme3.scene.Spatial;
-import com.jme3.scene.VertexBuffer;
+import com.jme3.scene.*;
 
 
 import java.nio.FloatBuffer;
 import java.nio.FloatBuffer;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
+import java.util.*;
 
 
 /**
 /**
  * The class that creates a mesh to display how bones behave. If it is supplied
  * The class that creates a mesh to display how bones behave. If it is supplied
  * with the bones' lengths it will show exactly how the bones look like on the
  * with the bones' lengths it will show exactly how the bones look like on the
  * scene. If not then only connections between each bone heads will be shown.
  * scene. If not then only connections between each bone heads will be shown.
  */
  */
-public class SkeletonDebugger extends BatchNode {
+public class ArmatureDebugger extends BatchNode {
 
 
     /**
     /**
      * The lines of the bones or the wires between their heads.
      * The lines of the bones or the wires between their heads.
      */
      */
-    private SkeletonBone bones;
+    private ArmatureBone bones;
 
 
-    private Skeleton skeleton;
+    private Armature armature;
     /**
     /**
      * The dotted lines between a bone's tail and the had of its children. Not
      * The dotted lines between a bone's tail and the had of its children. Not
      * available if the length data was not provided.
      * available if the length data was not provided.
      */
      */
-    private SkeletonInterBoneWire interBoneWires;
-    private List<Bone> selectedBones = new ArrayList<Bone>();
+    private ArmatureInterJointsWire interJointWires;
+    private Geometry wires;
+    private List<Bone> selectedJoints = new ArrayList<Bone>();
 
 
-    public SkeletonDebugger() {
+    public ArmatureDebugger() {
     }
     }
 
 
     /**
     /**
@@ -80,38 +71,42 @@ public class SkeletonDebugger extends BatchNode {
      * and no dotted line of inter bones connection will be visible.
      * and no dotted line of inter bones connection will be visible.
      *
      *
      * @param name     the name of the debugger's node
      * @param name     the name of the debugger's node
-     * @param skeleton the skeleton that will be shown
+     * @param armature the armature that will be shown
      */
      */
-    public SkeletonDebugger(String name, Skeleton skeleton, boolean guessBonesOrientation) {
+    public ArmatureDebugger(String name, Armature armature, boolean guessJointsOrientation) {
         super(name);
         super(name);
-        this.skeleton = skeleton;
-        skeleton.reset();
-        skeleton.updateWorldVectors();
-        Map<Integer, Float> boneLengths = new HashMap<Integer, Float>();
-
-        for (Bone bone : skeleton.getRoots()) {
-            computeLength(bone, boneLengths, skeleton);
+        this.armature = armature;
+//        armature.reset();
+        armature.update();
+        //Joints have no length we want to display the as bones so we compute their length
+        Map<Integer, Float> bonesLength = new HashMap<Integer, Float>();
+
+        for (Joint joint : armature.getRoots()) {
+            computeLength(joint, bonesLength, armature);
         }
         }
 
 
-        bones = new SkeletonBone(skeleton, boneLengths, guessBonesOrientation);
+        bones = new ArmatureBone(armature, bonesLength, guessJointsOrientation);
 
 
         this.attachChild(bones);
         this.attachChild(bones);
 
 
-        interBoneWires = new SkeletonInterBoneWire(skeleton, boneLengths, guessBonesOrientation);
-        Geometry g = new Geometry(name + "_interwires", interBoneWires);
-        g.setBatchHint(BatchHint.Never);
-        this.attachChild(g);
+        interJointWires = new ArmatureInterJointsWire(armature, bonesLength, guessJointsOrientation);
+        wires = new Geometry(name + "_interwires", interJointWires);
+        this.attachChild(wires);
     }
     }
 
 
     protected void initialize(AssetManager assetManager) {
     protected void initialize(AssetManager assetManager) {
-        Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
-        mat.setColor("Color", new ColorRGBA(0.05f, 0.05f, 0.05f, 1.0f));//new ColorRGBA(0.1f, 0.1f, 0.1f, 1.0f)   
+        Material mat = new Material(assetManager, "Common/MatDefs/Misc/fakeLighting.j3md");
+        mat.setColor("Color", new ColorRGBA(0.2f, 0.2f, 0.2f, 1));
         setMaterial(mat);
         setMaterial(mat);
-        Material mat2 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
-        mat2.setBoolean("VertexColor", true);
-        bones.setMaterial(mat2);
-        batch();
 
 
+        Material matWires = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+        matWires.setColor("Color", ColorRGBA.Black);
+        wires.setMaterial(matWires);
+        //wires.setQueueBucket(RenderQueue.Bucket.Transparent);
+//        Material mat2 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+//        mat2.setBoolean("VertexColor", true);
+//        bones.setMaterial(mat2);
+//        batch();
     }
     }
 
 
     @Override
     @Override
@@ -125,29 +120,29 @@ public class SkeletonDebugger extends BatchNode {
         }
         }
     }
     }
 
 
-    public Skeleton getSkeleton() {
-        return skeleton;
+    public Armature getArmature() {
+        return armature;
     }
     }
 
 
 
 
-    private void computeLength(Bone b, Map<Integer, Float> boneLengths, Skeleton skeleton) {
-        if (b.getChildren().isEmpty()) {
-            if (b.getParent() != null) {
-                boneLengths.put(skeleton.getBoneIndex(b), boneLengths.get(skeleton.getBoneIndex(b.getParent())) * 0.75f);
+    private void computeLength(Joint joint, Map<Integer, Float> jointsLength, Armature armature) {
+        if (joint.getChildren().isEmpty()) {
+            if (joint.getParent() != null) {
+                jointsLength.put(armature.getJointIndex(joint), jointsLength.get(armature.getJointIndex(joint.getParent())) * 0.75f);
             } else {
             } else {
-                boneLengths.put(skeleton.getBoneIndex(b), 0.1f);
+                jointsLength.put(armature.getJointIndex(joint), 0.1f);
             }
             }
         } else {
         } else {
             float length = Float.MAX_VALUE;
             float length = Float.MAX_VALUE;
-            for (Bone bone : b.getChildren()) {
-                float len = b.getModelSpacePosition().subtract(bone.getModelSpacePosition()).length();
+            for (Joint child : joint.getChildren()) {
+                float len = joint.getModelTransform().getTranslation().subtract(child.getModelTransform().getTranslation()).length();
                 if (len < length) {
                 if (len < length) {
                     length = len;
                     length = len;
                 }
                 }
             }
             }
-            boneLengths.put(skeleton.getBoneIndex(b), length);
-            for (Bone bone : b.getChildren()) {
-                computeLength(bone, boneLengths, skeleton);
+            jointsLength.put(armature.getJointIndex(joint), length);
+            for (Joint child : joint.getChildren()) {
+                computeLength(child, jointsLength, armature);
             }
             }
         }
         }
     }
     }
@@ -156,17 +151,17 @@ public class SkeletonDebugger extends BatchNode {
     public void updateLogicalState(float tpf) {
     public void updateLogicalState(float tpf) {
         super.updateLogicalState(tpf);
         super.updateLogicalState(tpf);
         bones.updateGeometry();
         bones.updateGeometry();
-        if (interBoneWires != null) {
-            interBoneWires.updateGeometry();
+        if (interJointWires != null) {
+            interJointWires.updateGeometry();
         }
         }
     }
     }
 
 
     ColorRGBA selectedColor = ColorRGBA.Orange;
     ColorRGBA selectedColor = ColorRGBA.Orange;
     ColorRGBA baseColor = new ColorRGBA(0.05f, 0.05f, 0.05f, 1f);
     ColorRGBA baseColor = new ColorRGBA(0.05f, 0.05f, 0.05f, 1f);
 
 
-    protected Bone select(Geometry g) {
+    protected Joint select(Geometry g) {
         Node oldNode = bones.getSelectedNode();
         Node oldNode = bones.getSelectedNode();
-        Bone b = bones.select(g);
+        Joint b = bones.select(g);
         if (b == null) {
         if (b == null) {
             return null;
             return null;
         }
         }
@@ -178,17 +173,17 @@ public class SkeletonDebugger extends BatchNode {
     }
     }
 
 
     /**
     /**
-     * @return the skeleton wires
+     * @return the armature wires
      */
      */
-    public SkeletonBone getBoneShapes() {
+    public ArmatureBone getBoneShapes() {
         return bones;
         return bones;
     }
     }
 
 
     /**
     /**
      * @return the dotted line between bones (can be null)
      * @return the dotted line between bones (can be null)
      */
      */
-    public SkeletonInterBoneWire getInterBoneWires() {
-        return interBoneWires;
+    public ArmatureInterJointsWire getInterJointWires() {
+        return interJointWires;
     }
     }
 
 
     protected void markSelected(Node n, boolean selected) {
     protected void markSelected(Node n, boolean selected) {

+ 29 - 31
jme3-core/src/main/java/com/jme3/scene/debug/custom/SkeletonInterBoneWire.java → jme3-core/src/main/java/com/jme3/scene/debug/custom/ArmatureInterJointsWire.java

@@ -33,34 +33,32 @@ package com.jme3.scene.debug.custom;
  */
  */
 
 
 
 
-import java.nio.FloatBuffer;
-import java.util.Map;
-
-import com.jme3.animation.Bone;
-import com.jme3.animation.Skeleton;
+import com.jme3.animation.Armature;
+import com.jme3.animation.Joint;
 import com.jme3.math.Vector3f;
 import com.jme3.math.Vector3f;
 import com.jme3.scene.Mesh;
 import com.jme3.scene.Mesh;
 import com.jme3.scene.VertexBuffer;
 import com.jme3.scene.VertexBuffer;
-import com.jme3.scene.VertexBuffer.Format;
-import com.jme3.scene.VertexBuffer.Type;
-import com.jme3.scene.VertexBuffer.Usage;
+import com.jme3.scene.VertexBuffer.*;
 import com.jme3.util.BufferUtils;
 import com.jme3.util.BufferUtils;
 
 
+import java.nio.FloatBuffer;
+import java.util.Map;
+
 /**
 /**
  * A class that displays a dotted line between a bone tail and its childrens' heads.
  * A class that displays a dotted line between a bone tail and its childrens' heads.
  *
  *
  * @author Marcin Roguski (Kaelthas)
  * @author Marcin Roguski (Kaelthas)
  */
  */
-public class SkeletonInterBoneWire extends Mesh {
-    private static final int POINT_AMOUNT = 10;
+public class ArmatureInterJointsWire extends Mesh {
+    private static final int POINT_AMOUNT = 50;
     /**
     /**
      * The amount of connections between bones.
      * The amount of connections between bones.
      */
      */
     private int connectionsAmount;
     private int connectionsAmount;
     /**
     /**
-     * The skeleton that will be showed.
+     * The armature that will be showed.
      */
      */
-    private Skeleton skeleton;
+    private Armature armature;
     /**
     /**
      * The map between the bone index and its length.
      * The map between the bone index and its length.
      */
      */
@@ -71,18 +69,17 @@ public class SkeletonInterBoneWire extends Mesh {
     /**
     /**
      * Creates buffers for points. Each line has POINT_AMOUNT of points.
      * Creates buffers for points. Each line has POINT_AMOUNT of points.
      *
      *
-     * @param skeleton    the skeleton that will be showed
+     * @param armature    the armature that will be showed
      * @param boneLengths the lengths of the bones
      * @param boneLengths the lengths of the bones
      */
      */
-    public SkeletonInterBoneWire(Skeleton skeleton, Map<Integer, Float> boneLengths, boolean guessBonesOrientation) {
-        this.skeleton = skeleton;
+    public ArmatureInterJointsWire(Armature armature, Map<Integer, Float> boneLengths, boolean guessBonesOrientation) {
+        this.armature = armature;
 
 
-        for (Bone bone : skeleton.getRoots()) {
-            this.countConnections(bone);
+        for (Joint joint : armature.getRoots()) {
+            this.countConnections(joint);
         }
         }
 
 
         this.setMode(Mode.Points);
         this.setMode(Mode.Points);
-        this.setPointSize(2);
         this.boneLengths = boneLengths;
         this.boneLengths = boneLengths;
 
 
         VertexBuffer pb = new VertexBuffer(Type.Position);
         VertexBuffer pb = new VertexBuffer(Type.Position);
@@ -95,27 +92,28 @@ public class SkeletonInterBoneWire extends Mesh {
     }
     }
 
 
     /**
     /**
-     * The method updates the geometry according to the poitions of the bones.
+     * The method updates the geometry according to the positions of the bones.
      */
      */
     public void updateGeometry() {
     public void updateGeometry() {
         VertexBuffer vb = this.getBuffer(Type.Position);
         VertexBuffer vb = this.getBuffer(Type.Position);
         FloatBuffer posBuf = this.getFloatBuffer(Type.Position);
         FloatBuffer posBuf = this.getFloatBuffer(Type.Position);
         posBuf.clear();
         posBuf.clear();
-        for (int i = 0; i < skeleton.getBoneCount(); ++i) {
-            Bone bone = skeleton.getBone(i);
-            Vector3f parentTail = bone.getModelSpacePosition().add(bone.getModelSpaceRotation().mult(Vector3f.UNIT_Y.mult(boneLengths.get(i))));
+        for (int i = 0; i < armature.getJointCount(); ++i) {
+            Joint joint = armature.getJoint(i);
+            Vector3f parentTail = joint.getModelTransform().getTranslation().add(joint.getModelTransform().getRotation().mult(Vector3f.UNIT_Y.mult(boneLengths.get(i))));
 
 
             if (guessBonesOrientation) {
             if (guessBonesOrientation) {
-                parentTail = bone.getModelSpacePosition();
+                parentTail = joint.getModelTransform().getTranslation();
             }
             }
 
 
-            for (Bone child : bone.getChildren()) {
-                Vector3f childHead = child.getModelSpacePosition();
+            for (Joint child : joint.getChildren()) {
+                Vector3f childHead = child.getModelTransform().getTranslation();
                 Vector3f v = childHead.subtract(parentTail);
                 Vector3f v = childHead.subtract(parentTail);
-                float pointDelta = v.length() / POINT_AMOUNT;
+                float len = v.length();
+                float pointDelta = 1f / POINT_AMOUNT;
                 v.normalizeLocal().multLocal(pointDelta);
                 v.normalizeLocal().multLocal(pointDelta);
                 Vector3f pointPosition = parentTail.clone();
                 Vector3f pointPosition = parentTail.clone();
-                for (int j = 0; j < POINT_AMOUNT; ++j) {
+                for (int j = 0; j < POINT_AMOUNT * len; ++j) {
                     posBuf.put(pointPosition.getX()).put(pointPosition.getY()).put(pointPosition.getZ());
                     posBuf.put(pointPosition.getX()).put(pointPosition.getY()).put(pointPosition.getZ());
                     pointPosition.addLocal(v);
                     pointPosition.addLocal(v);
                 }
                 }
@@ -128,12 +126,12 @@ public class SkeletonInterBoneWire extends Mesh {
     }
     }
 
 
     /**
     /**
-     * Th method couns the connections between bones.
+     * Th method counts the connections between bones.
      *
      *
-     * @param bone the bone where counting starts
+     * @param joint the bone where counting starts
      */
      */
-    private void countConnections(Bone bone) {
-        for (Bone child : bone.getChildren()) {
+    private void countConnections(Joint joint) {
+        for (Joint child : joint.getChildren()) {
             ++connectionsAmount;
             ++connectionsAmount;
             this.countConnections(child);
             this.countConnections(child);
         }
         }

+ 101 - 347
jme3-core/src/main/java/com/jme3/scene/debug/custom/BoneShape.java

@@ -32,20 +32,11 @@
 // $Id: Cylinder.java 4131 2009-03-19 20:15:28Z blaine.dev $
 // $Id: Cylinder.java 4131 2009-03-19 20:15:28Z blaine.dev $
 package com.jme3.scene.debug.custom;
 package com.jme3.scene.debug.custom;
 
 
-import com.jme3.export.InputCapsule;
-import com.jme3.export.JmeExporter;
-import com.jme3.export.JmeImporter;
-import com.jme3.export.OutputCapsule;
-import com.jme3.math.FastMath;
-import com.jme3.math.Vector3f;
-import com.jme3.scene.Mesh;
+import com.jme3.math.*;
 import com.jme3.scene.VertexBuffer.Type;
 import com.jme3.scene.VertexBuffer.Type;
-import com.jme3.scene.mesh.IndexBuffer;
+import com.jme3.scene.shape.AbstractBox;
 import com.jme3.util.BufferUtils;
 import com.jme3.util.BufferUtils;
 
 
-import static com.jme3.util.BufferUtils.*;
-
-import java.io.IOException;
 import java.nio.FloatBuffer;
 import java.nio.FloatBuffer;
 
 
 /**
 /**
@@ -55,362 +46,125 @@ import java.nio.FloatBuffer;
  * @author Mark Powell
  * @author Mark Powell
  * @version $Revision: 4131 $, $Date: 2009-03-19 16:15:28 -0400 (Thu, 19 Mar 2009) $
  * @version $Revision: 4131 $, $Date: 2009-03-19 16:15:28 -0400 (Thu, 19 Mar 2009) $
  */
  */
-public class BoneShape extends Mesh {
-
-    private int axisSamples;
-
-    private int radialSamples;
-
-    private float radius;
-    private float radius2;
-
-    private float height;
-    private boolean closed;
-    private boolean inverted;
-
-    /**
-     * Default constructor for serialization only. Do not use.
-     */
-    public BoneShape() {
+public class BoneShape extends AbstractBox {
+
+    private static Vector3f topN = new Vector3f(0, 1, 0);
+    private static Vector3f botN = new Vector3f(0, -1, 0);
+    private static Vector3f rigN = new Vector3f(1, 0, 0);
+    private static Vector3f lefN = new Vector3f(-1, 0, 0);
+
+    static {
+        Quaternion q = new Quaternion().fromAngleAxis(-FastMath.PI / 16f, Vector3f.UNIT_X);
+        q.multLocal(topN);
+        q.inverseLocal();
+        q.multLocal(botN);
+        q = new Quaternion().fromAngleAxis(FastMath.PI / 16f, Vector3f.UNIT_Y);
+        q.multLocal(rigN);
+        q.inverseLocal();
+        q.multLocal(lefN);
     }
     }
 
 
-    /**
-     * Creates a new Cylinder. By default its center is the origin. Usually, a
-     * higher sample number creates a better looking cylinder, but at the cost
-     * of more vertex information.
-     *
-     * @param axisSamples   Number of triangle samples along the axis.
-     * @param radialSamples Number of triangle samples along the radial.
-     * @param radius        The radius of the cylinder.
-     * @param height        The cylinder's height.
-     */
-    public BoneShape(int axisSamples, int radialSamples,
-                     float radius, float height) {
-        this(axisSamples, radialSamples, radius, height, false);
-    }
-
-    /**
-     * Creates a new Cylinder. By default its center is the origin. Usually, a
-     * higher sample number creates a better looking cylinder, but at the cost
-     * of more vertex information. <br>
-     * If the cylinder is closed the texture is split into axisSamples parts:
-     * top most and bottom most part is used for top and bottom of the cylinder,
-     * rest of the texture for the cylinder wall. The middle of the top is
-     * mapped to texture coordinates (0.5, 1), bottom to (0.5, 0). Thus you need
-     * a suited distorted texture.
-     *
-     * @param axisSamples   Number of triangle samples along the axis.
-     * @param radialSamples Number of triangle samples along the radial.
-     * @param radius        The radius of the cylinder.
-     * @param height        The cylinder's height.
-     * @param closed        true to create a cylinder with top and bottom surface
-     */
-    public BoneShape(int axisSamples, int radialSamples,
-                     float radius, float height, boolean closed) {
-        this(axisSamples, radialSamples, radius, height, closed, false);
-    }
+    private static final short[] GEOMETRY_INDICES_DATA = {
+            2, 1, 0, 3, 2, 0, // back
+            6, 5, 4, 7, 6, 4, // right
+            10, 9, 8, 11, 10, 8, // front
+            14, 13, 12, 15, 14, 12, // left
+            18, 17, 16, 19, 18, 16, // top
+            22, 21, 20, 23, 22, 20  // bottom
+    };
+
+    private static final float[] GEOMETRY_NORMALS_DATA = {
+            0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, // back
+            rigN.x, rigN.y, rigN.z, rigN.x, rigN.y, rigN.z, rigN.x, rigN.y, rigN.z, rigN.x, rigN.y, rigN.z, // right
+            0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, // front
+            lefN.x, lefN.y, lefN.z, lefN.x, lefN.y, lefN.z, lefN.x, lefN.y, lefN.z, lefN.x, lefN.y, lefN.z, // left
+            topN.x, topN.y, topN.z, topN.x, topN.y, topN.z, topN.x, topN.y, topN.z, topN.x, topN.y, topN.z, // top
+            botN.x, botN.y, botN.z, botN.x, botN.y, botN.z, botN.x, botN.y, botN.z, botN.x, botN.y, botN.z  // bottom
+    };
+
+    private static final float[] GEOMETRY_TEXTURE_DATA = {
+            1, 0, 0, 0, 0, 1, 1, 1, // back
+            1, 0, 0, 0, 0, 1, 1, 1, // right
+            1, 0, 0, 0, 0, 1, 1, 1, // front
+            1, 0, 0, 0, 0, 1, 1, 1, // left
+            1, 0, 0, 0, 0, 1, 1, 1, // top
+            1, 0, 0, 0, 0, 1, 1, 1  // bottom
+    };
+
+    private static final float[] GEOMETRY_POSITION_DATA = {
+            -0.5f, -0.5f, 0, 0.5f, -0.5f, 0, 0.5f, 0.5f, 0, -0.5f, 0.5f, 0, //back
+            0.5f, -0.5f, 0, 0.25f, -0.25f, 1, 0.25f, 0.25f, 1, 0.5f, 0.5f, 0, //right
+            0.25f, -0.25f, 1, -0.25f, -0.25f, 1, -0.25f, 0.25f, 1, 0.25f, 0.25f, 1, //front
+            -0.25f, -0.25f, 1, -0.5f, -0.5f, 0, -0.5f, 0.5f, 0, -0.25f, 0.25f, 1, //left
+            0.5f, 0.5f, 0, 0.25f, 0.25f, 1, -0.25f, 0.25f, 1, -0.5f, 0.5f, 0, // top
+            -0.5f, -0.5f, 0, -0.25f, -0.25f, 1, 0.25f, -0.25f, 1, 0.5f, -0.5f, 0 // bottom
+    };
+
+    //0,1,2,3
+    //1,4,6,2
+    //4,5,7,6
+    //5,0,3,7,
+    //2,6,7,3
+    //0,5,4,1
+
+
+//    v[0].x, v[0].y, v[0].z, v[1].x, v[1].y, v[1].z, v[2].x, v[2].y, v[2].z, v[3].x, v[3].y, v[3].z, // back
+//    v[1].x, v[1].y, v[1].z, v[4].x, v[4].y, v[4].z, v[6].x, v[6].y, v[6].z, v[2].x, v[2].y, v[2].z, // right
+//    v[4].x, v[4].y, v[4].z, v[5].x, v[5].y, v[5].z, v[7].x, v[7].y, v[7].z, v[6].x, v[6].y, v[6].z, // front
+//    v[5].x, v[5].y, v[5].z, v[0].x, v[0].y, v[0].z, v[3].x, v[3].y, v[3].z, v[7].x, v[7].y, v[7].z, // left
+//    v[2].x, v[2].y, v[2].z, v[6].x, v[6].y, v[6].z, v[7].x, v[7].y, v[7].z, v[3].x, v[3].y, v[3].z, // top
+//    v[0].x, v[0].y, v[0].z, v[5].x, v[5].y, v[5].z, v[4].x, v[4].y, v[4].z, v[1].x, v[1].y, v[1].z  // bottom
 
 
     /**
     /**
-     * Creates a new Cylinder. By default its center is the origin. Usually, a
-     * higher sample number creates a better looking cylinder, but at the cost
-     * of more vertex information. <br>
-     * If the cylinder is closed the texture is split into axisSamples parts:
-     * top most and bottom most part is used for top and bottom of the cylinder,
-     * rest of the texture for the cylinder wall. The middle of the top is
-     * mapped to texture coordinates (0.5, 1), bottom to (0.5, 0). Thus you need
-     * a suited distorted texture.
+     * Creates a new box.
+     * <p>
+     * The box has a center of 0,0,0 and extends in the out from the center by
+     * the given amount in <em>each</em> direction. So, for example, a box
+     * with extent of 0.5 would be the unit cube.
      *
      *
-     * @param axisSamples   Number of triangle samples along the axis.
-     * @param radialSamples Number of triangle samples along the radial.
-     * @param radius        The radius of the cylinder.
-     * @param height        The cylinder's height.
-     * @param closed        true to create a cylinder with top and bottom surface
-     * @param inverted      true to create a cylinder that is meant to be viewed from the
-     *                      interior.
+     * @param x the size of the box along the x axis, in both directions.
+     * @param y the size of the box along the y axis, in both directions.
+     * @param z the size of the box along the z axis, in both directions.
      */
      */
-    public BoneShape(int axisSamples, int radialSamples,
-                     float radius, float height, boolean closed, boolean inverted) {
-        this(axisSamples, radialSamples, radius, radius, height, closed, inverted);
-    }
-
-    public BoneShape(int axisSamples, int radialSamples,
-                     float radius, float radius2, float height, boolean closed, boolean inverted) {
+    public BoneShape() {
         super();
         super();
-        updateGeometry(axisSamples, radialSamples, radius, radius2, height, closed, inverted);
-    }
-
-    /**
-     * @return the number of samples along the cylinder axis
-     */
-    public int getAxisSamples() {
-        return axisSamples;
-    }
-
-    /**
-     * @return Returns the height.
-     */
-    public float getHeight() {
-        return height;
-    }
-
-    /**
-     * @return number of samples around cylinder
-     */
-    public int getRadialSamples() {
-        return radialSamples;
-    }
-
-    /**
-     * @return Returns the radius.
-     */
-    public float getRadius() {
-        return radius;
-    }
-
-    public float getRadius2() {
-        return radius2;
-    }
-
-    /**
-     * @return true if end caps are used.
-     */
-    public boolean isClosed() {
-        return closed;
+        updateGeometry();
     }
     }
 
 
     /**
     /**
-     * @return true if normals and uvs are created for interior use
+     * Creates a clone of this box.
+     * <p>
+     * The cloned box will have '_clone' appended to it's name, but all other
+     * properties will be the same as this box.
      */
      */
-    public boolean isInverted() {
-        return inverted;
+    @Override
+    public BoneShape clone() {
+        return new BoneShape();
     }
     }
 
 
-    /**
-     * Rebuilds the cylinder based on a new set of parameters.
-     *
-     * @param axisSamples   the number of samples along the axis.
-     * @param radialSamples the number of samples around the radial.
-     * @param radius        the radius of the bottom of the cylinder.
-     * @param radius2       the radius of the top of the cylinder.
-     * @param height        the cylinder's height.
-     * @param closed        should the cylinder have top and bottom surfaces.
-     * @param inverted      is the cylinder is meant to be viewed from the inside.
-     */
-    public void updateGeometry(int axisSamples, int radialSamples,
-                               float radius, float radius2, float height, boolean closed, boolean inverted) {
-        this.axisSamples = axisSamples + (closed ? 2 : 0);
-        this.radialSamples = radialSamples;
-        this.radius = radius;
-        this.radius2 = radius2;
-        this.height = height;
-        this.closed = closed;
-        this.inverted = inverted;
-
-//        VertexBuffer pvb = getBuffer(Type.Position);
-//        VertexBuffer nvb = getBuffer(Type.Normal);
-//        VertexBuffer tvb = getBuffer(Type.TexCoord);
-
-        // Vertices
-        int vertCount = axisSamples * (radialSamples + 1) + (closed ? 2 : 0);
-
-        setBuffer(Type.Position, 3, createVector3Buffer(getFloatBuffer(Type.Position), vertCount));
-
-        // Normals
-        setBuffer(Type.Normal, 3, createVector3Buffer(getFloatBuffer(Type.Normal), vertCount));
-
-        // Texture co-ordinates
-        setBuffer(Type.TexCoord, 2, createVector2Buffer(vertCount));
-
-        int triCount = ((closed ? 2 : 0) + 2 * (axisSamples - 1)) * radialSamples;
-
-        setBuffer(Type.Index, 3, createShortBuffer(getShortBuffer(Type.Index), 3 * triCount));
-
-        //Color
-        setBuffer(Type.Color, 4, createFloatBuffer(vertCount * 4));
-
-        // generate geometry
-        float inverseRadial = 1.0f / radialSamples;
-        float inverseAxisLess = 1.0f / (closed ? axisSamples - 3 : axisSamples - 1);
-        float inverseAxisLessTexture = 1.0f / (axisSamples - 1);
-        float halfHeight = 0.5f * height;
-
-        // Generate points on the unit circle to be used in computing the mesh
-        // points on a cylinder slice.
-        float[] sin = new float[radialSamples + 1];
-        float[] cos = new float[radialSamples + 1];
-
-        for (int radialCount = 0; radialCount < radialSamples; radialCount++) {
-            float angle = FastMath.TWO_PI * inverseRadial * radialCount;
-            cos[radialCount] = FastMath.cos(angle);
-            sin[radialCount] = FastMath.sin(angle);
-        }
-        sin[radialSamples] = sin[0];
-        cos[radialSamples] = cos[0];
-
-        // calculate normals
-        Vector3f[] vNormals = null;
-        Vector3f vNormal = Vector3f.UNIT_Z;
-
-        if ((height != 0.0f) && (radius != radius2)) {
-            vNormals = new Vector3f[radialSamples];
-            Vector3f vHeight = Vector3f.UNIT_Z.mult(height);
-            Vector3f vRadial = new Vector3f();
-
-            for (int radialCount = 0; radialCount < radialSamples; radialCount++) {
-                vRadial.set(cos[radialCount], sin[radialCount], 0.0f);
-                Vector3f vRadius = vRadial.mult(radius);
-                Vector3f vRadius2 = vRadial.mult(radius2);
-                Vector3f vMantle = vHeight.subtract(vRadius2.subtract(vRadius));
-                Vector3f vTangent = vRadial.cross(Vector3f.UNIT_Z);
-                vNormals[radialCount] = vMantle.cross(vTangent).normalize();
-            }
-        }
-
-        FloatBuffer nb = getFloatBuffer(Type.Normal);
-        FloatBuffer pb = getFloatBuffer(Type.Position);
-        FloatBuffer tb = getFloatBuffer(Type.TexCoord);
-        FloatBuffer cb = getFloatBuffer(Type.Color);
-
-        cb.rewind();
-        for (int i = 0; i < vertCount; i++) {
-            cb.put(0.05f).put(0.05f).put(0.05f).put(1f);
-        }
-
-        // generate the cylinder itself
-        Vector3f tempNormal = new Vector3f();
-        for (int axisCount = 0, i = 0; axisCount < axisSamples; axisCount++, i++) {
-            float axisFraction;
-            float axisFractionTexture;
-            int topBottom = 0;
-            if (!closed) {
-                axisFraction = axisCount * inverseAxisLess; // in [0,1]
-                axisFractionTexture = axisFraction;
-            } else {
-                if (axisCount == 0) {
-                    topBottom = -1; // bottom
-                    axisFraction = 0;
-                    axisFractionTexture = inverseAxisLessTexture;
-                } else if (axisCount == axisSamples - 1) {
-                    topBottom = 1; // top
-                    axisFraction = 1;
-                    axisFractionTexture = 1 - inverseAxisLessTexture;
-                } else {
-                    axisFraction = (axisCount - 1) * inverseAxisLess;
-                    axisFractionTexture = axisCount * inverseAxisLessTexture;
-                }
-            }
-
-            // compute center of slice
-            float z = height * axisFraction;
-            Vector3f sliceCenter = new Vector3f(0, 0, z);
-
-            // compute slice vertices with duplication at end point
-            int save = i;
-            for (int radialCount = 0; radialCount < radialSamples; radialCount++, i++) {
-                float radialFraction = radialCount * inverseRadial; // in [0,1)
-                tempNormal.set(cos[radialCount], sin[radialCount], 0.0f);
-
-                if (vNormals != null) {
-                    vNormal = vNormals[radialCount];
-                } else if (radius == radius2) {
-                    vNormal = tempNormal;
-                }
-
-                if (topBottom == 0) {
-                    if (!inverted)
-                        nb.put(vNormal.x).put(vNormal.y).put(vNormal.z);
-                    else
-                        nb.put(-vNormal.x).put(-vNormal.y).put(-vNormal.z);
-                } else {
-                    nb.put(0).put(0).put(topBottom * (inverted ? -1 : 1));
-                }
-
-                tempNormal.multLocal((radius - radius2) * axisFraction + radius2)
-                        .addLocal(sliceCenter);
-                pb.put(tempNormal.x).put(tempNormal.y).put(tempNormal.z);
-
-                tb.put((inverted ? 1 - radialFraction : radialFraction))
-                        .put(axisFractionTexture);
-            }
-
-            BufferUtils.copyInternalVector3(pb, save, i);
-            BufferUtils.copyInternalVector3(nb, save, i);
-
-            tb.put((inverted ? 0.0f : 1.0f))
-                    .put(axisFractionTexture);
-        }
-
-        if (closed) {
-            pb.put(0).put(0).put(-halfHeight); // bottom center
-            nb.put(0).put(0).put(-1 * (inverted ? -1 : 1));
-            tb.put(0.5f).put(0);
-            pb.put(0).put(0).put(halfHeight); // top center
-            nb.put(0).put(0).put(1 * (inverted ? -1 : 1));
-            tb.put(0.5f).put(1);
+    protected void doUpdateGeometryIndices() {
+        if (getBuffer(Type.Index) == null) {
+            setBuffer(Type.Index, 3, BufferUtils.createShortBuffer(GEOMETRY_INDICES_DATA));
         }
         }
+    }
 
 
-        IndexBuffer ib = getIndexBuffer();
-        int index = 0;
-        // Connectivity
-        for (int axisCount = 0, axisStart = 0; axisCount < axisSamples - 1; axisCount++) {
-            int i0 = axisStart;
-            int i1 = i0 + 1;
-            axisStart += radialSamples + 1;
-            int i2 = axisStart;
-            int i3 = i2 + 1;
-            for (int i = 0; i < radialSamples; i++) {
-                if (closed && axisCount == 0) {
-                    if (!inverted) {
-                        ib.put(index++, i0++);
-                        ib.put(index++, vertCount - 2);
-                        ib.put(index++, i1++);
-                    } else {
-                        ib.put(index++, i0++);
-                        ib.put(index++, i1++);
-                        ib.put(index++, vertCount - 2);
-                    }
-                } else if (closed && axisCount == axisSamples - 2) {
-                    ib.put(index++, i2++);
-                    ib.put(index++, inverted ? vertCount - 1 : i3++);
-                    ib.put(index++, inverted ? i3++ : vertCount - 1);
-                } else {
-                    ib.put(index++, i0++);
-                    ib.put(index++, inverted ? i2 : i1);
-                    ib.put(index++, inverted ? i1 : i2);
-                    ib.put(index++, i1++);
-                    ib.put(index++, inverted ? i2++ : i3++);
-                    ib.put(index++, inverted ? i3++ : i2++);
-                }
-            }
+    protected void doUpdateGeometryNormals() {
+        if (getBuffer(Type.Normal) == null) {
+            setBuffer(Type.Normal, 3, BufferUtils.createFloatBuffer(GEOMETRY_NORMALS_DATA));
         }
         }
-
-        updateBound();
     }
     }
 
 
-    @Override
-    public void read(JmeImporter e) throws IOException {
-        super.read(e);
-        InputCapsule capsule = e.getCapsule(this);
-        axisSamples = capsule.readInt("axisSamples", 0);
-        radialSamples = capsule.readInt("radialSamples", 0);
-        radius = capsule.readFloat("radius", 0);
-        radius2 = capsule.readFloat("radius2", 0);
-        height = capsule.readFloat("height", 0);
-        closed = capsule.readBoolean("closed", false);
-        inverted = capsule.readBoolean("inverted", false);
+    protected void doUpdateGeometryTextures() {
+        if (getBuffer(Type.TexCoord) == null) {
+            setBuffer(Type.TexCoord, 2, BufferUtils.createFloatBuffer(GEOMETRY_TEXTURE_DATA));
+        }
     }
     }
 
 
-    @Override
-    public void write(JmeExporter e) throws IOException {
-        super.write(e);
-        OutputCapsule capsule = e.getCapsule(this);
-        capsule.write(axisSamples, "axisSamples", 0);
-        capsule.write(radialSamples, "radialSamples", 0);
-        capsule.write(radius, "radius", 0);
-        capsule.write(radius2, "radius2", 0);
-        capsule.write(height, "height", 0);
-        capsule.write(closed, "closed", false);
-        capsule.write(inverted, "inverted", false);
+    protected void doUpdateGeometryVertices() {
+        FloatBuffer fpb = BufferUtils.createVector3Buffer(24);
+        fpb.put(GEOMETRY_POSITION_DATA);
+        setBuffer(Type.Position, 3, fpb);
+        updateBound();
     }
     }
 
 
 
 

+ 0 - 156
jme3-core/src/main/java/com/jme3/scene/debug/custom/SkeletonDebugAppState.java

@@ -1,156 +0,0 @@
-/*
- * To change this template, choose Tools | Templates
- * and open the template in the editor.
- */
-package com.jme3.scene.debug.custom;
-
-import com.jme3.animation.Bone;
-import com.jme3.animation.Skeleton;
-import com.jme3.animation.SkeletonControl;
-import com.jme3.app.Application;
-import com.jme3.app.state.AbstractAppState;
-import com.jme3.app.state.AppStateManager;
-import com.jme3.collision.CollisionResults;
-import com.jme3.input.MouseInput;
-import com.jme3.input.controls.ActionListener;
-import com.jme3.input.controls.MouseButtonTrigger;
-import com.jme3.math.Ray;
-import com.jme3.math.Vector2f;
-import com.jme3.math.Vector3f;
-import com.jme3.renderer.ViewPort;
-import com.jme3.scene.Geometry;
-import com.jme3.scene.Node;
-import com.jme3.scene.Spatial;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * @author Nehon
- */
-public class SkeletonDebugAppState extends AbstractAppState {
-
-    private Node debugNode = new Node("debugNode");
-    private Map<Skeleton, SkeletonDebugger> skeletons = new HashMap<Skeleton, SkeletonDebugger>();
-    private Map<Skeleton, Bone> selectedBones = new HashMap<Skeleton, Bone>();
-    private Application app;
-
-    @Override
-    public void initialize(AppStateManager stateManager, Application app) {
-        ViewPort vp = app.getRenderManager().createMainView("debug", app.getCamera());
-        vp.attachScene(debugNode);
-        vp.setClearDepth(true);
-        this.app = app;
-        for (SkeletonDebugger skeletonDebugger : skeletons.values()) {
-            skeletonDebugger.initialize(app.getAssetManager());
-        }
-        app.getInputManager().addListener(actionListener, "shoot");
-        app.getInputManager().addMapping("shoot", new MouseButtonTrigger(MouseInput.BUTTON_LEFT), new MouseButtonTrigger(MouseInput.BUTTON_RIGHT));
-        super.initialize(stateManager, app);
-    }
-
-    @Override
-    public void update(float tpf) {
-        debugNode.updateLogicalState(tpf);
-        debugNode.updateGeometricState();
-    }
-
-    public SkeletonDebugger addSkeleton(SkeletonControl skeletonControl, boolean guessBonesOrientation) {
-        Skeleton skeleton = skeletonControl.getSkeleton();
-        Spatial forSpatial = skeletonControl.getSpatial();
-        return addSkeleton(skeleton, forSpatial, guessBonesOrientation);
-    }
-
-    public SkeletonDebugger addSkeleton(Skeleton skeleton, Spatial forSpatial, boolean guessBonesOrientation) {
-
-        SkeletonDebugger sd = new SkeletonDebugger(forSpatial.getName() + "_Skeleton", skeleton, guessBonesOrientation);
-        sd.setLocalTransform(forSpatial.getWorldTransform());
-        if (forSpatial instanceof Node) {
-            List<Geometry> geoms = new ArrayList<>();
-            findGeoms((Node) forSpatial, geoms);
-            if (geoms.size() == 1) {
-                sd.setLocalTransform(geoms.get(0).getWorldTransform());
-            }
-        }
-        skeletons.put(skeleton, sd);
-        debugNode.attachChild(sd);
-        if (isInitialized()) {
-            sd.initialize(app.getAssetManager());
-        }
-        return sd;
-    }
-
-    private void findGeoms(Node node, List<Geometry> geoms) {
-        for (Spatial spatial : node.getChildren()) {
-            if (spatial instanceof Geometry) {
-                geoms.add((Geometry) spatial);
-            } else if (spatial instanceof Node) {
-                findGeoms((Node) spatial, geoms);
-            }
-        }
-    }
-
-    /**
-     * Pick a Target Using the Mouse Pointer. <ol><li>Map "pick target" action
-     * to a MouseButtonTrigger. <li>flyCam.setEnabled(false);
-     * <li>inputManager.setCursorVisible(true); <li>Implement action in
-     * AnalogListener (TODO).</ol>
-     */
-    private ActionListener actionListener = new ActionListener() {
-        public void onAction(String name, boolean isPressed, float tpf) {
-            if (name.equals("shoot") && isPressed) {
-                CollisionResults results = new CollisionResults();
-                Vector2f click2d = app.getInputManager().getCursorPosition();
-                Vector3f click3d = app.getCamera().getWorldCoordinates(new Vector2f(click2d.x, click2d.y), 0f).clone();
-                Vector3f dir = app.getCamera().getWorldCoordinates(new Vector2f(click2d.x, click2d.y), 1f).subtractLocal(click3d);
-                Ray ray = new Ray(click3d, dir);
-
-                debugNode.collideWith(ray, results);
-
-                if (results.size() > 0) {
-                    // The closest result is the target that the player picked:
-                    Geometry target = results.getClosestCollision().getGeometry();
-                    for (SkeletonDebugger skeleton : skeletons.values()) {
-                        Bone selectedBone = skeleton.select(target);
-                        if (selectedBone != null) {
-                            selectedBones.put(skeleton.getSkeleton(), selectedBone);
-                            System.err.println("-----------------------");
-                            System.err.println("Selected Bone : " + selectedBone.getName() + " in skeleton " + skeleton.getName());
-                            System.err.println("Root Bone : " + (selectedBone.getParent() == null));
-                            System.err.println("-----------------------");
-                            System.err.println("Bind translation: " + selectedBone.getBindPosition());
-                            System.err.println("Bind rotation: " + selectedBone.getBindRotation());
-                            System.err.println("Bind scale: " + selectedBone.getBindScale());
-                            System.err.println("---");
-                            System.err.println("Local translation: " + selectedBone.getLocalPosition());
-                            System.err.println("Local rotation: " + selectedBone.getLocalRotation());
-                            System.err.println("Local scale: " + selectedBone.getLocalScale());
-                            System.err.println("---");
-                            System.err.println("Model translation: " + selectedBone.getModelSpacePosition());
-                            System.err.println("Model rotation: " + selectedBone.getModelSpaceRotation());
-                            System.err.println("Model scale: " + selectedBone.getModelSpaceScale());
-                            System.err.println("---");
-                            System.err.println("Bind inverse Transform: ");
-                            System.err.println(selectedBone.getBindInverseTransform());
-                            return;
-                        }
-                    }
-                }
-            }
-        }
-    };
-
-    public Map<Skeleton, Bone> getSelectedBones() {
-        return selectedBones;
-    }
-
-    public Node getDebugNode() {
-        return debugNode;
-    }
-
-    public void setDebugNode(Node debugNode) {
-        this.debugNode = debugNode;
-    }
-}

+ 10 - 12
jme3-core/src/main/java/com/jme3/scene/shape/AbstractBox.java

@@ -31,12 +31,10 @@
  */
  */
 package com.jme3.scene.shape;
 package com.jme3.scene.shape;
 
 
-import com.jme3.export.InputCapsule;
-import com.jme3.export.JmeExporter;
-import com.jme3.export.JmeImporter;
-import com.jme3.export.OutputCapsule;
+import com.jme3.export.*;
 import com.jme3.math.Vector3f;
 import com.jme3.math.Vector3f;
 import com.jme3.scene.Mesh;
 import com.jme3.scene.Mesh;
+
 import java.io.IOException;
 import java.io.IOException;
 
 
 /**
 /**
@@ -88,12 +86,12 @@ public abstract class AbstractBox extends Mesh {
     /**
     /**
      * Convert the indices into the list of vertices that define the box's geometry.
      * Convert the indices into the list of vertices that define the box's geometry.
      */
      */
-    protected abstract void duUpdateGeometryIndices();
+    protected abstract void doUpdateGeometryIndices();
     
     
     /**
     /**
      * Update the normals of each of the box's planes.
      * Update the normals of each of the box's planes.
      */
      */
-    protected abstract void duUpdateGeometryNormals();
+    protected abstract void doUpdateGeometryNormals();
 
 
     /**
     /**
      * Update the points that define the texture of the box.
      * Update the points that define the texture of the box.
@@ -101,14 +99,14 @@ public abstract class AbstractBox extends Mesh {
      * It's a one-to-one ratio, where each plane of the box has its own copy
      * It's a one-to-one ratio, where each plane of the box has its own copy
      * of the texture. That is, the texture is repeated one time for each face.
      * of the texture. That is, the texture is repeated one time for each face.
      */
      */
-    protected abstract void duUpdateGeometryTextures();
+    protected abstract void doUpdateGeometryTextures();
 
 
     /**
     /**
      * Update the position of the vertices that define the box.
      * Update the position of the vertices that define the box.
      * <p>
      * <p>
      * These eight points are determined from the minimum and maximum point.
      * These eight points are determined from the minimum and maximum point.
      */
      */
-    protected abstract void duUpdateGeometryVertices();
+    protected abstract void doUpdateGeometryVertices();
 
 
     /** 
     /** 
      * Get the center point of this box. 
      * Get the center point of this box. 
@@ -145,10 +143,10 @@ public abstract class AbstractBox extends Mesh {
      * need to call this method afterwards in order to update the box.
      * need to call this method afterwards in order to update the box.
      */
      */
     public final void updateGeometry() {
     public final void updateGeometry() {
-        duUpdateGeometryVertices();
-        duUpdateGeometryNormals();
-        duUpdateGeometryTextures();
-        duUpdateGeometryIndices();
+        doUpdateGeometryVertices();
+        doUpdateGeometryNormals();
+        doUpdateGeometryTextures();
+        doUpdateGeometryIndices();
         setStatic();
         setStatic();
     }
     }
 
 

+ 5 - 4
jme3-core/src/main/java/com/jme3/scene/shape/Box.java

@@ -35,6 +35,7 @@ package com.jme3.scene.shape;
 import com.jme3.math.Vector3f;
 import com.jme3.math.Vector3f;
 import com.jme3.scene.VertexBuffer.Type;
 import com.jme3.scene.VertexBuffer.Type;
 import com.jme3.util.BufferUtils;
 import com.jme3.util.BufferUtils;
+
 import java.nio.FloatBuffer;
 import java.nio.FloatBuffer;
 
 
 /**
 /**
@@ -144,25 +145,25 @@ public class Box extends AbstractBox {
         return new Box(center.clone(), xExtent, yExtent, zExtent);
         return new Box(center.clone(), xExtent, yExtent, zExtent);
     }
     }
 
 
-    protected void duUpdateGeometryIndices() {
+    protected void doUpdateGeometryIndices() {
         if (getBuffer(Type.Index) == null){
         if (getBuffer(Type.Index) == null){
             setBuffer(Type.Index, 3, BufferUtils.createShortBuffer(GEOMETRY_INDICES_DATA));
             setBuffer(Type.Index, 3, BufferUtils.createShortBuffer(GEOMETRY_INDICES_DATA));
         }
         }
     }
     }
 
 
-    protected void duUpdateGeometryNormals() {
+    protected void doUpdateGeometryNormals() {
         if (getBuffer(Type.Normal) == null){
         if (getBuffer(Type.Normal) == null){
             setBuffer(Type.Normal, 3, BufferUtils.createFloatBuffer(GEOMETRY_NORMALS_DATA));
             setBuffer(Type.Normal, 3, BufferUtils.createFloatBuffer(GEOMETRY_NORMALS_DATA));
         }
         }
     }
     }
 
 
-    protected void duUpdateGeometryTextures() {
+    protected void doUpdateGeometryTextures() {
         if (getBuffer(Type.TexCoord) == null){
         if (getBuffer(Type.TexCoord) == null){
             setBuffer(Type.TexCoord, 2, BufferUtils.createFloatBuffer(GEOMETRY_TEXTURE_DATA));
             setBuffer(Type.TexCoord, 2, BufferUtils.createFloatBuffer(GEOMETRY_TEXTURE_DATA));
         }
         }
     }
     }
 
 
-    protected void duUpdateGeometryVertices() {
+    protected void doUpdateGeometryVertices() {
         FloatBuffer fpb = BufferUtils.createVector3Buffer(24);
         FloatBuffer fpb = BufferUtils.createVector3Buffer(24);
         Vector3f[] v = computeVertices();
         Vector3f[] v = computeVertices();
         fpb.put(new float[] {
         fpb.put(new float[] {

+ 5 - 4
jme3-core/src/main/java/com/jme3/scene/shape/StripBox.java

@@ -35,6 +35,7 @@ package com.jme3.scene.shape;
 import com.jme3.math.Vector3f;
 import com.jme3.math.Vector3f;
 import com.jme3.scene.VertexBuffer.Type;
 import com.jme3.scene.VertexBuffer.Type;
 import com.jme3.util.BufferUtils;
 import com.jme3.util.BufferUtils;
+
 import java.nio.FloatBuffer;
 import java.nio.FloatBuffer;
 
 
 /**
 /**
@@ -138,13 +139,13 @@ public class StripBox extends AbstractBox {
         return new StripBox(center.clone(), xExtent, yExtent, zExtent);
         return new StripBox(center.clone(), xExtent, yExtent, zExtent);
     }
     }
 
 
-    protected void duUpdateGeometryIndices() {
+    protected void doUpdateGeometryIndices() {
         if (getBuffer(Type.Index) == null){
         if (getBuffer(Type.Index) == null){
             setBuffer(Type.Index, 3, BufferUtils.createShortBuffer(GEOMETRY_INDICES_DATA));
             setBuffer(Type.Index, 3, BufferUtils.createShortBuffer(GEOMETRY_INDICES_DATA));
         }
         }
     }
     }
 
 
-    protected void duUpdateGeometryNormals() {
+    protected void doUpdateGeometryNormals() {
         if (getBuffer(Type.Normal) == null){
         if (getBuffer(Type.Normal) == null){
             float[] normals = new float[8 * 3];
             float[] normals = new float[8 * 3];
             
             
@@ -163,13 +164,13 @@ public class StripBox extends AbstractBox {
         }
         }
     }
     }
 
 
-    protected void duUpdateGeometryTextures() {
+    protected void doUpdateGeometryTextures() {
         if (getBuffer(Type.TexCoord) == null){
         if (getBuffer(Type.TexCoord) == null){
             setBuffer(Type.TexCoord, 2, BufferUtils.createFloatBuffer(GEOMETRY_TEXTURE_DATA));
             setBuffer(Type.TexCoord, 2, BufferUtils.createFloatBuffer(GEOMETRY_TEXTURE_DATA));
         }
         }
     }
     }
 
 
-    protected void duUpdateGeometryVertices() {
+    protected void doUpdateGeometryVertices() {
         FloatBuffer fpb = BufferUtils.createVector3Buffer(8 * 3);
         FloatBuffer fpb = BufferUtils.createVector3Buffer(8 * 3);
         Vector3f[] v = computeVertices();
         Vector3f[] v = computeVertices();
         fpb.put(new float[] {
         fpb.put(new float[] {

+ 49 - 0
jme3-core/src/main/resources/Common/MatDefs/Misc/fakeLighting.j3md

@@ -0,0 +1,49 @@
+MaterialDef FakeLighting {
+    MaterialParameters {
+        Vector4 Color
+    }
+
+    Technique {
+       WorldParameters {
+           WorldViewProjectionMatrix
+           NormalMatrix
+       }
+
+       VertexShaderNodes {
+           ShaderNode Mat3Vec3Mult {
+               Definition: Mat3Vec3Mult: Common/MatDefs/ShaderNodes/Basic/Mat3Vec3Mult.j3sn
+               InputMappings {
+                   matrix3 = WorldParam.NormalMatrix
+                   vector3 = Attr.inNormal
+               }
+               OutputMappings {
+               }
+           }
+           ShaderNode CommonVert {
+               Definition: CommonVert: Common/MatDefs/ShaderNodes/Common/CommonVert.j3sn
+               InputMappings {
+                   worldViewProjectionMatrix = WorldParam.WorldViewProjectionMatrix
+                   modelPosition = Attr.inPosition
+               }
+               OutputMappings {
+                   Global.position = projPosition
+               }
+           }
+       }
+
+
+        FragmentShaderNodes {
+            ShaderNode FakeLighting {
+                Definition: FakeLighting: Common/MatDefs/ShaderNodes/Misc/fakeLighting.j3sn
+                InputMappings {
+                    inColor = MatParam.Color
+                    normal = Mat3Vec3Mult.outVector3.xyz
+                }
+                OutputMappings {
+                    Global.color = outColor
+                }
+            }
+        }
+
+    }
+}

+ 31 - 0
jme3-core/src/main/resources/Common/MatDefs/ShaderNodes/Basic/Mat3Vec3Mult.j3sn

@@ -0,0 +1,31 @@
+ShaderNodeDefinitions{
+    ShaderNodeDefinition Mat3Vec3Mult {
+        //Vertex/Fragment
+        Type: Vertex
+
+        //Shader GLSL<version>: <Path to shader>
+        Shader GLSL100: Common/MatDefs/ShaderNodes/Basic/Mat3Vec3Mult100.frag
+
+        Documentation{
+            //type documentation here. This is optional but recommended
+
+            //@input <glsltype> <varName> <description>
+            @input mat3 matrix3 the mat3
+            @input vec3 vector3 the vec3
+
+            //@output <glslType> <varName> <description>
+            @output vec3 outVector3 the output vector
+        }
+        Input {
+            //all the node inputs
+            //<glslType> <varName>
+            mat3 matrix3
+            vec3 vector3
+        }
+        Output {
+            //all the node outputs
+            //<glslType> <varName>
+            vec3 outVector3
+        }
+    }
+}

+ 3 - 0
jme3-core/src/main/resources/Common/MatDefs/ShaderNodes/Basic/Mat3Vec3Mult100.frag

@@ -0,0 +1,3 @@
+void main(){
+	outVector3 = matrix3 * vector3;
+}

+ 33 - 0
jme3-core/src/main/resources/Common/MatDefs/ShaderNodes/Misc/fakeLighting.j3sn

@@ -0,0 +1,33 @@
+ShaderNodeDefinitions{
+    ShaderNodeDefinition FakeLighting {
+        //Vertex/Fragment
+        Type: Fragment
+
+        //Shader GLSL<version>: <Path to shader>
+        Shader GLSL100: Common/MatDefs/ShaderNodes/Misc/fakeLighting100.frag
+
+        Documentation{
+            //type documentation here. This is optional but recommended
+
+            //@input <glsltype> <varName> <description>
+            @input vec4 inColor The input color
+            @input vec3 normal The normal in view space
+
+
+            //@output <glslType> <varName> <description>
+            @output vec4 outColor The modified output color
+        }
+        Input {
+            //all the node inputs
+            //<glslType> <varName>
+            vec4 inColor
+            vec3 normal
+            
+        }
+        Output {
+            //all the node outputs
+            //<glslType> <varName>
+            vec4 outColor
+        }
+    }
+}

+ 9 - 0
jme3-core/src/main/resources/Common/MatDefs/ShaderNodes/Misc/fakeLighting100.frag

@@ -0,0 +1,9 @@
+void main(){
+
+    vec4 dark = inColor * 0.3;
+    vec4 bright = min(inColor * 4.0, 1.0);
+    normal = normalize(normal);
+    vec3 dir = vec3(0,0,1);
+    float factor = dot(dir, normal);
+    outColor = mix(dark, bright, factor);
+}

+ 112 - 0
jme3-examples/src/main/java/jme3test/model/anim/TestArmature.java

@@ -0,0 +1,112 @@
+package jme3test.model.anim;
+
+import com.jme3.animation.*;
+import com.jme3.app.ChaseCameraAppState;
+import com.jme3.app.SimpleApplication;
+import com.jme3.light.DirectionalLight;
+import com.jme3.material.Material;
+import com.jme3.math.*;
+import com.jme3.scene.*;
+import com.jme3.scene.debug.custom.ArmatureDebugAppState;
+import com.jme3.util.TangentBinormalGenerator;
+
+/**
+ * Created by Nehon on 18/12/2017.
+ */
+public class TestArmature extends SimpleApplication {
+
+    Joint j1;
+    Joint j2;
+
+    public static void main(String... argv) {
+        TestArmature app = new TestArmature();
+        app.start();
+    }
+
+    @Override
+    public void simpleInitApp() {
+        renderManager.setSinglePassLightBatchSize(2);
+        //cam.setFrustumPerspective(90f, (float) cam.getWidth() / cam.getHeight(), 0.01f, 10f);
+        viewPort.setBackgroundColor(ColorRGBA.DarkGray);
+
+        Joint root = new Joint("Root_Joint");
+        j1 = new Joint("Joint_1");
+        j2 = new Joint("Joint_2");
+        root.addChild(j1);
+        j1.addChild(j2);
+        j1.setLocalTranslation(new Vector3f(0, 0.5f, 0));
+        j1.setLocalRotation(new Quaternion().fromAngleAxis(FastMath.HALF_PI * 0.3f, Vector3f.UNIT_Z));
+        j2.setLocalTranslation(new Vector3f(0, 0.2f, 0));
+        Joint[] joints = new Joint[]{root, j1, j2};
+
+        Armature armature = new Armature(joints);
+        armature.setBindPose();
+
+        ArmatureControl ac = new ArmatureControl(armature);
+        Node node = new Node("Test Armature");
+        rootNode.attachChild(node);
+
+        node.addControl(ac);
+
+        ArmatureDebugAppState debugAppState = new ArmatureDebugAppState();
+        debugAppState.addArmature(ac, true);
+        stateManager.attach(debugAppState);
+
+        rootNode.addLight(new DirectionalLight(new Vector3f(-1f, -1f, -1f).normalizeLocal()));
+
+        rootNode.addLight(new DirectionalLight(new Vector3f(1f, 1f, 1f).normalizeLocal(), new ColorRGBA(0.7f, 0.7f, 0.7f, 1.0f)));
+
+
+        flyCam.setEnabled(false);
+
+        ChaseCameraAppState chaseCam = new ChaseCameraAppState();
+        chaseCam.setTarget(node);
+        getStateManager().attach(chaseCam);
+        chaseCam.setInvertHorizontalAxis(true);
+        chaseCam.setInvertVerticalAxis(true);
+        chaseCam.setZoomSpeed(0.5f);
+        chaseCam.setMinVerticalRotation(-FastMath.HALF_PI);
+        chaseCam.setRotationSpeed(3);
+        chaseCam.setDefaultDistance(3);
+        chaseCam.setMinDistance(0.01f);
+        chaseCam.setZoomSpeed(0.01f);
+        chaseCam.setDefaultVerticalRotation(0.3f);
+    }
+
+
+    private void displayNormals(Spatial s) {
+        final Node debugTangents = new Node("debug tangents");
+        debugTangents.setCullHint(Spatial.CullHint.Never);
+
+        rootNode.attachChild(debugTangents);
+
+        final Material debugMat = assetManager.loadMaterial("Common/Materials/VertexColor.j3m");
+        debugMat.getAdditionalRenderState().setLineWidth(2);
+
+        s.depthFirstTraversal(new SceneGraphVisitorAdapter() {
+            @Override
+            public void visit(Geometry g) {
+                Mesh m = g.getMesh();
+                Geometry debug = new Geometry(
+                        "debug tangents geom",
+                        TangentBinormalGenerator.genNormalLines(m, 0.1f)
+                );
+                debug.setMaterial(debugMat);
+                debug.setCullHint(Spatial.CullHint.Never);
+                debug.setLocalTransform(g.getWorldTransform());
+                debugTangents.attachChild(debug);
+            }
+        });
+    }
+
+    float time = 0;
+
+    @Override
+    public void simpleUpdate(float tpf) {
+        time += tpf;
+        float rot = FastMath.sin(time);
+        j1.setLocalRotation(new Quaternion().fromAngleAxis(FastMath.HALF_PI * rot, Vector3f.UNIT_Z));
+        j2.setLocalRotation(new Quaternion().fromAngleAxis(FastMath.HALF_PI * rot, Vector3f.UNIT_Z));
+
+    }
+}