diff --git a/sdk/jme3-materialeditor/src/com/jme3/gde/shadernodedefinition/SNDefDataObject.java b/sdk/jme3-materialeditor/src/com/jme3/gde/shadernodedefinition/SNDefDataObject.java
new file mode 100644
index 000000000..5ef9fc194
--- /dev/null
+++ b/sdk/jme3-materialeditor/src/com/jme3/gde/shadernodedefinition/SNDefDataObject.java
@@ -0,0 +1,115 @@
+/*
+ * 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.shadernodedefinition;
+
+import java.io.IOException;
+import org.netbeans.core.spi.multiview.MultiViewElement;
+import org.netbeans.core.spi.multiview.text.MultiViewEditorElement;
+import org.openide.awt.ActionID;
+import org.openide.awt.ActionReference;
+import org.openide.awt.ActionReferences;
+import org.openide.filesystems.FileObject;
+import org.openide.filesystems.MIMEResolver;
+import org.openide.loaders.DataObject;
+import org.openide.loaders.DataObjectExistsException;
+import org.openide.loaders.MultiDataObject;
+import org.openide.loaders.MultiFileLoader;
+import org.openide.util.Lookup;
+import org.openide.util.NbBundle.Messages;
+import org.openide.windows.TopComponent;
+
+@Messages({
+ "LBL_SNDef_LOADER=Files of SNDef"
+})
+@MIMEResolver.ExtensionRegistration(
+ displayName = "#LBL_SNDef_LOADER",
+ mimeType = "text/x-j3sn",
+ extension = {"j3sn", "J3SN"}
+)
+@DataObject.Registration(
+ mimeType = "text/x-j3sn",
+ iconBase = "com/jme3/gde/materialdefinition/icons/node.png",
+ displayName = "#LBL_SNDef_LOADER",
+ position = 300
+)
+@ActionReferences({
+ @ActionReference(
+ path = "Loaders/text/x-j3sn/Actions",
+ id = @ActionID(category = "System", id = "org.openide.actions.OpenAction"),
+ position = 100,
+ separatorAfter = 200
+ ),
+ @ActionReference(
+ path = "Loaders/text/x-j3sn/Actions",
+ id = @ActionID(category = "Edit", id = "org.openide.actions.CutAction"),
+ position = 300
+ ),
+ @ActionReference(
+ path = "Loaders/text/x-j3sn/Actions",
+ id = @ActionID(category = "Edit", id = "org.openide.actions.CopyAction"),
+ position = 400,
+ separatorAfter = 500
+ ),
+ @ActionReference(
+ path = "Loaders/text/x-j3sn/Actions",
+ id = @ActionID(category = "Edit", id = "org.openide.actions.DeleteAction"),
+ position = 600
+ ),
+ @ActionReference(
+ path = "Loaders/text/x-j3sn/Actions",
+ id = @ActionID(category = "System", id = "org.openide.actions.RenameAction"),
+ position = 700,
+ separatorAfter = 800
+ ),
+ @ActionReference(
+ path = "Loaders/text/x-j3sn/Actions",
+ id = @ActionID(category = "System", id = "org.openide.actions.SaveAsTemplateAction"),
+ position = 900,
+ separatorAfter = 1000
+ ),
+ @ActionReference(
+ path = "Loaders/text/x-j3sn/Actions",
+ id = @ActionID(category = "System", id = "org.openide.actions.FileSystemAction"),
+ position = 1100,
+ separatorAfter = 1200
+ ),
+ @ActionReference(
+ path = "Loaders/text/x-j3sn/Actions",
+ id = @ActionID(category = "System", id = "org.openide.actions.ToolsAction"),
+ position = 1300
+ ),
+ @ActionReference(
+ path = "Loaders/text/x-j3sn/Actions",
+ id = @ActionID(category = "System", id = "org.openide.actions.PropertiesAction"),
+ position = 1400
+ )
+})
+public class SNDefDataObject extends MultiDataObject {
+
+ public SNDefDataObject(FileObject pf, MultiFileLoader loader) throws DataObjectExistsException, IOException {
+ super(pf, loader);
+ registerEditor("text/x-j3sn", true);
+ }
+
+ @Override
+ protected int associateLookup() {
+ return 1;
+ }
+
+ @MultiViewElement.Registration(
+ displayName = "#LBL_SNDef_EDITOR",
+ iconBase = "com/jme3/gde/materialdefinition/icons/node.png",
+ mimeType = "text/x-j3sn",
+ persistenceType = TopComponent.PERSISTENCE_ONLY_OPENED,
+ preferredID = "SNDef",
+ position = 1000
+ )
+ @Messages("LBL_SNDef_EDITOR=Source")
+ public static MultiViewEditorElement createEditor(Lookup lkp) {
+ return new MultiViewEditorElement(lkp);
+ }
+
+}
diff --git a/sdk/jme3-materialeditor/src/com/jme3/gde/shadernodedefinition/SNDefTemplate.j3sn b/sdk/jme3-materialeditor/src/com/jme3/gde/shadernodedefinition/SNDefTemplate.j3sn
new file mode 100644
index 000000000..4c5256034
--- /dev/null
+++ b/sdk/jme3-materialeditor/src/com/jme3/gde/shadernodedefinition/SNDefTemplate.j3sn
@@ -0,0 +1,25 @@
+ShaderNodeDefinitions{
+ ShaderNodeDefinition ${defName} {
+ Type: ${defType}
+ Shader GLSL100: ${shaderSnippet}
+ Documentation{
+ ${description}
+ <#list inputParams as param>
+ @input ${param[0]} ${param[1]} ${param[2]}
+ #list>
+ <#list outputParams as param>
+ @output ${param[0]} ${param[1]} ${param[2]}
+ #list>
+ }
+ Input {
+ <#list inputParams as param>
+ ${param[0]} ${param[1]}
+ #list>
+ }
+ Output {
+ <#list outputParams as param>
+ ${param[0]} ${param[1]}
+ #list>
+ }
+ }
+}
\ No newline at end of file
diff --git a/sdk/jme3-materialeditor/src/com/jme3/gde/shadernodedefinition/SNDefVisualElement.form b/sdk/jme3-materialeditor/src/com/jme3/gde/shadernodedefinition/SNDefVisualElement.form
new file mode 100644
index 000000000..4f9abb50d
--- /dev/null
+++ b/sdk/jme3-materialeditor/src/com/jme3/gde/shadernodedefinition/SNDefVisualElement.form
@@ -0,0 +1,28 @@
+
+
+
diff --git a/sdk/jme3-materialeditor/src/com/jme3/gde/shadernodedefinition/SNDefVisualElement.java b/sdk/jme3-materialeditor/src/com/jme3/gde/shadernodedefinition/SNDefVisualElement.java
new file mode 100644
index 000000000..f8e49f9b8
--- /dev/null
+++ b/sdk/jme3-materialeditor/src/com/jme3/gde/shadernodedefinition/SNDefVisualElement.java
@@ -0,0 +1,127 @@
+/*
+ * 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.shadernodedefinition;
+
+import javax.swing.Action;
+import javax.swing.JComponent;
+import javax.swing.JPanel;
+import javax.swing.JToolBar;
+import org.netbeans.core.spi.multiview.CloseOperationState;
+import org.netbeans.core.spi.multiview.MultiViewElement;
+import org.netbeans.core.spi.multiview.MultiViewElementCallback;
+import org.openide.awt.UndoRedo;
+import org.openide.util.Lookup;
+import org.openide.util.NbBundle.Messages;
+import org.openide.windows.TopComponent;
+
+@MultiViewElement.Registration(
+ displayName = "#LBL_SNDef_VISUAL",
+ iconBase = "com/jme3/gde/materialdefinition/icons/node.png",
+ mimeType = "text/x-j3sn",
+ persistenceType = TopComponent.PERSISTENCE_NEVER,
+ preferredID = "SNDefVisual",
+ position = 2000
+)
+@Messages("LBL_SNDef_VISUAL=Visual")
+public final class SNDefVisualElement extends JPanel implements MultiViewElement {
+
+ private SNDefDataObject obj;
+ private JToolBar toolbar = new JToolBar();
+ private transient MultiViewElementCallback callback;
+
+ public SNDefVisualElement(Lookup lkp) {
+ obj = lkp.lookup(SNDefDataObject.class);
+ assert obj != null;
+ initComponents();
+ }
+
+ @Override
+ public String getName() {
+ return "SNDefVisualElement";
+ }
+
+ /**
+ * 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() {
+
+ javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
+ this.setLayout(layout);
+ layout.setHorizontalGroup(
+ layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGap(0, 400, Short.MAX_VALUE)
+ );
+ layout.setVerticalGroup(
+ layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGap(0, 300, Short.MAX_VALUE)
+ );
+ }// //GEN-END:initComponents
+
+ // Variables declaration - do not modify//GEN-BEGIN:variables
+ // End of variables declaration//GEN-END:variables
+ @Override
+ public JComponent getVisualRepresentation() {
+ return this;
+ }
+
+ @Override
+ public JComponent getToolbarRepresentation() {
+ return toolbar;
+ }
+
+ @Override
+ public Action[] getActions() {
+ return new Action[0];
+ }
+
+ @Override
+ public Lookup getLookup() {
+ return obj.getLookup();
+ }
+
+ @Override
+ public void componentOpened() {
+ }
+
+ @Override
+ public void componentClosed() {
+ }
+
+ @Override
+ public void componentShowing() {
+ }
+
+ @Override
+ public void componentHidden() {
+ }
+
+ @Override
+ public void componentActivated() {
+ }
+
+ @Override
+ public void componentDeactivated() {
+ }
+
+ @Override
+ public UndoRedo getUndoRedo() {
+ return UndoRedo.NONE;
+ }
+
+ @Override
+ public void setMultiViewCallback(MultiViewElementCallback callback) {
+ this.callback = callback;
+ }
+
+ @Override
+ public CloseOperationState canCloseElement() {
+ return CloseOperationState.STATE_OK;
+ }
+
+}
diff --git a/sdk/jme3-materialeditor/src/com/jme3/gde/shadernodedefinition/ShaderNodeSource b/sdk/jme3-materialeditor/src/com/jme3/gde/shadernodedefinition/ShaderNodeSource
new file mode 100644
index 000000000..51b76b175
--- /dev/null
+++ b/sdk/jme3-materialeditor/src/com/jme3/gde/shadernodedefinition/ShaderNodeSource
@@ -0,0 +1,9 @@
+<#list inputParams as param>
+//@input ${param[0]} ${param[1]} ${param[2]}
+#list>
+<#list outputParams as param>
+//@output ${param[0]} ${param[1]} ${param[2]}
+#list>
+void main(){
+ //insert glsl code here
+}
\ No newline at end of file
diff --git a/sdk/jme3-materialeditor/src/com/jme3/gde/shadernodedefinition/sNDef.html b/sdk/jme3-materialeditor/src/com/jme3/gde/shadernodedefinition/sNDef.html
new file mode 100644
index 000000000..a0a7ab547
--- /dev/null
+++ b/sdk/jme3-materialeditor/src/com/jme3/gde/shadernodedefinition/sNDef.html
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+ A new Shader Node Definition file that can be instantiated as a Shader Node in the Shader Node editor
+
+
diff --git a/sdk/jme3-materialeditor/src/com/jme3/gde/shadernodedefinition/wizard/Bundle.properties b/sdk/jme3-materialeditor/src/com/jme3/gde/shadernodedefinition/wizard/Bundle.properties
new file mode 100644
index 000000000..5a8a44796
--- /dev/null
+++ b/sdk/jme3-materialeditor/src/com/jme3/gde/shadernodedefinition/wizard/Bundle.properties
@@ -0,0 +1,10 @@
+SNDefVisualPanel1.jLabel1.text=Definition Name
+SNDefVisualPanel1.defNameTextField.toolTipText=
+SNDefVisualPanel1.defNameTextField.text=
+SNDefVisualPanel1.jLabel2.text=Shader type
+SNDefVisualPanel1.jPanel2.border.title=Description
+SNDefVisualPanel2.addButton.text=
+SNDefVisualPanel2.titleLabel.text=Inputs
+SNDefVisualPanel2.addButton.toolTipText=Add an entry
+SNDefVisualPanel2.delButton.toolTipText=Delete an entry
+SNDefVisualPanel2.delButton.text=
diff --git a/sdk/jme3-materialeditor/src/com/jme3/gde/shadernodedefinition/wizard/SNDefVisualPanel1.form b/sdk/jme3-materialeditor/src/com/jme3/gde/shadernodedefinition/wizard/SNDefVisualPanel1.form
new file mode 100644
index 000000000..e0b0605aa
--- /dev/null
+++ b/sdk/jme3-materialeditor/src/com/jme3/gde/shadernodedefinition/wizard/SNDefVisualPanel1.form
@@ -0,0 +1,158 @@
+
+
+
diff --git a/sdk/jme3-materialeditor/src/com/jme3/gde/shadernodedefinition/wizard/SNDefVisualPanel1.java b/sdk/jme3-materialeditor/src/com/jme3/gde/shadernodedefinition/wizard/SNDefVisualPanel1.java
new file mode 100644
index 000000000..2134e0e83
--- /dev/null
+++ b/sdk/jme3-materialeditor/src/com/jme3/gde/shadernodedefinition/wizard/SNDefVisualPanel1.java
@@ -0,0 +1,146 @@
+/*
+ * 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.shadernodedefinition.wizard;
+
+import com.jme3.shader.Shader;
+import javax.swing.DefaultComboBoxModel;
+import javax.swing.JPanel;
+
+public final class SNDefVisualPanel1 extends JPanel {
+
+
+ /**
+ * Creates new form SNDefVisualPanel1
+ */
+ public SNDefVisualPanel1() {
+ initComponents();
+ DefaultComboBoxModel model = new DefaultComboBoxModel();
+ for (Shader.ShaderType shaderType : Shader.ShaderType.values()) {
+ model.addElement(shaderType.name());
+ }
+ shaderTypeCB.setModel(model);
+ }
+
+ @Override
+ public String getName() {
+ return "Shader node informations";
+ }
+
+ public String getDefName(){
+ return defNameTextField.getText();
+ }
+
+ public String getDefType(){
+ return (String)shaderTypeCB.getModel().getSelectedItem();
+ }
+
+ public String getDefDescription(){
+ return descriptionTextArea.getText();
+ }
+
+
+ /**
+ * 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();
+ jLabel1 = new javax.swing.JLabel();
+ defNameTextField = new javax.swing.JTextField();
+ jLabel2 = new javax.swing.JLabel();
+ shaderTypeCB = new javax.swing.JComboBox();
+ jPanel2 = new javax.swing.JPanel();
+ jScrollPane1 = new javax.swing.JScrollPane();
+ descriptionTextArea = new javax.swing.JTextArea();
+
+ org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(SNDefVisualPanel1.class, "SNDefVisualPanel1.jLabel1.text")); // NOI18N
+
+ defNameTextField.setText(org.openide.util.NbBundle.getMessage(SNDefVisualPanel1.class, "SNDefVisualPanel1.defNameTextField.text")); // NOI18N
+ defNameTextField.setToolTipText(org.openide.util.NbBundle.getMessage(SNDefVisualPanel1.class, "SNDefVisualPanel1.defNameTextField.toolTipText")); // NOI18N
+
+ org.openide.awt.Mnemonics.setLocalizedText(jLabel2, org.openide.util.NbBundle.getMessage(SNDefVisualPanel1.class, "SNDefVisualPanel1.jLabel2.text")); // NOI18N
+
+ shaderTypeCB.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" }));
+
+ jPanel2.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(SNDefVisualPanel1.class, "SNDefVisualPanel1.jPanel2.border.title"))); // NOI18N
+
+ descriptionTextArea.setColumns(20);
+ descriptionTextArea.setRows(5);
+ jScrollPane1.setViewportView(descriptionTextArea);
+
+ javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2);
+ jPanel2.setLayout(jPanel2Layout);
+ jPanel2Layout.setHorizontalGroup(
+ jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 376, Short.MAX_VALUE)
+ );
+ jPanel2Layout.setVerticalGroup(
+ jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 157, Short.MAX_VALUE)
+ );
+
+ javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
+ jPanel1.setLayout(jPanel1Layout);
+ jPanel1Layout.setHorizontalGroup(
+ jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
+ .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
+ .addGroup(jPanel1Layout.createSequentialGroup()
+ .addContainerGap()
+ .addComponent(jPanel2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+ .addGroup(jPanel1Layout.createSequentialGroup()
+ .addGap(14, 14, 14)
+ .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
+ .addComponent(jLabel2)
+ .addComponent(jLabel1))
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addComponent(defNameTextField)
+ .addComponent(shaderTypeCB, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))))
+ .addContainerGap())
+ );
+ jPanel1Layout.setVerticalGroup(
+ jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(jPanel1Layout.createSequentialGroup()
+ .addGap(40, 40, 40)
+ .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+ .addComponent(jLabel1)
+ .addComponent(defNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+ .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+ .addComponent(jLabel2)
+ .addComponent(shaderTypeCB, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(jPanel2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addContainerGap())
+ );
+
+ 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, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ );
+ layout.setVerticalGroup(
+ layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ );
+ }// //GEN-END:initComponents
+
+ // Variables declaration - do not modify//GEN-BEGIN:variables
+ private javax.swing.JTextField defNameTextField;
+ private javax.swing.JTextArea descriptionTextArea;
+ private javax.swing.JLabel jLabel1;
+ private javax.swing.JLabel jLabel2;
+ private javax.swing.JPanel jPanel1;
+ private javax.swing.JPanel jPanel2;
+ private javax.swing.JScrollPane jScrollPane1;
+ private javax.swing.JComboBox shaderTypeCB;
+ // End of variables declaration//GEN-END:variables
+}
diff --git a/sdk/jme3-materialeditor/src/com/jme3/gde/shadernodedefinition/wizard/SNDefVisualPanel2.form b/sdk/jme3-materialeditor/src/com/jme3/gde/shadernodedefinition/wizard/SNDefVisualPanel2.form
new file mode 100644
index 000000000..4c9ed4d2b
--- /dev/null
+++ b/sdk/jme3-materialeditor/src/com/jme3/gde/shadernodedefinition/wizard/SNDefVisualPanel2.form
@@ -0,0 +1,141 @@
+
+
+
diff --git a/sdk/jme3-materialeditor/src/com/jme3/gde/shadernodedefinition/wizard/SNDefVisualPanel2.java b/sdk/jme3-materialeditor/src/com/jme3/gde/shadernodedefinition/wizard/SNDefVisualPanel2.java
new file mode 100644
index 000000000..c058612d6
--- /dev/null
+++ b/sdk/jme3-materialeditor/src/com/jme3/gde/shadernodedefinition/wizard/SNDefVisualPanel2.java
@@ -0,0 +1,209 @@
+/*
+ * 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.shadernodedefinition.wizard;
+
+import java.awt.EventQueue;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import javax.swing.table.DefaultTableModel;
+
+public final class SNDefVisualPanel2 extends JPanel {
+
+ private final Object[] emptyObj = {"", "", ""};
+ private final String type;
+
+ /**
+ * Creates new form SNDefVisualPanel2
+ */
+ public SNDefVisualPanel2(String type) {
+ initComponents();
+ this.type = type;
+ titleLabel.setText(type);
+ varTable.getColumnModel().getSelectionModel().addListSelectionListener(new ExploreSelectionListener());
+ }
+
+ @Override
+ public String getName() {
+ return type;
+ }
+
+ public String[][] getData() {
+
+ DefaultTableModel model = (DefaultTableModel) varTable.getModel();
+ String[][] data = new String[model.getRowCount()][3];
+ for (int i = 0; i < model.getRowCount(); i++) {
+ data[i][0] = (String) model.getValueAt(i, 0);
+ data[i][1] = (String) model.getValueAt(i, 1);
+ data[i][2] = (String) model.getValueAt(i, 2);
+ }
+
+ return data;
+ }
+
+ // Add this class to the body of MyTable class.
+ private class ExploreSelectionListener implements ListSelectionListener {
+
+ public void valueChanged(ListSelectionEvent e) {
+ if (!e.getValueIsAdjusting()) {
+ int row = varTable.getSelectedRow();
+ int col = varTable.getSelectedColumn();
+ // Make sure we start with legal values.
+ if (col < 0) {
+ col = 0;
+ }
+ if (row < 0) {
+ row = 0;
+ }
+ // Find the next editable cell.
+ while (!varTable.isCellEditable(row, col)) {
+ col++;
+ if (col > varTable.getColumnCount() - 1) {
+ col = 1;
+ row = (row == varTable.getRowCount() - 1) ? 1 : row + 1;
+ }
+ }
+ // Select the cell in the table.
+ final int r = row, c = col;
+ EventQueue.invokeLater(new Runnable() {
+ public void run() {
+ varTable.changeSelection(r, c, false, false);
+ }
+ });
+ // Edit.
+ if (varTable.isCellEditable(row, col)) {
+ varTable.editCellAt(row, col);
+ ((JTextField) varTable.getEditorComponent()).selectAll();
+ varTable.getEditorComponent().requestFocusInWindow();
+ }
+ }
+ }
+ }
+
+ /**
+ * 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();
+ jScrollPane1 = new javax.swing.JScrollPane();
+ varTable = new javax.swing.JTable();
+ titleLabel = new javax.swing.JLabel();
+ addButton = new javax.swing.JButton();
+ delButton = new javax.swing.JButton();
+
+ varTable.setBackground(javax.swing.UIManager.getDefaults().getColor("Label.background"));
+ varTable.setModel(new javax.swing.table.DefaultTableModel(
+ new Object [][] {
+
+ },
+ new String [] {
+ "Type", "Name", "Description"
+ }
+ ) {
+ Class[] types = new Class [] {
+ java.lang.String.class, java.lang.String.class, java.lang.String.class
+ };
+
+ public Class getColumnClass(int columnIndex) {
+ return types [columnIndex];
+ }
+ });
+ jScrollPane1.setViewportView(varTable);
+
+ org.openide.awt.Mnemonics.setLocalizedText(titleLabel, org.openide.util.NbBundle.getMessage(SNDefVisualPanel2.class, "SNDefVisualPanel2.titleLabel.text")); // NOI18N
+
+ addButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/jme3/gde/materials/multiview/widgets/icons/picture_add.png"))); // NOI18N
+ org.openide.awt.Mnemonics.setLocalizedText(addButton, org.openide.util.NbBundle.getMessage(SNDefVisualPanel2.class, "SNDefVisualPanel2.addButton.text")); // NOI18N
+ addButton.setToolTipText(org.openide.util.NbBundle.getMessage(SNDefVisualPanel2.class, "SNDefVisualPanel2.addButton.toolTipText")); // NOI18N
+ addButton.setAlignmentX(0.5F);
+ addButton.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ addButtonActionPerformed(evt);
+ }
+ });
+
+ delButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/jme3/gde/materials/multiview/widgets/icons/picture_delete.png"))); // NOI18N
+ org.openide.awt.Mnemonics.setLocalizedText(delButton, org.openide.util.NbBundle.getMessage(SNDefVisualPanel2.class, "SNDefVisualPanel2.delButton.text")); // NOI18N
+ delButton.setToolTipText(org.openide.util.NbBundle.getMessage(SNDefVisualPanel2.class, "SNDefVisualPanel2.delButton.toolTipText")); // NOI18N
+ delButton.setAlignmentX(0.5F);
+ delButton.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ delButtonActionPerformed(evt);
+ }
+ });
+
+ javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
+ jPanel1.setLayout(jPanel1Layout);
+ jPanel1Layout.setHorizontalGroup(
+ jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(jPanel1Layout.createSequentialGroup()
+ .addContainerGap()
+ .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 388, Short.MAX_VALUE)
+ .addGroup(jPanel1Layout.createSequentialGroup()
+ .addComponent(titleLabel)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addComponent(addButton)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(delButton)))
+ .addContainerGap())
+ );
+ jPanel1Layout.setVerticalGroup(
+ jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
+ .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(jPanel1Layout.createSequentialGroup()
+ .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addComponent(titleLabel))
+ .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
+ .addComponent(delButton)
+ .addGap(0, 0, Short.MAX_VALUE))
+ .addGroup(jPanel1Layout.createSequentialGroup()
+ .addGap(0, 0, Short.MAX_VALUE)
+ .addComponent(addButton)))
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 278, javax.swing.GroupLayout.PREFERRED_SIZE))
+ );
+
+ 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, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ );
+ layout.setVerticalGroup(
+ layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ );
+ }// //GEN-END:initComponents
+
+ private void addButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addButtonActionPerformed
+ DefaultTableModel model = (DefaultTableModel) varTable.getModel();
+ model.addRow(emptyObj);
+ }//GEN-LAST:event_addButtonActionPerformed
+
+ private void delButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_delButtonActionPerformed
+ DefaultTableModel model = (DefaultTableModel) varTable.getModel();
+ int selRow = varTable.getSelectedRow();
+ if (selRow >= 0) {
+ model.removeRow(selRow);
+ }
+ }//GEN-LAST:event_delButtonActionPerformed
+
+ // Variables declaration - do not modify//GEN-BEGIN:variables
+ private javax.swing.JButton addButton;
+ private javax.swing.JButton delButton;
+ private javax.swing.JPanel jPanel1;
+ private javax.swing.JScrollPane jScrollPane1;
+ private javax.swing.JLabel titleLabel;
+ private javax.swing.JTable varTable;
+ // End of variables declaration//GEN-END:variables
+}
diff --git a/sdk/jme3-materialeditor/src/com/jme3/gde/shadernodedefinition/wizard/SNDefWizardIterator.java b/sdk/jme3-materialeditor/src/com/jme3/gde/shadernodedefinition/wizard/SNDefWizardIterator.java
new file mode 100644
index 000000000..e8c812c30
--- /dev/null
+++ b/sdk/jme3-materialeditor/src/com/jme3/gde/shadernodedefinition/wizard/SNDefWizardIterator.java
@@ -0,0 +1,222 @@
+/*
+ * 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.shadernodedefinition.wizard;
+
+import com.jme3.gde.core.assets.ProjectAssetManager;
+import java.awt.Component;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import javax.swing.JComponent;
+import javax.swing.event.ChangeListener;
+import javax.xml.transform.Templates;
+import org.netbeans.api.project.Project;
+import org.netbeans.api.project.ProjectUtils;
+import org.netbeans.api.project.SourceGroup;
+import org.netbeans.api.project.Sources;
+import org.netbeans.api.templates.TemplateRegistration;
+import org.netbeans.api.templates.TemplateRegistrations;
+import org.netbeans.spi.project.ui.templates.support.Templates;
+import org.openide.WizardDescriptor;
+import org.openide.filesystems.FileObject;
+import org.openide.loaders.DataFolder;
+import org.openide.loaders.DataObject;
+import org.openide.util.NbBundle.Messages;
+
+// TODO define position attribute
+@TemplateRegistrations({
+@TemplateRegistration(folder = "Material", content = "../SNDefTemplate.j3sn", displayName = "#SNDefWizardIterator_displayName", iconBase = "com/jme3/gde/materialdefinition/icons/node.png", description = "../sNDef.html", scriptEngine = "freemarker"),
+@TemplateRegistration(folder = "Material", content = "../ShaderNodeSource", scriptEngine = "freemarker")
+})
+@Messages("SNDefWizardIterator_displayName=Shader Node Definition")
+public final class SNDefWizardIterator implements WizardDescriptor.InstantiatingIterator {
+
+ private int index;
+
+ private WizardDescriptor wizard;
+ private List> panels;
+
+ private List> getPanels() {
+ if (panels == null) {
+ panels = new ArrayList>();
+ // Change to default new file panel and add our panel at bottom
+ Project p = Templates.getProject(wizard);
+ SourceGroup[] groups = ProjectUtils.getSources(p).getSourceGroups(Sources.TYPE_GENERIC);
+
+ // SimpleTargetChooser is the default new file panel,
+ // Add our panel at the bottom
+ WizardDescriptor.Panel advNewFilePanel = Templates.buildSimpleTargetChooser(p, groups).create();
+ panels.add(advNewFilePanel);
+ panels.add(new SNDefWizardPanel1());
+ panels.add(new SNDefWizardPanel2("Inputs"));
+ panels.add(new SNDefWizardPanel2("Outputs"));
+ String[] steps = createSteps();
+ for (int i = 0; i < panels.size(); i++) {
+ Component c = panels.get(i).getComponent();
+ if (steps[i] == null) {
+ // 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;
+ jc.putClientProperty(WizardDescriptor.PROP_CONTENT_SELECTED_INDEX, i);
+ jc.putClientProperty(WizardDescriptor.PROP_CONTENT_DATA, steps);
+ jc.putClientProperty(WizardDescriptor.PROP_AUTO_WIZARD_STYLE, true);
+ jc.putClientProperty(WizardDescriptor.PROP_CONTENT_DISPLAYED, true);
+ jc.putClientProperty(WizardDescriptor.PROP_CONTENT_NUMBERED, true);
+ }
+ }
+ }
+ return panels;
+ }
+
+ @Override
+ public Set> instantiate() throws IOException {
+
+ FileObject createdFile = null;
+
+ // Read Title from wizard
+ // String HtmlTitle = (String) wizard.getProperty(SNDefWizardPanel1.TITLE);
+ // FreeMarker Template will get its variables from HashMap.
+ // HashMap key is the variable name.
+ SNDefVisualPanel1 panel1 = ((SNDefWizardPanel1) panels.get(1)).getComponent();
+ SNDefVisualPanel2 panel2 = ((SNDefWizardPanel2) panels.get(2)).getComponent();
+ SNDefVisualPanel2 panel3 = ((SNDefWizardPanel2) panels.get(3)).getComponent();
+
+ Map args = new HashMap();
+ args.put("defName", panel1.getDefName());
+ args.put("defType", panel1.getDefType());
+ args.put("description", panel1.getDefDescription());
+ args.put("inputParams", panel2.getData());
+ args.put("outputParams", panel3.getData());
+
+ //Get the template and convert it:
+ FileObject tplSnd = Templates.getTemplate(wizard);
+ FileObject tplShd = tplSnd.getParent().getChildren()[1];
+
+ DataObject templateSnd = DataObject.find(tplSnd);
+ DataObject templateShd = DataObject.find(tplShd);
+
+
+
+ //Get the package:
+ FileObject dir = Templates.getTargetFolder(wizard);
+ DataFolder df = DataFolder.findFolder(dir);
+
+ ProjectAssetManager assetManager = new ProjectAssetManager(Templates.getProject(wizard),"assets");
+
+ //Get the class:
+ String targetName = Templates.getTargetName(wizard);
+ String shaderName = targetName;
+ if (panel1.getDefType().equals("Fragment")) {
+ shaderName += ".frag";
+ } else if (panel1.getDefType().equals("Vertex")) {
+ shaderName += ".vert";
+ } else {
+ shaderName += ".frag";
+ }
+
+ args.put("shaderSnippet",assetManager.getRelativeAssetPath(dir.getPath()+"/"+shaderName));
+
+ //Define the template from the above,
+ //passing the package, the file name, and the map of strings to the template:
+ // DataObject dobj = templateSnd.createFromTemplate(df, targetName, args);
+
+
+ DataObject sobj = templateShd.createFromTemplate(df, shaderName, args);
+ DataObject dobj = templateSnd.createFromTemplate(df, targetName, args);
+ //Obtain a FileObject:
+ createdFile = dobj.getPrimaryFile();
+
+ // Return the created file.
+ return Collections.singleton(createdFile);
+ }
+
+ @Override
+ public void initialize(WizardDescriptor wizard) {
+ this.wizard = wizard;
+ }
+
+ @Override
+ public void uninitialize(WizardDescriptor wizard) {
+ panels = null;
+ }
+
+ @Override
+ public WizardDescriptor.Panel current() {
+ return getPanels().get(index);
+ }
+
+ @Override
+ public String name() {
+ return index + 1 + ". from " + getPanels().size();
+ }
+
+ @Override
+ public boolean hasNext() {
+ return index < getPanels().size() - 1;
+ }
+
+ @Override
+ public boolean hasPrevious() {
+ return index > 0;
+ }
+
+ @Override
+ public void nextPanel() {
+ if (!hasNext()) {
+ throw new NoSuchElementException();
+ }
+ index++;
+ }
+
+ @Override
+ public void previousPanel() {
+ if (!hasPrevious()) {
+ throw new NoSuchElementException();
+ }
+ index--;
+ }
+
+ // If nothing unusual changes in the middle of the wizard, simply:
+ @Override
+ public void addChangeListener(ChangeListener l) {
+ }
+
+ @Override
+ public void removeChangeListener(ChangeListener l) {
+ }
+ // If something changes dynamically (besides moving between panels), e.g.
+ // the number of panels changes in response to user input, then use
+ // ChangeSupport to implement add/removeChangeListener and call fireChange
+ // when needed
+
+ // You could safely ignore this method. Is is here to keep steps which were
+ // there before this wizard was instantiated. It should be better handled
+ // by NetBeans Wizard API itself rather than needed to be implemented by a
+ // client code.
+ private String[] createSteps() {
+ String[] beforeSteps = (String[]) wizard.getProperty("WizardPanel_contentData");
+ assert beforeSteps != null : "This wizard may only be used embedded in the template wizard";
+ String[] res = new String[(beforeSteps.length - 1) + panels.size()];
+ for (int i = 0; i < res.length; i++) {
+ if (i < (beforeSteps.length - 1)) {
+ res[i] = beforeSteps[i];
+ } else {
+ res[i] = panels.get(i - beforeSteps.length + 1).getComponent().getName();
+ }
+ }
+ return res;
+ }
+
+}
diff --git a/sdk/jme3-materialeditor/src/com/jme3/gde/shadernodedefinition/wizard/SNDefWizardPanel1.java b/sdk/jme3-materialeditor/src/com/jme3/gde/shadernodedefinition/wizard/SNDefWizardPanel1.java
new file mode 100644
index 000000000..98beef9fb
--- /dev/null
+++ b/sdk/jme3-materialeditor/src/com/jme3/gde/shadernodedefinition/wizard/SNDefWizardPanel1.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.shadernodedefinition.wizard;
+
+import javax.swing.event.ChangeListener;
+import org.openide.WizardDescriptor;
+import org.openide.util.HelpCtx;
+
+public class SNDefWizardPanel1 implements WizardDescriptor.Panel {
+
+ /**
+ * The visual component that displays this panel. If you need to access the
+ * component from this class, just use getComponent().
+ */
+ private SNDefVisualPanel1 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.
+ @Override
+ public SNDefVisualPanel1 getComponent() {
+ if (component == null) {
+ component = new SNDefVisualPanel1();
+ }
+ return component;
+ }
+
+ @Override
+ public HelpCtx getHelp() {
+ // Show no Help button for this panel:
+ return HelpCtx.DEFAULT_HELP;
+ // If you have context help:
+ // return new HelpCtx("help.key.here");
+ }
+
+ @Override
+ 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...) and
+ // this condition changes (last form field filled in...) then
+ // use ChangeSupport to implement add/removeChangeListener below.
+ // WizardDescriptor.ERROR/WARNING/INFORMATION_MESSAGE will also be useful.
+ }
+
+ @Override
+ public void addChangeListener(ChangeListener l) {
+ }
+
+ @Override
+ public void removeChangeListener(ChangeListener l) {
+ }
+
+ @Override
+ public void readSettings(WizardDescriptor wiz) {
+ // use wiz.getProperty to retrieve previous panel state
+ }
+
+ @Override
+ public void storeSettings(WizardDescriptor wiz) {
+ // use wiz.putProperty to remember current panel state
+ }
+
+}
diff --git a/sdk/jme3-materialeditor/src/com/jme3/gde/shadernodedefinition/wizard/SNDefWizardPanel2.java b/sdk/jme3-materialeditor/src/com/jme3/gde/shadernodedefinition/wizard/SNDefWizardPanel2.java
new file mode 100644
index 000000000..ae68c8d1c
--- /dev/null
+++ b/sdk/jme3-materialeditor/src/com/jme3/gde/shadernodedefinition/wizard/SNDefWizardPanel2.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.shadernodedefinition.wizard;
+
+import javax.swing.event.ChangeListener;
+import org.openide.WizardDescriptor;
+import org.openide.util.HelpCtx;
+
+public class SNDefWizardPanel2 implements WizardDescriptor.Panel {
+
+ /**
+ * The visual component that displays this panel. If you need to access the
+ * component from this class, just use getComponent().
+ */
+ private SNDefVisualPanel2 component;
+ private final String type;
+
+ public SNDefWizardPanel2(String type) {
+ this.type = type;
+ }
+
+ // 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.
+ @Override
+ public SNDefVisualPanel2 getComponent() {
+ if (component == null) {
+ component = new SNDefVisualPanel2(type);
+ }
+ return component;
+ }
+
+ @Override
+ public HelpCtx getHelp() {
+ // Show no Help button for this panel:
+ return HelpCtx.DEFAULT_HELP;
+ // If you have context help:
+ // return new HelpCtx("help.key.here");
+ }
+
+ @Override
+ 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...) and
+ // this condition changes (last form field filled in...) then
+ // use ChangeSupport to implement add/removeChangeListener below.
+ // WizardDescriptor.ERROR/WARNING/INFORMATION_MESSAGE will also be useful.
+ }
+
+ @Override
+ public void addChangeListener(ChangeListener l) {
+ }
+
+ @Override
+ public void removeChangeListener(ChangeListener l) {
+ }
+
+ @Override
+ public void readSettings(WizardDescriptor wiz) {
+ // use wiz.getProperty to retrieve previous panel state
+ }
+
+ @Override
+ public void storeSettings(WizardDescriptor wiz) {
+ // use wiz.putProperty to remember current panel state
+ }
+
+}
diff --git a/sdk/jme3-materialeditor/src/com/jme3/gde/shadernodedefinition/wizard/sNDef.html b/sdk/jme3-materialeditor/src/com/jme3/gde/shadernodedefinition/wizard/sNDef.html
new file mode 100644
index 000000000..7996c72b7
--- /dev/null
+++ b/sdk/jme3-materialeditor/src/com/jme3/gde/shadernodedefinition/wizard/sNDef.html
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+