diff --git a/sdk/jme3-navmesh-gen/src/com/jme3/gde/nmgen/wizard/NavMeshGeneratorNode.java b/sdk/jme3-navmesh-gen/src/com/jme3/gde/nmgen/wizard/NavMeshGeneratorNode.java
new file mode 100644
index 000000000..fbf26df38
--- /dev/null
+++ b/sdk/jme3-navmesh-gen/src/com/jme3/gde/nmgen/wizard/NavMeshGeneratorNode.java
@@ -0,0 +1,54 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.jme3.gde.nmgen.wizard;
+
+import com.jme3.asset.AssetKey;
+import com.jme3.gde.core.util.PropertyUtils;
+import com.jme3.gde.nmgen.NavMeshGenerator;
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.Field;
+import org.openide.nodes.AbstractNode;
+import org.openide.nodes.Children;
+import org.openide.nodes.Node.Property;
+import org.openide.nodes.PropertySupport;
+import org.openide.nodes.Sheet;
+import org.openide.util.Exceptions;
+
+/**
+ *
+ * @author normenhansen
+ */
+public class NavMeshGeneratorNode extends AbstractNode {
+
+ private NavMeshGenerator key;
+
+ public NavMeshGeneratorNode(NavMeshGenerator key) {
+ super(Children.LEAF);
+ this.key = key;
+ }
+
+ @Override
+ protected Sheet createSheet() {
+ Sheet sheet = super.createSheet();
+ Sheet.Set set = sheet.createPropertiesSet();
+ set.setName("NavMeshGenerator");
+ set.setDisplayName("Settings");
+ for (Field field : key.getClass().getDeclaredFields()) {
+ PropertyDescriptor prop = PropertyUtils.getPropertyDescriptor(key.getClass(), field);
+ if (prop != null) {
+ try {
+ Property sup = new PropertySupport.Reflection(key, prop.getPropertyType(), prop.getReadMethod(), prop.getWriteMethod());
+ sup.setName(prop.getName());
+ sup.setDisplayName(prop.getDisplayName());
+ set.put(sup);
+ } catch (Exception e) {
+ Exceptions.printStackTrace(e);
+ }
+ }
+ }
+ sheet.put(set);
+ return sheet;
+ }
+}
diff --git a/sdk/jme3-navmesh-gen/src/com/jme3/gde/nmgen/wizard/NewNavMeshVisualPanel1.form b/sdk/jme3-navmesh-gen/src/com/jme3/gde/nmgen/wizard/NewNavMeshVisualPanel1.form
new file mode 100644
index 000000000..a48d18901
--- /dev/null
+++ b/sdk/jme3-navmesh-gen/src/com/jme3/gde/nmgen/wizard/NewNavMeshVisualPanel1.form
@@ -0,0 +1,34 @@
+
+
+
diff --git a/sdk/jme3-navmesh-gen/src/com/jme3/gde/nmgen/wizard/NewNavMeshVisualPanel1.java b/sdk/jme3-navmesh-gen/src/com/jme3/gde/nmgen/wizard/NewNavMeshVisualPanel1.java
new file mode 100644
index 000000000..297d314ff
--- /dev/null
+++ b/sdk/jme3-navmesh-gen/src/com/jme3/gde/nmgen/wizard/NewNavMeshVisualPanel1.java
@@ -0,0 +1,64 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.jme3.gde.nmgen.wizard;
+
+import com.jme3.gde.nmgen.NavMeshGenerator;
+import javax.swing.JPanel;
+import org.openide.WizardDescriptor;
+import org.openide.explorer.propertysheet.PropertySheet;
+import org.openide.nodes.Node;
+
+public final class NewNavMeshVisualPanel1 extends JPanel {
+
+ private PropertySheet ps;
+
+ /** Creates new form NewNavMeshVisualPanel1 */
+ public NewNavMeshVisualPanel1() {
+ initComponents();
+ ps = new PropertySheet();
+ ps.setNodes(new Node[]{});
+ jPanel1.add(ps);
+ }
+
+ @Override
+ public String getName() {
+ return "Step #1";
+ }
+
+ public void loadSettings(WizardDescriptor wiz){
+ NavMeshGenerator gen = (NavMeshGenerator)wiz.getProperty("generator");
+ ps.setNodes(new Node[]{new NavMeshGeneratorNode(gen)});
+ }
+
+ public void saveSettings(WizardDescriptor wiz){
+ }
+
+ /** This method is called from within the constructor to
+ * initialize the form.
+ * WARNING: Do NOT modify this code. The content of this method is
+ * always regenerated by the Form Editor.
+ */
+ // //GEN-BEGIN:initComponents
+ private void initComponents() {
+
+ jPanel1 = new javax.swing.JPanel();
+
+ jPanel1.setLayout(new javax.swing.BoxLayout(jPanel1, javax.swing.BoxLayout.LINE_AXIS));
+
+ javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
+ this.setLayout(layout);
+ layout.setHorizontalGroup(
+ layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 400, Short.MAX_VALUE)
+ );
+ layout.setVerticalGroup(
+ layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 300, Short.MAX_VALUE)
+ );
+ }// //GEN-END:initComponents
+ // Variables declaration - do not modify//GEN-BEGIN:variables
+ private javax.swing.JPanel jPanel1;
+ // End of variables declaration//GEN-END:variables
+}
diff --git a/sdk/jme3-navmesh-gen/src/com/jme3/gde/nmgen/wizard/NewNavMeshWizardAction.java b/sdk/jme3-navmesh-gen/src/com/jme3/gde/nmgen/wizard/NewNavMeshWizardAction.java
new file mode 100644
index 000000000..7e565a03f
--- /dev/null
+++ b/sdk/jme3-navmesh-gen/src/com/jme3/gde/nmgen/wizard/NewNavMeshWizardAction.java
@@ -0,0 +1,136 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.jme3.gde.nmgen.wizard;
+
+import com.jme3.bounding.BoundingBox;
+import com.jme3.gde.core.sceneexplorer.nodes.actions.AbstractNewSpatialWizardAction;
+import com.jme3.gde.core.sceneexplorer.nodes.actions.NewSpatialAction;
+import com.jme3.gde.nmgen.NavMeshGenerator;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Mesh;
+import com.jme3.scene.Node;
+import com.jme3.scene.Spatial;
+import com.jme3.scene.Spatial.CullHint;
+import com.jme3.terrain.Terrain;
+import java.awt.Component;
+import java.awt.Dialog;
+import java.text.MessageFormat;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import javax.swing.JComponent;
+import jme3tools.optimize.GeometryBatchFactory;
+import org.critterai.nmgen.IntermediateData;
+import org.openide.DialogDisplayer;
+import org.openide.WizardDescriptor;
+
+@org.openide.util.lookup.ServiceProvider(service = NewSpatialAction.class)
+public final class NewNavMeshWizardAction extends AbstractNewSpatialWizardAction {
+
+ private WizardDescriptor.Panel[] panels;
+
+ public NewNavMeshWizardAction() {
+ name = "NavMesh..";
+ }
+
+ @Override
+ protected Object showWizard(org.openide.nodes.Node node) {
+ WizardDescriptor wizardDescriptor = new WizardDescriptor(getPanels());
+ // {0} will be replaced by WizardDesriptor.Panel.getComponent().getName()
+ wizardDescriptor.setTitleFormat(new MessageFormat("{0}"));
+ wizardDescriptor.setTitle("Your wizard dialog title here");
+ NavMeshGenerator gen = new NavMeshGenerator();
+ wizardDescriptor.putProperty("generator", gen);
+
+ Dialog dialog = DialogDisplayer.getDefault().createDialog(wizardDescriptor);
+ dialog.setVisible(true);
+ dialog.toFront();
+ boolean cancelled = wizardDescriptor.getValue() != WizardDescriptor.FINISH_OPTION;
+ if (!cancelled) {
+ return wizardDescriptor;
+ }
+ return null;
+ }
+
+ @Override
+ protected Spatial doCreateSpatial(com.jme3.scene.Node rootNode, Object configuration) {
+ if (configuration == null) {
+ return null;
+ }
+ //TODO: maybe offload to other thread..
+ WizardDescriptor wizardDescriptor = (WizardDescriptor) configuration;
+
+ NavMeshGenerator generator = (NavMeshGenerator) wizardDescriptor.getProperty("generator");
+ IntermediateData id = new IntermediateData();
+
+ generator.setIntermediateData(null);
+
+ Mesh mesh = new Mesh();
+
+ GeometryBatchFactory.mergeGeometries(findGeometries(rootNode, new LinkedList(), generator), mesh);
+ Mesh optiMesh = generator.optimize(mesh);
+
+ final Geometry navMesh = new Geometry("NavMesh");
+ navMesh.setMesh(optiMesh);
+ navMesh.setCullHint(CullHint.Always);
+ navMesh.setModelBound(new BoundingBox());
+
+ return navMesh;
+ }
+
+ private List findGeometries(Node node, List geoms, NavMeshGenerator generator) {
+ for (Iterator it = node.getChildren().iterator(); it.hasNext();) {
+ Spatial spatial = it.next();
+ if (spatial instanceof Geometry) {
+ geoms.add((Geometry) spatial);
+ } else if (spatial instanceof Node) {
+ if (spatial instanceof Terrain) {
+ Mesh merged = generator.terrain2mesh((Terrain) spatial);
+ Geometry g = new Geometry("mergedTerrain");
+ g.setMesh(merged);
+ geoms.add(g);
+ } else {
+ findGeometries((Node) spatial, geoms, generator);
+ }
+ }
+ }
+ return geoms;
+ }
+
+ /**
+ * Initialize panels representing individual wizard's steps and sets
+ * various properties for them influencing wizard appearance.
+ */
+ private WizardDescriptor.Panel[] getPanels() {
+ if (panels == null) {
+ panels = new WizardDescriptor.Panel[]{
+ new NewNavMeshWizardPanel1()
+ };
+ String[] steps = new String[panels.length];
+ for (int i = 0; i < panels.length; i++) {
+ Component c = panels[i].getComponent();
+ // Default step name to component name of panel. Mainly useful
+ // for getting the name of the target chooser to appear in the
+ // list of steps.
+ steps[i] = c.getName();
+ if (c instanceof JComponent) { // assume Swing components
+ JComponent jc = (JComponent) c;
+ // Sets step number of a component
+ // TODO if using org.openide.dialogs >= 7.8, can use WizardDescriptor.PROP_*:
+ jc.putClientProperty("WizardPanel_contentSelectedIndex", new Integer(i));
+ // Sets steps names for a panel
+ jc.putClientProperty("WizardPanel_contentData", steps);
+ // Turn on subtitle creation on each step
+ jc.putClientProperty("WizardPanel_autoWizardStyle", Boolean.TRUE);
+ // Show steps on the left side with the image on the background
+ jc.putClientProperty("WizardPanel_contentDisplayed", Boolean.TRUE);
+ // Turn on numbering of all steps
+ jc.putClientProperty("WizardPanel_contentNumbered", Boolean.TRUE);
+ }
+ }
+ }
+ return panels;
+ }
+}
diff --git a/sdk/jme3-navmesh-gen/src/com/jme3/gde/nmgen/wizard/NewNavMeshWizardPanel1.java b/sdk/jme3-navmesh-gen/src/com/jme3/gde/nmgen/wizard/NewNavMeshWizardPanel1.java
new file mode 100644
index 000000000..2d7d58879
--- /dev/null
+++ b/sdk/jme3-navmesh-gen/src/com/jme3/gde/nmgen/wizard/NewNavMeshWizardPanel1.java
@@ -0,0 +1,88 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.jme3.gde.nmgen.wizard;
+
+import java.awt.Component;
+import javax.swing.event.ChangeListener;
+import org.openide.WizardDescriptor;
+import org.openide.util.HelpCtx;
+
+public class NewNavMeshWizardPanel1 implements WizardDescriptor.Panel {
+
+ /**
+ * The visual component that displays this panel. If you need to access the
+ * component from this class, just use getComponent().
+ */
+ private NewNavMeshVisualPanel1 component;
+
+ // Get the visual component for the panel. In this template, the component
+ // is kept separate. This can be more efficient: if the wizard is created
+ // but never displayed, or not all panels are displayed, it is better to
+ // create only those which really need to be visible.
+ public Component getComponent() {
+ if (component == null) {
+ component = new NewNavMeshVisualPanel1();
+ }
+ return component;
+ }
+
+ public HelpCtx getHelp() {
+ // Show no Help button for this panel:
+ return HelpCtx.DEFAULT_HELP;
+ // If you have context help:
+ // return new HelpCtx(SampleWizardPanel1.class);
+ }
+
+ public boolean isValid() {
+ // If it is always OK to press Next or Finish, then:
+ return true;
+ // If it depends on some condition (form filled out...), then:
+ // return someCondition();
+ // and when this condition changes (last form field filled in...) then:
+ // fireChangeEvent();
+ // and uncomment the complicated stuff below.
+ }
+
+ public final void addChangeListener(ChangeListener l) {
+ }
+
+ public final void removeChangeListener(ChangeListener l) {
+ }
+ /*
+ private final Set listeners = new HashSet(1); // or can use ChangeSupport in NB 6.0
+ public final void addChangeListener(ChangeListener l) {
+ synchronized (listeners) {
+ listeners.add(l);
+ }
+ }
+ public final void removeChangeListener(ChangeListener l) {
+ synchronized (listeners) {
+ listeners.remove(l);
+ }
+ }
+ protected final void fireChangeEvent() {
+ Iterator it;
+ synchronized (listeners) {
+ it = new HashSet(listeners).iterator();
+ }
+ ChangeEvent ev = new ChangeEvent(this);
+ while (it.hasNext()) {
+ it.next().stateChanged(ev);
+ }
+ }
+ */
+
+ // You can use a settings object to keep track of state. Normally the
+ // settings object will be the WizardDescriptor, so you can use
+ // WizardDescriptor.getProperty & putProperty to store information entered
+ // by the user.
+ public void readSettings(Object settings) {
+ component.loadSettings((WizardDescriptor)settings);
+ }
+
+ public void storeSettings(Object settings) {
+ component.saveSettings((WizardDescriptor)settings);
+ }
+}