Browse Source

formatting and line endings

rickard 3 years ago
parent
commit
6af69fb8ca

+ 545 - 544
jme3-materialeditor/src/com/jme3/gde/materialdefinition/editor/ShaderNodeDiagram.java

@@ -1,544 +1,545 @@
-/*
- *  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.editor.nodes.Connection;
-import com.jme3.gde.core.editor.nodes.Diagram;
-import com.jme3.gde.core.editor.nodes.NodePanel;
-import com.jme3.gde.core.editor.nodes.Selectable;
-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.core.editor.icons.Icons;
-import com.jme3.gde.core.errorreport.ExceptionUtils;
-import com.jme3.gde.materialdefinition.utils.MaterialUtils;
-import com.jme3.material.Material;
-import com.jme3.shader.Shader;
-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.util.ArrayList;
-import java.util.List;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-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 ComponentListener {
-
-    protected List<ShaderOutBusPanel> outBuses = new ArrayList<ShaderOutBusPanel>();
-    private String currentTechniqueName;
-    private final BackdropPanel backDrop = new BackdropPanel();
-    private final Point pp = new Point();
-    private Thread backgroundThread;
-    private UpdateBackgroundRunnable backgroundUpdate = new UpdateBackgroundRunnable();
-
-    @SuppressWarnings("LeakingThisInConstructor")
-    public ShaderNodeDiagram() {
-        super();
-    }
-    
-    @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();
-        backgroundUpdate.setRunning(false);
-    }
-
-    @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;
-
-    }
-
-    @Override
-    public void toggleUpdateThread(boolean on) {
-        if(on && !backgroundUpdate.isRunning()){
-            backgroundUpdate.setRunning(true);
-            backgroundThread = new Thread(backgroundUpdate);
-            backgroundThread.setDaemon(true);
-            backgroundThread.start();
-        } else if (!on && backgroundUpdate.isRunning()){
-            try {
-                backgroundUpdate.setRunning(false);
-                backgroundThread.join();
-            } catch (InterruptedException ex) {
-                Thread.currentThread().interrupt();
-            }
-        }
-    }
-
-    private final class UpdateBackgroundRunnable implements Runnable{
-
-        private boolean running;
-        @Override
-        public void run() {
-            while(running) {
-                if (backDrop.isVisible() && !backDrop.getRenderer().isPreviewRequested()) {
-                    backDrop.refreshOnly();
-                }
-                try {
-                    Thread.sleep(20);
-                } catch (InterruptedException ex) {
-                    running = false;
-                    ExceptionUtils.caughtException(ex, "Material update thread caught an exception and shut down.");
-                }
-                if(!ShaderNodeDiagram.this.isShowing()){
-                    running = false;
-                }
-            }
-            Logger.getLogger(ShaderNodeDiagram.class.getName()).log(Level.INFO, "UpdateThread stopped");
-        }
-        
-        public boolean isRunning() {
-            return running;
-        }
-        
-        public void setRunning(boolean on) {
-            this.running = on;
-        }
-    }
-    
-}
+/*
+ *  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.editor.nodes.Connection;
+import com.jme3.gde.core.editor.nodes.Diagram;
+import com.jme3.gde.core.editor.nodes.NodePanel;
+import com.jme3.gde.core.editor.nodes.Selectable;
+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.core.editor.icons.Icons;
+import com.jme3.gde.core.errorreport.ExceptionUtils;
+import com.jme3.gde.materialdefinition.utils.MaterialUtils;
+import com.jme3.material.Material;
+import com.jme3.shader.Shader;
+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.util.ArrayList;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+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 ComponentListener {
+
+    protected List<ShaderOutBusPanel> outBuses = new ArrayList<ShaderOutBusPanel>();
+    private String currentTechniqueName;
+    private final BackdropPanel backDrop = new BackdropPanel();
+    private Thread backgroundThread;
+    private UpdateBackgroundRunnable backgroundUpdate = new UpdateBackgroundRunnable();
+
+    @SuppressWarnings("LeakingThisInConstructor")
+    public ShaderNodeDiagram() {
+        super();
+    }
+    
+    @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();
+        backgroundUpdate.setRunning(false);
+    }
+
+    @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;
+
+    }
+
+    @Override
+    public void toggleUpdateThread(boolean on) {
+        if (on && !backgroundUpdate.isRunning()) {
+            backgroundUpdate.setRunning(true);
+            backgroundThread = new Thread(backgroundUpdate);
+            backgroundThread.setDaemon(true);
+            backgroundThread.start();
+        } else if (!on && backgroundUpdate.isRunning()) {
+            try {
+                backgroundUpdate.setRunning(false);
+                backgroundThread.join();
+            } catch (InterruptedException ex) {
+                Thread.currentThread().interrupt();
+            }
+        }
+    }
+
+    private final class UpdateBackgroundRunnable implements Runnable {
+
+        private boolean running;
+
+        @Override
+        public void run() {
+            while (running) {
+                if (backDrop.isVisible() && !backDrop.getRenderer().isPreviewRequested()) {
+                    backDrop.refreshOnly();
+                }
+                try {
+                    Thread.sleep(20);
+                } catch (InterruptedException ex) {
+                    running = false;
+                    ExceptionUtils.caughtException(ex, "Material update thread caught an exception and shut down.");
+                }
+                if (!ShaderNodeDiagram.this.isShowing()) {
+                    running = false;
+                }
+            }
+            Logger.getLogger(ShaderNodeDiagram.class.getName()).log(Level.INFO, "UpdateThread stopped");
+        }
+
+        public boolean isRunning() {
+            return running;
+        }
+
+        public void setRunning(boolean on) {
+            this.running = on;
+        }
+    }
+    
+}