2
0
Эх сурвалжийг харах

scenecomposer : added new gizmos for lights and audio node

Dokthar 9 жил өмнө
parent
commit
be46130197
18 өөрчлөгдсөн 1359 нэмэгдсэн , 0 устгасан
  1. 32 0
      jme3-scenecomposer/src/com/jme3/gde/scenecomposer/gizmo/GizmoFactory.java
  2. 166 0
      jme3-scenecomposer/src/com/jme3/gde/scenecomposer/gizmo/NodeCallback.java
  3. 104 0
      jme3-scenecomposer/src/com/jme3/gde/scenecomposer/gizmo/audio/AudioGizmoFactory.java
  4. 54 0
      jme3-scenecomposer/src/com/jme3/gde/scenecomposer/gizmo/light/DirectionalLightGizmo.java
  5. 47 0
      jme3-scenecomposer/src/com/jme3/gde/scenecomposer/gizmo/light/LightColorUpdate.java
  6. 73 0
      jme3-scenecomposer/src/com/jme3/gde/scenecomposer/gizmo/light/LightConeRadiusUpdate.java
  7. 68 0
      jme3-scenecomposer/src/com/jme3/gde/scenecomposer/gizmo/light/LightDirectionUpdate.java
  8. 174 0
      jme3-scenecomposer/src/com/jme3/gde/scenecomposer/gizmo/light/LightGizmoFactory.java
  9. 63 0
      jme3-scenecomposer/src/com/jme3/gde/scenecomposer/gizmo/light/LightPositionUpdate.java
  10. 43 0
      jme3-scenecomposer/src/com/jme3/gde/scenecomposer/gizmo/light/LightRadiusUpdate.java
  11. 45 0
      jme3-scenecomposer/src/com/jme3/gde/scenecomposer/gizmo/light/LightRangeUpdate.java
  12. 99 0
      jme3-scenecomposer/src/com/jme3/gde/scenecomposer/gizmo/light/PointLightGizmo.java
  13. 83 0
      jme3-scenecomposer/src/com/jme3/gde/scenecomposer/gizmo/light/SpotLightGizmo.java
  14. 23 0
      jme3-scenecomposer/src/com/jme3/gde/scenecomposer/gizmo/mat/dashed/Dashed.j3sn
  15. 10 0
      jme3-scenecomposer/src/com/jme3/gde/scenecomposer/gizmo/mat/dashed/Dashed100.frag
  16. 38 0
      jme3-scenecomposer/src/com/jme3/gde/scenecomposer/gizmo/mat/dashed/dashed.j3md
  17. 172 0
      jme3-scenecomposer/src/com/jme3/gde/scenecomposer/gizmo/shape/RadiusShape.java
  18. 65 0
      jme3-scenecomposer/src/com/jme3/gde/scenecomposer/gizmo/shape/Triangle.java

+ 32 - 0
jme3-scenecomposer/src/com/jme3/gde/scenecomposer/gizmo/GizmoFactory.java

@@ -0,0 +1,32 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.jme3.gde.scenecomposer.gizmo;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.gde.core.sceneexplorer.nodes.AbstractSceneExplorerNode;
+import com.jme3.gde.core.sceneexplorer.nodes.JmeAudioNode;
+import com.jme3.gde.core.sceneexplorer.nodes.JmeLight;
+import com.jme3.gde.scenecomposer.gizmo.audio.AudioGizmoFactory;
+import com.jme3.gde.scenecomposer.gizmo.light.LightGizmoFactory;
+import com.jme3.scene.Spatial;
+
+/**
+ *
+ * @author dokthar
+ */
+public class GizmoFactory {
+
+    public static Spatial createGizmo(AssetManager assetManager, AbstractSceneExplorerNode node) {
+        if (node instanceof JmeLight) {
+            return LightGizmoFactory.createGizmo(assetManager, (JmeLight) node);
+        } else if (node instanceof JmeAudioNode) {
+            return AudioGizmoFactory.createGizmo(assetManager, (JmeAudioNode) node);
+        }
+
+        return null;
+    }
+
+}

+ 166 - 0
jme3-scenecomposer/src/com/jme3/gde/scenecomposer/gizmo/NodeCallback.java

@@ -0,0 +1,166 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.jme3.gde.scenecomposer.gizmo;
+
+import com.jme3.math.Matrix3f;
+import com.jme3.math.Quaternion;
+import com.jme3.math.Transform;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Node;
+import com.jme3.scene.Spatial;
+
+/**
+ *
+ * @author dokthar
+ */
+public abstract class NodeCallback extends Node {
+
+    private final boolean applyTranslation;
+    private final boolean applyRotation;
+    private final boolean applyScale;
+
+    public NodeCallback(String name) {
+        this(name, true, true, true);
+    }
+
+    public NodeCallback(String name, boolean applyTranslation, boolean applyRotation, boolean applyScale) {
+        super(name);
+        this.applyTranslation = applyTranslation;
+        this.applyRotation = applyRotation;
+        this.applyScale = applyScale;
+    }
+
+    @Override
+    public void setLocalRotation(Matrix3f rotation) {
+        onRotation(getLocalRotation(), new Quaternion().fromRotationMatrix(rotation));
+        if (applyRotation) {
+            super.setLocalRotation(rotation);
+        }
+    }
+
+    @Override
+    public void setLocalRotation(Quaternion quaternion) {
+        onRotation(getLocalRotation(), quaternion);
+        if (applyRotation) {
+            super.setLocalRotation(quaternion);
+        }
+    }
+
+    @Override
+    public void setLocalScale(Vector3f localScale) {
+        onResize(getLocalScale(), localScale);
+        if (applyScale) {
+            super.setLocalScale(localScale);
+        }
+    }
+
+    @Override
+    public void setLocalScale(float localScale) {
+        onResize(getLocalScale(), new Vector3f(localScale, localScale, localScale));
+        if (applyScale) {
+            super.setLocalScale(localScale);
+        }
+    }
+
+    @Override
+    public void setLocalScale(float x, float y, float z) {
+        onResize(getLocalScale(), new Vector3f(x, y, z));
+        if (applyScale) {
+            super.setLocalScale(x, y, z);
+        }
+    }
+
+    @Override
+    public void setLocalTransform(Transform t) {
+        onTranslation(getLocalTranslation(), t.getTranslation());
+        onRotation(getLocalRotation(), t.getRotation());
+        onResize(getLocalScale(), t.getScale());
+
+        if (applyRotation || applyScale || applyTranslation) {
+            super.setLocalTransform(t);
+        }
+    }
+
+    @Override
+    public void setLocalTranslation(Vector3f localTranslation) {
+        onTranslation(getLocalTranslation(), localTranslation);
+        if (applyTranslation) {
+            super.setLocalTranslation(localTranslation);
+        }
+    }
+
+    @Override
+    public void setLocalTranslation(float x, float y, float z) {
+        onTranslation(getLocalTranslation(), new Vector3f(x, y, z));
+        if (applyTranslation) {
+            super.setLocalTranslation(x, y, z);
+        }
+    }
+
+    @Override
+    public Spatial move(Vector3f offset) {
+        onTranslation(getLocalTranslation(), getLocalTranslation().add(offset));
+        if (applyTranslation) {
+            super.move(offset);
+        }
+        return this;
+    }
+
+    @Override
+    public Spatial move(float x, float y, float z) {
+        onTranslation(getLocalTranslation(), getLocalTranslation().add(x, y, z));
+        if (applyTranslation) {
+            super.move(x, y, z);
+        }
+        return this;
+    }
+
+    @Override
+    public Spatial rotate(Quaternion rot) {
+        onRotation(getLocalRotation(), getLocalRotation().mult(rot));
+        if (applyRotation) {
+            super.rotate(rot);
+        }
+        return this;
+    }
+
+    @Override
+    public Spatial scale(float s) {
+        onResize(getLocalScale(), getLocalScale().mult(s));
+        if (applyScale) {
+            super.scale(s);
+        }
+        return this;
+    }
+
+    @Override
+    public Spatial scale(float x, float y, float z) {
+        onResize(getLocalScale(), getLocalScale().mult(new Vector3f(x, y, z)));
+        if (applyScale) {
+            super.scale(x, y, z);
+        }
+        return this;
+    }
+
+    public void silentLocalTranslation(Vector3f translation) {
+        super.setLocalTranslation(translation);
+    }
+
+    public void silentLocalRotation(Quaternion rotation) {
+        super.setLocalRotation(rotation);
+    }
+
+    public void silentLocalScale(Vector3f scale) {
+        super.setLocalScale(scale);
+    }
+
+    public abstract void onTranslation(Vector3f oldTranslation, Vector3f newTranslation);
+
+    public abstract void onResize(Vector3f oldScale, Vector3f newScale);
+
+    public abstract void onRotation(Quaternion oldRotation, Quaternion newRotation);
+
+}

+ 104 - 0
jme3-scenecomposer/src/com/jme3/gde/scenecomposer/gizmo/audio/AudioGizmoFactory.java

@@ -0,0 +1,104 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.jme3.gde.scenecomposer.gizmo.audio;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.audio.AudioNode;
+import com.jme3.gde.core.sceneexplorer.nodes.JmeAudioNode;
+import com.jme3.material.Material;
+import com.jme3.material.RenderState;
+import com.jme3.math.Vector3f;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.ViewPort;
+import com.jme3.renderer.queue.RenderQueue;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Node;
+import com.jme3.scene.Spatial;
+import com.jme3.scene.control.BillboardControl;
+import com.jme3.scene.control.Control;
+import com.jme3.scene.shape.Quad;
+import com.jme3.texture.Texture;
+
+/**
+ *
+ * @author dokthar
+ */
+public class AudioGizmoFactory {
+
+    private Material audioMarkerMaterial;
+
+    public static Spatial createGizmo(AssetManager assetManager, JmeAudioNode node) {
+        AudioNode audio = node.getLookup().lookup(AudioNode.class);
+        if (audio == null) {
+            return null;
+        }
+        
+        return createAudioGizmo(assetManager, node, audio);
+
+        // This marker is not part of the scene, but is part of the tools node. 
+        //return audio;
+    }
+
+    private static Spatial createAudioGizmo(AssetManager assetManager, JmeAudioNode node, AudioNode audio) {
+        Node gizmo = new Node("Audio node Gizmo");
+        Spatial marker = createAudioMarker(assetManager);
+        gizmo.attachChild(marker);
+        
+        gizmo.addControl(new AudioMarkerControl(audio));
+        return gizmo;
+    }
+    
+    /**
+     * Updates the marker's position whenever the audio node has moved. It is
+     * also a BillboardControl, so this marker always faces the camera
+     */
+    protected static class AudioMarkerControl extends BillboardControl {
+
+        private final AudioNode audio;
+        private final Vector3f lastPos = new Vector3f();
+        private final Vector3f audioPos;
+
+        AudioMarkerControl(AudioNode a) {
+            super();
+            audio = a;
+            audioPos = audio.getPosition();
+        }
+
+        @Override
+        protected void controlUpdate(float f) {
+            super.controlUpdate(f);
+            Spatial marker = getSpatial();
+            if (marker != null && !audioPos.equals(lastPos)) {
+                lastPos.set(audioPos);
+                marker.getParent().worldToLocal(lastPos, lastPos);
+                marker.setLocalTranslation(lastPos);
+            }
+        }
+
+        @Override
+        protected void controlRender(RenderManager rm, ViewPort vp) {
+            super.controlRender(rm, vp);
+        }
+    }
+
+    /**
+     * A marker on the screen that shows where an audio node is.
+     */
+    protected static Geometry createAudioMarker(AssetManager assetManager) {
+        Quad q = new Quad(0.5f, 0.5f);
+        Geometry audioMarker = new Geometry("light bulb", q);
+        audioMarker.move(-q.getHeight() / 2f, -q.getWidth() / 2f, 0);
+
+        Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+        Texture tex = assetManager.loadTexture("com/jme3/gde/scenecomposer/audionode.gif");
+        mat.setTexture("ColorMap", tex);
+        mat.getAdditionalRenderState().setBlendMode(RenderState.BlendMode.Alpha);
+        audioMarker.setMaterial(mat);
+        audioMarker.setQueueBucket(RenderQueue.Bucket.Transparent);
+
+        return audioMarker;
+    }
+}

+ 54 - 0
jme3-scenecomposer/src/com/jme3/gde/scenecomposer/gizmo/light/DirectionalLightGizmo.java

@@ -0,0 +1,54 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.jme3.gde.scenecomposer.gizmo.light;
+
+import com.jme3.bounding.BoundingSphere;
+import com.jme3.bounding.BoundingVolume;
+import com.jme3.gde.core.sceneexplorer.nodes.JmeDirectionalLight;
+import com.jme3.gde.scenecomposer.gizmo.NodeCallback;
+import com.jme3.light.DirectionalLight;
+import com.jme3.math.Quaternion;
+import com.jme3.math.Vector3f;
+
+/**
+ *
+ * @author dokthar
+ */
+public class DirectionalLightGizmo extends NodeCallback {
+
+    private Vector3f initalDirection;
+    private JmeDirectionalLight jmeLight;
+    private DirectionalLight light;
+
+    public DirectionalLightGizmo(JmeDirectionalLight jmelight) {
+        super("directional light gizmo", true, true, false);
+        jmeLight = jmelight;
+        light = jmeLight.getLookup().lookup(DirectionalLight.class);
+        initalDirection = light.getDirection().clone();
+    }
+
+    @Override
+    public void onTranslation(Vector3f oldTranslation, Vector3f newTranslation) {
+    }
+
+    @Override
+    public void onResize(Vector3f oldScale, Vector3f newScale) {
+    }
+
+    @Override
+    public void onRotation(Quaternion oldRotation, Quaternion newRotation) {
+        light.setDirection(newRotation.mult(initalDirection));
+        jmeLight.setValue("direction", light.getDirection());
+    }
+
+    private final BoundingSphere bv = new BoundingSphere(10f, getWorldTranslation());
+
+    @Override
+    public BoundingVolume getWorldBound() {
+        return bv;
+    }
+
+}

+ 47 - 0
jme3-scenecomposer/src/com/jme3/gde/scenecomposer/gizmo/light/LightColorUpdate.java

@@ -0,0 +1,47 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.jme3.gde.scenecomposer.gizmo.light;
+
+import com.jme3.light.Light;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.ViewPort;
+import com.jme3.scene.control.AbstractControl;
+
+/**
+ *
+ * @author dokthar
+ */
+public class LightColorUpdate extends AbstractControl {
+
+    private Light light;
+    private final ColorRGBA lastCol = new ColorRGBA();
+    private ColorRGBA lightCol;
+    private Material mat;
+    private String name;
+
+    public LightColorUpdate(Light l, Material mat, String name) {
+        light = l;
+        lightCol = light.getColor();
+        this.mat = mat;
+        this.name = name;
+        mat.setColor(name, lightCol);
+    }
+
+    @Override
+    protected void controlUpdate(float f) {
+        if (!lightCol.equals(lastCol)) {
+            lastCol.set(lightCol);
+            mat.setColor(name, lastCol);
+        }
+    }
+
+    @Override
+    protected void controlRender(RenderManager rm, ViewPort vp) {
+    }
+
+}

+ 73 - 0
jme3-scenecomposer/src/com/jme3/gde/scenecomposer/gizmo/light/LightConeRadiusUpdate.java

@@ -0,0 +1,73 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.jme3.gde.scenecomposer.gizmo.light;
+
+import com.jme3.light.SpotLight;
+import com.jme3.math.FastMath;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.ViewPort;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.control.AbstractControl;
+
+/**
+ *
+ * @author dokthar
+ */
+public class LightConeRadiusUpdate extends AbstractControl {
+
+    private SpotLight light;
+    private float lastInnerAngle = -1;
+    private float lastOuterAngle = -1;
+    private float lastRange = -1;
+    private Geometry inner, outer;
+
+    public LightConeRadiusUpdate(SpotLight l, Geometry inner, Geometry outer) {
+        this.light = l;
+        this.inner = inner;
+        this.outer = outer;
+
+        light.getSpotInnerAngle();
+        light.getSpotOuterAngle();
+    }
+
+    private static float oppositeSide(float angle, float adjacent) {
+        // tan(angle) = opposite / adjacent
+        return FastMath.tan(angle) * adjacent;
+    }
+
+    @Override
+    protected void controlUpdate(float f) {
+        float a = light.getSpotInnerAngle();
+        if (a != lastInnerAngle) {
+            lastInnerAngle = a;
+            float r = oppositeSide(lastInnerAngle, light.getSpotRange());
+            inner.setLocalScale(r, r, r);
+        }
+
+        a = light.getSpotOuterAngle();
+        if (a != lastOuterAngle) {
+            lastOuterAngle = a;
+            float r = oppositeSide(lastOuterAngle, light.getSpotRange());
+            outer.setLocalScale(r, r, r);
+            if (getSpatial() != null) {
+                spatial.setLocalScale(r, spatial.getLocalScale().y, 1);
+            }
+        }
+
+        a = light.getSpotRange();
+        if (a != lastRange) {
+            lastRange = a;
+        }
+        if (getSpatial() != null) {
+            spatial.setLocalScale(spatial.getLocalScale().x, light.getSpotRange(), 1);
+        }
+    }
+
+    @Override
+    protected void controlRender(RenderManager rm, ViewPort vp) {
+    }
+
+}

+ 68 - 0
jme3-scenecomposer/src/com/jme3/gde/scenecomposer/gizmo/light/LightDirectionUpdate.java

@@ -0,0 +1,68 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.jme3.gde.scenecomposer.gizmo.light;
+
+import com.jme3.gde.scenecomposer.gizmo.NodeCallback;
+import com.jme3.light.Light;
+import com.jme3.math.Quaternion;
+import com.jme3.math.Vector3f;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.ViewPort;
+import com.jme3.scene.control.AbstractControl;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import org.openide.util.Exceptions;
+
+/**
+ *
+ * @author dokthar
+ */
+public class LightDirectionUpdate extends AbstractControl {
+
+    private Light light;
+    private NodeCallback gizmo;
+
+    private final Vector3f lastDir = new Vector3f();
+    private Vector3f lightDir;
+
+    public LightDirectionUpdate(Light l, NodeCallback g) {
+        gizmo = g;
+        light = l;
+
+        try {
+            Method getDirection = light.getClass().getMethod("getDirection");
+            lightDir = (Vector3f) getDirection.invoke(light);
+        } catch (NoSuchMethodException ex) {
+            //light type doesn't have a get position method, silancing the exception
+        } catch (SecurityException ex) {
+            Exceptions.printStackTrace(ex);
+        } catch (IllegalAccessException ex) {
+            Exceptions.printStackTrace(ex);
+        } catch (IllegalArgumentException ex) {
+            Exceptions.printStackTrace(ex);
+        } catch (InvocationTargetException ex) {
+            Exceptions.printStackTrace(ex);
+        }
+    }
+
+    @Override
+    protected void controlUpdate(float f) {
+        if (!lightDir.equals(lastDir)) {
+            lastDir.set(lightDir);
+
+            Vector3f axis = Vector3f.UNIT_Y.cross(lastDir);
+            float angle = Vector3f.UNIT_Y.angleBetween(lastDir);
+            //Quaternion rotation = gizmo.getWorldRotation().inverse().mult(new Quaternion().fromAngleAxis(angle, axis));
+            Quaternion rotation = new Quaternion().fromAngleAxis(angle, axis);
+            gizmo.silentLocalRotation(rotation);
+        }
+    }
+
+    @Override
+    protected void controlRender(RenderManager rm, ViewPort vp) {
+    }
+
+}

+ 174 - 0
jme3-scenecomposer/src/com/jme3/gde/scenecomposer/gizmo/light/LightGizmoFactory.java

@@ -0,0 +1,174 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.jme3.gde.scenecomposer.gizmo.light;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.gde.core.sceneexplorer.nodes.JmeDirectionalLight;
+import com.jme3.gde.core.sceneexplorer.nodes.JmeLight;
+import com.jme3.gde.core.sceneexplorer.nodes.JmePointLight;
+import com.jme3.gde.core.sceneexplorer.nodes.JmeSpotLight;
+import com.jme3.gde.scenecomposer.gizmo.shape.RadiusShape;
+import com.jme3.gde.scenecomposer.gizmo.shape.Triangle;
+import com.jme3.light.DirectionalLight;
+import com.jme3.light.Light;
+import com.jme3.light.PointLight;
+import com.jme3.light.SpotLight;
+import com.jme3.material.Material;
+import com.jme3.material.RenderState;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.FastMath;
+import com.jme3.math.Quaternion;
+import com.jme3.math.Vector3f;
+import com.jme3.renderer.queue.RenderQueue;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Node;
+import com.jme3.scene.Spatial;
+import com.jme3.scene.control.BillboardControl;
+import com.jme3.scene.debug.Arrow;
+import com.jme3.scene.shape.Quad;
+import com.jme3.texture.Texture;
+
+/**
+ *
+ * @author dokthar
+ */
+public class LightGizmoFactory {
+    
+    private static Quaternion pitch90 = new Quaternion().fromAngleAxis(FastMath.HALF_PI, Vector3f.UNIT_X);
+    
+    public static Spatial createGizmo(AssetManager assetManager, JmeLight lightNode) {
+        Light light = lightNode.getLookup().lookup(Light.class);
+        if (light == null) {
+            return null;
+        }
+        switch (light.getType()) {
+            case Point:
+                return createPointGizmo(assetManager, (JmePointLight) lightNode, light);
+            case Spot:
+                return createSpotGizmo(assetManager, (JmeSpotLight) lightNode, light);
+            case Directional:
+                return createDirectionalGizmo(assetManager, (JmeDirectionalLight) lightNode, light);
+
+            //  default:
+            //      return createDefaultGizmo(assetManager, lightNode);
+        }
+        return null;
+    }
+    
+    private static Node createDefaultGizmo(AssetManager assetManager, JmeLight jmeLight, Light light) {
+        Node gizmo = new Node("debug Light Gizmo");
+        
+        Node gizmoBillboard = new Node("billboard lightGizmo");
+        gizmoBillboard.attachChild(createLightBulbe(assetManager));
+        gizmoBillboard.addControl(new BillboardControl());
+        gizmo.attachChild(gizmoBillboard);
+        
+        return gizmo;
+    }
+    
+    private static Node createPointGizmo(AssetManager assetManager, JmePointLight jmeLight, Light light) {
+        PointLightGizmo gizmo = new PointLightGizmo(jmeLight);
+        gizmo.addControl(new LightPositionUpdate(light, gizmo));
+        
+        Node billboardNode = new Node("billboard lightGizmo");
+        billboardNode.addControl(new BillboardControl());
+        gizmo.attachChild(billboardNode);
+        billboardNode.attachChild(createLightBulbe(assetManager));
+        
+        Geometry radius = RadiusShape.createShape(assetManager, "radius shape");
+        radius.addControl(new LightRadiusUpdate((PointLight) light));
+        radius.addControl(new LightColorUpdate(light, radius.getMaterial(), "Color"));
+        billboardNode.attachChild(radius);
+        
+        return gizmo;
+    }
+    
+    private static Node createDirectionalGizmo(AssetManager assetManager, JmeDirectionalLight jmeLight, Light light) {
+        DirectionalLightGizmo gizmo = new DirectionalLightGizmo(jmeLight);
+        gizmo.move(0, 5, 0);
+        
+        Node billboardNode = new Node("billboard lightGizmo");
+        billboardNode.addControl(new BillboardControl());
+        gizmo.attachChild(billboardNode);
+        billboardNode.attachChild(createLightBulbe(assetManager));
+        
+        Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+        mat.setColor("Color", ColorRGBA.White);
+        mat.getAdditionalRenderState().setLineWidth(2f);
+        
+        Geometry arrow = new Geometry("direction arrow", new Arrow(((DirectionalLight) light).getDirection().mult(5f)));
+        arrow.setMaterial(mat);
+        arrow.addControl(new LightColorUpdate(light, arrow.getMaterial(), "Color"));
+        
+        gizmo.attachChild(arrow);
+        
+        return gizmo;
+    }
+    
+    private static Node createSpotGizmo(AssetManager assetManager, JmeSpotLight jmeLight, Light light) {
+        SpotLightGizmo gizmo = new SpotLightGizmo(jmeLight);
+        gizmo.addControl(new LightDirectionUpdate(light, gizmo));
+        gizmo.addControl(new LightPositionUpdate(light, gizmo));
+        
+        Node billboardNode = new Node("billboard lightGizmo");
+        gizmo.attachChild(billboardNode);
+        billboardNode.addControl(new BillboardControl());
+        billboardNode.attachChild(createLightBulbe(assetManager));
+        
+        Node radiusNode = new Node("radius Node");
+        gizmo.attachChild(radiusNode);
+        
+        Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+        mat.setColor("Color", ColorRGBA.White);
+        mat.getAdditionalRenderState().setLineWidth(1f);
+        
+        Geometry arrow = new Geometry("direction arrow", new Arrow(Vector3f.UNIT_Y.mult(1f)));
+        arrow.setMaterial(mat);
+        arrow.addControl(new LightColorUpdate(light, arrow.getMaterial(), "Color"));
+        gizmo.attachChild(arrow);
+        
+        Geometry inRadius = RadiusShape.createShape(assetManager, "inner radius shape");
+        inRadius.rotate(pitch90);
+        inRadius.addControl(new LightColorUpdate(light, inRadius.getMaterial(), "Color"));
+        inRadius.getMaterial().setFloat("DashSize", 0.875f);
+        radiusNode.attachChild(inRadius);
+        
+        Geometry outRadius = RadiusShape.createShape(assetManager, "outer radius shape");
+        outRadius.addControl(new LightColorUpdate(light, outRadius.getMaterial(), "Color"));
+        outRadius.getMaterial().setFloat("DashSize", 0.125f);
+        radiusNode.attachChild(outRadius);
+        outRadius.rotate(pitch90);
+        
+        Geometry cone = new Geometry("cone shape", new Triangle(1f, -1f));
+        cone.setMaterial(mat);
+        BillboardControl bc = new BillboardControl();
+        bc.setAlignment(BillboardControl.Alignment.AxialY);
+        cone.addControl(bc);
+        cone.addControl(new LightColorUpdate(light, outRadius.getMaterial(), "Color"));
+        cone.addControl(new LightConeRadiusUpdate((SpotLight) light, inRadius, outRadius));
+        radiusNode.attachChild(cone);
+        
+        radiusNode.addControl(new LightRangeUpdate((SpotLight) light, arrow));
+        
+        return gizmo;
+    }
+    
+    protected static Geometry createLightBulbe(AssetManager assetManager) {
+        Quad q = new Quad(0.5f, 0.5f);
+        Geometry lightBulb = new Geometry("light bulb", q);
+        lightBulb.move(-q.getHeight() / 2f, -q.getWidth() / 2f, 0);
+        
+        Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+        Texture tex = assetManager.loadTexture("com/jme3/gde/scenecomposer/lightbulb32.png");
+        mat.setTexture("ColorMap", tex);
+        mat.getAdditionalRenderState().setBlendMode(RenderState.BlendMode.Alpha);
+        lightBulb.setMaterial(mat);
+        lightBulb.setQueueBucket(RenderQueue.Bucket.Transparent);
+        
+        return lightBulb;
+    }
+    
+}

+ 63 - 0
jme3-scenecomposer/src/com/jme3/gde/scenecomposer/gizmo/light/LightPositionUpdate.java

@@ -0,0 +1,63 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.jme3.gde.scenecomposer.gizmo.light;
+
+import com.jme3.gde.scenecomposer.gizmo.NodeCallback;
+import com.jme3.light.Light;
+import com.jme3.math.Vector3f;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.ViewPort;
+import com.jme3.scene.control.AbstractControl;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import org.openide.util.Exceptions;
+
+/**
+ *
+ * @author dokthar
+ */
+public class LightPositionUpdate extends AbstractControl {
+
+    private Light light;
+    private NodeCallback gizmo;
+    
+    private final Vector3f lastPos = new Vector3f();
+    private Vector3f lightPos;
+
+    public LightPositionUpdate(Light l, NodeCallback g) {
+        gizmo = g;
+        light = l;
+
+        try {
+            Method getPosition = light.getClass().getMethod("getPosition");
+            lightPos = (Vector3f) getPosition.invoke(light);
+        } catch (NoSuchMethodException ex) {
+            //light type doesn't have a get position method, silancing the exception
+        } catch (SecurityException ex) {
+            Exceptions.printStackTrace(ex);
+        } catch (IllegalAccessException ex) {
+            Exceptions.printStackTrace(ex);
+        } catch (IllegalArgumentException ex) {
+            Exceptions.printStackTrace(ex);
+        } catch (InvocationTargetException ex) {
+            Exceptions.printStackTrace(ex);
+        }
+    }
+
+    @Override
+    protected void controlUpdate(float f) {
+        if (!lightPos.equals(lastPos)) {
+            lastPos.set(lightPos);
+            gizmo.getParent().worldToLocal(lastPos, lastPos);
+            gizmo.silentLocalTranslation(lastPos);
+        }
+    }
+
+    @Override
+    protected void controlRender(RenderManager rm, ViewPort vp) {
+    }
+
+}

+ 43 - 0
jme3-scenecomposer/src/com/jme3/gde/scenecomposer/gizmo/light/LightRadiusUpdate.java

@@ -0,0 +1,43 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.jme3.gde.scenecomposer.gizmo.light;
+
+import com.jme3.light.PointLight;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.ViewPort;
+import com.jme3.scene.control.AbstractControl;
+
+/**
+ *
+ * @author dokthar
+ */
+public class LightRadiusUpdate extends AbstractControl{
+    
+    private PointLight light;
+    private float lastRad = -1f;
+    
+
+    public LightRadiusUpdate(PointLight l) {
+        light = l; 
+    }
+
+    @Override
+    protected void controlUpdate(float f) {
+        float r = light.getRadius();
+        
+        if (lastRad != r) {
+            lastRad = r;
+            if(getSpatial() != null){
+                getSpatial().setLocalScale(lastRad);
+            }
+        }
+    }
+    
+    @Override
+    protected void controlRender(RenderManager rm, ViewPort vp) {
+    }
+    
+}

+ 45 - 0
jme3-scenecomposer/src/com/jme3/gde/scenecomposer/gizmo/light/LightRangeUpdate.java

@@ -0,0 +1,45 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.jme3.gde.scenecomposer.gizmo.light;
+
+import com.jme3.light.SpotLight;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.ViewPort;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.control.AbstractControl;
+
+/**
+ *
+ * @author dokthar
+ */
+class LightRangeUpdate extends AbstractControl{
+
+    private SpotLight light;
+    private float lastRange = -1;
+    private Geometry arrow;
+    
+    public LightRangeUpdate(SpotLight l, Geometry arrow) {
+        light = l;
+        this.arrow = arrow;
+    }
+
+    @Override
+    protected void controlUpdate(float f) {
+        float r = light.getSpotRange();
+        if(lastRange != r){
+            lastRange = r;
+            if(getSpatial() != null){
+                getSpatial().setLocalTranslation(0, lastRange, 0);
+            }
+            arrow.setLocalScale(lastRange);
+        }
+    }
+
+    @Override
+    protected void controlRender(RenderManager rm, ViewPort vp) {
+    }
+    
+}

+ 99 - 0
jme3-scenecomposer/src/com/jme3/gde/scenecomposer/gizmo/light/PointLightGizmo.java

@@ -0,0 +1,99 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.jme3.gde.scenecomposer.gizmo.light;
+
+import com.jme3.bounding.BoundingBox;
+import com.jme3.bounding.BoundingSphere;
+import com.jme3.bounding.BoundingVolume;
+import com.jme3.gde.core.sceneexplorer.nodes.JmePointLight;
+import com.jme3.gde.scenecomposer.gizmo.NodeCallback;
+import com.jme3.light.PointLight;
+import com.jme3.math.FastMath;
+import com.jme3.math.Quaternion;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Spatial;
+
+/**
+ * Updates the marker's position whenever the light has moved.
+ */
+public class PointLightGizmo extends NodeCallback {
+
+    private PointLight light;
+    private JmePointLight jmeLight;
+
+    public PointLightGizmo(JmePointLight jmelight) {
+        super("point light callback", true, false, false);
+        jmeLight = jmelight;
+        light = jmeLight.getLookup().lookup(PointLight.class);
+
+    }
+
+    @Override
+    public void onTranslation(Vector3f oldTranslation, Vector3f newTranslation) {
+        light.setPosition(getWorldTranslation());
+        jmeLight.setValue("position", light.getPosition());
+    }
+
+    private final float eps = 0.0000125f;
+
+    @Override
+    public void onResize(Vector3f oldScale, Vector3f newScale) {
+        float m;
+
+        float x = FastMath.abs(newScale.x);
+        float y = FastMath.abs(newScale.y);
+        float z = FastMath.abs(newScale.z);
+        float max = Math.max(Math.max(x, y), z);
+        float min = Math.min(Math.min(x, y), z);
+
+        if (max - min <= eps) {
+            // x == y == z
+            m = x;
+        } else {
+            int nbMax = 0;
+            if (max - x <= eps) {
+                nbMax++;
+            }
+            if (max - y <= eps) {
+                nbMax++;
+            }
+            if (max - z <= eps) {
+                nbMax++;
+            }
+            if (nbMax >= 2) {
+                m = min;
+            } else {
+                m = max;
+            }
+        }
+
+        light.setRadius(m);
+        jmeLight.setValue("radius", light.getRadius());
+    }
+
+    @Override
+    public void onRotation(Quaternion oldRotation, Quaternion newRotation) {
+    }
+
+    @Override
+    public Vector3f getLocalScale() {
+        float r = light.getRadius();
+        return new Vector3f(r, r, r);
+    }
+
+    @Override
+    public Vector3f getWorldScale() {
+        float r = light.getRadius();
+        return new Vector3f(r, r, r);
+    }
+
+    @Override
+    public BoundingVolume getWorldBound() {
+        //return new BoundingBox(light.getPosition(), light.getRadius(), light.getRadius(), light.getRadius());
+        return new BoundingSphere(light.getRadius(), light.getPosition());
+    }
+
+}

+ 83 - 0
jme3-scenecomposer/src/com/jme3/gde/scenecomposer/gizmo/light/SpotLightGizmo.java

@@ -0,0 +1,83 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.jme3.gde.scenecomposer.gizmo.light;
+
+import com.jme3.bounding.BoundingSphere;
+import com.jme3.bounding.BoundingVolume;
+import com.jme3.gde.core.sceneexplorer.nodes.JmeSpotLight;
+import com.jme3.gde.scenecomposer.gizmo.NodeCallback;
+import com.jme3.light.SpotLight;
+import com.jme3.math.FastMath;
+import com.jme3.math.Quaternion;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Spatial;
+
+/**
+ *
+ * @author dokthar
+ */
+public class SpotLightGizmo extends NodeCallback {
+
+    private SpotLight light;
+    private JmeSpotLight jmeLight;
+
+    public SpotLightGizmo(JmeSpotLight jmelight) {
+        super("spot light callback", true, true, false);
+        jmeLight = jmelight;
+        light = jmeLight.getLookup().lookup(SpotLight.class);
+    }
+
+    @Override
+    public void onTranslation(Vector3f oldTranslation, Vector3f newTranslation) {
+        light.setPosition(getWorldTranslation());
+        jmeLight.setValue("position", light.getPosition());
+    }
+
+    private final float eps = 0.0000125f;
+
+    @Override
+    public void onResize(Vector3f oldScale, Vector3f newScale) {
+        float x = FastMath.abs(newScale.x);
+        float y = FastMath.abs(newScale.y);
+        float z = FastMath.abs(newScale.z);
+
+        light.setSpotRange(y);
+        light.setSpotInnerAngle(x);
+        light.setSpotOuterAngle(z);
+
+        jmeLight.setValue("spotInnerAngle", light.getSpotInnerAngle());
+        jmeLight.setValue("spotOuterAngle", light.getSpotOuterAngle());
+        jmeLight.setValue("spotRange", light.getSpotRange());
+    }
+
+    @Override
+    public void onRotation(Quaternion oldRotation, Quaternion newRotation) {
+        light.setDirection(newRotation.mult(Vector3f.UNIT_Y));
+        jmeLight.setValue("direction", light.getDirection());
+    }
+
+    @Override
+    public Vector3f getLocalScale() {
+        float i = light.getSpotInnerAngle();
+        float r = light.getSpotRange();
+        float o = light.getSpotOuterAngle();
+        return new Vector3f(i, r, o);
+    }
+
+    @Override
+    public Vector3f getWorldScale() {
+        float i = light.getSpotInnerAngle();
+        float r = light.getSpotRange();
+        float o = light.getSpotOuterAngle();
+        return new Vector3f(i, r, o);
+    }
+
+    @Override
+    public BoundingVolume getWorldBound() {
+        return new BoundingSphere(light.getSpotRange(), light.getPosition());
+    }
+
+}

+ 23 - 0
jme3-scenecomposer/src/com/jme3/gde/scenecomposer/gizmo/mat/dashed/Dashed.j3sn

@@ -0,0 +1,23 @@
+ShaderNodeDefinitions{ 
+    ShaderNodeDefinition Dashed {      
+        Type: Fragment
+
+        Shader GLSL100: com/jme3/gde/scenecomposer/gizmo/mat/dashed/Dashed100.frag
+        
+        Documentation{
+            Renders dashed lines            
+            @input vec2 texCoord The texture coordinates
+            @input float size the size of the dashes
+            @input vec4 inColor the color of the fragment so far
+            @outColor vec4 color the output color
+        }
+        Input {
+            vec2 texCoord
+            vec4 inColor
+            float size
+        }
+        Output {
+            vec4 outColor
+        }
+    }
+}

+ 10 - 0
jme3-scenecomposer/src/com/jme3/gde/scenecomposer/gizmo/mat/dashed/Dashed100.frag

@@ -0,0 +1,10 @@
+void main(){
+        //@input vec2 texCoord The texture coordinates
+    //@input float size the size of the dashes
+    //@output vec4 color the output color
+
+    //insert glsl code here
+    outColor = inColor;
+    outColor.a = step(1.0 - size, texCoord.x);
+    
+}

+ 38 - 0
jme3-scenecomposer/src/com/jme3/gde/scenecomposer/gizmo/mat/dashed/dashed.j3md

@@ -0,0 +1,38 @@
+MaterialDef Simple {
+    MaterialParameters {
+        Float DashSize
+        Vector4 Color
+    }
+    Technique {
+        WorldParameters {
+            WorldViewProjectionMatrix
+        }
+        VertexShaderNodes {
+            ShaderNode CommonVert {
+                Definition : CommonVert : Common/MatDefs/ShaderNodes/Common/CommonVert.j3sn
+                InputMappings {
+                    worldViewProjectionMatrix = WorldParam.WorldViewProjectionMatrix
+                    modelPosition = Global.position.xyz
+                    texCoord1 = Attr.inTexCoord
+                    vertColor = Attr.inColor
+                }
+                OutputMappings {
+                    Global.position = projPosition
+                }
+            }
+        }
+        FragmentShaderNodes {
+            ShaderNode Dashed {
+                Definition : Dashed : com/jme3/gde/scenecomposer/gizmo/mat/dashed/Dashed.j3sn
+                InputMappings {
+                    texCoord = CommonVert.texCoord1
+                    inColor = MatParam.Color
+                    size = MatParam.DashSize
+                }
+                OutputMappings {
+                    Global.color = outColor
+                }
+            }
+        }
+    }
+}

+ 172 - 0
jme3-scenecomposer/src/com/jme3/gde/scenecomposer/gizmo/shape/RadiusShape.java

@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2009-2015 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ *   may be used to endorse or promote products derived from this software
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.jme3.gde.scenecomposer.gizmo.shape;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.material.Material;
+import com.jme3.material.RenderState;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.FastMath;
+import com.jme3.renderer.queue.RenderQueue;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Mesh;
+import com.jme3.scene.VertexBuffer.Type;
+import com.jme3.util.BufferUtils;
+import java.nio.FloatBuffer;
+import java.nio.ShortBuffer;
+
+/**
+ *
+ * A debuging shape for a BoundingSphere Consists of 3 axis aligned circles.
+ *
+ * @author nehon
+ */
+public class RadiusShape extends Mesh {
+
+    protected int vertCount;
+    protected int triCount;
+    protected int radialSamples = 256;
+    protected boolean useEvenSlices;
+    protected boolean interior;
+    /**
+     * the distance from the center point each point falls on
+     */
+    public float radius;
+
+    public float getRadius() {
+        return radius;
+    }
+
+    public RadiusShape(int radialSamples) {
+        this.radialSamples = radialSamples;
+        setGeometryData();
+        setIndexData();
+    }
+
+    /**
+     * builds the vertices based on the radius
+     */
+    private void setGeometryData() {
+        setMode(Mode.Lines);
+
+        FloatBuffer posBuf = BufferUtils.createVector3Buffer((radialSamples + 1));
+        FloatBuffer colBuf = BufferUtils.createFloatBuffer((radialSamples + 1) * 4);
+        FloatBuffer texBuf = BufferUtils.createVector2Buffer(radialSamples + 1);
+
+        setBuffer(Type.Position, 3, posBuf);
+        setBuffer(Type.Color, 4, colBuf);
+        setBuffer(Type.TexCoord, 2, texBuf);
+
+        // generate geometry
+        float fInvRS = 1.0f / radialSamples;
+
+        // Generate points on the unit circle to be used in computing the mesh
+        // points on a sphere slice.
+        float[] afSin = new float[(radialSamples + 1)];
+        float[] afCos = new float[(radialSamples + 1)];
+        for (int iR = 0; iR < radialSamples; iR++) {
+            float fAngle = FastMath.TWO_PI * fInvRS * iR;
+            afCos[iR] = FastMath.cos(fAngle);
+            afSin[iR] = FastMath.sin(fAngle);
+        }
+        afSin[radialSamples] = afSin[0];
+        afCos[radialSamples] = afCos[0];
+
+        for (int iR = 0; iR <= radialSamples; iR++) {
+            posBuf.put(afCos[iR])
+                    .put(afSin[iR])
+                    .put(0);
+            colBuf.put(ColorRGBA.Orange.r)
+                    .put(ColorRGBA.Orange.g)
+                    .put(ColorRGBA.Orange.b)
+                    .put(ColorRGBA.Orange.a);
+            texBuf.put(iR % 2f)
+                    .put(iR % 2f);
+
+        }
+
+        updateBound();
+        setStatic();
+    }
+
+    /**
+     * sets the indices for rendering the sphere.
+     */
+    private void setIndexData() {
+        // allocate connectivity
+        int nbSegments = (radialSamples);// * 3;
+
+        ShortBuffer idxBuf = BufferUtils.createShortBuffer(2 * nbSegments);
+        setBuffer(Type.Index, 2, idxBuf);
+
+        int idx = 0;
+        int segDone = 0;
+        while (segDone < nbSegments) {
+            idxBuf.put((short) idx);
+            idxBuf.put((short) (idx + 1));
+            idx++;
+            segDone++;
+        }
+
+    }
+
+    /**
+     * Convenience factory method that creates a debuging bounding sphere
+     * geometry
+     *
+     * @param assetManager the assetManager
+     * @return the bounding sphere debug geometry.
+     */
+    public static Geometry createShape(AssetManager assetManager, String name) {
+        return createShape(assetManager, name, 256);
+    }
+
+    public static Geometry createShape(AssetManager assetManager, String name, int radialSample) {
+        RadiusShape b = new RadiusShape(radialSample);
+        Geometry geom = new Geometry(name, b);
+
+        Material mat = new Material(assetManager, "com/jme3/gde/scenecomposer/gizmo/mat/dashed/dashed.j3md");
+        mat.getAdditionalRenderState().setWireframe(true);
+        mat.getAdditionalRenderState().setBlendMode(RenderState.BlendMode.Alpha);
+        mat.getAdditionalRenderState().setDepthWrite(false);
+        mat.getAdditionalRenderState().setDepthTest(false);
+        mat.getAdditionalRenderState().setLineWidth(2f);
+
+        mat.setColor("Color", ColorRGBA.Orange);
+        mat.setFloat("DashSize", 0.5f);
+        geom.setQueueBucket(RenderQueue.Bucket.Transparent);
+
+        geom.setMaterial(mat);
+        return geom;
+
+    }
+}

+ 65 - 0
jme3-scenecomposer/src/com/jme3/gde/scenecomposer/gizmo/shape/Triangle.java

@@ -0,0 +1,65 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.jme3.gde.scenecomposer.gizmo.shape;
+
+import com.jme3.scene.Mesh;
+import com.jme3.scene.VertexBuffer;
+import com.jme3.util.BufferUtils;
+import java.nio.FloatBuffer;
+import java.nio.ShortBuffer;
+
+/**
+ *
+ * @author dokthar
+ */
+public class Triangle extends Mesh {
+
+    private final float width;
+    private final float height;
+
+    public Triangle(float width, float height) {
+        this.width = width;
+        this.height = height;
+
+        setGeometryData();
+        setIndexData();
+        
+        updateBound();
+    }
+
+    private void setGeometryData() {
+        setMode(Mode.Lines);
+
+        FloatBuffer posBuf = BufferUtils.createVector3Buffer(3);
+        FloatBuffer texBuf = BufferUtils.createVector2Buffer(3);
+
+        setBuffer(VertexBuffer.Type.Position, 3, posBuf);
+        setBuffer(VertexBuffer.Type.TexCoord, 2, texBuf);
+
+        posBuf.put(-width).put(0).put(0);
+        posBuf.put(0).put(height).put(0);
+        posBuf.put(width).put(0).put(0);
+        
+        texBuf.put(-width).put(0);
+        texBuf.put(0).put(height);
+        texBuf.put(width).put(0);
+    }
+
+    private void setIndexData() {
+        int nbSegments = 3;
+
+        ShortBuffer idxBuf = BufferUtils.createShortBuffer(2 * nbSegments);
+        setBuffer(VertexBuffer.Type.Index, 2, idxBuf);
+        idxBuf.put((short) 0);
+        idxBuf.put((short) 1);
+
+        idxBuf.put((short) 1);
+        idxBuf.put((short) 2);
+
+        idxBuf.put((short) 2);
+        idxBuf.put((short) 0);
+    }
+}