From 212a2d6e9631dc85d64a7dca4f67fbb2dc502f3c Mon Sep 17 00:00:00 2001 From: Nehon Date: Sat, 7 Feb 2015 00:42:06 +0100 Subject: [PATCH] Millions of fixes, fixes for me - Fixed hanging save on a Material definition file. - Fixed Node editor blow up when changing a shader node definition content. - Enhanced error reporting. - and many more. --- .../EditableMatDefFile.java | 64 +++++---- .../editor/MatDefEditorlElement.java | 126 ++++++++++-------- .../editor/ShaderEditPanel.java | 90 +++++++++---- .../materials/MaterialPreviewRenderer.java | 14 +- 4 files changed, 186 insertions(+), 108 deletions(-) diff --git a/sdk/jme3-materialeditor/src/com/jme3/gde/materialdefinition/EditableMatDefFile.java b/sdk/jme3-materialeditor/src/com/jme3/gde/materialdefinition/EditableMatDefFile.java index 53a959d2e..5cd40f6fe 100644 --- a/sdk/jme3-materialeditor/src/com/jme3/gde/materialdefinition/EditableMatDefFile.java +++ b/sdk/jme3-materialeditor/src/com/jme3/gde/materialdefinition/EditableMatDefFile.java @@ -30,8 +30,8 @@ import com.jme3.util.blockparser.Statement; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.IOException; +import java.io.InputStream; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; @@ -55,7 +55,7 @@ import org.openide.util.WeakListeners; public class EditableMatDefFile { private FileObject matDefFile; - private MatDefDataObject obj; + private final MatDefDataObject obj; private Material material; private MatDefBlock matDefStructure; private TechniqueBlock currentTechnique; @@ -64,7 +64,7 @@ public class EditableMatDefFile { // MatParamTopComponent matParamComponent; private ShaderGenerator glsl100; private ShaderGenerator glsl150; - private String selectedTechnique = "Default"; + private final String selectedTechnique = "Default"; private final static String GLSL100 = "GLSL100"; private final static String GLSL150 = "GLSL150"; private Lookup lookup; @@ -78,6 +78,7 @@ public class EditableMatDefFile { } public final void load(Lookup lookup) { + loaded = false; this.matDefFile = obj.getPrimaryFile(); this.assetManager = lookup.lookup(ProjectAssetManager.class); this.glsl100 = new Glsl100ShaderGenerator(assetManager); @@ -92,20 +93,27 @@ public class EditableMatDefFile { obj.getLookupContents().remove(materialDef); materialDef = null; } + if (material != null) { + obj.getLookupContents().remove(material); + matToRemove = material; + material = null; + } FileLock lock = null; + InputStream in = null; + boolean matParseError = false; try { lock = matDefFile.lock(); - List sta = BlockLanguageParser.parse(obj.getPrimaryFile().getInputStream()); + in = obj.getPrimaryFile().getInputStream(); + List sta = BlockLanguageParser.parse(in); matDefStructure = new MatDefBlock(sta.get(0)); - if(assetManager!=null){ + if (assetManager != null) { AssetKey matDefKey = new AssetKey(assetManager.getRelativeAssetPath(assetManager.getRelativeAssetPath(matDefFile.getPath()))); assetManager.deleteFromCache(matDefKey); materialDef = (MaterialDef) assetManager.loadAsset(assetManager.getRelativeAssetPath(matDefFile.getPath())); } - lock.releaseLock(); } catch (Exception ex) { Throwable t = ex.getCause(); - boolean matParseError = false; + while (t != null) { if (t instanceof MatParseException) { Logger.getLogger(EditableMatDefFile.class.getName()).log(Level.SEVERE, t.getMessage()); @@ -120,8 +128,15 @@ public class EditableMatDefFile { if (lock != null) { lock.releaseLock(); } + if (in != null) { + try { + in.close(); + } catch (IOException ex) { + Exceptions.printStackTrace(ex); + } + } } - if (materialDef != null) { + if (materialDef != null && !matParseError) { currentTechnique = matDefStructure.getTechniques().get(0); registerListener(matDefStructure); @@ -164,8 +179,7 @@ public class EditableMatDefFile { glsl150.initialize(material.getActiveTechnique()); s = glsl150.generateShader(); } - for (Iterator it = s.getSources().iterator(); it.hasNext();) { - Shader.ShaderSource source = it.next(); + for (Shader.ShaderSource source : s.getSources()) { if (source.getType() == type) { return source.getSource(); } @@ -177,13 +191,6 @@ public class EditableMatDefFile { } } -// public MatParamTopComponent getMatParamComponent() { -// return matParamComponent; -// } -// -// public void setMatParamComponent(MatParamTopComponent matParamComponent) { -// this.matParamComponent = matParamComponent; -// } public TechniqueBlock getCurrentTechnique() { return currentTechnique; } @@ -191,7 +198,7 @@ public class EditableMatDefFile { public MatDefBlock getMatDefStructure() { return matDefStructure; } - private MatStructChangeListener changeListener = new MatStructChangeListener(); + private final MatStructChangeListener changeListener = new MatStructChangeListener(); J3MLoader loader = new J3MLoader(); private void updateLookupWithMaterialData(MatDefDataObject obj) { @@ -202,7 +209,12 @@ public class EditableMatDefFile { material.selectTechnique("Default", SceneApplication.getApplication().getRenderManager()); if (matToRemove != null) { for (MatParam matParam : matToRemove.getParams()) { - material.setParam(matParam.getName(), matParam.getVarType(), matParam.getValue()); + try { + material.setParam(matParam.getName(), matParam.getVarType(), matParam.getValue()); + } catch (IllegalArgumentException ie) { + matToRemove.clearParam(matParam.getName()); + } + } obj.getLookupContents().remove(matToRemove); matToRemove = null; @@ -264,13 +276,13 @@ public class EditableMatDefFile { for (ShaderNodeBlock shaderNodeBlock : currentTechnique.getShaderNodes()) { if (shaderNodeBlock.getCondition() != null && shaderNodeBlock.getCondition().contains(oldValue.getName())) { - shaderNodeBlock.setCondition(shaderNodeBlock.getCondition().replaceAll(oldValue.getName(), "").trim()); + shaderNodeBlock.setCondition(shaderNodeBlock.getCondition().replaceAll(oldValue.getName(), "").trim()); } List lin = shaderNodeBlock.getInputs(); if (lin != null) { for (InputMappingBlock inputMappingBlock : shaderNodeBlock.getInputs()) { if (inputMappingBlock.getCondition() != null && inputMappingBlock.getCondition().contains(oldValue.getName())) { - inputMappingBlock.setCondition(inputMappingBlock.getCondition().replaceAll(oldValue.getName(), "").trim()); + inputMappingBlock.setCondition(inputMappingBlock.getCondition().replaceAll(oldValue.getName(), "").trim()); } } } @@ -278,7 +290,7 @@ public class EditableMatDefFile { if (l != null) { for (OutputMappingBlock outputMappingBlock : l) { if (outputMappingBlock.getCondition() != null && outputMappingBlock.getCondition().contains(oldValue.getName())) { - outputMappingBlock.setCondition(outputMappingBlock.getCondition().replaceAll(oldValue.getName(), "").trim()); + outputMappingBlock.setCondition(outputMappingBlock.getCondition().replaceAll(oldValue.getName(), "").trim()); } } } @@ -303,10 +315,10 @@ public class EditableMatDefFile { NbDocument.runAtomicAsUser(ec.getDocument(), new Runnable() { public void run() { try { - doc.remove(0, doc.getLength()); - doc.insertString(doc.getLength(), - matDefStructure.toString(), - SimpleAttributeSet.EMPTY); + doc.remove(0, doc.getLength()); + doc.insertString(doc.getLength(), + matDefStructure.toString(), + SimpleAttributeSet.EMPTY); } catch (BadLocationException e) { exc[0] = e; } diff --git a/sdk/jme3-materialeditor/src/com/jme3/gde/materialdefinition/editor/MatDefEditorlElement.java b/sdk/jme3-materialeditor/src/com/jme3/gde/materialdefinition/editor/MatDefEditorlElement.java index af9406a56..8835b32c3 100644 --- a/sdk/jme3-materialeditor/src/com/jme3/gde/materialdefinition/editor/MatDefEditorlElement.java +++ b/sdk/jme3-materialeditor/src/com/jme3/gde/materialdefinition/editor/MatDefEditorlElement.java @@ -52,16 +52,20 @@ import com.jme3.shader.ShaderNodeVariable; import com.jme3.shader.ShaderUtils; import java.awt.Color; import java.awt.Dimension; +import java.awt.Font; import java.awt.Point; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import java.beans.PropertyVetoException; +import java.io.BufferedReader; import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Collection; +import java.util.HashMap; import java.util.List; +import java.util.Map; import javax.swing.Action; -import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JPanel; @@ -71,10 +75,12 @@ import org.netbeans.core.spi.multiview.MultiViewElement; import org.netbeans.core.spi.multiview.MultiViewElementCallback; import org.netbeans.core.spi.multiview.text.MultiViewEditorElement; import org.openide.awt.UndoRedo; +import org.openide.cookies.EditorCookie; import org.openide.filesystems.FileObject; import org.openide.filesystems.FileUtil; import org.openide.nodes.Children; import org.openide.nodes.Node; +import org.openide.text.EditorSupport; import org.openide.util.Exceptions; import org.openide.util.Lookup; import org.openide.util.LookupEvent; @@ -85,12 +91,12 @@ import org.openide.util.lookup.InstanceContent; import org.openide.windows.TopComponent; @MultiViewElement.Registration( - displayName = "#LBL_MatDef_EDITOR", -iconBase = "com/jme3/gde/materialdefinition/icons/matdef.png", -mimeType = "text/jme-materialdefinition", -persistenceType = TopComponent.PERSISTENCE_ONLY_OPENED, -preferredID = "MatDefVisual", -position = 2000) + displayName = "#LBL_MatDef_EDITOR", + iconBase = "com/jme3/gde/materialdefinition/icons/matdef.png", + mimeType = "text/jme-materialdefinition", + persistenceType = TopComponent.PERSISTENCE_ONLY_OPENED, + preferredID = "MatDefVisual", + position = 2000) @Messages("LBL_MatDef_EDITOR=Editor") public final class MatDefEditorlElement extends JPanel implements MultiViewElement { @@ -100,7 +106,7 @@ public final class MatDefEditorlElement extends JPanel implements MultiViewEleme InstanceContent content; Selectable prevNode; MatDefMetaData metaData; - + public MatDefEditorlElement(final Lookup lkp) { initComponents(); obj = lkp.lookup(MatDefDataObject.class); @@ -109,14 +115,14 @@ public final class MatDefEditorlElement extends JPanel implements MultiViewEleme final EditableMatDefFile file = obj.getEditableFile(); shaderEditPanel1.setVisible(false); shaderEditPanel1.setParent(this); - reload(file, lkp); + reload(file, lkp); } private void initDiagram(Lookup lkp) throws NumberFormatException { - + diagram1.clear(); diagram1.setParent(this); - + Material mat = lkp.lookup(Material.class); ProjectAssetManager manager = obj.getLookup().lookup(ProjectAssetManager.class); @@ -213,7 +219,6 @@ public final class MatDefEditorlElement extends JPanel implements MultiViewEleme diagram1.revalidate(); jScrollPane1.addComponentListener(diagram1); - diagram1.refreshPreviews(mat); final Lookup.Result resMat = obj.getLookup().lookupResult(Material.class); resMat.addLookupListener(new LookupListener() { @@ -226,7 +231,6 @@ public final class MatDefEditorlElement extends JPanel implements MultiViewEleme } }); - final MatDefNavigatorPanel nav = obj.getLookup().lookup(MatDefNavigatorPanel.class); if (nav != null) { @@ -267,7 +271,7 @@ public final class MatDefEditorlElement extends JPanel implements MultiViewEleme Exceptions.printStackTrace(ex); } } - + public void refresh() { Lookup.Result resMat = obj.getLookup().lookupResult(Material.class); @@ -278,32 +282,52 @@ public final class MatDefEditorlElement extends JPanel implements MultiViewEleme } } - - public void setModified(){ - obj.setModified(true); + + public void setModified() { + obj.setModified(true); } - - public ProjectAssetManager getAssetManager(){ + + public ProjectAssetManager getAssetManager() { return obj.getLookup().lookup(ProjectAssetManager.class); } - - public void showShaderEditor(String nodeName,NodePanel.NodeType type,ListpathList){ - + + public void showShaderEditor(String nodeName, NodePanel.NodeType type, List pathList) { + List fos = new ArrayList(); - for (String path : pathList) { - FileObject text = FileUtil.toFileObject(new File(getAssetManager().getAbsoluteAssetPath(path))); - fos.add(text); + Map readOnlyFiles = new HashMap(); + for (String path : pathList) { + try { + FileObject text = FileUtil.toFileObject(new File(getAssetManager().getAbsoluteAssetPath(path))); + fos.add(text); + } catch (NullPointerException e) { + try { + //cannot load the files because they are probably in a jar + InputStream is = getAssetManager().getResourceAsStream(path); + BufferedReader reader = new BufferedReader(new InputStreamReader(is)); + StringBuilder out = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + out.append(line).append("\n"); + } + readOnlyFiles.put(path.substring(path.lastIndexOf("/") + 1), out.toString()); //Prints the string content read from input stream + reader.close(); + } catch (IOException ex) { + Exceptions.printStackTrace(ex); + } + + } + } - shaderEditPanel1.setFiles(nodeName, type, fos); + shaderEditPanel1.setFiles(nodeName, type, fos, readOnlyFiles); shaderEditPanel1.revalidate(); - if(!shaderEditPanel1.isVisible() || jSplitPane.getDividerLocation() == jSplitPane.getMinimumDividerLocation()){ + if (!shaderEditPanel1.isVisible() || jSplitPane.getDividerLocation() == jSplitPane.getMinimumDividerLocation()) { shaderEditPanel1.setVisible(true); jSplitPane.setDividerLocation(650); } - + } - - public ShaderEditPanel getShaderEditor(){ + + public ShaderEditPanel getShaderEditor() { return shaderEditPanel1; } @@ -496,13 +520,13 @@ public final class MatDefEditorlElement extends JPanel implements MultiViewEleme } public void notifyAddMapParam(String type, String name) { - MatDefBlock matDef = obj.getLookup().lookup(MatDefBlock.class); + MatDefBlock matDef = obj.getLookup().lookup(MatDefBlock.class); MatParamBlock param = new MatParamBlock(type, name, null, null); matDef.addMatParam(param); } public void notifyAddWorldParam(String name) { - MatDefBlock matDef = obj.getLookup().lookup(MatDefBlock.class); + MatDefBlock matDef = obj.getLookup().lookup(MatDefBlock.class); WorldParamBlock param = new WorldParamBlock(name); getTechnique(matDef).addWorldParam(param); } @@ -596,7 +620,6 @@ public final class MatDefEditorlElement extends JPanel implements MultiViewEleme } - for (WorldParamBlock worldParamBlock : technique.getWorldParams()) { ShaderNodeVariable var = new ShaderNodeVariable("", "WorldParam", worldParamBlock.getName()); var.setType(MaterialUtils.getWorldParamType(var.getName())); @@ -633,9 +656,15 @@ public final class MatDefEditorlElement extends JPanel implements MultiViewEleme metaData.setProperty(diagram1.getCurrentTechniqueName() + "/" + key, x + "," + y); } - - public void reload(){ - reload(obj.getEditableFile(), obj.getLookup()); + + public void reload() { + try { + obj.getLookup().lookup(EditorCookie.class).saveDocument(); + obj.getEditableFile().load(obj.getLookup()); + reload(obj.getEditableFile(), obj.getLookup()); + } catch (IOException ex) { + Exceptions.printStackTrace(ex); + } } private void reload(final EditableMatDefFile file, final Lookup lkp) throws NumberFormatException { @@ -647,21 +676,14 @@ public final class MatDefEditorlElement extends JPanel implements MultiViewEleme } } else { diagram1.clear(); - JLabel error = new JLabel("Cannot load material definition."); - error.setForeground(Color.RED); - error.setBounds(0, 0, 200, 20); + JLabel error = new JLabel("
Cannot load material definition.
Please see the error log and fix it in the text editor
"); + error.setForeground(Color.ORANGE); + error.setFont(new Font("Arial", Font.BOLD, 24)); + error.setBounds(0, 0, 400, 100); + jScrollPane1.getHorizontalScrollBar().setValue(0); + error.setLocation(jScrollPane1.getViewport().getWidth() / 2 - 200, jScrollPane1.getViewport().getHeight() / 2 - 50); diagram1.add(error); - JButton btn = new JButton("retry"); - btn.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - file.load(lkp); - if (file.isLoaded()) { - initDiagram(lkp); - } - } - }); - btn.setBounds(0, 25, 150, 20); - diagram1.add(btn); + diagram1.repaint(); } } diff --git a/sdk/jme3-materialeditor/src/com/jme3/gde/materialdefinition/editor/ShaderEditPanel.java b/sdk/jme3-materialeditor/src/com/jme3/gde/materialdefinition/editor/ShaderEditPanel.java index c7073cbff..bcda369ad 100644 --- a/sdk/jme3-materialeditor/src/com/jme3/gde/materialdefinition/editor/ShaderEditPanel.java +++ b/sdk/jme3-materialeditor/src/com/jme3/gde/materialdefinition/editor/ShaderEditPanel.java @@ -13,8 +13,10 @@ import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.io.IOException; import java.util.List; +import java.util.Map; import javax.swing.JPanel; import javax.swing.JToggleButton; +import javax.swing.text.DefaultStyledDocument; import javax.swing.text.EditorKit; import org.openide.awt.UndoRedo; import org.openide.cookies.EditorCookie; @@ -34,25 +36,26 @@ public class ShaderEditPanel extends JPanel { private DataObject currentDataObject = null; private MatDefEditorlElement parent = null; private UndoRedo.Manager undoRedoManager; + private final String MIME = "text/x-glsl"; /** * Creates new form ShaderEditPanel */ public ShaderEditPanel() { initComponents(); - String mime = "text/x-glsl"; - EditorKit ek = CloneableEditorSupport.getEditorKit(mime); - shaderEditorPane.setEditorKit(ek); - shaderEditorPane.setContentType(mime); + EditorKit ek = CloneableEditorSupport.getEditorKit(MIME); + shaderEditorPane.setEditorKit(ek); + shaderEditorPane.setContentType(MIME); + shaderEditorPane.addKeyListener(new KeyListener() { public void keyTyped(KeyEvent e) { } - public void keyPressed(KeyEvent e) { + public void keyPressed(KeyEvent e) { if ((e.getKeyCode() == KeyEvent.VK_S) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) { - saveCurrent(); + saveCurrent(); } } @@ -63,11 +66,12 @@ public class ShaderEditPanel extends JPanel { public void setParent(MatDefEditorlElement parent) { this.parent = parent; - undoRedoManager = (UndoRedo.Manager)parent.getUndoRedo(); + undoRedoManager = (UndoRedo.Manager) parent.getUndoRedo(); } - public void setFiles(String title, NodePanel.NodeType type, List fos) { + public void setFiles(String title, NodePanel.NodeType type, List fos, final Map readOnlyFiles) { + headerText.setText(title); headerText.setIcon(Icons.getIconForShaderType(type)); boolean firstItem = true; @@ -75,7 +79,7 @@ public class ShaderEditPanel extends JPanel { buttonGroup1.remove((JToggleButton) component); } buttonPanel.removeAll(); - buttonPanel.repaint(); + buttonPanel.repaint(); for (FileObject fo : fos) { final Tab b = new Tab(); @@ -86,51 +90,83 @@ public class ShaderEditPanel extends JPanel { b.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { saveCurrent(); - try { - shaderEditorPane.setDocument(b.dataObject.getLookup().lookup(EditorCookie.class).openDocument()); - undoRedoManager.discardAllEdits(); - shaderEditorPane.getDocument().addUndoableEditListener(undoRedoManager); + try { + switchEditableDoc(b); } catch (IOException ex) { Exceptions.printStackTrace(ex); } - currentDataObject = b.dataObject; } - }); if (firstItem) { - shaderEditorPane.setDocument(b.dataObject.getLookup().lookup(EditorCookie.class).openDocument()); - undoRedoManager.discardAllEdits(); - shaderEditorPane.getDocument().addUndoableEditListener(undoRedoManager); - currentDataObject = b.dataObject; + switchEditableDoc(b); b.setSelected(true); - firstItem = false; + firstItem = false; } } catch (IOException ex) { Exceptions.printStackTrace(ex); } + buttonPanel.add(b); + } + for (String key : readOnlyFiles.keySet()) { + final Tab b = new Tab(); + b.setText(key); + buttonGroup1.add(b); + final String theKey = key; + b.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + switchReadOnlyDoc(readOnlyFiles.get(theKey)); + } + + }); + if (firstItem) { + switchReadOnlyDoc(readOnlyFiles.get(key)); + b.setSelected(true); + firstItem = false; + } buttonPanel.add(b); } } + private void switchEditableDoc(Tab b) throws IOException { + if(currentDataObject != null){ + currentDataObject.getLookup().lookup(EditorCookie.class).close(); + } + shaderEditorPane.setDocument(b.dataObject.getLookup().lookup(EditorCookie.class).openDocument()); + undoRedoManager.discardAllEdits(); + shaderEditorPane.getDocument().addUndoableEditListener(undoRedoManager); + shaderEditorPane.setEditable(true); + currentDataObject = b.dataObject; + } + + private void switchReadOnlyDoc(String text) { + if(currentDataObject != null){ + currentDataObject.getLookup().lookup(EditorCookie.class).close(); + } + shaderEditorPane.setText(text); + undoRedoManager.discardAllEdits(); + shaderEditorPane.setEditable(false); + currentDataObject = null; + } + public void saveCurrent() { if (currentDataObject != null && currentDataObject.isModified()) { FileLock lock = null; - + try { currentDataObject.getLookup().lookup(EditorCookie.class).saveDocument(); currentDataObject.setModified(false); - if(currentDataObject.getPrimaryFile().getExt().equalsIgnoreCase("j3sn")){ - parent.reload(); - } + if (currentDataObject.getPrimaryFile().getExt().equalsIgnoreCase("j3sn")) { + parent.reload(); + } parent.refresh(); } catch (DataObjectNotFoundException ex) { Exceptions.printStackTrace(ex); } catch (IOException ex) { Exceptions.printStackTrace(ex); - }finally{ - if (lock!=null){ + } finally { + if (lock != null) { lock.releaseLock(); } } @@ -139,7 +175,7 @@ public class ShaderEditPanel extends JPanel { private class Tab extends JToggleButton { - DataObject dataObject; + DataObject dataObject; } /** diff --git a/sdk/jme3-materialeditor/src/com/jme3/gde/materials/MaterialPreviewRenderer.java b/sdk/jme3-materialeditor/src/com/jme3/gde/materials/MaterialPreviewRenderer.java index e49409e69..df11b15f4 100644 --- a/sdk/jme3-materialeditor/src/com/jme3/gde/materials/MaterialPreviewRenderer.java +++ b/sdk/jme3-materialeditor/src/com/jme3/gde/materials/MaterialPreviewRenderer.java @@ -117,7 +117,7 @@ public class MaterialPreviewRenderer implements SceneListener { label.setIcon(Icons.error); } }); - Logger.getLogger(MaterialPreviewRenderer.class.getName()).log(Level.SEVERE, "Error rendering material{0}", e.getMessage()); + smartLog("Error rendering material{0}", e.getMessage()); } } }); @@ -126,10 +126,18 @@ public class MaterialPreviewRenderer implements SceneListener { return mat; } }); - } - public Material reloadMaterial(Material mat) { + private int lastErrorHash = 0; + private void smartLog(String expText, String message){ + int hash = message.hashCode(); + if(hash != lastErrorHash){ + Logger.getLogger(MaterialPreviewRenderer.class.getName()).log(Level.SEVERE, expText, message); + lastErrorHash = hash; + } + } + + public Material reloadMaterial(Material mat) { ((ProjectAssetManager)mat.getMaterialDef().getAssetManager()).clearCache();