Browse Source

Fix Regression introduced in ca6afbbe0efa9336482442adf8bc4229095528de (Forgot to commit the renamed, deleted and added files as they are ordered like that in my Git UI)

MeFisto94 6 years ago
parent
commit
168ba73b98

+ 111 - 62
jme3-materialeditor/src/com/jme3/gde/materialdefinition/editor/Dot.java → jme3-materialeditor/src/com/jme3/gde/materialdefinition/editor/ConnectionEndpoint.java

@@ -1,12 +1,38 @@
 /*
- * To change this template, choose Tools | Templates
- * and open the template in the editor.
+ *  Copyright (c) 2009-2018 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.materialdefinition.editor;
 
 import com.jme3.gde.materialdefinition.icons.Icons;
 import com.jme3.shader.Shader;
-import com.jme3.shader.ShaderUtils;
 import java.awt.Component;
 import java.awt.Dimension;
 import java.awt.Graphics;
@@ -18,19 +44,17 @@ import javax.swing.SwingUtilities;
 import javax.swing.event.MouseInputListener;
 
 /**
- *
+ * The ConnectionEndpoint class represents an Endpoint of a {@link Connection}
  * @author Nehon
  */
-public class Dot extends JPanel implements MouseInputListener {
-
+public abstract class ConnectionEndpoint extends JPanel implements MouseInputListener {
     public static boolean pressed = false;
     protected ImageIcon img;
     protected ImageIcon prevImg;
     private String type;
-    private ParamType paramType;
-    protected Shader.ShaderType shaderType;
+    protected ParamType paramType;
     private String text = "";
-    private DraggablePanel node;
+    protected DraggablePanel node;
     private int index = 1;
 
     public String getText() {
@@ -48,7 +72,7 @@ public class Dot extends JPanel implements MouseInputListener {
     }
 
     @SuppressWarnings("LeakingThisInConstructor")
-    public Dot() {
+    public ConnectionEndpoint() {
         super();
         setMaximumSize(new Dimension(10, 10));
         setMinimumSize(new Dimension(10, 10));
@@ -58,31 +82,25 @@ public class Dot extends JPanel implements MouseInputListener {
         addMouseListener(this);
        
     }
-    
-    public void setShaderType(Shader.ShaderType shaderType){
-         this.shaderType = shaderType;
-    }
+
 
     @Override
     protected void paintComponent(Graphics g) {
         if (img == null) {
-
             img = Icons.imgGrey;
         }
         g.drawImage(img.getImage(), 0, 0, this);
     }
 
     @Override
-    public void mouseClicked(MouseEvent e) {
-    }
+    public void mouseClicked(MouseEvent e) {}
 
     @Override
     public void mousePressed(MouseEvent e) {
-        prevImg = img;
-        img = Icons.imgOrange;
         Diagram diag = getDiagram();
         diag.draggedFrom = this;
-        repaint();
+        prevImg = img;
+        setIcon(Icons.imgOrange);
         e.consume();
     }
 
@@ -95,14 +113,26 @@ public class Dot extends JPanel implements MouseInputListener {
         }
     }
 
+    /**
+     * Returns the Diagram (the surface containing all the nodes and curves)
+     * @return the diagram
+     */
     public Diagram getDiagram() {
         return node.getDiagram();
     }
 
+    /**
+     * Returns the Node this ConnectionEndpoint belongs to
+     * @return the node
+     */
     public DraggablePanel getNode() {
         return node;
     }
 
+    /**
+     * Sets the Node this ConnectionEndpoint belongs to
+     * @param node the node
+     */
     public void setNode(DraggablePanel node) {
         this.node = node;
     }
@@ -127,14 +157,27 @@ public class Dot extends JPanel implements MouseInputListener {
         e.consume();
     }
 
-    public void reset() {
-        img = prevImg;
+    /**
+     * Changes the look of this connector. Implies repainting
+     * @param icon The Icon to use
+     */
+    public void setIcon(ImageIcon icon) {
+        img = icon;
         repaint();
     }
+    
+    /**
+     * Resets the Icon to be the previous image.
+     */
+    public void reset() {
+        setIcon(prevImg);
+    }
 
+    /**
+     * Changes the Icon to the disconnect state.
+     */
     public void disconnect() {
-        img = Icons.imgGrey;
-        repaint();
+        setIcon(Icons.imgGrey);
     }
 
     @Override
@@ -149,49 +192,36 @@ public class Dot extends JPanel implements MouseInputListener {
 
     }
 
-    public boolean canConnect(Dot pair) {
-        
-        if (pair == null || paramType == ParamType.Input || 
-                 ((pair.getNode() instanceof OutBusPanel || node instanceof OutBusPanel) && shaderType != pair.shaderType)) {
-            img = Icons.imgOrange;
-            repaint();
+    /**
+     * Determines whether this dot can form a {@link Connection} with the other
+     * specified dot. Subclasses should only override this, when they want to
+     * change the icon behavior because otherwise the logic like not connecting
+     * input to input has to be replicated as well. It is preferred to 
+     * implement {@link #allowConnection(com.jme3.gde.materialdefinition.editor.ConnectionEndpoint) }
+     * instead.
+     * 
+     * @param pair The other dot to form a connection with
+     * @return Whether the dots can be connected
+     */
+    public boolean canConnect(ConnectionEndpoint pair) {
+        // cannot connect to: nothing || input panels ||
+        if (pair == null || paramType == ParamType.Input) {
+            setIcon(Icons.imgOrange);
             return false;
-        }
-
-        
-        if (matches(pair.getType(), type) && (pair.getParamType() != paramType
-                || pair.getParamType() == ParamType.Both
-                || paramType == ParamType.Both)
-                || ShaderUtils.isSwizzlable(pair.getType()) && ShaderUtils.isSwizzlable(type)) {
-            img = Icons.imgGreen;
-            repaint();
+        } else if (allowConnection(pair)) {
+            setIcon(Icons.imgGreen);
             return true;
+        } else {
+            setIcon(Icons.imgRed);
+            return false;
         }
-
-
-        img = Icons.imgRed;
-        repaint();
-        return false;
-    }
-
-    private boolean matches(String type1, String type2) {
-        String[] s1 = type1.split("\\|");
-        String[] s2 = type2.split("\\|");
-        for (String string : s1) {
-            for (String string1 : s2) {
-                if (string.equals(string1)) {
-                    return true;
-                }
-            }
-        }
-        return false;
-
     }
+    
+    protected abstract boolean allowConnection(ConnectionEndpoint pair);
 
     protected void connect(Connection connection) {
-        img = Icons.imgGreen;
         getNode().addComponentListener(connection);
-        repaint();
+        setIcon(Icons.imgGreen);
     }
 
     @Override
@@ -241,9 +271,9 @@ public class Dot extends JPanel implements MouseInputListener {
     }
 
     @Override
-    public void mouseMoved(MouseEvent e) {
-    }
+    public void mouseMoved(MouseEvent e) {}
 
+    // This is implementation specific...
     public String getType() {
         return type;
     }
@@ -252,19 +282,38 @@ public class Dot extends JPanel implements MouseInputListener {
         this.type = type;
     }
 
+    /**
+     * Returns the parameter type
+     * @return the paramtype 
+     */
     public ParamType getParamType() {
         return paramType;
     }
 
+    /**
+     * Sets the parameter type (if this dot is Input, Output or Both)
+     * @param paramType The parameter type
+     */
     public void setParamType(ParamType paramType) {
         this.paramType = paramType;
     }
 
+    /**
+     * The Index is the "y-position" of this dot in the parental node.
+     * The index is multiplied by an offset to generate the position
+     * @return The index of this dot on the node
+     */
     public int getIndex() {
         return index;
     }
 
+    /**
+     * The Index is the "y-position" of this dot in the parental node.
+     * The index is multiplied by an offset to generate the position
+     * @param index The index of this dot on the node
+     */
     public void setIndex(int index) {
         this.index = index;
     }
+
 }

+ 88 - 0
jme3-materialeditor/src/com/jme3/gde/materialdefinition/editor/NodeEditor.java

@@ -0,0 +1,88 @@
+/*
+ *  Copyright (c) 2009-2018 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.materialdefinition.editor;
+
+import java.awt.Point;
+
+/**
+ * The Top Component (the one containing the diagram) has to implement this
+ * interface.
+ * @author MeFisto94
+ */
+public interface NodeEditor {
+    
+    /**
+     * Load the position of the given node (by key) from the meta data. That
+     * enables saving the node layout inbetween uses.
+     * @param key The key/nodeId
+     * @param defaultx The default x position (if key is not found)
+     * @param defaulty The default y position (if key is not found)
+     * @return The position on the screen
+     * @throws NumberFormatException if the metadata contained invalid integers
+     */
+    Point getPositionFromMetaData(String key, int defaultx, int defaulty) throws NumberFormatException;
+    
+    /**
+     * Save the position of the given node (by key) from the meta data. That
+     * enables saving the node layout inbetween uses.
+     * @param key The key/nodeId
+     * @param x The X Position
+     * @param y The Y Position
+     */
+    void savePositionToMetaData(String key, int x, int y);
+    
+    /**
+     * Transfer the UI Mapping to the Model part of your editor, that means:
+     * apply the new connection to the underlying structures
+     * @param conn The connection which has been formed
+     */
+    void makeMapping(Connection conn);
+    
+    /**
+     * The connection has been removed, unlink it again
+     * @param conn The connection which used to be
+     */
+    void notifyRemoveConnection(Connection conn);
+    
+    /**
+     * Called when a node has been removed from the diagram
+     * @param node the node
+     */
+    void notifyRemoveNode(NodePanel node);
+    
+    /**
+     * Called when a node/connection has been selected. Use this to change the
+     * Properties Dialog and others.
+     * @param selectable The selected item
+     */
+    void selectionChanged(Selectable selectable);
+}

+ 492 - 0
jme3-materialeditor/src/com/jme3/gde/materialdefinition/editor/ShaderNodeDiagram.java

@@ -0,0 +1,492 @@
+/*
+ *  Copyright (c) 2009-2018 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.materialdefinition.editor;
+
+import com.jme3.gde.core.assets.ProjectAssetManager;
+import com.jme3.gde.materialdefinition.dialog.AddAttributeDialog;
+import com.jme3.gde.materialdefinition.dialog.AddMaterialParameterDialog;
+import com.jme3.gde.materialdefinition.dialog.AddNodeDialog;
+import com.jme3.gde.materialdefinition.dialog.AddWorldParameterDialog;
+import com.jme3.gde.materialdefinition.editor.ShaderNodePanel.NodeType;
+import com.jme3.gde.materialdefinition.fileStructure.ShaderNodeBlock;
+import com.jme3.gde.materialdefinition.fileStructure.leaves.MappingBlock;
+import com.jme3.gde.materialdefinition.icons.Icons;
+import com.jme3.gde.materialdefinition.utils.MaterialUtils;
+import com.jme3.material.Material;
+import com.jme3.shader.Shader;
+//import static com.jme3.gde.materialdefinition.editor.ShaderNodePanel.NodeType;
+import com.jme3.shader.ShaderNodeDefinition;
+import com.jme3.shader.ShaderNodeVariable;
+import com.jme3.shader.UniformBinding;
+import com.jme3.shader.VarType;
+import java.awt.Point;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ComponentEvent;
+import java.awt.event.ComponentListener;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseMotionListener;
+import java.util.ArrayList;
+import java.util.List;
+import javax.swing.JMenuItem;
+import javax.swing.JViewport;
+import javax.swing.SwingUtilities;
+
+/**
+ * The Diagram is the main canvas where all nodes {@link DraggablePanel} and
+ * their connections {@link ConnectionEndpoint} {@link Connection} are added onto.
+ * @author Nehon
+ */
+public class ShaderNodeDiagram extends Diagram implements
+        MouseMotionListener, ComponentListener {
+
+    protected List<ShaderOutBusPanel> outBuses = new ArrayList<ShaderOutBusPanel>();
+    private String currentTechniqueName;
+    private final BackdropPanel backDrop = new BackdropPanel();
+    private final Point pp = new Point();
+
+    @SuppressWarnings("LeakingThisInConstructor")
+    public ShaderNodeDiagram() {
+        addMouseListener(this);
+        addMouseMotionListener(this);
+        createPopupMenu();
+    }
+    
+    @Override
+    protected boolean mouseLMBPrePressedEvent(MouseEvent e) {
+        for (ShaderOutBusPanel outBusPanel : outBuses) {
+            Point p = SwingUtilities.convertPoint(this, e.getX(), e.getY(), outBusPanel);
+            if (outBusPanel.contains(p)) {
+                MouseEvent me = SwingUtilities.convertMouseEvent(this, e, outBusPanel);
+                outBusPanel.dispatchEvent(me);
+                if (me.isConsumed()) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+    
+    @Override
+    public void mouseReleased(MouseEvent e) {
+        if (SwingUtilities.isLeftMouseButton(e)) {
+            if (draggedFrom != null && draggedFrom.getNode() instanceof ShaderOutBusPanel) {
+                MouseEvent me = SwingUtilities.convertMouseEvent(this, e, draggedFrom.getNode());
+                draggedFrom.getNode().dispatchEvent(me);
+                if (me.isConsumed()) {
+                    return;
+                }
+            }
+
+            dispatchToOutBuses(e);
+        } else {
+            super.mouseReleased(e); // Handle all the UI Stuff
+        }
+
+    }
+    
+    @Override
+    public void mouseMoved(MouseEvent e) {
+        super.mouseMoved(e);
+        dispatchToOutBuses(e);
+    }
+    
+    @Override
+    public void mouseDragged(MouseEvent e) {
+        if (SwingUtilities.isLeftMouseButton(e)) {
+            if (draggedFrom == null) {
+                for (Selectable selectedItem : selectedItems) {
+                    if (selectedItem instanceof ShaderOutBusPanel) {
+                        ShaderOutBusPanel bus = (ShaderOutBusPanel) selectedItem;
+                        MouseEvent me = SwingUtilities.convertMouseEvent(this, e, bus);
+                        bus.dispatchEvent(me);
+                    }
+                }
+            }
+        } else {
+            super.mouseDragged(e); // Handle all the UI Stuff
+        }
+    }
+
+    /**
+     * Called by {@link ConnectionEndpoint} when a Curve has been dragged
+     */
+    @Override
+    protected void draggingDot(MouseEvent e) {
+        for (ShaderOutBusPanel outBusPanel: outBuses) {
+            Point p = SwingUtilities.convertPoint(this, e.getX(), e.getY(), outBusPanel);
+            if (outBusPanel.contains(p)) {
+                MouseEvent me = SwingUtilities.convertMouseEvent(this, e, outBusPanel);
+                outBusPanel.draggingDot(me);
+                if (me.isConsumed()) {
+                    return;
+                }
+            }
+        }
+    }
+    
+    
+    public void refreshPreviews(Material mat, String technique) {
+        for (ShaderOutBusPanel outBusPanel : outBuses) {
+            outBusPanel.updatePreview(mat, technique);
+        }
+        if (backDrop.isVisible()) {
+            backDrop.showMaterial(mat, technique);
+        }
+    }
+
+    public void displayBackdrop() {
+        if (backDrop.getParent() == null) {
+            add(backDrop);
+            ((JViewport)getParent()).addChangeListener(backDrop);
+        }
+
+        backDrop.setVisible(true);
+        backDrop.update(((JViewport)getParent()));
+    }
+    
+    public void setCurrentTechniqueName(String currentTechniqueName) {
+        this.currentTechniqueName = currentTechniqueName;
+    }
+
+    public String getCurrentTechniqueName() {
+        return currentTechniqueName;
+    }
+
+    @Override
+    public void addConnection(Connection conn) {
+        super.addConnection(conn);
+        
+        // Adjust outBuses and repaint again
+        for (ShaderOutBusPanel bus : outBuses) {
+            setComponentZOrder(bus, getComponentCount() - 1);
+        }
+        repaint();
+    }
+    
+    @Override
+    protected void showEdit(NodePanel node) {
+        if (node instanceof ShaderNodePanel &&
+                parent instanceof MatDefEditorlElement) {
+            ((MatDefEditorlElement)parent).showShaderEditor(node.getName(), 
+                    ((ShaderNodePanel)node).getType(), 
+                    ((ShaderNodePanel)node).filePaths);
+        }
+    }
+
+    @Override
+    public void addNode(NodePanel node) {
+        super.addNode(node);
+        if (node instanceof ShaderNodePanel) {
+            ((ShaderNodePanel)node).setTechName(currentTechniqueName);
+        }
+    }
+
+    public void addOutBus(ShaderOutBusPanel bus) {
+        outBuses.add(bus);
+        bus.setDiagram(this);
+        add(bus);
+        setComponentZOrder(bus, getComponentCount() - 1);
+        addComponentListener(bus);
+        bus.componentResized(new ComponentEvent(this, ActionEvent.ACTION_PERFORMED));
+        bus.revalidate();
+    }
+
+    private String fixNodeName(String name) {
+        return fixNodeName(name, 0);
+    }
+
+    private String fixNodeName(String name, int count) {
+        for (NodePanel nodePanel : nodes) {
+            if ((name + (count == 0 ? "" : count)).equals(nodePanel.getName())) {
+                return fixNodeName(name, count + 1);
+            }
+        }
+        return name + (count == 0 ? "" : count);
+    }
+    
+    public void addNodesFromDefs(List<ShaderNodeDefinition> defList, String path, Point clickPosition) {
+        int i = 0;
+        for (ShaderNodeDefinition def : defList) {
+            ShaderNodeBlock sn = new ShaderNodeBlock(def, path);
+            sn.setName(fixNodeName(sn.getName()));
+            NodePanel np = new ShaderNodePanel(sn, def);
+            addNode(np);
+            np.setLocation(clickPosition.x + i * 150, clickPosition.y);
+            sn.setSpatialOrder(np.getLocation().x);
+            i++;
+            np.revalidate();
+            ((MatDefEditorlElement)getEditorParent()).notifyAddNode(sn, def);
+        }
+        repaint();
+    }
+
+    public void addMatParam(String type, String name, Point point) {
+        String fixedType = type;
+        if (type.equals("Color")) {
+            fixedType = "Vector4";
+        }
+        ShaderNodeVariable param = new ShaderNodeVariable(VarType.valueOf(fixedType).getGlslType(), name);
+        NodePanel np = new ShaderNodePanel(param, NodeType.MatParam);
+        addNode(np);
+        np.setLocation(point.x, point.y);
+        np.revalidate();
+        repaint();
+        ((MatDefEditorlElement)getEditorParent()).notifyAddMapParam(type, name);
+    }
+
+    public void addWorldParam(UniformBinding binding, Point point) {
+        ShaderNodeVariable param = new ShaderNodeVariable(binding.getGlslType(), binding.name());
+        NodePanel np = new ShaderNodePanel(param, NodeType.WorldParam);
+        addNode(np);
+        np.setLocation(point.x, point.y);
+        np.revalidate();
+        repaint();
+        ((MatDefEditorlElement)getEditorParent()).notifyAddWorldParam(binding.name());
+    }
+
+    public void addAttribute(String name, String type, Point point) {
+        ShaderNodeVariable param = new ShaderNodeVariable(type, "Attr", name);
+        NodePanel np = new ShaderNodePanel(param, NodeType.Attribute);
+        addNode(np);
+        np.setLocation(point.x, point.y);
+        np.revalidate();
+        repaint();
+    }
+
+    @Override
+    public String makeKeyForConnection(Connection con, Object obj) {
+        return MaterialUtils.makeKey((MappingBlock)obj, currentTechniqueName);
+    }
+
+    /**
+     * Find a OutBusPanel which corresponds to the given key (unique id). 
+     * Use this to locate busses on the diagram
+     * 
+     * @param key The key
+     * @return hopefully the correct panel
+     */
+    public ShaderOutBusPanel getOutBusPanel(String key) {
+        for (ShaderOutBusPanel out : outBuses) {
+            if (out.getKey().equals(key)) {
+                return out;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    protected Selectable trySelect(String key) {
+        for (ShaderOutBusPanel outBusPanel : outBuses) {
+            if (outBusPanel.getKey().equals(key)) {
+                return outBusPanel;
+            }
+        }
+        
+        return null;
+    }
+    
+    @Override
+    public void clear() {
+        super.clear();
+        outBuses.clear();
+    }
+
+    @Override
+    protected void createPopupMenu() {
+        super.createPopupMenu();
+
+        JMenuItem nodeItem = createMenuItem("Node", Icons.node);
+        nodeItem.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                AddNodeDialog d = new AddNodeDialog(null, true, 
+                        ((MatDefEditorlElement)parent).obj.getLookup()
+                            .lookup(ProjectAssetManager.class), 
+                    ShaderNodeDiagram.this, clickLoc);
+                d.setLocationRelativeTo(null);
+                d.setVisible(true);
+            }
+        });
+
+        contextMenu.add(nodeItem);
+        contextMenu.add(createSeparator());
+        JMenuItem matParamItem = createMenuItem("Material Parameter", Icons.mat);
+        matParamItem.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                AddMaterialParameterDialog d = new AddMaterialParameterDialog(null, true, ShaderNodeDiagram.this, clickLoc);
+                d.setLocationRelativeTo(null);
+                d.setVisible(true);
+            }
+        });
+        contextMenu.add(matParamItem);
+        JMenuItem worldParamItem = createMenuItem("World Parameter", Icons.world);
+        worldParamItem.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                AddWorldParameterDialog d = new AddWorldParameterDialog(null, true, ShaderNodeDiagram.this, clickLoc);
+                d.setLocationRelativeTo(null);
+                d.setVisible(true);
+            }
+        });
+        contextMenu.add(worldParamItem);
+        JMenuItem attributeItem = createMenuItem("Attribute", Icons.attrib);
+        attributeItem.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                AddAttributeDialog d = new AddAttributeDialog(null, true, ShaderNodeDiagram.this, clickLoc);
+                d.setLocationRelativeTo(null);
+                d.setVisible(true);
+            }
+        });
+        contextMenu.add(attributeItem);
+        contextMenu.add(createSeparator());
+        JMenuItem outputItem = createMenuItem("Output color", Icons.output);
+        contextMenu.add(outputItem);
+        outputItem.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                ShaderOutBusPanel p2 = new ShaderOutBusPanel("color" + (outBuses.size() - 1), Shader.ShaderType.Fragment);
+                p2.setBounds(0, 350 + 50 * (outBuses.size() - 1), p2.getWidth(), p2.getHeight());
+
+                addOutBus(p2);
+
+            }
+        });
+    }
+
+    private void dispatchToOutBuses(MouseEvent e) {
+        for (ShaderOutBusPanel outBusPanel : outBuses) {
+            Point p = SwingUtilities.convertPoint(this, e.getX(), e.getY(), outBusPanel);
+            if (outBusPanel.contains(p)) {
+                MouseEvent me = SwingUtilities.convertMouseEvent(this, e, outBusPanel);
+                outBusPanel.dispatchEvent(me);
+                if (me.isConsumed()) {
+                    return;
+                }
+            }
+        }
+    }
+
+    @Override
+    protected int calcMaxWidth() {
+        int maxHeight = 0;
+        for (ShaderOutBusPanel outBusPanel : outBuses) {
+            int h = outBusPanel.getLocation().y + outBusPanel.getHeight();
+            if (h > maxHeight) {
+                maxHeight = h;
+            }
+        }
+        return maxHeight;
+    }
+    
+    @Override
+    protected int calcMaxHeight() {
+        return 0;
+    }
+    
+    int minWidth = 0;
+    int minHeight = 0;
+
+    @Override
+    public void autoLayout() {
+
+        int offset = 550;
+        for (ShaderOutBusPanel outBus : outBuses) {
+            if (outBus.getKey().equalsIgnoreCase("position")) {
+                outBus.setLocation(0, 100);
+                
+            } else {
+                outBus.setLocation(0, offset);
+                offset += 260;
+            }
+            getEditorParent().savePositionToMetaData(outBus.getKey(), outBus.getLocation().x, outBus.getLocation().y);
+        }
+        offset = 0;
+        String keys = "";
+        for (NodePanel nodeP: nodes) {
+            ShaderNodePanel node;
+            if (nodeP instanceof ShaderNodePanel) {
+                node = (ShaderNodePanel)nodeP;
+            } else {
+                continue; // Don't layout foreign nodes, actually they shouldnt
+                // even be there...
+            }
+            if (node.getType() == NodeType.Vertex || node.getType() == NodeType.Fragment) {
+                node.setLocation(offset + 200, getNodeTop(node));
+                getEditorParent().savePositionToMetaData(node.getKey(), node.getLocation().x, node.getLocation().y);
+                int pad = getNodeTop(node);
+                for (Connection connection: connections) {
+                    if (connection.getEnd().getNode() == node) {
+                        if (connection.getStart().getNode() instanceof ShaderNodePanel) {
+                            ShaderNodePanel startP = (ShaderNodePanel)connection.getStart().getNode();
+                            if (startP.getType() != NodeType.Vertex && startP.getType() != NodeType.Fragment) {
+                                startP.setLocation(offset + 30, pad);
+                                getEditorParent().savePositionToMetaData(startP.getKey(), startP.getLocation().x, startP.getLocation().y);
+                                keys += startP.getKey() + "|";
+                                pad += 50;
+                            }
+                        }
+                    }
+                }
+            }
+            offset += 320;
+        }
+        offset = 0;
+        for (NodePanel nodeP: nodes) {
+            ShaderNodePanel node;
+            if (nodeP instanceof ShaderNodePanel) {
+                node = (ShaderNodePanel)nodeP;
+            } else {
+                continue; // Don't layout foreign nodes, actually they shouldnt
+                // even be there...
+            }
+            if (node.getType() != NodeType.Vertex && node.getType() != NodeType.Fragment && !(keys.contains(node.getKey()))) {
+                node.setLocation(offset + 10, 0);
+                getEditorParent().savePositionToMetaData(node.getKey(), node.getLocation().x, node.getLocation().y);
+                offset += 130;
+            }
+        }
+    }
+
+    private int getNodeTop(ShaderNodePanel node) {
+        if (node.getType() == NodeType.Vertex) {
+            return 150;
+        }
+        if (node.getType() == NodeType.Fragment) {
+            return 400;
+        }
+        return 0;
+
+    }
+}

+ 102 - 0
jme3-materialeditor/src/com/jme3/gde/materialdefinition/editor/ShaderNodeDot.java

@@ -0,0 +1,102 @@
+/*
+ *  Copyright (c) 2009-2018 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.materialdefinition.editor;
+
+import com.jme3.gde.materialdefinition.icons.Icons;
+import com.jme3.shader.Shader;
+import com.jme3.shader.ShaderUtils;
+
+/**
+ * This is the input/ouput connector of a ShaderNode.
+ * @author MeFisto94
+ */
+public class ShaderNodeDot extends ConnectionEndpoint {
+    protected Shader.ShaderType shaderType;
+    
+        
+    public void setShaderType(Shader.ShaderType shaderType){
+         this.shaderType = shaderType;
+    }
+    
+    @Override
+    public boolean canConnect(ConnectionEndpoint pair) {
+        // One is at least outBus but the shaderType doesn't match
+        if (pair != null && pair instanceof ShaderNodeDot &&
+                (pair.getNode() instanceof ShaderOutBusPanel || 
+                    node instanceof ShaderOutBusPanel) && 
+                    shaderType != ((ShaderNodeDot)pair).shaderType) {
+            setIcon(Icons.imgOrange);
+            return false;
+        }
+        
+        // cannot connect to: nothing || input panels ||
+        if (pair == null || paramType == ParamType.Input) {
+            setIcon(Icons.imgOrange);
+            return false;
+        } else if (allowConnection(pair)) {
+            setIcon(Icons.imgGreen);
+            return true;
+        } else {
+            setIcon(Icons.imgRed);
+            return false;
+        }
+    }
+    
+    @Override
+    protected boolean allowConnection(ConnectionEndpoint pair) {
+        return matches(pair.getType(), getType()) && (pair.getParamType() != getParamType()
+            || pair.getParamType() == ParamType.Both
+            || getParamType() == ParamType.Both)
+            || ShaderUtils.isSwizzlable(pair.getType())
+            && ShaderUtils.isSwizzlable(getType());
+    }
+    
+    /**
+     * This method checks if any of the both strings contain the same substring
+     * seperated by \|
+     * @param type1 The Typelist 1
+     * @param type2 The Typelist 2
+     * @return whether they contain the same substring
+     */
+    private boolean matches(String type1, String type2) {
+        String[] s1 = type1.split("\\|");
+        String[] s2 = type2.split("\\|");
+        for (String string : s1) {
+            for (String string1 : s2) {
+                if (string.equals(string1)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+}

+ 235 - 0
jme3-materialeditor/src/com/jme3/gde/materialdefinition/editor/ShaderNodePanel.java

@@ -0,0 +1,235 @@
+/*
+ *  Copyright (c) 2009-2018 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.materialdefinition.editor;
+
+import com.jme3.gde.materialdefinition.fileStructure.ShaderNodeBlock;
+import com.jme3.gde.materialdefinition.fileStructure.leaves.DefinitionBlock;
+import com.jme3.gde.materialdefinition.icons.Icons;
+import com.jme3.shader.Shader;
+import com.jme3.shader.ShaderNodeDefinition;
+import com.jme3.shader.ShaderNodeVariable;
+import java.awt.Color;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.util.ArrayList;
+import java.util.List;
+import javax.swing.JLabel;
+import org.openide.util.WeakListeners;
+
+/**
+ * The ShaderNodePanel is the ShaderNode specific implementation of 
+ * {@link NodePanel}. 
+ * @author MeFisto94
+ */
+public class ShaderNodePanel extends NodePanel implements PropertyChangeListener {
+    private NodeType type = NodeType.Vertex;
+    protected Shader.ShaderType shaderType;
+    // The Name of the currently active Technique
+    private String techName;
+    // Required for the Editor
+    protected List<String> filePaths = new ArrayList<String>();
+    
+    public enum NodeType {
+        Vertex(new Color(220, 220, 70)),//yellow
+        Fragment(new Color(114, 200, 255)),//bleue
+        Attribute(Color.WHITE),
+        MatParam(new Color(70, 220, 70)),//green
+        WorldParam(new Color(220, 70, 70)); //red
+        private Color color;
+
+        private NodeType() {
+        }
+
+        private NodeType(Color color) {
+            this.color = color;
+        }
+
+        public Color getColor() {
+            return color;
+        }
+    }
+
+    public ShaderNodePanel(ShaderNodeBlock node, ShaderNodeDefinition def) {
+        super();
+        
+        shaderType = def.getType();
+        if (shaderType == Shader.ShaderType.Vertex) {
+            type = NodeType.Vertex;
+        } else {
+            type = NodeType.Fragment;
+        }
+        
+        node.addPropertyChangeListener(WeakListeners.propertyChange(this, node));
+        this.addPropertyChangeListener(WeakListeners.propertyChange(node, this));
+        
+        init(def.getInputs(), def.getOutputs());
+        setToolbar(new ShaderNodeToolBar(this));
+        refresh(node);
+        
+        filePaths.addAll(def.getShadersPath());
+        String defPath = ((DefinitionBlock)node.getContents().get(0)).getPath();
+        filePaths.add(defPath);    
+    }
+
+    public ShaderNodePanel(ShaderNodeVariable singleOut, NodeType type) {
+        super();
+        this.type = type;
+        List<ShaderNodeVariable> outputs = new ArrayList<ShaderNodeVariable>();
+        outputs.add(singleOut);
+        init(new ArrayList<ShaderNodeVariable>(), outputs);
+        setToolbar(new ShaderNodeToolBar(this));
+    }
+    
+    private void init(List<ShaderNodeVariable> inputs, List<ShaderNodeVariable> outputs) {
+        setBounds(0, 0, 120, 30 + inputs.size() * 20 + outputs.size() * 20);
+
+        for (ShaderNodeVariable input : inputs) {
+            JLabel label = createLabel(input.getType(), input.getName(), ConnectionEndpoint.ParamType.Input);
+            ConnectionEndpoint dot = createConnectionEndpoint(input.getType(), ConnectionEndpoint.ParamType.Input, input.getName());
+            inputLabels.add(label);
+            inputDots.add(dot);
+        }
+        int index = 0;
+        for (ShaderNodeVariable output : outputs) {
+            String outName = output.getName();
+            JLabel label = createLabel(output.getType(), outName, ConnectionEndpoint.ParamType.Output);
+            ConnectionEndpoint dot = createConnectionEndpoint(output.getType(), ConnectionEndpoint.ParamType.Output, outName);
+            dot.setIndex(index++);
+            outputLabels.add(label);
+            outputDots.add(dot);
+        }
+
+        initComponents();
+        updateType();
+        setOpaque(false);
+    }
+
+    @Override
+    public void propertyChange(PropertyChangeEvent evt) {
+        if (evt.getPropertyName().equals("name")) {
+            refresh((ShaderNodeBlock) evt.getSource());
+        }
+    }
+    
+    @Override
+    /**
+     * Keys are important for Selectable
+     */
+    public String getKey() {
+        switch (type) {
+            case Attribute:
+                return "Attr." + outputLabels.get(0).getText();
+            case WorldParam:
+                return "WorldParam." + outputLabels.get(0).getText();
+            case MatParam:
+                return "MatParam." + outputLabels.get(0).getText();
+            default:
+                return techName + "/" + name;
+        }
+    }
+    
+    public NodeType getType() {
+        return type;
+    }
+    
+    public void setTechName(String techName) {
+        this.techName = techName;
+    }
+    
+    /**
+     * This methods is responsible for setting the correct icon and text
+     * in the header-bar of the node. Call this from your constructor,
+     * _after_ components have been inited.
+     */
+    protected void updateType() {
+        switch (type) {
+            case Vertex:
+                header.setIcon(Icons.vert);
+                break;
+            case Fragment:
+                header.setIcon(Icons.frag);
+                break;
+            case Attribute:
+                header.setIcon(Icons.attrib);
+                setNameAndTitle("Attribute"); // sets text _and_ tooltip the same
+                break;
+            case WorldParam:
+                header.setIcon(Icons.world);
+                setNameAndTitle("WorldParam");
+                break;
+            case MatParam:
+                header.setIcon(Icons.mat);
+                setNameAndTitle("MatParam");
+                break;
+        }
+        color = type.getColor();
+    }
+    
+    /**
+     * Utility method to update the node text when the underlying ShaderNode
+     * has been changed (called by PropertyChangeListeners)
+     * @param node The source shadernode
+     */
+    protected final void refresh(ShaderNodeBlock node) {
+        setNameAndTitle(node.getName());
+    }
+    
+    @Override
+    protected boolean canEdit() {
+        return (type == NodeType.Fragment || type == NodeType.Vertex);
+    }
+    
+    /**
+     * Create a Label for a given ShaderNodes' Input/Output
+     * @param glslType The Type (class) of this variable
+     * @param txt The Name of this variable
+     * @param type Whether this is the input or output
+     * @return The IO Label
+     */
+    protected JLabel createLabel(String glslType, String txt, ConnectionEndpoint.ParamType type) {
+        JLabel label = super.createLabel(txt, type);
+        label.setToolTipText(glslType + " " + txt);
+        return label;
+    }
+    
+    @Override
+    public ConnectionEndpoint createConnectionEndpoint(String type, 
+            ConnectionEndpoint.ParamType paramType, String paramName) {
+        ShaderNodeDot dot1 = new ShaderNodeDot();
+        dot1.setShaderType(shaderType);
+        dot1.setNode(this);
+        dot1.setText(paramName);
+        dot1.setParamType(paramType);
+        dot1.setType(type);
+        return dot1;
+    }
+}

+ 5 - 11
jme3-materialeditor/src/com/jme3/gde/materialdefinition/editor/NodeToolBar.form → jme3-materialeditor/src/com/jme3/gde/materialdefinition/editor/ShaderNodeToolBar.form

@@ -26,7 +26,7 @@
           <Image iconType="3" name="/com/jme3/gde/materialdefinition/icons/code.png"/>
         </Property>
         <Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
-          <ResourceString bundle="com/jme3/gde/materialdefinition/editor/Bundle.properties" key="NodeToolBar.codeButton.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+          <ResourceString bundle="com/jme3/gde/materialdefinition/editor/Bundle.properties" key="ShaderNodeToolBar.codeButton.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
         </Property>
         <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
           <Border info="null"/>
@@ -34,7 +34,7 @@
         <Property name="borderPainted" type="boolean" value="false"/>
         <Property name="contentAreaFilled" type="boolean" value="false"/>
         <Property name="cursor" type="java.awt.Cursor" editor="org.netbeans.modules.form.editors2.CursorEditor">
-          <Color id="Curseur par d&#xe9;faut"/>
+          <Color id="Standardcursor"/>
         </Property>
         <Property name="focusable" type="boolean" value="false"/>
         <Property name="iconTextGap" type="int" value="0"/>
@@ -44,9 +44,6 @@
         <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
           <Dimension value="[24, 24]"/>
         </Property>
-        <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
-          <Dimension value="[16, 16]"/>
-        </Property>
         <Property name="rolloverIcon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
           <Image iconType="3" name="/com/jme3/gde/materialdefinition/icons/codeHover.png"/>
         </Property>
@@ -69,10 +66,10 @@
           <Image iconType="3" name="/com/jme3/gde/materialdefinition/icons/deleteNode.png"/>
         </Property>
         <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
-          <ResourceString bundle="com/jme3/gde/materialdefinition/editor/Bundle.properties" key="NodeToolBar.deleteButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+          <ResourceString bundle="com/jme3/gde/materialdefinition/editor/Bundle.properties" key="ShaderNodeToolBar.deleteButton.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/materialdefinition/editor/Bundle.properties" key="NodeToolBar.deleteButton.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+          <ResourceString bundle="com/jme3/gde/materialdefinition/editor/Bundle.properties" key="ShaderNodeToolBar.deleteButton.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
         </Property>
         <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
           <Border info="null"/>
@@ -80,7 +77,7 @@
         <Property name="borderPainted" type="boolean" value="false"/>
         <Property name="contentAreaFilled" type="boolean" value="false"/>
         <Property name="cursor" type="java.awt.Cursor" editor="org.netbeans.modules.form.editors2.CursorEditor">
-          <Color id="Curseur par d&#xe9;faut"/>
+          <Color id="Standardcursor"/>
         </Property>
         <Property name="focusable" type="boolean" value="false"/>
         <Property name="iconTextGap" type="int" value="0"/>
@@ -90,9 +87,6 @@
         <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
           <Dimension value="[24, 24]"/>
         </Property>
-        <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
-          <Dimension value="[16, 16]"/>
-        </Property>
         <Property name="rolloverIcon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
           <Image iconType="3" name="/com/jme3/gde/materialdefinition/icons/deleteNodeHover.png"/>
         </Property>

+ 132 - 0
jme3-materialeditor/src/com/jme3/gde/materialdefinition/editor/ShaderNodeToolBar.java

@@ -0,0 +1,132 @@
+/*
+ *  Copyright (c) 2009-2018 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.materialdefinition.editor;
+
+/**
+ * This class displays a small bar with an edit and remove icon.
+ * 
+ * @author Nehon
+ * @author MeFisto94
+ */
+public class ShaderNodeToolBar extends NodeToolBar {
+    private final ShaderNodePanel node;
+
+    /**
+     * Creates new ShaderNodeToolBar
+     */
+    @SuppressWarnings("LeakingThisInConstructor")
+    public ShaderNodeToolBar(ShaderNodePanel node) {
+        super(node);
+        this.node = node;
+        if (node.getType() != ShaderNodePanel.NodeType.Fragment && 
+                node.getType() != ShaderNodePanel.NodeType.Vertex) {
+            // Only (Frag and Vert) Shaders can be edited, no params
+            remove(codeButton);
+        }
+    }
+
+    /**
+     * 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.
+     * Comment by MeFisto94: If you see a compile error here, code-gen has
+     * changed the method signature. it should be protected void with 
+     * @Override since it implements NodeToolBar's initComponents actually
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    protected void initComponents() {
+
+        codeButton = new javax.swing.JButton();
+        deleteButton = new javax.swing.JButton();
+
+        setOpaque(false);
+        java.awt.GridBagLayout layout = new java.awt.GridBagLayout();
+        layout.rowHeights = new int[] {16};
+        setLayout(layout);
+
+        codeButton.setBackground(new java.awt.Color(255, 255, 255));
+        codeButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/jme3/gde/materialdefinition/icons/code.png"))); // NOI18N
+        codeButton.setToolTipText(org.openide.util.NbBundle.getMessage(ShaderNodeToolBar.class, "ShaderNodeToolBar.codeButton.toolTipText")); // NOI18N
+        codeButton.setBorder(null);
+        codeButton.setBorderPainted(false);
+        codeButton.setContentAreaFilled(false);
+        codeButton.setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR));
+        codeButton.setFocusable(false);
+        codeButton.setIconTextGap(0);
+        codeButton.setMaximumSize(new java.awt.Dimension(24, 24));
+        codeButton.setMinimumSize(new java.awt.Dimension(24, 24));
+        codeButton.setRolloverIcon(new javax.swing.ImageIcon(getClass().getResource("/com/jme3/gde/materialdefinition/icons/codeHover.png"))); // NOI18N
+        codeButton.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                codeButtonActionPerformed(evt);
+            }
+        });
+        add(codeButton, new java.awt.GridBagConstraints());
+
+        deleteButton.setBackground(new java.awt.Color(255, 255, 255));
+        deleteButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/jme3/gde/materialdefinition/icons/deleteNode.png"))); // NOI18N
+        org.openide.awt.Mnemonics.setLocalizedText(deleteButton, org.openide.util.NbBundle.getMessage(ShaderNodeToolBar.class, "ShaderNodeToolBar.deleteButton.text")); // NOI18N
+        deleteButton.setToolTipText(org.openide.util.NbBundle.getMessage(ShaderNodeToolBar.class, "ShaderNodeToolBar.deleteButton.toolTipText")); // NOI18N
+        deleteButton.setBorder(null);
+        deleteButton.setBorderPainted(false);
+        deleteButton.setContentAreaFilled(false);
+        deleteButton.setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR));
+        deleteButton.setFocusable(false);
+        deleteButton.setIconTextGap(0);
+        deleteButton.setMaximumSize(new java.awt.Dimension(24, 24));
+        deleteButton.setMinimumSize(new java.awt.Dimension(24, 24));
+        deleteButton.setRolloverIcon(new javax.swing.ImageIcon(getClass().getResource("/com/jme3/gde/materialdefinition/icons/deleteNodeHover.png"))); // NOI18N
+        deleteButton.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                deleteButtonActionPerformed(evt);
+            }
+        });
+        add(deleteButton, new java.awt.GridBagConstraints());
+    }// </editor-fold>//GEN-END:initComponents
+
+    private void codeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_codeButtonActionPerformed
+        node.edit();
+    }//GEN-LAST:event_codeButtonActionPerformed
+
+    private void deleteButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteButtonActionPerformed
+        node.delete();
+    }//GEN-LAST:event_deleteButtonActionPerformed
+
+
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JButton codeButton;
+    private javax.swing.JButton deleteButton;
+    // End of variables declaration//GEN-END:variables
+
+}

+ 51 - 17
jme3-materialeditor/src/com/jme3/gde/materialdefinition/editor/OutBusPanel.java → jme3-materialeditor/src/com/jme3/gde/materialdefinition/editor/ShaderOutBusPanel.java

@@ -1,10 +1,36 @@
 /*
- * To change this template, choose Tools | Templates
- * and open the template in the editor.
+ *  Copyright (c) 2009-2018 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.materialdefinition.editor;
 
-import com.jme3.gde.core.scene.SceneApplication;
 import com.jme3.gde.materialdefinition.fileStructure.leaves.InputMappingBlock;
 import com.jme3.gde.materialdefinition.fileStructure.leaves.OutputMappingBlock;
 import com.jme3.material.Material;
@@ -27,18 +53,17 @@ import javax.swing.JLabel;
 import javax.swing.SwingUtilities;
 
 /**
- *
+ * The ShaderOutBusPanel is the horizontal line describing the shader outputs.
  * @author Nehon
  */
-public class OutBusPanel extends DraggablePanel implements ComponentListener, Selectable, InOut {
-
+public class ShaderOutBusPanel extends DraggablePanel implements ComponentListener, Selectable, InOut {
     private Color color = new Color(220, 220, 70);
     private String name = "";
     private final InnerPanel panel;
     private final MatPanel preview;
     private final Shader.ShaderType type;
 
-    public OutBusPanel(String name, Shader.ShaderType type) {
+    public ShaderOutBusPanel(String name, Shader.ShaderType type) {
         super(true);
         this.type = type;
         if (type == Shader.ShaderType.Fragment) {
@@ -82,13 +107,19 @@ public class OutBusPanel extends DraggablePanel implements ComponentListener, Se
     @Override
     public void setDiagram(final Diagram diagram) {
         super.setDiagram(diagram);
+        
+        if (!(diagram instanceof ShaderNodeDiagram)) {
+            throw new IllegalStateException("ShaderOutBusPanel requires a "
+                    + "Diagram extending ShaderNodeDiagram");
+        }
+        
         // preview.setBounds(350,300,128,100);
         diagram.add(preview);
         preview.update(this);
         preview.setExpandActionListener(new ActionListener() {
-
+            @Override
             public void actionPerformed(ActionEvent e) {
-                diagram.displayBackdrop();
+                ((ShaderNodeDiagram)diagram).displayBackdrop();
             }
         });
         
@@ -127,8 +158,6 @@ public class OutBusPanel extends DraggablePanel implements ComponentListener, Se
         g.fillRect(5, 10, 6, getHeight() - 20);
         g.fillRect(13, 10, 9, getHeight() - 20);
         g.fillRect(24, 10, 12, getHeight() - 20);
-
-
     }
 
     @Override
@@ -175,7 +204,7 @@ public class OutBusPanel extends DraggablePanel implements ComponentListener, Se
         }
     }
 
-    public Dot getConnectPoint() {
+    public ConnectionEndpoint getConnectPoint() {
         return panel;
     }
 
@@ -203,6 +232,7 @@ public class OutBusPanel extends DraggablePanel implements ComponentListener, Se
 
     }
 
+    @Override
     public String getKey() {
         return name;
     }
@@ -219,28 +249,32 @@ public class OutBusPanel extends DraggablePanel implements ComponentListener, Se
         return false;
     }
 
+    @Override
     public void addInputMapping(InputMappingBlock block) {
     }
 
+    @Override
     public void removeInputMapping(InputMappingBlock block) {
     }
 
+    @Override
     public void addOutputMapping(OutputMappingBlock block) {
     }
 
+    @Override
     public void removeOutputMapping(OutputMappingBlock block) {
     }
 
-    class InnerPanel extends Dot {
-
+    // That's the gradient bar/line it seems
+    class InnerPanel extends ShaderNodeDot {
         boolean over = false;
         boolean dragging = false;
 
         public InnerPanel() {
-            this.shaderType = OutBusPanel.this.type;            
+            this.shaderType = ShaderOutBusPanel.this.type;            
             setOpaque(false);
-            setNode(OutBusPanel.this);
-            setParamType(Dot.ParamType.Both);
+            setNode(ShaderOutBusPanel.this);
+            setParamType(ConnectionEndpoint.ParamType.Both);
             setType("vec4");
             setText(name);
         }