/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package com.jme3.gde.materialdefinition; import com.jme3.asset.AssetKey; import com.jme3.gde.core.assets.ProjectAssetManager; import com.jme3.gde.core.scene.SceneApplication; import com.jme3.gde.materialdefinition.fileStructure.MatDefBlock; import com.jme3.gde.materialdefinition.fileStructure.ShaderNodeBlock; import com.jme3.gde.materialdefinition.fileStructure.TechniqueBlock; import com.jme3.gde.materialdefinition.fileStructure.UberStatement; import com.jme3.gde.materialdefinition.fileStructure.leaves.InputMappingBlock; import com.jme3.gde.materialdefinition.fileStructure.leaves.LeafStatement; import com.jme3.gde.materialdefinition.fileStructure.leaves.MatParamBlock; import com.jme3.gde.materialdefinition.fileStructure.leaves.OutputMappingBlock; import com.jme3.gde.materialdefinition.navigator.node.MatDefNode; import com.jme3.material.MatParam; import com.jme3.material.Material; import com.jme3.material.MaterialDef; import com.jme3.material.plugins.J3MLoader; import com.jme3.material.plugins.MatParseException; import com.jme3.shader.Glsl100ShaderGenerator; import com.jme3.shader.Glsl150ShaderGenerator; import com.jme3.shader.Shader; import com.jme3.shader.ShaderGenerator; import com.jme3.util.blockparser.BlockLanguageParser; 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.List; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.text.BadLocationException; import javax.swing.text.SimpleAttributeSet; import javax.swing.text.StyledDocument; import org.openide.cookies.EditorCookie; import org.openide.explorer.ExplorerManager; import org.openide.filesystems.FileLock; import org.openide.filesystems.FileObject; import org.openide.nodes.Node; import org.openide.text.NbDocument; import org.openide.util.Exceptions; import org.openide.util.Lookup; import org.openide.util.WeakListeners; /** * * @author Nehon */ public class EditableMatDefFile { private FileObject matDefFile; private final MatDefDataObject obj; private Material material; private MatDefBlock matDefStructure; private TechniqueBlock currentTechnique; private MaterialDef materialDef; private ProjectAssetManager assetManager; private ShaderGenerator glsl100; private ShaderGenerator glsl150; private final static String GLSL100 = "GLSL100"; private Lookup lookup; private boolean loaded = false; private boolean dirty = false; public EditableMatDefFile(Lookup lookup) { obj = lookup.lookup(MatDefDataObject.class); load(lookup); } public final void load(Lookup lookup) { loaded = false; this.matDefFile = obj.getPrimaryFile(); this.assetManager = lookup.lookup(ProjectAssetManager.class); this.glsl100 = new Glsl100ShaderGenerator(assetManager); this.glsl150 = new Glsl150ShaderGenerator(assetManager); this.lookup = lookup; if (matDefStructure != null) { obj.getLookupContents().remove(matDefStructure); matDefStructure = null; } if (materialDef != null) { 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(); in = obj.getPrimaryFile().getInputStream(); List sta = BlockLanguageParser.parse(in); matDefStructure = new MatDefBlock(sta.get(0)); if (assetManager != null) { AssetKey matDefKey = new AssetKey(assetManager.getRelativeAssetPath(assetManager.getRelativeAssetPath(matDefFile.getPath()))); assetManager.deleteFromCache(matDefKey); materialDef = (MaterialDef) assetManager.loadAsset(assetManager.getRelativeAssetPath(matDefFile.getPath())); } } catch (Exception ex) { Throwable t = ex.getCause(); while (t != null) { if (t instanceof MatParseException) { Logger.getLogger(EditableMatDefFile.class.getName()).log(Level.SEVERE, t.getMessage()); matParseError = true; } t = t.getCause(); } if (!matParseError) { Exceptions.printStackTrace(ex); } } finally { if (lock != null) { lock.releaseLock(); } if (in != null) { try { in.close(); } catch (IOException ex) { Exceptions.printStackTrace(ex); } } } if (materialDef != null && !matParseError) { if(currentTechnique == null){ currentTechnique = matDefStructure.getTechniques().get(0); } registerListener(matDefStructure); obj.getLookupContents().add(matDefStructure); updateLookupWithMaterialData(obj); loaded = true; } } private void registerListener(Statement sta) { if (sta instanceof UberStatement) { ((UberStatement) sta).addPropertyChangeListener(WeakListeners.propertyChange(changeListener, ((UberStatement) sta))); } else if (sta instanceof LeafStatement) { ((LeafStatement) sta).addPropertyChangeListener(WeakListeners.propertyChange(changeListener, ((LeafStatement) sta))); } if (sta.getContents() != null) { for (Statement statement : sta.getContents()) { registerListener(statement); } } } public void buildOverview(ExplorerManager mgr) { if (materialDef != null) { mgr.setRootContext(new MatDefNode(lookup)); } else { mgr.setRootContext(Node.EMPTY); } } public String getShaderCode(String version, Shader.ShaderType type) { try { material.selectTechnique(currentTechnique.getName(), SceneApplication.getApplication().getRenderManager()); Shader s; if (version.equals(GLSL100)) { glsl100.initialize(material.getActiveTechnique()); s = glsl100.generateShader(); } else { glsl150.initialize(material.getActiveTechnique()); s = glsl150.generateShader(); } for (Shader.ShaderSource source : s.getSources()) { if (source.getType() == type) { return source.getSource(); } } return ""; } catch (Exception e) { Exceptions.printStackTrace(e); return "error generating shader " + e.getMessage(); } } public TechniqueBlock getCurrentTechnique() { return currentTechnique; } public void setCurrentTechnique(TechniqueBlock tech){ this.currentTechnique = tech; } public MatDefBlock getMatDefStructure() { return matDefStructure; } private final MatStructChangeListener changeListener = new MatStructChangeListener(); J3MLoader loader = new J3MLoader(); private void updateLookupWithMaterialData(MatDefDataObject obj) { obj.getLookupContents().add(materialDef); material = new Material(materialDef); try { material.selectTechnique("Default", SceneApplication.getApplication().getRenderManager()); if (matToRemove != null) { for (MatParam matParam : matToRemove.getParams()) { try { material.setParam(matParam.getName(), matParam.getVarType(), matParam.getValue()); } catch (IllegalArgumentException ie) { matToRemove.clearParam(matParam.getName()); } } obj.getLookupContents().remove(matToRemove); matToRemove = null; } obj.getLookupContents().add(material); } catch (Exception e) { Logger.getLogger(EditableMatDefFile.class.getName()).log(Level.WARNING, "Error making material {0}", e.getMessage()); material = matToRemove; } } public boolean isLoaded() { return loaded; } public boolean isDirty() { return dirty; } public void setDirty(boolean dirty) { this.dirty = dirty; } public void setLoaded(boolean loaded) { this.loaded = loaded; } private class MatStructChangeListener implements PropertyChangeListener { public void propertyChange(PropertyChangeEvent evt) { if (evt.getSource() instanceof ShaderNodeBlock && evt.getPropertyName().equals("name")) { String oldValue = (String) evt.getOldValue(); String newValue = (String) evt.getNewValue(); for (ShaderNodeBlock shaderNodeBlock : currentTechnique.getShaderNodes()) { List lin = shaderNodeBlock.getInputs(); if (lin != null) { for (InputMappingBlock inputMappingBlock : shaderNodeBlock.getInputs()) { if (inputMappingBlock.getLeftNameSpace().equals(oldValue)) { inputMappingBlock.setLeftNameSpace(newValue); } if (inputMappingBlock.getRightNameSpace().equals(oldValue)) { inputMappingBlock.setRightNameSpace(newValue); } } } List l = shaderNodeBlock.getOutputs(); if (l != null) { for (OutputMappingBlock outputMappingBlock : l) { if (outputMappingBlock.getRightNameSpace().equals(oldValue)) { outputMappingBlock.setRightNameSpace(newValue); } } } } } if (evt.getPropertyName().equals(MatDefBlock.REMOVE_MAT_PARAM)) { MatParamBlock oldValue = (MatParamBlock) evt.getOldValue(); for (ShaderNodeBlock shaderNodeBlock : currentTechnique.getShaderNodes()) { if (shaderNodeBlock.getCondition() != null && shaderNodeBlock.getCondition().contains(oldValue.getName())) { 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()); } } } List l = shaderNodeBlock.getOutputs(); if (l != null) { for (OutputMappingBlock outputMappingBlock : l) { if (outputMappingBlock.getCondition() != null && outputMappingBlock.getCondition().contains(oldValue.getName())) { outputMappingBlock.setCondition(outputMappingBlock.getCondition().replaceAll(oldValue.getName(), "").trim()); } } } } } if (evt.getPropertyName().equals(MatDefBlock.ADD_MAT_PARAM) || evt.getPropertyName().equals(TechniqueBlock.ADD_SHADER_NODE) || evt.getPropertyName().equals(ShaderNodeBlock.ADD_MAPPING)) { registerListener((Statement) evt.getNewValue()); } applyChange(); } } Material matToRemove; private void applyChange() { try { EditorCookie ec = lookup.lookup(EditorCookie.class); final StyledDocument doc = ec.getDocument(); final BadLocationException[] exc = new BadLocationException[]{null}; NbDocument.runAtomicAsUser(ec.getDocument(), new Runnable() { public void run() { try { doc.remove(0, doc.getLength()); doc.insertString(doc.getLength(), matDefStructure.toString(), SimpleAttributeSet.EMPTY); } catch (BadLocationException e) { exc[0] = e; } } }); } catch (BadLocationException ex) { Exceptions.printStackTrace(ex); } AssetKey key = new AssetKey(assetManager.getRelativeAssetPath(matDefFile.getPath())); obj.getLookupContents().remove(materialDef); matToRemove = material; List l = new ArrayList(); l.add(matDefStructure); try { materialDef = loader.loadMaterialDef(l, assetManager, key); } catch (IOException ex) { Logger.getLogger(EditableMatDefFile.class.getName()).log(Level.SEVERE, ex.getMessage()); } updateLookupWithMaterialData(obj); } }