Browse Source

Merge pull request #398 from neph1/200_Add_normals_debug

NormalViewState appstate and hook up for SceneViewer
Rickard Edén 2 years ago
parent
commit
1e5f02eefb

+ 9 - 0
jme3-core/src/com/jme3/gde/core/scene/SceneApplication.java

@@ -36,6 +36,7 @@ import com.jme3.gde.core.assets.AssetData;
 import com.jme3.gde.core.assets.AssetDataObject;
 import com.jme3.gde.core.scene.controller.AbstractCameraController;
 import com.jme3.gde.core.scene.processors.WireProcessor;
+import com.jme3.gde.core.scene.state.NormalViewState;
 import com.jme3.gde.core.sceneexplorer.nodes.NodeUtility;
 import com.jme3.gde.core.sceneviewer.SceneViewerTopComponent;
 import com.jme3.gde.core.undoredo.SceneUndoRedoManager;
@@ -769,4 +770,12 @@ public class SceneApplication extends LegacyApplication implements LookupProvide
     public boolean isAwt() {
         return java.awt.EventQueue.isDispatchThread();
     }
+
+    public void enableNormalView(boolean selected) {
+        if(selected) {
+            stateManager.attach(new NormalViewState());
+        } else if(stateManager.getState(NormalViewState.class) != null) {
+            stateManager.detach(stateManager.getState(NormalViewState.class));
+        }
+    }
 }

+ 109 - 0
jme3-core/src/com/jme3/gde/core/scene/state/NormalViewState.java

@@ -0,0 +1,109 @@
+/*
+ *  Copyright (c) 2009-2022 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.core.scene.state;
+
+import com.jme3.app.Application;
+import com.jme3.app.state.BaseAppState;
+import com.jme3.gde.core.scene.SceneApplication;
+import com.jme3.material.Material;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Node;
+import com.jme3.scene.Spatial;
+import com.jme3.util.TangentBinormalGenerator;
+import java.util.ArrayList;
+import java.util.List;
+import jme3tools.optimize.GeometryBatchFactory;
+
+/**
+ * Generates a set of geometries for debugging normals. Does not support moving
+ * or animated meshes. Implementation ref:
+ * https://hub.jmonkeyengine.org/t/debug-graphics-show-normals-as-lines/35058/3
+ *
+ * @author rickard
+ */
+public final class NormalViewState extends BaseAppState {
+
+    private final Node debugNode = new Node("Normals debug");
+    private final float normalLength = 0.2f;
+
+    @Override
+    protected void initialize(final Application app) {
+        // not used
+    }
+
+    @Override
+    protected void cleanup(final Application app) {
+        // not used
+    }
+
+    @Override
+    protected void onEnable() {
+        final SceneApplication app = (SceneApplication) getApplication();
+        final List<Geometry> geometries = new ArrayList<>();
+        GeometryBatchFactory.gatherGeoms(app.getRootNode(), geometries);
+        final Material debugMat = app.getAssetManager().loadMaterial(
+                "Common/Materials/VertexColor.j3m");
+
+        for (final Geometry geometry : geometries) {
+            final Geometry debug = new Geometry(geometry.getName(),
+                    TangentBinormalGenerator.genNormalLines(geometry.getMesh(),
+                            normalLength));
+            debug.setMaterial(debugMat);
+            debug.setCullHint(Spatial.CullHint.Never);
+            debug.setLocalTransform(geometry.getWorldTransform());
+            debugNode.attachChild(debug);
+        }
+        app.getRootNode().attachChild(debugNode);
+    }
+
+    @Override
+    public void update(float tpf) {
+        super.update(tpf);
+
+        final Node rootNode = ((SceneApplication) getApplication()).getRootNode();
+        for (final Spatial debug : debugNode.getChildren()) {
+            final Spatial original = rootNode.getChild(debug.getName());
+            if (original == null) {
+                debug.removeFromParent();
+                continue;
+            }
+            debug.setLocalTransform(original.getWorldTransform());
+        }
+    }
+
+    @Override
+    protected void onDisable() {
+        debugNode.removeFromParent();
+        debugNode.detachAllChildren();
+    }
+
+}

+ 22 - 0
jme3-core/src/com/jme3/gde/core/sceneviewer/SceneViewerTopComponent.form

@@ -196,6 +196,28 @@
             <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="enablePBRSkyActionPerformed"/>
           </Events>
         </Component>
+        <Component class="javax.swing.JToggleButton" name="enableNormalView">
+          <Properties>
+            <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
+              <Connection code="IconList.chimpMad" type="code"/>
+            </Property>
+            <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+              <ResourceString bundle="com/jme3/gde/core/sceneviewer/Bundle.properties" key="SceneViewerTopComponent.enableNormalView.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+            </Property>
+            <Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+              <ResourceString bundle="com/jme3/gde/core/sceneviewer/Bundle.properties" key="SceneViewerTopComponent.enableNormalView.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+            </Property>
+            <Property name="focusable" type="boolean" value="false"/>
+            <Property name="horizontalTextPosition" type="int" value="0"/>
+            <Property name="selectedIcon" type="javax.swing.Icon" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
+              <Connection code="IconList.chimpMad" type="code"/>
+            </Property>
+            <Property name="verticalTextPosition" type="int" value="3"/>
+          </Properties>
+          <Events>
+            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="enableNormalViewActionPerformed"/>
+          </Events>
+        </Component>
         <Container class="javax.swing.JPanel" name="jPanel1">
 
           <Layout class="org.netbeans.modules.form.compat2.layouts.DesignFlowLayout"/>

+ 20 - 0
jme3-core/src/com/jme3/gde/core/sceneviewer/SceneViewerTopComponent.java

@@ -171,6 +171,7 @@ public final class SceneViewerTopComponent extends TopComponent {
         enableWireframe = new javax.swing.JToggleButton();
         enablePBREnv = new javax.swing.JToggleButton();
         enablePBRSky = new javax.swing.JToggleButton();
+        enableNormalView = new javax.swing.JToggleButton();
         jPanel1 = new javax.swing.JPanel();
         enableStats = new javax.swing.JToggleButton();
         oGLPanel = new javax.swing.JPanel();
@@ -268,6 +269,20 @@ public final class SceneViewerTopComponent extends TopComponent {
             }
         });
         jToolBar1.add(enablePBRSky);
+
+        enableNormalView.setIcon(IconList.chimpMad);
+        org.openide.awt.Mnemonics.setLocalizedText(enableNormalView, org.openide.util.NbBundle.getMessage(SceneViewerTopComponent.class, "SceneViewerTopComponent.enableNormalView.text")); // NOI18N
+        enableNormalView.setToolTipText(org.openide.util.NbBundle.getMessage(SceneViewerTopComponent.class, "SceneViewerTopComponent.enableNormalView.toolTipText")); // NOI18N
+        enableNormalView.setFocusable(false);
+        enableNormalView.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
+        enableNormalView.setSelectedIcon(IconList.chimpMad);
+        enableNormalView.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
+        enableNormalView.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                enableNormalViewActionPerformed(evt);
+            }
+        });
+        jToolBar1.add(enableNormalView);
         jToolBar1.add(jPanel1);
 
         enableStats.setIcon(IconList.sceneInfo);
@@ -314,8 +329,13 @@ public final class SceneViewerTopComponent extends TopComponent {
         app.enablePBRSkybox(enablePBRSky.isSelected());
     }//GEN-LAST:event_enablePBRSkyActionPerformed
 
+    private void enableNormalViewActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_enableNormalViewActionPerformed
+        app.enableNormalView(enableNormalView.isSelected());
+    }//GEN-LAST:event_enableNormalViewActionPerformed
+
     // Variables declaration - do not modify//GEN-BEGIN:variables
     private javax.swing.JToggleButton enableCamLight;
+    private javax.swing.JToggleButton enableNormalView;
     private javax.swing.JToggleButton enablePBREnv;
     private javax.swing.JToggleButton enablePBRSky;
     private javax.swing.JToggleButton enableStats;