Преглед на файлове

Fixes #144 - Directional Light Gizmo not being updated by changing the Properties in the PropertyEditor

MeFisto94 преди 7 години
родител
ревизия
3f0e815f88

+ 20 - 2
jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/JmeDirectionalLight.java

@@ -32,6 +32,7 @@
 
 package com.jme3.gde.core.sceneexplorer.nodes;
 
+import com.jme3.gde.core.sceneexplorer.nodes.gizmo.DirectionalLightGizmoInterface;
 import com.jme3.light.DirectionalLight;
 import com.jme3.math.Vector3f;
 import com.jme3.scene.Spatial;
@@ -43,8 +44,9 @@ import org.openide.nodes.Sheet;
  */
 @org.openide.util.lookup.ServiceProvider(service=SceneExplorerNode.class)
 @SuppressWarnings({"unchecked", "rawtypes"})
-public class JmeDirectionalLight extends JmeLight{
+public class JmeDirectionalLight extends JmeLight {
     protected DirectionalLight directionalLight;
+    protected DirectionalLightGizmoInterface gizmo;
 
     public JmeDirectionalLight() {
     }
@@ -68,7 +70,7 @@ public class JmeDirectionalLight extends JmeLight{
             return sheet;
         }
 
-        set.put(makeProperty(obj, Vector3f.class, "getDirection", "setDirection", "Direction"));
+        set.put(makeEmbedProperty(this, JmeDirectionalLight.class, Vector3f.class, "getDirection", "setDirection", "Direction"));
 
         sheet.put(set);
         return sheet;
@@ -85,4 +87,20 @@ public class JmeDirectionalLight extends JmeLight{
         return JmeDirectionalLight.class;
     }
 
+    public void setGizmo(DirectionalLightGizmoInterface gizmo) {
+        this.gizmo = gizmo;
+    }
+
+    public void setDirection(Vector3f direction) {
+        // Don't directly pass it on to the Light
+        if (gizmo == null) {
+            directionalLight.setDirection(direction.normalize());
+        } else {
+            gizmo.onSetDirection(direction.normalize());
+        }
+    }
+    
+    public Vector3f getDirection() {
+        return directionalLight.getDirection();
+    }
 }

+ 1 - 0
jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/JmeLight.java

@@ -156,6 +156,7 @@ public class JmeLight extends AbstractSceneExplorerNode {
     
     
 
+    @Override
     public Class getExplorerObjectClass() {
         return Light.class;
     }

+ 23 - 0
jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/gizmo/DirectionalLightGizmoInterface.java

@@ -0,0 +1,23 @@
+package com.jme3.gde.core.sceneexplorer.nodes.gizmo;
+
+import com.jme3.math.Vector3f;
+
+/**
+ * This is the Interface of DirectionalLightGizmo. It has to be used because
+ * Gizmos are part of the SceneComposer Module but some classes which call them
+ * are still part of the Core Module. This means the Core Module would induce
+ * a dependency on the SceneComposer which is undesired.
+ * On the long view one should move all scene composer classes in core to the
+ * SceneComposer Module.
+ * 
+ * Actually: The Gizmos are SceneComposer (the 3d view) whereas the Nodes
+ * of the SceneGraph are in the SceneExplorer (the tree view). Both could be 
+ * merged into a Scene Module
+ * 
+ * @author MeFisto94
+ */
+
+
+public interface DirectionalLightGizmoInterface {
+    public void onSetDirection(Vector3f direction);
+}

+ 6 - 0
jme3-scenecomposer/src/com/jme3/gde/scenecomposer/SceneComposerTopComponent.java

@@ -1011,6 +1011,7 @@ private void jToggleSelectGeomActionPerformed(java.awt.event.ActionEvent evt) {/
     private void setSelectedObjectText(final String text) {
         java.awt.EventQueue.invokeLater(new Runnable() {
 
+            @Override
             public void run() {
                 if (text != null) {
                     ((TitledBorder) jPanel4.getBorder()).setTitle("Utilities - " + text);
@@ -1230,6 +1231,7 @@ private void jToggleSelectGeomActionPerformed(java.awt.event.ActionEvent evt) {/
             final SpatialAssetDataObject dobj = ((SpatialAssetDataObject) currentRequest.getDataObject());
             listener = new ProjectAssetManager.ClassPathChangeListener() {
 
+                @Override
                 public void classPathChanged(final ProjectAssetManager manager) {
                     if (dobj.isModified()) {
                         Confirmation msg = new NotifyDescriptor.Confirmation(
@@ -1307,4 +1309,8 @@ private void jToggleSelectGeomActionPerformed(java.awt.event.ActionEvent evt) {/
         Message msg = new NotifyDescriptor.Message(info);
         DialogDisplayer.getDefault().notifyLater(msg);
     }
+
+    public SceneComposerToolController getToolController() {
+        return toolController;
+    }
 }

+ 2 - 1
jme3-scenecomposer/src/com/jme3/gde/scenecomposer/SceneEditTool.java

@@ -129,7 +129,8 @@ public abstract class SceneEditTool {
 
     /**
      * Called when the selected spatial has been modified outside of the tool.
-     * TODO: why? just move the tool where the object is each frame?
+     * @TODO: why? just move the tool where the object is each frame?
+     * Proposed Answer: Performance.
      */
     public void updateToolsTransformation() {
 

+ 4 - 1
jme3-scenecomposer/src/com/jme3/gde/scenecomposer/gizmo/NodeCallback.java

@@ -13,7 +13,10 @@ import com.jme3.scene.Node;
 import com.jme3.scene.Spatial;
 
 /**
- *
+ * This Class allows "hooking" transformation events of a Node.
+ * As such it is used to update gizmos and others to react to
+ * Property Panel Input.
+ * 
  * @author dokthar
  */
 public abstract class NodeCallback extends Node {

+ 48 - 8
jme3-scenecomposer/src/com/jme3/gde/scenecomposer/gizmo/light/DirectionalLightGizmo.java

@@ -8,26 +8,40 @@ 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.core.sceneexplorer.nodes.gizmo.DirectionalLightGizmoInterface;
+import com.jme3.gde.scenecomposer.SceneComposerToolController;
+import com.jme3.gde.scenecomposer.SceneComposerTopComponent;
+import com.jme3.gde.scenecomposer.SceneEditTool;
 import com.jme3.gde.scenecomposer.gizmo.NodeCallback;
 import com.jme3.light.DirectionalLight;
+import com.jme3.math.FastMath;
 import com.jme3.math.Quaternion;
 import com.jme3.math.Vector3f;
 
 /**
- *
+ * Handles the DirectionalLight's Gizmo.
+ * 
+ * Note: There are actually three classes involved:
+ * The DirectionalLight (jme class) is not added to the gizmo.
+ * The Gizmo is a seperate node, which just passes it's transforms to
+ * the lights transform (powered by NodeCallback) (but the light obviously has
+ * another parent, because that affects lighting).
+ * 
+ * The JmeDirectionalLight / JmeLight is responsible for making the Light appear
+ * in SceneExplorer as node and it handles the properties.
+ * 
  * @author dokthar
  */
-public class DirectionalLightGizmo extends NodeCallback {
-
-    private Vector3f initalDirection;
-    private JmeDirectionalLight jmeLight;
-    private DirectionalLight light;
+public class DirectionalLightGizmo extends NodeCallback implements DirectionalLightGizmoInterface {
+    private final Vector3f initialDirection;
+    private final JmeDirectionalLight jmeLight;
+    private final 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();
+        initialDirection = light.getDirection().clone();
     }
 
     @Override
@@ -40,9 +54,35 @@ public class DirectionalLightGizmo extends NodeCallback {
 
     @Override
     public void onRotation(Quaternion oldRotation, Quaternion newRotation) {
-        light.setDirection(newRotation.mult(initalDirection));
+        light.setDirection(newRotation.mult(initialDirection));
         jmeLight.setValue("direction", light.getDirection());
     }
+    
+    @Override
+    public void onSetDirection(Vector3f direction) {
+        // We cannot set the light direction directly, we have to adjust the
+        // rotation as well (which in turn calls onRotation to set the direction)
+         
+        // Black Quaternion Magic taken from https://stackoverflow.com/a/11741520
+        float k_cos_theta = initialDirection.dot(direction);
+        float k = FastMath.sqrt(initialDirection.lengthSquared() * direction.lengthSquared());
+
+        if (FastMath.approximateEquals(k_cos_theta / k, 1)) {
+            setLocalRotation(Quaternion.IDENTITY);
+        } else if (FastMath.approximateEquals(k_cos_theta / k, -1f)) {
+            // 180 degree rotation around any orthogonal vector
+            Vector3f anyOrthogonal = initialDirection.cross(Vector3f.UNIT_Y).normalize();
+            setLocalRotation(new Quaternion(anyOrthogonal.x, anyOrthogonal.y, anyOrthogonal.z, 0));
+        } else {
+            Vector3f xyz = initialDirection.cross(direction);
+            setLocalRotation(new Quaternion(xyz.x, xyz.y, xyz.z, k_cos_theta + k));
+        }
+        
+        SceneComposerToolController sctc = SceneComposerTopComponent.findInstance().getToolController();
+        if (sctc.getSelectedSpatial() != null) {
+           sctc.selectedSpatialTransformed();
+        }
+    }
 
     private final BoundingSphere bv = new BoundingSphere(10f, getWorldTranslation());
 

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

@@ -100,6 +100,7 @@ public class LightGizmoFactory {
         
         gizmo.attachChild(arrow);
         
+        jmeLight.setGizmo(gizmo);
         return gizmo;
     }