Core system git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@10432 75d07b2b-3a1a-0410-a2c5-0572b91ccdca3.0
parent
9e3a98931a
commit
55d065ab78
@ -0,0 +1,112 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2009-2012 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.material.plugins; |
||||||
|
|
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.List; |
||||||
|
import java.util.regex.Matcher; |
||||||
|
import java.util.regex.Pattern; |
||||||
|
|
||||||
|
/** |
||||||
|
* An utility class that allows to parse a define condition in a glsl language |
||||||
|
* style. |
||||||
|
* |
||||||
|
* extractDefines is able to get a list of defines in an expression and update |
||||||
|
* the formatter expression with upercased defines |
||||||
|
* |
||||||
|
* @author Nehon |
||||||
|
*/ |
||||||
|
public class ConditionParser { |
||||||
|
|
||||||
|
private String formattedExpression = ""; |
||||||
|
|
||||||
|
public static void main(String argv[]) { |
||||||
|
ConditionParser parser = new ConditionParser(); |
||||||
|
List<String> defines = parser.extractDefines("(LightMap && SeparateTexCoord) || !ColorMap"); |
||||||
|
|
||||||
|
for (String string : defines) { |
||||||
|
System.err.println(string); |
||||||
|
} |
||||||
|
System.err.println(parser.formattedExpression); |
||||||
|
|
||||||
|
defines = parser.extractDefines("#if (defined(LightMap) && defined(SeparateTexCoord)) || !defined(ColorMap)"); |
||||||
|
|
||||||
|
for (String string : defines) { |
||||||
|
System.err.println(string); |
||||||
|
} |
||||||
|
System.err.println(parser.formattedExpression); |
||||||
|
|
||||||
|
|
||||||
|
// System.err.println(parser.getFormattedExpression());
|
||||||
|
//
|
||||||
|
// parser.parse("ShaderNode.var.xyz");
|
||||||
|
// parser.parse("var.xyz");
|
||||||
|
// parser.parse("ShaderNode.var");
|
||||||
|
// parser.parse("var");
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* parse a condition and returns the list of defines of this condition. |
||||||
|
* additionally this methods updates the formattedExpression with uppercased |
||||||
|
* defines names |
||||||
|
* |
||||||
|
* supported expression syntax example: |
||||||
|
* "(LightMap && SeparateTexCoord) || !ColorMap" |
||||||
|
* "#if (defined(LightMap) && defined(SeparateTexCoord)) || !defined(ColorMap)" |
||||||
|
* "#ifdef LightMap" |
||||||
|
* "#ifdef (LightMap && SeparateTexCoord) || !ColorMap" |
||||||
|
* |
||||||
|
* @param expression the expression to parse |
||||||
|
* @return the list of defines |
||||||
|
*/ |
||||||
|
public List<String> extractDefines(String expression) { |
||||||
|
List<String> defines = new ArrayList<String>(); |
||||||
|
expression = expression.replaceAll("#ifdef", "").replaceAll("#if", "").replaceAll("defined", ""); |
||||||
|
Pattern pattern = Pattern.compile("(\\w+)"); |
||||||
|
formattedExpression = expression; |
||||||
|
Matcher m = pattern.matcher(expression); |
||||||
|
while (m.find()) { |
||||||
|
String match = m.group(); |
||||||
|
defines.add(match); |
||||||
|
formattedExpression = formattedExpression.replaceAll(match, "defined(" + match.toUpperCase() + ")"); |
||||||
|
} |
||||||
|
return defines; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @return the formatted expression previously updated by extractDefines |
||||||
|
*/ |
||||||
|
public String getFormattedExpression() { |
||||||
|
return formattedExpression; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,90 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2009-2012 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.material.plugins; |
||||||
|
|
||||||
|
import com.jme3.util.blockparser.Statement; |
||||||
|
import java.io.IOException; |
||||||
|
|
||||||
|
/** |
||||||
|
* Custom Exception to report a j3md Material definition file parsing error. |
||||||
|
* This exception reports the line number where the error occured. |
||||||
|
* |
||||||
|
* @author Nehon |
||||||
|
*/ |
||||||
|
public class MatParseException extends IOException { |
||||||
|
|
||||||
|
/** |
||||||
|
* creates a MatParseException |
||||||
|
* |
||||||
|
* @param expected the expected value |
||||||
|
* @param got the actual value |
||||||
|
* @param statement the read statement |
||||||
|
*/ |
||||||
|
public MatParseException(String expected, String got, Statement statement) { |
||||||
|
super("Error On line " + statement.getLineNumber() + " : " + statement.getLine() + "\n->Expected " + (expected == null ? "a statement" : expected) + ", got '" + got + "'!"); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* creates a MatParseException |
||||||
|
* |
||||||
|
* @param text the error message |
||||||
|
* @param statement the statement where the error occur |
||||||
|
*/ |
||||||
|
public MatParseException(String text, Statement statement) { |
||||||
|
super("Error On line " + statement.getLineNumber() + " : " + statement.getLine() + "\n->" + text); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* creates a MatParseException |
||||||
|
* |
||||||
|
* @param expected the expected value |
||||||
|
* @param got the actual value |
||||||
|
* @param statement the read statement |
||||||
|
* @param cause the embed exception that occured |
||||||
|
*/ |
||||||
|
public MatParseException(String expected, String got, Statement statement, Throwable cause) { |
||||||
|
super("Error On line " + statement.getLineNumber() + " : " + statement.getLine() + "\n->Expected " + (expected == null ? "a statement" : expected) + ", got '" + got + "'!", cause); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* creates a MatParseException |
||||||
|
* |
||||||
|
* @param text the error message |
||||||
|
* @param statement the statement where the error occur |
||||||
|
* @param cause the embed exception that occured |
||||||
|
*/ |
||||||
|
public MatParseException(String text, Statement statement, Throwable cause) { |
||||||
|
super("Error On line " + statement.getLineNumber() + " : " + statement.getLine() + "\n->" + text, cause); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,85 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2009-2012 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.material.plugins; |
||||||
|
|
||||||
|
import com.jme3.asset.AssetInfo; |
||||||
|
import com.jme3.asset.AssetKey; |
||||||
|
import com.jme3.asset.AssetLoadException; |
||||||
|
import com.jme3.asset.AssetLoader; |
||||||
|
import com.jme3.asset.ShaderNodeDefinitionKey; |
||||||
|
import com.jme3.util.blockparser.BlockLanguageParser; |
||||||
|
import com.jme3.util.blockparser.Statement; |
||||||
|
import java.io.IOException; |
||||||
|
import java.io.InputStream; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
/** |
||||||
|
* ShaderNodeDefnition file loader (.j3sn) |
||||||
|
* |
||||||
|
* a j3sn file is a block style file like j3md or j3m. It must contain one |
||||||
|
* ShaderNodeDefinition{} block that contains several ShaderNodeDefinition{} |
||||||
|
* blocks |
||||||
|
* |
||||||
|
* @author Nehon |
||||||
|
*/ |
||||||
|
public class ShaderNodeDefinitionLoader implements AssetLoader { |
||||||
|
|
||||||
|
private ShaderNodeLoaderDelegate loaderDelegate; |
||||||
|
|
||||||
|
@Override |
||||||
|
public Object load(AssetInfo assetInfo) throws IOException { |
||||||
|
AssetKey k = assetInfo.getKey(); |
||||||
|
if (!(k instanceof ShaderNodeDefinitionKey)) { |
||||||
|
throw new IOException("ShaderNodeDefinition file must be loaded via ShaderNodeDefinitionKey"); |
||||||
|
} |
||||||
|
ShaderNodeDefinitionKey key = (ShaderNodeDefinitionKey) k; |
||||||
|
loaderDelegate = new ShaderNodeLoaderDelegate(); |
||||||
|
|
||||||
|
InputStream in = assetInfo.openStream(); |
||||||
|
List<Statement> roots = BlockLanguageParser.parse(in); |
||||||
|
|
||||||
|
if (roots.size() == 2) { |
||||||
|
Statement exception = roots.get(0); |
||||||
|
String line = exception.getLine(); |
||||||
|
if (line.startsWith("Exception")) { |
||||||
|
throw new AssetLoadException(line.substring("Exception ".length())); |
||||||
|
} else { |
||||||
|
throw new MatParseException("In multiroot shader node definition, expected first statement to be 'Exception'", exception); |
||||||
|
} |
||||||
|
} else if (roots.size() != 1) { |
||||||
|
throw new MatParseException("Too many roots in J3SN file", roots.get(0)); |
||||||
|
} |
||||||
|
|
||||||
|
return loaderDelegate.readNodesDefinitions(roots.get(0).getContents(), key); |
||||||
|
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,937 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2009-2012 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.material.plugins; |
||||||
|
|
||||||
|
import com.jme3.asset.AssetManager; |
||||||
|
import com.jme3.asset.AssetNotFoundException; |
||||||
|
import com.jme3.asset.ShaderNodeDefinitionKey; |
||||||
|
import com.jme3.material.MatParam; |
||||||
|
import com.jme3.material.MaterialDef; |
||||||
|
import com.jme3.material.ShaderGenerationInfo; |
||||||
|
import com.jme3.material.TechniqueDef; |
||||||
|
import com.jme3.shader.Shader; |
||||||
|
import com.jme3.shader.ShaderNode; |
||||||
|
import com.jme3.shader.ShaderNodeDefinition; |
||||||
|
import com.jme3.shader.ShaderNodeVariable; |
||||||
|
import com.jme3.shader.ShaderUtils; |
||||||
|
import com.jme3.shader.UniformBinding; |
||||||
|
import com.jme3.shader.VariableMapping; |
||||||
|
import com.jme3.util.blockparser.Statement; |
||||||
|
import java.io.IOException; |
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.List; |
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
/** |
||||||
|
* This class is here to be able to load shaderNodeDefinition from both the |
||||||
|
* J3MLoader and ShaderNodeDefinitionLoader. |
||||||
|
* |
||||||
|
* Also it allows to load the ShaderNodes from a j3md file and build the |
||||||
|
* ShaderNodes list of each technique and the ShaderGenerationInfo needed to |
||||||
|
* generate the sahders |
||||||
|
* |
||||||
|
* @author Nehon |
||||||
|
*/ |
||||||
|
public class ShaderNodeLoaderDelegate { |
||||||
|
|
||||||
|
protected Map<String, ShaderNodeDefinition> nodeDefinitions; |
||||||
|
protected Map<String, ShaderNode> nodes; |
||||||
|
protected ShaderNodeDefinition shaderNodeDefinition; |
||||||
|
protected ShaderNode shaderNode; |
||||||
|
protected TechniqueDef techniqueDef; |
||||||
|
protected Map<String, ShaderNodeVariable> attributes = new HashMap<String, ShaderNodeVariable>(); |
||||||
|
protected Map<String, ShaderNodeVariable> vertexDeclaredUniforms = new HashMap<String, ShaderNodeVariable>(); |
||||||
|
protected Map<String, ShaderNodeVariable> fragmentDeclaredUniforms = new HashMap<String, ShaderNodeVariable>(); |
||||||
|
protected Map<String, ShaderNodeVariable> varyings = new HashMap<String, ShaderNodeVariable>(); |
||||||
|
protected MaterialDef materialDef; |
||||||
|
protected String shaderLanguage; |
||||||
|
protected String shaderName; |
||||||
|
protected String varNames = ""; |
||||||
|
protected AssetManager assetManager; |
||||||
|
protected ConditionParser conditionParser = new ConditionParser(); |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Read the ShaderNodesDefinitions block and returns a list of |
||||||
|
* ShaderNodesDefinition This method is used by the j3sn loader |
||||||
|
* |
||||||
|
* note that the order of the definitions in the list is not guaranteed. |
||||||
|
* |
||||||
|
* @param statements the list statements to parse |
||||||
|
* @param key the ShaderNodeDefinitionKey |
||||||
|
* @return a list of ShaderNodesDefinition |
||||||
|
* @throws IOException |
||||||
|
*/ |
||||||
|
public List<ShaderNodeDefinition> readNodesDefinitions(List<Statement> statements, ShaderNodeDefinitionKey key) throws IOException { |
||||||
|
|
||||||
|
for (Statement statement : statements) { |
||||||
|
String[] split = statement.getLine().split("[ \\{]"); |
||||||
|
if (statement.getLine().startsWith("ShaderNodeDefinition")) { |
||||||
|
String name = statement.getLine().substring("ShaderNodeDefinition".length()).trim(); |
||||||
|
|
||||||
|
|
||||||
|
if (!getNodeDefinitions().containsKey(name)) { |
||||||
|
shaderNodeDefinition = new ShaderNodeDefinition(); |
||||||
|
getNodeDefinitions().put(name, shaderNodeDefinition); |
||||||
|
shaderNodeDefinition.setName(name); |
||||||
|
readShaderNodeDefinition(statement.getContents(), key); |
||||||
|
|
||||||
|
} |
||||||
|
} else { |
||||||
|
throw new MatParseException("ShaderNodeDefinition", split[0], statement); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return new ArrayList<ShaderNodeDefinition>(getNodeDefinitions().values()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Read the ShaderNodesDefinitions block and internally stores a map of |
||||||
|
* ShaderNodesDefinition This method is used by the j3m loader. |
||||||
|
* |
||||||
|
* When loaded in a material, the definitions are not stored as a list, but |
||||||
|
* they are stores in Shadernodes based onthis definition. |
||||||
|
* |
||||||
|
* The map is here to map the defintion to the nodes, and ovoid reloading |
||||||
|
* already loaded definitions |
||||||
|
* |
||||||
|
* @param statements the list of statements to parse |
||||||
|
* @throws IOException |
||||||
|
*/ |
||||||
|
public void readNodesDefinitions(List<Statement> statements) throws IOException { |
||||||
|
readNodesDefinitions(statements, new ShaderNodeDefinitionKey()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* effectiveliy reads the ShaderNodesDefinitions block |
||||||
|
* |
||||||
|
* @param statements the list of statements to parse |
||||||
|
* @param key the ShaderNodeDefinitionKey |
||||||
|
* @throws IOException |
||||||
|
*/ |
||||||
|
protected void readShaderNodeDefinition(List<Statement> statements, ShaderNodeDefinitionKey key) throws IOException { |
||||||
|
boolean isLoadDoc = key instanceof ShaderNodeDefinitionKey && ((ShaderNodeDefinitionKey) key).isLoadDocumentation(); |
||||||
|
for (Statement statement : statements) { |
||||||
|
String[] split = statement.getLine().split("[ \\{]"); |
||||||
|
String line = statement.getLine(); |
||||||
|
|
||||||
|
if (line.startsWith("Type")) { |
||||||
|
String type = line.substring(line.lastIndexOf(':') + 1).trim(); |
||||||
|
shaderNodeDefinition.setType(Shader.ShaderType.valueOf(type)); |
||||||
|
} else if (line.startsWith("Shader ")) { |
||||||
|
readShaderStatement(statement); |
||||||
|
shaderNodeDefinition.getShadersLanguage().add(shaderLanguage); |
||||||
|
shaderNodeDefinition.getShadersPath().add(shaderName); |
||||||
|
} else if (line.startsWith("Documentation")) { |
||||||
|
if (isLoadDoc) { |
||||||
|
String doc = ""; |
||||||
|
for (Statement statement1 : statement.getContents()) { |
||||||
|
doc += "\n" + statement1.getLine(); |
||||||
|
} |
||||||
|
shaderNodeDefinition.setDocumentation(doc); |
||||||
|
} |
||||||
|
} else if (line.startsWith("Input")) { |
||||||
|
varNames = ""; |
||||||
|
for (Statement statement1 : statement.getContents()) { |
||||||
|
shaderNodeDefinition.getInputs().add(readVariable(statement1)); |
||||||
|
} |
||||||
|
} else if (line.startsWith("Output")) { |
||||||
|
varNames = ""; |
||||||
|
for (Statement statement1 : statement.getContents()) { |
||||||
|
shaderNodeDefinition.getOutputs().add(readVariable(statement1)); |
||||||
|
} |
||||||
|
} else { |
||||||
|
throw new MatParseException("one of Type, Shader, Documentation, Input, Output", split[0], statement); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* reads a variable declaration statement <glslType> <varName> |
||||||
|
* |
||||||
|
* @param statement the statement to parse |
||||||
|
* @return a ShaderNodeVariable axtracted from the statement |
||||||
|
* @throws IOException |
||||||
|
*/ |
||||||
|
protected ShaderNodeVariable readVariable(Statement statement) throws IOException { |
||||||
|
String[] splitVar = statement.getLine().trim().split("\\s"); |
||||||
|
if (varNames.contains(splitVar[1] + ";")) { |
||||||
|
throw new MatParseException("Duplicate variable name " + splitVar[1], statement); |
||||||
|
} |
||||||
|
varNames += splitVar[1] + ";"; |
||||||
|
return new ShaderNodeVariable(splitVar[0], splitVar[1]); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* reads the VertexShaderNodes{} block |
||||||
|
* |
||||||
|
* @param statements the list of statements to parse |
||||||
|
* @throws IOException |
||||||
|
*/ |
||||||
|
public void readVertexShaderNodes(List<Statement> statements) throws IOException { |
||||||
|
attributes.clear(); |
||||||
|
readNodes(statements); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* reads a list of ShaderNode{} blocks |
||||||
|
* |
||||||
|
* @param statements the list of statements to parse |
||||||
|
* @throws IOException |
||||||
|
*/ |
||||||
|
protected void readShaderNode(List<Statement> statements) throws IOException { |
||||||
|
for (Statement statement : statements) { |
||||||
|
String line = statement.getLine(); |
||||||
|
String[] split = statement.getLine().split("[ \\{]"); |
||||||
|
if (line.startsWith("Definition")) { |
||||||
|
ShaderNodeDefinition def = findDefinition(statement); |
||||||
|
shaderNode.setDefinition(def); |
||||||
|
} else if (line.startsWith("Condition")) { |
||||||
|
String condition = line.substring(line.lastIndexOf(":") + 1).trim(); |
||||||
|
extractCondition(condition, statement); |
||||||
|
shaderNode.setCondition(conditionParser.getFormattedExpression()); |
||||||
|
} else if (line.startsWith("InputMapping")) { |
||||||
|
for (Statement statement1 : statement.getContents()) { |
||||||
|
VariableMapping mapping = readInputMapping(statement1); |
||||||
|
techniqueDef.getShaderGenerationInfo().getUnusedNodes().remove(mapping.getRightVariable().getNameSpace()); |
||||||
|
shaderNode.getInputMapping().add(mapping); |
||||||
|
} |
||||||
|
} else if (line.startsWith("OutputMapping")) { |
||||||
|
for (Statement statement1 : statement.getContents()) { |
||||||
|
VariableMapping mapping = readOutputMapping(statement1); |
||||||
|
techniqueDef.getShaderGenerationInfo().getUnusedNodes().remove(shaderNode.getName()); |
||||||
|
shaderNode.getOutputMapping().add(mapping); |
||||||
|
} |
||||||
|
} else { |
||||||
|
throw new MatParseException("ShaderNodeDefinition", split[0], statement); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* reads a mapping statement. Sets the nameSpace, name and swizzling of the |
||||||
|
* left variable. Sets the name, nameSpace and swizzling of the right |
||||||
|
* variable types will be determined later. |
||||||
|
* |
||||||
|
* Format : <nameSpace>.<varName>[.<swizzling>] = |
||||||
|
* <nameSpace>.<varName>[.<swizzling>][:Condition] |
||||||
|
* |
||||||
|
* @param statement the statement to read |
||||||
|
* @return the read mapping |
||||||
|
*/ |
||||||
|
protected VariableMapping parseMapping(Statement statement, boolean[] hasNameSpace) throws IOException { |
||||||
|
VariableMapping mapping = new VariableMapping(); |
||||||
|
String[] cond = statement.getLine().split(":"); |
||||||
|
|
||||||
|
String[] vars = cond[0].split("="); |
||||||
|
checkMappingFormat(vars, statement); |
||||||
|
ShaderNodeVariable[] variables = new ShaderNodeVariable[2]; |
||||||
|
String[] swizzle = new String[2]; |
||||||
|
for (int i = 0; i < vars.length; i++) { |
||||||
|
String[] expression = vars[i].trim().split("\\."); |
||||||
|
if (hasNameSpace[i]) { |
||||||
|
if (expression.length <= 3) { |
||||||
|
variables[i] = new ShaderNodeVariable("", expression[0].trim(), expression[1].trim()); |
||||||
|
} |
||||||
|
if (expression.length == 3) { |
||||||
|
swizzle[i] = expression[2].trim(); |
||||||
|
} |
||||||
|
} else { |
||||||
|
if (expression.length <= 2) { |
||||||
|
variables[i] = new ShaderNodeVariable("", expression[0].trim()); |
||||||
|
} |
||||||
|
if (expression.length == 2) { |
||||||
|
swizzle[i] = expression[1].trim(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
mapping.setLeftVariable(variables[0]); |
||||||
|
mapping.setLeftSwizzling(swizzle[0] != null ? swizzle[0] : ""); |
||||||
|
mapping.setRightVariable(variables[1]); |
||||||
|
mapping.setRightSwizzling(swizzle[1] != null ? swizzle[1] : ""); |
||||||
|
|
||||||
|
if (cond.length > 1) { |
||||||
|
extractCondition(cond[1], statement); |
||||||
|
mapping.setCondition(conditionParser.getFormattedExpression()); |
||||||
|
} |
||||||
|
|
||||||
|
return mapping; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* reads the FragmentShaderNodes{} block |
||||||
|
* |
||||||
|
* @param statements the list of statements to parse |
||||||
|
* @throws IOException |
||||||
|
*/ |
||||||
|
public void readFragmentShaderNodes(List<Statement> statements) throws IOException { |
||||||
|
readNodes(statements); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Reads a Shader statement of this form <TYPE> <LANG> : <SOURCE> |
||||||
|
* |
||||||
|
* @param statement |
||||||
|
* @throws IOException |
||||||
|
*/ |
||||||
|
protected void readShaderStatement(Statement statement) throws IOException { |
||||||
|
String[] split = statement.getLine().split(":"); |
||||||
|
if (split.length != 2) { |
||||||
|
throw new MatParseException("Shader statement syntax incorrect", statement); |
||||||
|
} |
||||||
|
String[] typeAndLang = split[0].split("\\p{javaWhitespace}+"); |
||||||
|
if (typeAndLang.length != 2) { |
||||||
|
throw new MatParseException("Shader statement syntax incorrect", statement); |
||||||
|
} |
||||||
|
shaderName = split[1].trim(); |
||||||
|
shaderLanguage = typeAndLang[1]; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Sets the technique definition currently being loaded |
||||||
|
* |
||||||
|
* @param techniqueDef the technique def |
||||||
|
*/ |
||||||
|
public void setTechniqueDef(TechniqueDef techniqueDef) { |
||||||
|
this.techniqueDef = techniqueDef; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* sets the material def currently being loaded |
||||||
|
* |
||||||
|
* @param materialDef |
||||||
|
*/ |
||||||
|
public void setMaterialDef(MaterialDef materialDef) { |
||||||
|
this.materialDef = materialDef; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* searcha variable in the given list and updates its type and namespace |
||||||
|
* |
||||||
|
* @param var the variable to update |
||||||
|
* @param list the variables list |
||||||
|
* @return true if the variable has been found and updated |
||||||
|
*/ |
||||||
|
protected boolean updateVariableFromList(ShaderNodeVariable var, List<ShaderNodeVariable> list) { |
||||||
|
for (ShaderNodeVariable shaderNodeVariable : list) { |
||||||
|
if (shaderNodeVariable.getName().equals(var.getName())) { |
||||||
|
var.setType(shaderNodeVariable.getType()); |
||||||
|
var.setNameSpace(shaderNode.getName()); |
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* updates the type of the right variable of a mapping from the type of the |
||||||
|
* left variable |
||||||
|
* |
||||||
|
* @param mapping the mapping to consider |
||||||
|
*/ |
||||||
|
protected void updateRightTypeFromLeftType(VariableMapping mapping) { |
||||||
|
String type = mapping.getLeftVariable().getType(); |
||||||
|
int card = ShaderUtils.getCardinality(type, mapping.getRightSwizzling()); |
||||||
|
if (card > 0) { |
||||||
|
if (card == 1) { |
||||||
|
type = "float"; |
||||||
|
} else { |
||||||
|
type = "vec" + card; |
||||||
|
} |
||||||
|
} |
||||||
|
mapping.getRightVariable().setType(type); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* check if once a mapping expression is split by "=" the resulting array |
||||||
|
* have 2 elements |
||||||
|
* |
||||||
|
* @param vars the array |
||||||
|
* @param statement the statement |
||||||
|
* @throws IOException |
||||||
|
*/ |
||||||
|
protected void checkMappingFormat(String[] vars, Statement statement) throws IOException { |
||||||
|
if (vars.length != 2) { |
||||||
|
throw new MatParseException("Not a valid expression should be '<varName>[.<swizzling>] = <nameSpace>.<varName>[.<swizzling>][:Condition]'", statement); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* finds a MatParam in the materialDef from the given name |
||||||
|
* |
||||||
|
* @param varName the matparam name |
||||||
|
* @return the MatParam |
||||||
|
*/ |
||||||
|
protected MatParam findMatParam(String varName) { |
||||||
|
for (MatParam matParam : materialDef.getMaterialParams()) { |
||||||
|
if (varName.equals(matParam.getName())) { |
||||||
|
return matParam; |
||||||
|
} |
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* finds an UniformBinding representing a WorldParam from the techniqueDef |
||||||
|
* |
||||||
|
* @param varName the name of the WorldParam |
||||||
|
* @return the corresponding UniformBinding to the WorldParam |
||||||
|
*/ |
||||||
|
protected UniformBinding findWorldParam(String varName) { |
||||||
|
for (UniformBinding worldParam : techniqueDef.getWorldBindings()) { |
||||||
|
if (varName.equals(worldParam.toString())) { |
||||||
|
return worldParam; |
||||||
|
} |
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* updates the right variable of the given mapping from a UniformBinding (a |
||||||
|
* WorldParam) it checks if the unifrom hasn't already been loaded, add it |
||||||
|
* to the maps if not. |
||||||
|
* |
||||||
|
* @param param the WorldParam UniformBinding |
||||||
|
* @param mapping the mapping |
||||||
|
* @param map the map of uniforms to search into |
||||||
|
* @return true if the param was added to the map |
||||||
|
*/ |
||||||
|
protected boolean updateRightFromUniforms(UniformBinding param, VariableMapping mapping, Map<String, ShaderNodeVariable> map) { |
||||||
|
ShaderNodeVariable right = mapping.getRightVariable(); |
||||||
|
String name = "g_" + param.toString(); |
||||||
|
ShaderNodeVariable var = map.get(name); |
||||||
|
if (var == null) { |
||||||
|
right.setType(param.getGlslType()); |
||||||
|
right.setName(name); |
||||||
|
map.put(right.getName(), right); |
||||||
|
mapping.setRightVariable(right); |
||||||
|
return true; |
||||||
|
} |
||||||
|
mapping.setRightVariable(var); |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* updates the right variable of the given mapping from a MatParam (a |
||||||
|
* WorldParam) it checks if the unifrom hasn't already been loaded, add it |
||||||
|
* to the maps if not. |
||||||
|
* |
||||||
|
* @param param the MatParam |
||||||
|
* @param mapping the mapping |
||||||
|
* @param map the map of uniforms to search into |
||||||
|
* @return true if the param was added to the map |
||||||
|
*/ |
||||||
|
public boolean updateRightFromUniforms(MatParam param, VariableMapping mapping, Map<String, ShaderNodeVariable> map) { |
||||||
|
ShaderNodeVariable right = mapping.getRightVariable(); |
||||||
|
ShaderNodeVariable var = map.get(param.getPrefixedName()); |
||||||
|
if (var == null) { |
||||||
|
right.setType(param.getVarType().getGlslType()); |
||||||
|
right.setName(param.getPrefixedName()); |
||||||
|
map.put(right.getName(), right); |
||||||
|
mapping.setRightVariable(right); |
||||||
|
return true; |
||||||
|
} |
||||||
|
mapping.setRightVariable(var); |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* updates a variable from the Attribute list |
||||||
|
* |
||||||
|
* @param right the variable |
||||||
|
* @param mapping the mapping |
||||||
|
*/ |
||||||
|
public void updateVarFromAttributes(ShaderNodeVariable right, VariableMapping mapping) { |
||||||
|
ShaderNodeVariable var = attributes.get(right.getName()); |
||||||
|
if (var == null) { |
||||||
|
updateRightTypeFromLeftType(mapping); |
||||||
|
} else { |
||||||
|
|
||||||
|
mapping.setRightVariable(var); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Adds a define to the techniquedef |
||||||
|
* |
||||||
|
* @param paramName |
||||||
|
*/ |
||||||
|
public void addDefine(String paramName) { |
||||||
|
if (techniqueDef.getShaderParamDefine(paramName) == null) { |
||||||
|
techniqueDef.addShaderParamDefine(paramName, paramName.toUpperCase()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* find a variable with the given name from the list of variable |
||||||
|
* |
||||||
|
* @param vars a list of shaderNodeVariables |
||||||
|
* @param rightVarName the variable name to search for |
||||||
|
* @return the found variable or null is not found |
||||||
|
*/ |
||||||
|
public ShaderNodeVariable findNodeOutput(List<ShaderNodeVariable> vars, String rightVarName) { |
||||||
|
ShaderNodeVariable var = null; |
||||||
|
for (ShaderNodeVariable variable : vars) { |
||||||
|
if (variable.getName().equals(rightVarName)) { |
||||||
|
var = variable; |
||||||
|
} |
||||||
|
} |
||||||
|
return var; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* extract and check a condition expression |
||||||
|
* |
||||||
|
* @param cond the condition expression |
||||||
|
* @param statement the statement being read |
||||||
|
* @throws IOException |
||||||
|
*/ |
||||||
|
public void extractCondition(String cond, Statement statement) throws IOException { |
||||||
|
List<String> defines = conditionParser.extractDefines(cond); |
||||||
|
for (String string : defines) { |
||||||
|
MatParam param = findMatParam(string); |
||||||
|
if (param != null) { |
||||||
|
addDefine(param.getName()); |
||||||
|
} else { |
||||||
|
throw new MatParseException("Invalid condition, condition must match a Material Parameter named " + cond, statement); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* reads an input mapping |
||||||
|
* |
||||||
|
* @param statement1 the statement being read |
||||||
|
* @return the mapping |
||||||
|
* @throws IOException |
||||||
|
*/ |
||||||
|
public VariableMapping readInputMapping(Statement statement1) throws IOException { |
||||||
|
VariableMapping mapping = null; |
||||||
|
try { |
||||||
|
mapping = parseMapping(statement1, new boolean[]{false, true}); |
||||||
|
} catch (Exception e) { |
||||||
|
throw new MatParseException("Unexpected mapping format", statement1, e); |
||||||
|
} |
||||||
|
ShaderNodeVariable left = mapping.getLeftVariable(); |
||||||
|
ShaderNodeVariable right = mapping.getRightVariable(); |
||||||
|
if (!updateVariableFromList(left, shaderNode.getDefinition().getInputs())) { |
||||||
|
throw new MatParseException(left.getName() + " is not an input variable of " + shaderNode.getDefinition().getName(), statement1); |
||||||
|
} |
||||||
|
|
||||||
|
if (left.getType().startsWith("sampler") && !right.getNameSpace().equals("MatParam")) { |
||||||
|
throw new MatParseException("Samplers can only be assigned to MatParams", statement1); |
||||||
|
} |
||||||
|
|
||||||
|
if (right.getNameSpace().equals("Global")) { |
||||||
|
right.setType("vec4");//Globals are all vec4 for now (maybe forever...)
|
||||||
|
updateCondition(right, mapping); |
||||||
|
storeGlobal(right, statement1); |
||||||
|
|
||||||
|
} else if (right.getNameSpace().equals("Attr")) { |
||||||
|
if (shaderNode.getDefinition().getType() == Shader.ShaderType.Fragment) { |
||||||
|
throw new MatParseException("Cannot have an attribute as input in a fragment shader" + right.getName(), statement1); |
||||||
|
} |
||||||
|
updateVarFromAttributes(mapping.getRightVariable(), mapping); |
||||||
|
updateCondition(mapping.getRightVariable(), mapping); |
||||||
|
storeAttribute(mapping.getRightVariable()); |
||||||
|
} else if (right.getNameSpace().equals("MatParam")) { |
||||||
|
MatParam param = findMatParam(right.getName()); |
||||||
|
if (param == null) { |
||||||
|
throw new MatParseException("Could not find a Material Parameter named " + right.getName(), statement1); |
||||||
|
} |
||||||
|
if (shaderNode.getDefinition().getType() == Shader.ShaderType.Vertex) { |
||||||
|
if (updateRightFromUniforms(param, mapping, vertexDeclaredUniforms)) { |
||||||
|
updateCondition(mapping.getRightVariable(), mapping); |
||||||
|
storeVertexUniform(mapping.getRightVariable()); |
||||||
|
} |
||||||
|
} else { |
||||||
|
if (updateRightFromUniforms(param, mapping, fragmentDeclaredUniforms)) { |
||||||
|
if (mapping.getRightVariable().getType().contains("|")) { |
||||||
|
String type = fixSamplerType(left.getType(), mapping.getRightVariable().getType()); |
||||||
|
if (type != null) { |
||||||
|
mapping.getRightVariable().setType(type); |
||||||
|
} else { |
||||||
|
throw new MatParseException(param.getVarType().toString() + " can only be matched to one of " + param.getVarType().getGlslType().replaceAll("\\|", ",") + " found " + left.getType(), statement1); |
||||||
|
} |
||||||
|
} |
||||||
|
updateCondition(mapping.getRightVariable(), mapping); |
||||||
|
storeFragmentUniform(mapping.getRightVariable()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} else if (right.getNameSpace().equals("WorldParam")) { |
||||||
|
UniformBinding worldParam = findWorldParam(right.getName()); |
||||||
|
if (worldParam == null) { |
||||||
|
throw new MatParseException("Could not find a World Parameter named " + right.getName(), statement1); |
||||||
|
} |
||||||
|
if (shaderNode.getDefinition().getType() == Shader.ShaderType.Vertex) { |
||||||
|
if (updateRightFromUniforms(worldParam, mapping, vertexDeclaredUniforms)) { |
||||||
|
updateCondition(mapping.getRightVariable(), mapping); |
||||||
|
storeVertexUniform(mapping.getRightVariable()); |
||||||
|
} |
||||||
|
} else { |
||||||
|
if (updateRightFromUniforms(worldParam, mapping, fragmentDeclaredUniforms)) { |
||||||
|
updateCondition(mapping.getRightVariable(), mapping); |
||||||
|
storeFragmentUniform(mapping.getRightVariable()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} else { |
||||||
|
ShaderNode node = nodes.get(right.getNameSpace()); |
||||||
|
if (node == null) { |
||||||
|
throw new MatParseException("Undeclared node" + right.getNameSpace() + ". Make sure this node is declared before the current node", statement1); |
||||||
|
} |
||||||
|
ShaderNodeVariable var = findNodeOutput(node.getDefinition().getOutputs(), right.getName()); |
||||||
|
if (var == null) { |
||||||
|
throw new MatParseException("Cannot find output variable" + right.getName() + " form ShaderNode " + node.getName(), statement1); |
||||||
|
} |
||||||
|
right.setNameSpace(node.getName()); |
||||||
|
right.setType(var.getType()); |
||||||
|
mapping.setRightVariable(right); |
||||||
|
updateCondition(mapping.getRightVariable(), mapping); |
||||||
|
storeVaryings(node, mapping.getRightVariable()); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
checkTypes(mapping, statement1); |
||||||
|
|
||||||
|
return mapping; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* reads an output mapping |
||||||
|
* |
||||||
|
* @param statement1 the staement being read |
||||||
|
* @return the mapping |
||||||
|
* @throws IOException |
||||||
|
*/ |
||||||
|
public VariableMapping readOutputMapping(Statement statement1) throws IOException { |
||||||
|
VariableMapping mapping = null; |
||||||
|
try { |
||||||
|
mapping = parseMapping(statement1, new boolean[]{true, false}); |
||||||
|
} catch (Exception e) { |
||||||
|
throw new MatParseException("Unexpected mapping format", statement1, e); |
||||||
|
} |
||||||
|
ShaderNodeVariable left = mapping.getLeftVariable(); |
||||||
|
ShaderNodeVariable right = mapping.getRightVariable(); |
||||||
|
|
||||||
|
|
||||||
|
if (left.getType().startsWith("sampler") || right.getType().startsWith("sampler")) { |
||||||
|
throw new MatParseException("Samplers can only be inputs", statement1); |
||||||
|
} |
||||||
|
|
||||||
|
if (left.getNameSpace().equals("Global")) { |
||||||
|
left.setType("vec4");//Globals are all vec4 for now (maybe forever...)
|
||||||
|
updateCondition(left, mapping); |
||||||
|
storeGlobal(left, statement1); |
||||||
|
} else { |
||||||
|
throw new MatParseException("Only Global nameSpace is allowed for outputMapping, got" + left.getNameSpace(), statement1); |
||||||
|
} |
||||||
|
|
||||||
|
if (!updateVariableFromList(right, shaderNode.getDefinition().getOutputs())) { |
||||||
|
throw new MatParseException(right.getName() + " is not an output variable of " + shaderNode.getDefinition().getName(), statement1); |
||||||
|
} |
||||||
|
|
||||||
|
checkTypes(mapping, statement1); |
||||||
|
|
||||||
|
return mapping; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Reads alist of ShaderNodes |
||||||
|
* |
||||||
|
* @param statements the list of statements to read |
||||||
|
* @throws IOException |
||||||
|
*/ |
||||||
|
public void readNodes(List<Statement> statements) throws IOException { |
||||||
|
if (techniqueDef.getShaderNodes() == null) { |
||||||
|
techniqueDef.setShaderNodes(new ArrayList<ShaderNode>()); |
||||||
|
techniqueDef.setShaderGenerationInfo(new ShaderGenerationInfo()); |
||||||
|
} |
||||||
|
|
||||||
|
for (Statement statement : statements) { |
||||||
|
String[] split = statement.getLine().split("[ \\{]"); |
||||||
|
if (statement.getLine().startsWith("ShaderNode ")) { |
||||||
|
String name = statement.getLine().substring("ShaderNode".length()).trim(); |
||||||
|
if (nodes == null) { |
||||||
|
nodes = new HashMap<String, ShaderNode>(); |
||||||
|
} |
||||||
|
if (!nodes.containsKey(name)) { |
||||||
|
shaderNode = new ShaderNode(); |
||||||
|
shaderNode.setName(name); |
||||||
|
techniqueDef.getShaderGenerationInfo().getUnusedNodes().add(name); |
||||||
|
|
||||||
|
readShaderNode(statement.getContents()); |
||||||
|
nodes.put(name, shaderNode); |
||||||
|
techniqueDef.getShaderNodes().add(shaderNode); |
||||||
|
} else { |
||||||
|
throw new MatParseException("ShaderNode " + name + " is already defined", statement); |
||||||
|
} |
||||||
|
|
||||||
|
} else { |
||||||
|
throw new MatParseException("ShaderNode", split[0], statement); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* retrieve the leftType corresponding sampler type from the rightType |
||||||
|
* |
||||||
|
* @param leftType the left samplerType |
||||||
|
* @param rightType the right sampler type (can be multiple types sparated |
||||||
|
* by "|" |
||||||
|
* @return the type or null if not found |
||||||
|
*/ |
||||||
|
public String fixSamplerType(String leftType, String rightType) { |
||||||
|
String[] types = rightType.split("\\|"); |
||||||
|
for (String string : types) { |
||||||
|
if (leftType.equals(string)) { |
||||||
|
return string; |
||||||
|
} |
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* stores a global output |
||||||
|
* |
||||||
|
* @param var the variable to store |
||||||
|
* @param statement1 the statement being read |
||||||
|
* @throws IOException |
||||||
|
*/ |
||||||
|
public void storeGlobal(ShaderNodeVariable var, Statement statement1) throws IOException { |
||||||
|
var.setShaderOutput(true); |
||||||
|
if (shaderNode.getDefinition().getType() == Shader.ShaderType.Vertex) { |
||||||
|
ShaderNodeVariable global = techniqueDef.getShaderGenerationInfo().getVertexGlobal(); |
||||||
|
if (global != null) { |
||||||
|
global.setCondition(mergeConditions(global.getCondition(), var.getCondition(), "||")); |
||||||
|
var.setCondition(global.getCondition()); |
||||||
|
if (!global.getName().equals(var.getName())) { |
||||||
|
throw new MatParseException("A global output is already defined for the vertex shader: " + global.getName() + ". vertex shader can only have one global output", statement1); |
||||||
|
} |
||||||
|
} else { |
||||||
|
techniqueDef.getShaderGenerationInfo().setVertexGlobal(var); |
||||||
|
} |
||||||
|
} else if (shaderNode.getDefinition().getType() == Shader.ShaderType.Fragment) { |
||||||
|
mergeConditionsAndStoreVariable(var, techniqueDef.getShaderGenerationInfo().getFragmentGlobals()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* store an attribute |
||||||
|
* |
||||||
|
* @param var the variable ot store |
||||||
|
*/ |
||||||
|
public void storeAttribute(ShaderNodeVariable var) { |
||||||
|
mergeConditionsAndStoreVariable(var, techniqueDef.getShaderGenerationInfo().getAttributes()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* store a vertex uniform |
||||||
|
* |
||||||
|
* @param var the variable ot store |
||||||
|
*/ |
||||||
|
public void storeVertexUniform(ShaderNodeVariable var) { |
||||||
|
mergeConditionsAndStoreVariable(var, techniqueDef.getShaderGenerationInfo().getVertexUniforms()); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* store a fragment uniform |
||||||
|
* |
||||||
|
* @param var the variable ot store |
||||||
|
*/ |
||||||
|
public void storeFragmentUniform(ShaderNodeVariable var) { |
||||||
|
mergeConditionsAndStoreVariable(var, techniqueDef.getShaderGenerationInfo().getFragmentUniforms()); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* sets the assetManager |
||||||
|
* |
||||||
|
* @param assetManager |
||||||
|
*/ |
||||||
|
public void setAssetManager(AssetManager assetManager) { |
||||||
|
this.assetManager = assetManager; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* find the definiton from this statement (loads it if necessary) |
||||||
|
* |
||||||
|
* @param statement the statement being read |
||||||
|
* @return the definition |
||||||
|
* @throws IOException |
||||||
|
*/ |
||||||
|
public ShaderNodeDefinition findDefinition(Statement statement) throws IOException { |
||||||
|
String defLine[] = statement.getLine().split(":"); |
||||||
|
String defName = defLine[1].trim(); |
||||||
|
|
||||||
|
ShaderNodeDefinition def = getNodeDefinitions().get(defName); |
||||||
|
if (def == null) { |
||||||
|
if (defLine.length == 3) { |
||||||
|
List<ShaderNodeDefinition> defs = null; |
||||||
|
try { |
||||||
|
defs = assetManager.loadAsset(new ShaderNodeDefinitionKey(defLine[2].trim())); |
||||||
|
} catch (AssetNotFoundException e) { |
||||||
|
throw new MatParseException("Couldn't find " + defLine[2].trim(), statement, e); |
||||||
|
} |
||||||
|
|
||||||
|
for (ShaderNodeDefinition definition : defs) { |
||||||
|
definition.setPath(defLine[2].trim()); |
||||||
|
if (defName.equals(definition.getName())) { |
||||||
|
def = definition; |
||||||
|
} |
||||||
|
if (!(getNodeDefinitions().containsKey(definition.getName()))) { |
||||||
|
getNodeDefinitions().put(definition.getName(), definition); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
if (def == null) { |
||||||
|
throw new MatParseException(defName + " is not a declared as Shader Node Definition", statement); |
||||||
|
} |
||||||
|
} |
||||||
|
return def; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* updates a variable condition form a mapping condition |
||||||
|
* |
||||||
|
* @param var the variable |
||||||
|
* @param mapping the mapping |
||||||
|
*/ |
||||||
|
public void updateCondition(ShaderNodeVariable var, VariableMapping mapping) { |
||||||
|
|
||||||
|
String condition = mergeConditions(shaderNode.getCondition(), mapping.getCondition(), "&&"); |
||||||
|
|
||||||
|
if (var.getCondition() == null) { |
||||||
|
var.setCondition(condition); |
||||||
|
} else { |
||||||
|
var.setCondition(mergeConditions(var.getCondition(), condition, "||")); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* store a varying |
||||||
|
* |
||||||
|
* @param node the shaderNode |
||||||
|
* @param variable the variable to store |
||||||
|
*/ |
||||||
|
public void storeVaryings(ShaderNode node, ShaderNodeVariable variable) { |
||||||
|
variable.setShaderOutput(true); |
||||||
|
if (node.getDefinition().getType() == Shader.ShaderType.Vertex && shaderNode.getDefinition().getType() == Shader.ShaderType.Fragment) { |
||||||
|
ShaderNodeVariable var = varyings.get(variable.getName()); |
||||||
|
if (var == null) { |
||||||
|
techniqueDef.getShaderGenerationInfo().getVaryings().add(variable); |
||||||
|
varyings.put(variable.getName(), variable); |
||||||
|
} else { |
||||||
|
var.setCondition(mergeConditions(var.getCondition(), variable.getCondition(), "||")); |
||||||
|
variable.setCondition(var.getCondition()); |
||||||
|
} |
||||||
|
//if a variable is declared with the same name as an input and an output and is a varying, set it as a shader output so it's declared as a varying only once.
|
||||||
|
for (VariableMapping variableMapping : node.getInputMapping()) { |
||||||
|
if (variableMapping.getLeftVariable().getName().equals(variable.getName())) { |
||||||
|
variableMapping.getLeftVariable().setShaderOutput(true); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* merges 2 condition with the given operator |
||||||
|
* |
||||||
|
* @param condition1 the first condition |
||||||
|
* @param condition2 the second condition |
||||||
|
* @param operator the operator ("&&" or "||&) |
||||||
|
* @return the merged condition |
||||||
|
*/ |
||||||
|
public String mergeConditions(String condition1, String condition2, String operator) { |
||||||
|
if (operator.equals("||") && (condition1 == null || condition2 == null)) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
if (condition1 != null) { |
||||||
|
if (condition2 == null) { |
||||||
|
return condition1; |
||||||
|
} else { |
||||||
|
String mergedCondition = "(" + condition1 + ") " + operator + " (" + condition2 + ")"; |
||||||
|
return mergedCondition; |
||||||
|
} |
||||||
|
} else { |
||||||
|
return condition2; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* search a variable in a list from its name and merge the conditions of the |
||||||
|
* variables |
||||||
|
* |
||||||
|
* @param variable the variable |
||||||
|
* @param varList the variable list |
||||||
|
*/ |
||||||
|
public void mergeConditionsAndStoreVariable(ShaderNodeVariable variable, List<ShaderNodeVariable> varList) { |
||||||
|
for (ShaderNodeVariable var : varList) { |
||||||
|
if (var.getName().equals(variable.getName())) { |
||||||
|
var.setCondition(mergeConditions(var.getCondition(), variable.getCondition(), "||")); |
||||||
|
variable.setCondition(var.getCondition()); |
||||||
|
return; |
||||||
|
} |
||||||
|
} |
||||||
|
varList.add(variable); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* check the types of a mapping, left type must match right type tkae the |
||||||
|
* swizzle into account |
||||||
|
* |
||||||
|
* @param mapping the mapping |
||||||
|
* @param statement1 the statement being read |
||||||
|
* @throws MatParseException |
||||||
|
*/ |
||||||
|
protected void checkTypes(VariableMapping mapping, Statement statement1) throws MatParseException { |
||||||
|
if (!ShaderUtils.typesMatch(mapping)) { |
||||||
|
String ls = mapping.getLeftSwizzling().length() == 0 ? "" : "." + mapping.getLeftSwizzling(); |
||||||
|
String rs = mapping.getRightSwizzling().length() == 0 ? "" : "." + mapping.getRightSwizzling(); |
||||||
|
throw new MatParseException("Type mismatch, cannot convert" + mapping.getLeftVariable().getType() + ls + " to " + mapping.getRightVariable().getType() + rs, statement1); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private Map<String, ShaderNodeDefinition> getNodeDefinitions() { |
||||||
|
if (nodeDefinitions == null) { |
||||||
|
nodeDefinitions = new HashMap<String, ShaderNodeDefinition>(); |
||||||
|
} |
||||||
|
return nodeDefinitions; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,89 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2009-2012 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.asset; |
||||||
|
|
||||||
|
import com.jme3.asset.cache.AssetCache; |
||||||
|
import com.jme3.shader.ShaderNodeDefinition; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
/** |
||||||
|
* Used for loading {@link ShaderNodeDefinition shader nodes definition} |
||||||
|
* |
||||||
|
* Tells if the defintion has to be loaded with or without its documentation |
||||||
|
* |
||||||
|
* @author Kirill Vainer |
||||||
|
*/ |
||||||
|
public class ShaderNodeDefinitionKey extends AssetKey<List<ShaderNodeDefinition>> { |
||||||
|
|
||||||
|
private boolean loadDocumentation = false; |
||||||
|
|
||||||
|
/** |
||||||
|
* creates a ShaderNodeDefinitionKey |
||||||
|
* |
||||||
|
* @param name the name of the asset to load |
||||||
|
*/ |
||||||
|
public ShaderNodeDefinitionKey(String name) { |
||||||
|
super(name); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* creates a ShaderNodeDefinitionKey |
||||||
|
*/ |
||||||
|
public ShaderNodeDefinitionKey() { |
||||||
|
super(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Class<? extends AssetCache> getCacheType() { |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @return true if the asset loaded with this key will contain its |
||||||
|
* documentation |
||||||
|
*/ |
||||||
|
public boolean isLoadDocumentation() { |
||||||
|
return loadDocumentation; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* sets to true to load the documentation along with the |
||||||
|
* ShaderNodeDefinition |
||||||
|
* |
||||||
|
* @param loadDocumentation true to load the documentation along with the |
||||||
|
* ShaderNodeDefinition |
||||||
|
*/ |
||||||
|
public void setLoadDocumentation(boolean loadDocumentation) { |
||||||
|
this.loadDocumentation = loadDocumentation; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,190 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2009-2012 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.material; |
||||||
|
|
||||||
|
import com.jme3.export.InputCapsule; |
||||||
|
import com.jme3.export.JmeExporter; |
||||||
|
import com.jme3.export.JmeImporter; |
||||||
|
import com.jme3.export.OutputCapsule; |
||||||
|
import com.jme3.export.Savable; |
||||||
|
import com.jme3.shader.ShaderNodeVariable; |
||||||
|
import java.io.IOException; |
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
/** |
||||||
|
* this class is basically a struct that contains the ShaderNodes informations |
||||||
|
* in an appropriate way to ease the shader generation process and make it |
||||||
|
* faster. |
||||||
|
* |
||||||
|
* @author Nehon |
||||||
|
*/ |
||||||
|
public class ShaderGenerationInfo implements Savable { |
||||||
|
|
||||||
|
/** |
||||||
|
* the list of attributes of the vertex shader |
||||||
|
*/ |
||||||
|
protected List<ShaderNodeVariable> attributes = new ArrayList<ShaderNodeVariable>(); |
||||||
|
/** |
||||||
|
* the list of all the uniforms to declare in the vertex shader |
||||||
|
*/ |
||||||
|
protected List<ShaderNodeVariable> vertexUniforms = new ArrayList<ShaderNodeVariable>(); |
||||||
|
/** |
||||||
|
* the global output of the vertex shader (to assign ot gl_Position) |
||||||
|
*/ |
||||||
|
protected ShaderNodeVariable vertexGlobal = null; |
||||||
|
/** |
||||||
|
* the list of varyings |
||||||
|
*/ |
||||||
|
protected List<ShaderNodeVariable> varyings = new ArrayList<ShaderNodeVariable>(); |
||||||
|
/** |
||||||
|
* the list of all the uniforms to declare in the fragment shader |
||||||
|
*/ |
||||||
|
protected List<ShaderNodeVariable> fragmentUniforms = new ArrayList<ShaderNodeVariable>(); |
||||||
|
/** |
||||||
|
* the list of all the fragment shader global outputs (to assign ot gl_FragColor or gl_Fragdata[n]) |
||||||
|
*/ |
||||||
|
protected List<ShaderNodeVariable> fragmentGlobals = new ArrayList<ShaderNodeVariable>(); |
||||||
|
/** |
||||||
|
* the unused node names of this shader (node whose output are never used) |
||||||
|
*/ |
||||||
|
protected List<String> unusedNodes = new ArrayList<String>(); |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @return the attributes |
||||||
|
*/ |
||||||
|
public List<ShaderNodeVariable> getAttributes() { |
||||||
|
return attributes; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @return the vertex shader uniforms |
||||||
|
*/ |
||||||
|
public List<ShaderNodeVariable> getVertexUniforms() { |
||||||
|
return vertexUniforms; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @return the fragment shader uniforms |
||||||
|
*/ |
||||||
|
public List<ShaderNodeVariable> getFragmentUniforms() { |
||||||
|
return fragmentUniforms; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @return the vertex shader global ouput |
||||||
|
*/ |
||||||
|
public ShaderNodeVariable getVertexGlobal() { |
||||||
|
return vertexGlobal; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @return the fragment shader global outputs |
||||||
|
*/ |
||||||
|
public List<ShaderNodeVariable> getFragmentGlobals() { |
||||||
|
return fragmentGlobals; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @return the varyings |
||||||
|
*/ |
||||||
|
public List<ShaderNodeVariable> getVaryings() { |
||||||
|
return varyings; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* sets the vertex shader global output |
||||||
|
* |
||||||
|
* @param vertexGlobal the global output |
||||||
|
*/ |
||||||
|
public void setVertexGlobal(ShaderNodeVariable vertexGlobal) { |
||||||
|
this.vertexGlobal = vertexGlobal; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @return the list on unused node names |
||||||
|
*/ |
||||||
|
public List<String> getUnusedNodes() { |
||||||
|
return unusedNodes; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* the list of unused node names |
||||||
|
* @param unusedNodes |
||||||
|
*/ |
||||||
|
public void setUnusedNodes(List<String> unusedNodes) { |
||||||
|
this.unusedNodes = unusedNodes; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* convenient toString method |
||||||
|
* |
||||||
|
* @return the informations |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public String toString() { |
||||||
|
return "ShaderGenerationInfo{" + "attributes=" + attributes + ", vertexUniforms=" + vertexUniforms + ", vertexGlobal=" + vertexGlobal + ", varyings=" + varyings + ", fragmentUniforms=" + fragmentUniforms + ", fragmentGlobals=" + fragmentGlobals + '}'; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public void write(JmeExporter ex) throws IOException { |
||||||
|
OutputCapsule oc = ex.getCapsule(this); |
||||||
|
oc.writeSavableArrayList((ArrayList) attributes, "attributes", new ArrayList<ShaderNodeVariable>()); |
||||||
|
oc.writeSavableArrayList((ArrayList) vertexUniforms, "vertexUniforms", new ArrayList<ShaderNodeVariable>()); |
||||||
|
oc.writeSavableArrayList((ArrayList) varyings, "varyings", new ArrayList<ShaderNodeVariable>()); |
||||||
|
oc.writeSavableArrayList((ArrayList) fragmentUniforms, "fragmentUniforms", new ArrayList<ShaderNodeVariable>()); |
||||||
|
oc.writeSavableArrayList((ArrayList) fragmentGlobals, "fragmentGlobals", new ArrayList<ShaderNodeVariable>()); |
||||||
|
oc.write(vertexGlobal, "vertexGlobal", null); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void read(JmeImporter im) throws IOException { |
||||||
|
InputCapsule ic = im.getCapsule(this); |
||||||
|
attributes = ic.readSavableArrayList("attributes", new ArrayList<ShaderNodeVariable>()); |
||||||
|
vertexUniforms = ic.readSavableArrayList("vertexUniforms", new ArrayList<ShaderNodeVariable>()); |
||||||
|
varyings = ic.readSavableArrayList("varyings", new ArrayList<ShaderNodeVariable>()); |
||||||
|
fragmentUniforms = ic.readSavableArrayList("fragmentUniforms", new ArrayList<ShaderNodeVariable>()); |
||||||
|
fragmentGlobals = ic.readSavableArrayList("fragmentGlobals", new ArrayList<ShaderNodeVariable>()); |
||||||
|
vertexGlobal = (ShaderNodeVariable) ic.readSavable("vertexGlobal", null); |
||||||
|
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,572 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2009-2012 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.shader; |
||||||
|
|
||||||
|
import com.jme3.asset.AssetManager; |
||||||
|
import com.jme3.material.ShaderGenerationInfo; |
||||||
|
import com.jme3.material.plugins.ConditionParser; |
||||||
|
import com.jme3.shader.Shader.ShaderType; |
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
/** |
||||||
|
* This shader Generator can generate Vertex and Fragment shaders from |
||||||
|
* shadernodes for GLSL 1.0 |
||||||
|
* |
||||||
|
* @author Nehon |
||||||
|
*/ |
||||||
|
public class Glsl100ShaderGenerator extends ShaderGenerator { |
||||||
|
|
||||||
|
/** |
||||||
|
* the indentation characters 1à tabulation characters |
||||||
|
*/ |
||||||
|
private final static String INDENTCHAR = "\t\t\t\t\t\t\t\t\t\t"; |
||||||
|
|
||||||
|
/** |
||||||
|
* creates a Glsl100ShaderGenerator |
||||||
|
* @param assetManager the assetManager |
||||||
|
*/ |
||||||
|
public Glsl100ShaderGenerator(AssetManager assetManager) { |
||||||
|
super(assetManager); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void generateUniforms(StringBuilder source, ShaderGenerationInfo info, ShaderType type) { |
||||||
|
generateUniforms(source, type == ShaderType.Vertex ? info.getVertexUniforms() : info.getFragmentUniforms()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* decalre a list of uniforms |
||||||
|
* |
||||||
|
* @param source the source to append to |
||||||
|
* @param uniforms the list of uniforms |
||||||
|
*/ |
||||||
|
protected void generateUniforms(StringBuilder source, List<ShaderNodeVariable> uniforms) { |
||||||
|
source.append("\n"); |
||||||
|
for (ShaderNodeVariable var : uniforms) { |
||||||
|
declareVariable(source, var, false, "uniform"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritDoc} |
||||||
|
* |
||||||
|
* attributes are all declared, inPositon is decalred even if it's not in |
||||||
|
* the list and it's condition is nulled. |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
protected void generateAttributes(StringBuilder source, ShaderGenerationInfo info) { |
||||||
|
source.append("\n"); |
||||||
|
boolean inPosition = false; |
||||||
|
for (ShaderNodeVariable var : info.getAttributes()) { |
||||||
|
if (var.getName().equals("inPosition")) { |
||||||
|
inPosition = true; |
||||||
|
var.setCondition(null); |
||||||
|
} |
||||||
|
declareAttribute(source, var); |
||||||
|
|
||||||
|
} |
||||||
|
if (!inPosition) { |
||||||
|
declareAttribute(source, new ShaderNodeVariable("vec4", "inPosition")); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void generateVaryings(StringBuilder source, ShaderGenerationInfo info, ShaderType type) { |
||||||
|
source.append("\n"); |
||||||
|
for (ShaderNodeVariable var : info.getVaryings()) { |
||||||
|
declareVarying(source, var, type == ShaderType.Vertex ? false : true); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritDoc} |
||||||
|
* |
||||||
|
* if the declaration contains no code nothing is done, else it's appended |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
protected void generateDeclarativeSection(StringBuilder source, ShaderNode shaderNode, String nodeSource, ShaderGenerationInfo info) { |
||||||
|
if (nodeSource.replaceAll("\\n", "").trim().length() > 0) { |
||||||
|
nodeSource = updateDefinesName(nodeSource, shaderNode); |
||||||
|
source.append("\n"); |
||||||
|
unIndent(); |
||||||
|
startCondition(shaderNode.getCondition(), source); |
||||||
|
source.append(nodeSource); |
||||||
|
endCondition(shaderNode.getCondition(), source); |
||||||
|
indent(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritDoc} |
||||||
|
* |
||||||
|
* Shader outputs are declared and initialized inside the main section |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
protected void generateStartOfMainSection(StringBuilder source, ShaderGenerationInfo info, ShaderType type) { |
||||||
|
source.append("\n"); |
||||||
|
source.append("void main(){\n"); |
||||||
|
indent(); |
||||||
|
appendIndent(source); |
||||||
|
if (type == ShaderType.Vertex) { |
||||||
|
declareVariable(source, info.getVertexGlobal(), "inPosition"); |
||||||
|
} else if (type == ShaderType.Fragment) { |
||||||
|
for (ShaderNodeVariable global : info.getFragmentGlobals()) { |
||||||
|
declareVariable(source, global, "vec4(1.0)"); |
||||||
|
} |
||||||
|
} |
||||||
|
source.append("\n"); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritDoc} |
||||||
|
* |
||||||
|
* outputs are assigned to built in glsl output. then the main section is |
||||||
|
* closed |
||||||
|
* |
||||||
|
* This code accounts for multi render target and correctly output to |
||||||
|
* gl_FragData if several output are declared for the fragment shader |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
protected void generateEndOfMainSection(StringBuilder source, ShaderGenerationInfo info, ShaderType type) { |
||||||
|
source.append("\n"); |
||||||
|
if (type == ShaderType.Vertex) { |
||||||
|
appendOutput(source, "gl_Position", info.getVertexGlobal()); |
||||||
|
} else if (type == ShaderType.Fragment) { |
||||||
|
List<ShaderNodeVariable> globals = info.getFragmentGlobals(); |
||||||
|
if (globals.size() == 1) { |
||||||
|
appendOutput(source, "gl_FragColor", globals.get(0)); |
||||||
|
} else { |
||||||
|
int i = 0; |
||||||
|
//Multi Render Target
|
||||||
|
for (ShaderNodeVariable global : globals) { |
||||||
|
appendOutput(source, "gl_FragData[" + i + "]", global); |
||||||
|
i++; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
unIndent(); |
||||||
|
appendIndent(source); |
||||||
|
source.append("}\n"); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Appends an ouput assignment to a shader globalOutputName = |
||||||
|
* nameSpace_varName; |
||||||
|
* |
||||||
|
* @param source the source StringBuilter to append the code. |
||||||
|
* @param globalOutputName the name of the global output (can be gl_Position |
||||||
|
* or gl_FragColor etc...). |
||||||
|
* @param var the variable to assign to the output. |
||||||
|
*/ |
||||||
|
protected void appendOutput(StringBuilder source, String globalOutputName, ShaderNodeVariable var) { |
||||||
|
appendIndent(source); |
||||||
|
source.append(globalOutputName); |
||||||
|
source.append(" = "); |
||||||
|
source.append(var.getNameSpace()); |
||||||
|
source.append("_"); |
||||||
|
source.append(var.getName()); |
||||||
|
source.append(";\n"); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritDoc} |
||||||
|
* |
||||||
|
* this methods does things in this order : |
||||||
|
* |
||||||
|
* 1. declaring and mapping input<br> |
||||||
|
* variables : variable replaced with MatParams or WorldParams are not |
||||||
|
* declared and are replaced by the parma acual name in the code. For others |
||||||
|
* variables, the name space is appended with a "_" before the variable name |
||||||
|
* in the code to avoid names collision between shaderNodes. <br> |
||||||
|
* |
||||||
|
* 2. declaring output variables : <br> |
||||||
|
* variables are declared if they were not already |
||||||
|
* declared as input (inputs can also be outputs) or if they are not |
||||||
|
* declared as varyings. The variable name is also prefixed with the s=name |
||||||
|
* space and "_" in the shaderNode code <br> |
||||||
|
* |
||||||
|
* 3. append of the actual ShaderNode code <br> |
||||||
|
* |
||||||
|
* 4. mapping outputs to global output if needed<br> |
||||||
|
* |
||||||
|
*<br> |
||||||
|
* All of this is embed in a #if coditional statement if needed |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
protected void generateNodeMainSection(StringBuilder source, ShaderNode shaderNode, String nodeSource, ShaderGenerationInfo info) { |
||||||
|
|
||||||
|
nodeSource = updateDefinesName(nodeSource, shaderNode); |
||||||
|
source.append("\n"); |
||||||
|
comment(source, shaderNode, "Begin"); |
||||||
|
startCondition(shaderNode.getCondition(), source); |
||||||
|
|
||||||
|
List<String> declaredInputs = new ArrayList<String>(); |
||||||
|
for (VariableMapping mapping : shaderNode.getInputMapping()) { |
||||||
|
|
||||||
|
//all variables fed with a matparam or world param are replaced but the matparam itself
|
||||||
|
//it avoids issue with samplers that have to be uniforms, and it optimize a but the shader code.
|
||||||
|
if (isWorldOrMaterialParam(mapping.getRightVariable())) { |
||||||
|
nodeSource = replace(nodeSource, mapping.getLeftVariable(), mapping.getRightVariable().getName()); |
||||||
|
} else { |
||||||
|
if (mapping.getLeftVariable().getType().startsWith("sampler")) { |
||||||
|
throw new IllegalArgumentException("a Sampler must be a uniform"); |
||||||
|
} |
||||||
|
map(mapping, source); |
||||||
|
String newName = shaderNode.getName() + "_" + mapping.getLeftVariable().getName(); |
||||||
|
if (!declaredInputs.contains(newName)) { |
||||||
|
nodeSource = replace(nodeSource, mapping.getLeftVariable(), newName); |
||||||
|
declaredInputs.add(newName); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
for (ShaderNodeVariable var : shaderNode.getDefinition().getOutputs()) { |
||||||
|
ShaderNodeVariable v = new ShaderNodeVariable(var.getType(), shaderNode.getName(), var.getName()); |
||||||
|
if (!declaredInputs.contains(shaderNode.getName() + "_" + var.getName())) { |
||||||
|
if (!isVarying(info, v)) { |
||||||
|
declareVariable(source, v); |
||||||
|
} |
||||||
|
nodeSource = replaceVariableName(nodeSource, v); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
source.append(nodeSource); |
||||||
|
|
||||||
|
for (VariableMapping mapping : shaderNode.getOutputMapping()) { |
||||||
|
map(mapping, source); |
||||||
|
} |
||||||
|
endCondition(shaderNode.getCondition(), source); |
||||||
|
comment(source, shaderNode, "End"); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* declares a variable, embed in a conditional block if needed |
||||||
|
* @param source the StringBuilder to use |
||||||
|
* @param var the variable to declare |
||||||
|
* @param appendNameSpace true to append the nameSpace + "_" |
||||||
|
*/ |
||||||
|
protected void declareVariable(StringBuilder source, ShaderNodeVariable var, boolean appendNameSpace) { |
||||||
|
declareVariable(source, var, appendNameSpace, null); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* declares a variable, embed in a conditional block if needed. the namespace is appended with "_" |
||||||
|
* @param source the StringBuilder to use |
||||||
|
* @param var the variable to declare |
||||||
|
*/ |
||||||
|
protected void declareVariable(StringBuilder source, ShaderNodeVariable var) { |
||||||
|
declareVariable(source, var, true, null); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* declares a variable, embed in a conditional block if needed. the namespace is appended with "_" |
||||||
|
* @param source the StringBuilder to use |
||||||
|
* @param var the variable to declare |
||||||
|
* @param value the initialization value to assign the the variable |
||||||
|
*/ |
||||||
|
protected void declareVariable(StringBuilder source, ShaderNodeVariable var, String value) { |
||||||
|
declareVariable(source, var, value, true, null); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* declares a variable, embed in a conditional block if needed. |
||||||
|
* @param source the StringBuilder to use |
||||||
|
* @param var the variable to declare |
||||||
|
* @param appendNameSpace true to append the nameSpace + "_" |
||||||
|
* @param modifier the modifier of the variable (attribute, varying, in , out,...) |
||||||
|
*/ |
||||||
|
protected void declareVariable(StringBuilder source, ShaderNodeVariable var, boolean appendNameSpace, String modifier) { |
||||||
|
declareVariable(source, var, null, appendNameSpace, modifier); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* declares a variable, embed in a conditional block if needed. |
||||||
|
* @param source the StringBuilder to use |
||||||
|
* @param var the variable to declare |
||||||
|
* @param value the initialization value to assign the the variable |
||||||
|
* @param appendNameSpace true to append the nameSpace + "_" |
||||||
|
* @param modifier the modifier of the variable (attribute, varying, in , out,...) |
||||||
|
*/ |
||||||
|
protected void declareVariable(StringBuilder source, ShaderNodeVariable var, String value, boolean appendNameSpace, String modifier) { |
||||||
|
startCondition(var.getCondition(), source); |
||||||
|
appendIndent(source); |
||||||
|
if (modifier != null) { |
||||||
|
source.append(modifier); |
||||||
|
source.append(" "); |
||||||
|
} |
||||||
|
|
||||||
|
source.append(var.getType()); |
||||||
|
source.append(" "); |
||||||
|
if (appendNameSpace) { |
||||||
|
source.append(var.getNameSpace()); |
||||||
|
source.append("_"); |
||||||
|
} |
||||||
|
source.append(var.getName()); |
||||||
|
if (value != null) { |
||||||
|
source.append(" = "); |
||||||
|
source.append(value); |
||||||
|
} |
||||||
|
source.append(";\n"); |
||||||
|
endCondition(var.getCondition(), source); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Starts a conditional block |
||||||
|
* @param condition the block condition |
||||||
|
* @param source the StringBuilder to use |
||||||
|
*/ |
||||||
|
protected void startCondition(String condition, StringBuilder source) { |
||||||
|
if (condition != null) { |
||||||
|
appendIndent(source); |
||||||
|
source.append("#if "); |
||||||
|
source.append(condition); |
||||||
|
source.append("\n"); |
||||||
|
indent(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Ends a conditional block |
||||||
|
* @param condition the block condition |
||||||
|
* @param source the StringBuilder to use |
||||||
|
*/ |
||||||
|
protected void endCondition(String condition, StringBuilder source) { |
||||||
|
if (condition != null) { |
||||||
|
unIndent(); |
||||||
|
appendIndent(source); |
||||||
|
source.append("#endif\n"); |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Appends a mapping to the source, embed in a conditional block if needed, |
||||||
|
* with variables nameSpaces and swizzle. |
||||||
|
* @param mapping the VariableMapping to append |
||||||
|
* @param source the StringBuilder to use |
||||||
|
*/ |
||||||
|
protected void map(VariableMapping mapping, StringBuilder source) { |
||||||
|
startCondition(mapping.getCondition(), source); |
||||||
|
appendIndent(source); |
||||||
|
if (!mapping.getLeftVariable().isShaderOutput()) { |
||||||
|
source.append(mapping.getLeftVariable().getType()); |
||||||
|
source.append(" "); |
||||||
|
} |
||||||
|
source.append(mapping.getLeftVariable().getNameSpace()); |
||||||
|
source.append("_"); |
||||||
|
source.append(mapping.getLeftVariable().getName()); |
||||||
|
if (mapping.getLeftSwizzling().length() > 0) { |
||||||
|
source.append("."); |
||||||
|
source.append(mapping.getLeftSwizzling()); |
||||||
|
} |
||||||
|
source.append(" = "); |
||||||
|
String namePrefix = getAppendableNameSpace(mapping.getRightVariable()); |
||||||
|
source.append(namePrefix); |
||||||
|
source.append(mapping.getRightVariable().getName()); |
||||||
|
if (mapping.getRightSwizzling().length() > 0) { |
||||||
|
source.append("."); |
||||||
|
source.append(mapping.getRightSwizzling()); |
||||||
|
} |
||||||
|
source.append(";\n"); |
||||||
|
endCondition(mapping.getCondition(), source); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* replaces a variable name in a shaderNode source code by prefixing it |
||||||
|
* with its nameSpace and "_" if needed. |
||||||
|
* @param nodeSource the source ot modify |
||||||
|
* @param var the variable to replace |
||||||
|
* @return the modified source |
||||||
|
*/ |
||||||
|
protected String replaceVariableName(String nodeSource, ShaderNodeVariable var) { |
||||||
|
String namePrefix = getAppendableNameSpace(var); |
||||||
|
String newName = namePrefix + var.getName(); |
||||||
|
nodeSource = replace(nodeSource, var, newName); |
||||||
|
return nodeSource; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Finds if a variable is a varying |
||||||
|
* @param info the ShaderGenerationInfo |
||||||
|
* @param v the variable |
||||||
|
* @return true is the given variable is a varying |
||||||
|
*/ |
||||||
|
protected boolean isVarying(ShaderGenerationInfo info, ShaderNodeVariable v) { |
||||||
|
boolean isVarying = false; |
||||||
|
for (ShaderNodeVariable shaderNodeVariable : info.getVaryings()) { |
||||||
|
if (shaderNodeVariable.equals(v)) { |
||||||
|
isVarying = true; |
||||||
|
} |
||||||
|
} |
||||||
|
return isVarying; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Appends a comment to the generated code |
||||||
|
* @param source the StringBuilder to use |
||||||
|
* @param shaderNode the shader node being processed (to append its name) |
||||||
|
* @param comment the comment to append |
||||||
|
*/ |
||||||
|
protected void comment(StringBuilder source, ShaderNode shaderNode, String comment) { |
||||||
|
appendIndent(source); |
||||||
|
source.append("//"); |
||||||
|
source.append(shaderNode.getName()); |
||||||
|
source.append(" : "); |
||||||
|
source.append(comment); |
||||||
|
source.append("\n"); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* returns the name space to append for a variable. |
||||||
|
* Attributes, WorldParam and MatParam names psace must not be appended |
||||||
|
* @param var the variable |
||||||
|
* @return the namespace to append for this variable |
||||||
|
*/ |
||||||
|
protected String getAppendableNameSpace(ShaderNodeVariable var) { |
||||||
|
String namePrefix = var.getNameSpace() + "_"; |
||||||
|
if (namePrefix.equals("Attr_") || namePrefix.equals("WorldParam_") || namePrefix.equals("MatParam_")) { |
||||||
|
namePrefix = ""; |
||||||
|
} |
||||||
|
return namePrefix; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* transforms defines name is the shader node code. |
||||||
|
* One can use a #if defined(inputVariableName) in a shaderNode code. |
||||||
|
* This method is responsible for changing the variable name with the |
||||||
|
* appropriate defined based on the mapping condition of this variable. |
||||||
|
* Complex condition synthax are handled. |
||||||
|
* |
||||||
|
* @param nodeSource the sahderNode source code |
||||||
|
* @param shaderNode the ShaderNode being processed |
||||||
|
* @return the modified shaderNode source. |
||||||
|
*/ |
||||||
|
protected String updateDefinesName(String nodeSource, ShaderNode shaderNode) { |
||||||
|
String[] lines = nodeSource.split("\\n"); |
||||||
|
ConditionParser parser = new ConditionParser(); |
||||||
|
for (String line : lines) { |
||||||
|
|
||||||
|
if (line.trim().startsWith("#if")) { |
||||||
|
List<String> params = parser.extractDefines(line.trim()); |
||||||
|
String l = line.trim().replaceAll("defined", "").replaceAll("#if ", "").replaceAll("#ifdef", "");//parser.getFormattedExpression();
|
||||||
|
boolean match = false; |
||||||
|
for (String param : params) { |
||||||
|
for (VariableMapping map : shaderNode.getInputMapping()) { |
||||||
|
if ((map.getLeftVariable().getName()).equals(param)) { |
||||||
|
if (map.getCondition() != null) { |
||||||
|
l = l.replaceAll(param, map.getCondition()); |
||||||
|
match = true; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
if (match) { |
||||||
|
nodeSource = nodeSource.replace(line.trim(), "#if " + l); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return nodeSource; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* replaced a variable name in a source code with the given name |
||||||
|
* @param nodeSource the source to use |
||||||
|
* @param var the variable |
||||||
|
* @param newName the new name of the variable |
||||||
|
* @return the modified source code |
||||||
|
*/ |
||||||
|
protected String replace(String nodeSource, ShaderNodeVariable var, String newName) { |
||||||
|
nodeSource = nodeSource.replaceAll("(\\W)" + var.getName() + "(\\W)", "$1" + newName + "$2"); |
||||||
|
return nodeSource; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Finds if a variable is a world or a material parameter |
||||||
|
* @param var the variable |
||||||
|
* @return true if the variable is a Word or material parameter |
||||||
|
*/ |
||||||
|
protected boolean isWorldOrMaterialParam(ShaderNodeVariable var) { |
||||||
|
return var.getNameSpace().equals("MatParam") || var.getNameSpace().equals("WorldParam"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected String getLanguageAndVersion(ShaderType type) { |
||||||
|
return "GLSL100"; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* appends indentation. |
||||||
|
* @param source |
||||||
|
*/ |
||||||
|
protected void appendIndent(StringBuilder source) { |
||||||
|
source.append(INDENTCHAR.substring(0, indent)); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Declares an attribute |
||||||
|
* @param source the StringBuilder to use |
||||||
|
* @param var the variable to declare as an attribute |
||||||
|
*/ |
||||||
|
protected void declareAttribute(StringBuilder source, ShaderNodeVariable var) { |
||||||
|
declareVariable(source, var, false, "attribute"); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Declares a varying |
||||||
|
* @param source the StringBuilder to use |
||||||
|
* @param var the variable to declare as an varying |
||||||
|
* @param input a boolean set to true if the this varying is an input. |
||||||
|
* this in not used in this implementaiton but can be used in overidings |
||||||
|
* implementation |
||||||
|
*/ |
||||||
|
protected void declareVarying(StringBuilder source, ShaderNodeVariable var, boolean input) { |
||||||
|
declareVariable(source, var, true, "varying"); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Decrease indentation with a check so the indent is never negative. |
||||||
|
*/ |
||||||
|
protected void unIndent() { |
||||||
|
indent--; |
||||||
|
indent = Math.max(0, indent); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* increase indentation with a check so that indentation is never over 10 |
||||||
|
*/ |
||||||
|
protected void indent() { |
||||||
|
indent++; |
||||||
|
indent = Math.min(10, indent); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,146 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2009-2012 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.shader; |
||||||
|
|
||||||
|
import com.jme3.asset.AssetManager; |
||||||
|
import com.jme3.material.ShaderGenerationInfo; |
||||||
|
import com.jme3.shader.Shader.ShaderType; |
||||||
|
|
||||||
|
/** |
||||||
|
* This shader Generator can generate Vertex and Fragment shaders from |
||||||
|
* ShaderNodes for GLSL 1.5 |
||||||
|
* |
||||||
|
* @author Nehon |
||||||
|
*/ |
||||||
|
public class Glsl150ShaderGenerator extends Glsl100ShaderGenerator { |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a Glsl150ShaderGenerator |
||||||
|
* |
||||||
|
* @param assetManager the assetmanager |
||||||
|
*/ |
||||||
|
public Glsl150ShaderGenerator(AssetManager assetManager) { |
||||||
|
super(assetManager); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected String getLanguageAndVersion(ShaderType type) { |
||||||
|
return "GLSL150"; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritDoc} in glsl 1.5 attributes are prefixed with the "in" keyword |
||||||
|
* and not the "attribute" keyword |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
protected void declareAttribute(StringBuilder source, ShaderNodeVariable var) { |
||||||
|
declareVariable(source, var, false, "in"); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritDoc} in glsl 1.5 varying are prefixed with the "in" or "out" |
||||||
|
* keyword and not the "varying" keyword. |
||||||
|
* |
||||||
|
* "in" is used for Fragment shader (maybe Geometry shader later) "out" is |
||||||
|
* used for Vertex shader (maybe Geometry shader later) |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
protected void declareVarying(StringBuilder source, ShaderNodeVariable var, boolean input) { |
||||||
|
declareVariable(source, var, true, input ? "in" : "out"); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritDoc} |
||||||
|
* |
||||||
|
* Fragment shader outputs are declared before the "void main(){" with the |
||||||
|
* "out" keyword. |
||||||
|
* |
||||||
|
* after the "void main(){", the vertex output are declared and initialized |
||||||
|
* and the frgament outputs are declared |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
protected void generateStartOfMainSection(StringBuilder source, ShaderGenerationInfo info, Shader.ShaderType type) { |
||||||
|
source.append("\n"); |
||||||
|
|
||||||
|
if (type == Shader.ShaderType.Fragment) { |
||||||
|
for (ShaderNodeVariable global : info.getFragmentGlobals()) { |
||||||
|
declareVariable(source, global, null, true, "out"); |
||||||
|
} |
||||||
|
} |
||||||
|
source.append("\n"); |
||||||
|
|
||||||
|
appendIndent(source); |
||||||
|
source.append("void main(){\n"); |
||||||
|
indent(); |
||||||
|
|
||||||
|
if (type == Shader.ShaderType.Vertex) { |
||||||
|
declareVariable(source, info.getVertexGlobal(), "inPosition"); |
||||||
|
} else if (type == Shader.ShaderType.Fragment) { |
||||||
|
for (ShaderNodeVariable global : info.getFragmentGlobals()) { |
||||||
|
initVariable(source, global, "vec4(1.0)"); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritDoc} |
||||||
|
* |
||||||
|
* only vertex shader output are mapped here, since fragment shader outputs |
||||||
|
* must have been mapped in the main section. |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
protected void generateEndOfMainSection(StringBuilder source, ShaderGenerationInfo info, Shader.ShaderType type) { |
||||||
|
if (type == Shader.ShaderType.Vertex) { |
||||||
|
appendOutput(source, "gl_Position", info.getVertexGlobal()); |
||||||
|
} |
||||||
|
unIndent(); |
||||||
|
appendIndent(source); |
||||||
|
source.append("}\n"); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Append a variable initialization to the code |
||||||
|
* |
||||||
|
* @param source the StringBuilder to use |
||||||
|
* @param var the variable to initialize |
||||||
|
* @param initValue the init value to assign to the variable |
||||||
|
*/ |
||||||
|
protected void initVariable(StringBuilder source, ShaderNodeVariable var, String initValue) { |
||||||
|
appendIndent(source); |
||||||
|
source.append(var.getNameSpace()); |
||||||
|
source.append("_"); |
||||||
|
source.append(var.getName()); |
||||||
|
source.append(" = "); |
||||||
|
source.append(initValue); |
||||||
|
source.append(";\n"); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,290 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2009-2012 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.shader; |
||||||
|
|
||||||
|
import com.jme3.asset.AssetKey; |
||||||
|
import com.jme3.asset.AssetManager; |
||||||
|
import com.jme3.material.ShaderGenerationInfo; |
||||||
|
import com.jme3.material.Technique; |
||||||
|
import com.jme3.material.TechniqueDef; |
||||||
|
import com.jme3.shader.Shader.ShaderType; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
/** |
||||||
|
* This class is the base for a shader generator using the ShaderNodes system, |
||||||
|
* it contains basis mechnaism of generation, but no actual generation code. |
||||||
|
* This class is abstract, any Shader generator must extend it. |
||||||
|
* |
||||||
|
* @author Nehon |
||||||
|
*/ |
||||||
|
public abstract class ShaderGenerator { |
||||||
|
|
||||||
|
//the asset manager
|
||||||
|
protected AssetManager assetManager; |
||||||
|
//indentation value for generation
|
||||||
|
protected int indent; |
||||||
|
|
||||||
|
/** |
||||||
|
* Build a shaderGenerator |
||||||
|
* |
||||||
|
* @param assetManager |
||||||
|
*/ |
||||||
|
protected ShaderGenerator(AssetManager assetManager) { |
||||||
|
this.assetManager = assetManager; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Generate vertex and fragment shaders for the given technique |
||||||
|
* |
||||||
|
* @param technique the technique to use to generate the shaders |
||||||
|
* @return a Shader program |
||||||
|
*/ |
||||||
|
public Shader generateShader(Technique technique) { |
||||||
|
|
||||||
|
DefineList defines = technique.getAllDefines(); |
||||||
|
TechniqueDef def = technique.getDef(); |
||||||
|
ShaderGenerationInfo info = def.getShaderGenerationInfo(); |
||||||
|
|
||||||
|
String vertexSource = buildShader(def.getShaderNodes(), info, ShaderType.Vertex); |
||||||
|
String fragmentSource = buildShader(def.getShaderNodes(), info, ShaderType.Fragment); |
||||||
|
|
||||||
|
Shader shader = new Shader(); |
||||||
|
shader.initialize(); |
||||||
|
shader.addSource(Shader.ShaderType.Vertex, technique.getDef().getName() + ".vert", vertexSource, defines.getCompiled(), getLanguageAndVersion(ShaderType.Vertex)); |
||||||
|
shader.addSource(Shader.ShaderType.Fragment, technique.getDef().getName() + ".frag", fragmentSource, defines.getCompiled(), getLanguageAndVersion(ShaderType.Fragment)); |
||||||
|
|
||||||
|
return shader; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* This method is responsible for the shader generation. |
||||||
|
* |
||||||
|
* @param shaderNodes the list of shader nodes |
||||||
|
* @param info the ShaderGenerationInfo filled during the Technique loading |
||||||
|
* @param type the type of shader to generate |
||||||
|
* @return the code of the generated vertex shader |
||||||
|
*/ |
||||||
|
protected String buildShader(List<ShaderNode> shaderNodes, ShaderGenerationInfo info, ShaderType type) { |
||||||
|
indent = 0; |
||||||
|
|
||||||
|
StringBuilder sourceDeclaration = new StringBuilder(); |
||||||
|
StringBuilder source = new StringBuilder(); |
||||||
|
|
||||||
|
generateUniforms(sourceDeclaration, info, type); |
||||||
|
|
||||||
|
if (type == ShaderType.Vertex) { |
||||||
|
generateAttributes(sourceDeclaration, info); |
||||||
|
} |
||||||
|
generateVaryings(sourceDeclaration, info, type); |
||||||
|
|
||||||
|
generateStartOfMainSection(source, info, type); |
||||||
|
|
||||||
|
generateDeclarationAndMainBody(shaderNodes, sourceDeclaration, source, info, type); |
||||||
|
|
||||||
|
generateEndOfMainSection(source, info, type); |
||||||
|
|
||||||
|
sourceDeclaration.append(source); |
||||||
|
|
||||||
|
return sourceDeclaration.toString(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* iterates through shader nodes to load them and generate the shader |
||||||
|
* declaration part and main body extracted from the shader nodes, for the |
||||||
|
* given shader type |
||||||
|
* |
||||||
|
* @param shaderNodes the list of shader nodes |
||||||
|
* @param sourceDeclaration the declaration part StringBuilder of the shader |
||||||
|
* to generate |
||||||
|
* @param source the main part StringBuilder of the shader to generate |
||||||
|
* @param info the ShaderGenerationInfo |
||||||
|
* @param type the Shader type |
||||||
|
*/ |
||||||
|
protected void generateDeclarationAndMainBody(List<ShaderNode> shaderNodes, StringBuilder sourceDeclaration, StringBuilder source, ShaderGenerationInfo info, Shader.ShaderType type) { |
||||||
|
for (ShaderNode shaderNode : shaderNodes) { |
||||||
|
if (info.getUnusedNodes().contains(shaderNode.getName())) { |
||||||
|
continue; |
||||||
|
} |
||||||
|
if (shaderNode.getDefinition().getType() == type) { |
||||||
|
int index = findShaderIndexFromVersion(shaderNode, type); |
||||||
|
String loadedSource = (String) assetManager.loadAsset(new AssetKey(shaderNode.getDefinition().getShadersPath().get(index))); |
||||||
|
appendNodeDeclarationAndMain(loadedSource, sourceDeclaration, source, shaderNode, info); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Appends declaration and main part of a node to the shader declaration and |
||||||
|
* main part. the loadedSource is split by "void main(){" to split |
||||||
|
* declaration from main part of the node source code.The trailing "}" is |
||||||
|
* removed from the main part. Each part is then respectively passed to |
||||||
|
* generateDeclarativeSection and generateNodeMainSection. |
||||||
|
* |
||||||
|
* @see ShaderGenerator#generateDeclarativeSection |
||||||
|
* @see ShaderGenerator#generateNodeMainSection |
||||||
|
* |
||||||
|
* @param loadedSource the actual source code loaded for this node. |
||||||
|
* @param sourceDeclaration the Shader declaration part string builder. |
||||||
|
* @param source the Shader main part StringBuilder. |
||||||
|
* @param shaderNode the shader node. |
||||||
|
* @param info the ShaderGenerationInfo. |
||||||
|
*/ |
||||||
|
protected void appendNodeDeclarationAndMain(String loadedSource, StringBuilder sourceDeclaration, StringBuilder source, ShaderNode shaderNode, ShaderGenerationInfo info) { |
||||||
|
if (loadedSource.length() > 1) { |
||||||
|
loadedSource = loadedSource.substring(0, loadedSource.lastIndexOf("}")); |
||||||
|
String[] sourceParts = loadedSource.split("void main\\(\\)\\{"); |
||||||
|
generateDeclarativeSection(sourceDeclaration, shaderNode, sourceParts[0], info); |
||||||
|
generateNodeMainSection(source, shaderNode, sourceParts[1], info); |
||||||
|
} else { |
||||||
|
//if source is empty, we still call generateNodeMainSection so that mappings can be done.
|
||||||
|
generateNodeMainSection(source, shaderNode, loadedSource, info); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* returns the laguage + version of the shader should be somthing like |
||||||
|
* "GLSL100" for glsl 1.0 "GLSL150" for glsl 1.5. |
||||||
|
* |
||||||
|
* @param type the shader type for wich the version should be returned. |
||||||
|
* |
||||||
|
* @return the shaderLanguage and version. |
||||||
|
*/ |
||||||
|
protected abstract String getLanguageAndVersion(Shader.ShaderType type); |
||||||
|
|
||||||
|
/** |
||||||
|
* generates the uniforms declaration for a shader of the given type. |
||||||
|
* |
||||||
|
* @param source the source StringBuilder to append generated code. |
||||||
|
* @param info the ShaderGenerationInfo. |
||||||
|
* @param type the shader type the uniforms have to be generated for. |
||||||
|
*/ |
||||||
|
protected abstract void generateUniforms(StringBuilder source, ShaderGenerationInfo info, ShaderType type); |
||||||
|
|
||||||
|
/** |
||||||
|
* generates the attributes declaration for the vertex shader. There is no |
||||||
|
* Shader type passed here as attributes are only used in vertex shaders |
||||||
|
* |
||||||
|
* @param source the source StringBuilder to append generated code. |
||||||
|
* @param info the ShaderGenerationInfo. |
||||||
|
*/ |
||||||
|
protected abstract void generateAttributes(StringBuilder source, ShaderGenerationInfo info); |
||||||
|
|
||||||
|
/** |
||||||
|
* generates the varyings for the given shader type shader. Note that |
||||||
|
* varyings are deprecated in glsl 1.3, but this method will still be called |
||||||
|
* to generate all non global inputs and output of the shaders. |
||||||
|
* |
||||||
|
* @param source the source StringBuilder to append generated code. |
||||||
|
* @param info the ShaderGenerationInfo. |
||||||
|
* @param type the shader type the varyings have to be generated for. |
||||||
|
*/ |
||||||
|
protected abstract void generateVaryings(StringBuilder source, ShaderGenerationInfo info, ShaderType type); |
||||||
|
|
||||||
|
/** |
||||||
|
* Appends the given shaderNode declarative part to the shader declarative |
||||||
|
* part. If needed the sahder type can be determined by fetching the |
||||||
|
* shaderNode's definition type. |
||||||
|
* |
||||||
|
* @see ShaderNode#getDefinition() |
||||||
|
* @see ShaderNodeDefinition#getType() |
||||||
|
* |
||||||
|
* @param source the StringBuilder to append generated code. |
||||||
|
* @param shaderNode the shaderNode. |
||||||
|
* @param nodeSource the declaration part of the loaded shaderNode source. |
||||||
|
* @param info the ShaderGenerationInfo. |
||||||
|
*/ |
||||||
|
protected abstract void generateDeclarativeSection(StringBuilder source, ShaderNode shaderNode, String nodeDecalarationSource, ShaderGenerationInfo info); |
||||||
|
|
||||||
|
/** |
||||||
|
* generates the start of the shader main section. this method is |
||||||
|
* responsible of appending the "void main(){" in the shader and declaring |
||||||
|
* all global outputs of the shader |
||||||
|
* |
||||||
|
* @param source the StringBuilder to append generated code. |
||||||
|
* @param info the ShaderGenerationInfo. |
||||||
|
* @param type the shader type the section has to be generated for. |
||||||
|
*/ |
||||||
|
protected abstract void generateStartOfMainSection(StringBuilder source, ShaderGenerationInfo info, ShaderType type); |
||||||
|
|
||||||
|
/** |
||||||
|
* generates the end of the shader main section. this method is responsible |
||||||
|
* of appending the last "}" in the shader and mapping all global outputs of |
||||||
|
* the shader |
||||||
|
* |
||||||
|
* @param source the StringBuilder to append generated code. |
||||||
|
* @param info the ShaderGenerationInfo. |
||||||
|
* @param type the shader type the section has to be generated for. |
||||||
|
*/ |
||||||
|
protected abstract void generateEndOfMainSection(StringBuilder source, ShaderGenerationInfo info, ShaderType type); |
||||||
|
|
||||||
|
/** |
||||||
|
* Appends the given shaderNode main part to the shader declarative part. If |
||||||
|
* needed the sahder type can be determined by fetching the shaderNode's |
||||||
|
* definition type. |
||||||
|
* |
||||||
|
* @see ShaderNode#getDefinition() |
||||||
|
* @see ShaderNodeDefinition#getType() |
||||||
|
* |
||||||
|
* @param source the StringBuilder to append generated code. |
||||||
|
* @param shaderNode the shaderNode. |
||||||
|
* @param nodeSource the declaration part of the loaded shaderNode source. |
||||||
|
* @param info the ShaderGenerationInfo. |
||||||
|
*/ |
||||||
|
protected abstract void generateNodeMainSection(StringBuilder source, ShaderNode shaderNode, String nodeSource, ShaderGenerationInfo info); |
||||||
|
|
||||||
|
/** |
||||||
|
* returns the shaderpath index according to the version of the generator. |
||||||
|
* This allow to select the higher version of the shader that the generator |
||||||
|
* can handle |
||||||
|
* |
||||||
|
* @param shaderNode the shaderNode being processed |
||||||
|
* @param type the shaderType |
||||||
|
* @return the index of the shader path in ShaderNodeDefinition shadersPath |
||||||
|
* list |
||||||
|
* @throws NumberFormatException |
||||||
|
*/ |
||||||
|
protected int findShaderIndexFromVersion(ShaderNode shaderNode, ShaderType type) throws NumberFormatException { |
||||||
|
int index = 0; |
||||||
|
List<String> lang = shaderNode.getDefinition().getShadersLanguage(); |
||||||
|
int genVersion = Integer.parseInt(getLanguageAndVersion(type).substring(4)); |
||||||
|
int curVersion = 0; |
||||||
|
for (int i = 0; i < lang.size(); i++) { |
||||||
|
int version = Integer.parseInt(lang.get(i).substring(4)); |
||||||
|
if (version > curVersion && version <= genVersion) { |
||||||
|
curVersion = version; |
||||||
|
index = i; |
||||||
|
} |
||||||
|
} |
||||||
|
return index; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,215 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2009-2012 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.shader; |
||||||
|
|
||||||
|
import com.jme3.export.InputCapsule; |
||||||
|
import com.jme3.export.JmeExporter; |
||||||
|
import com.jme3.export.JmeImporter; |
||||||
|
import com.jme3.export.OutputCapsule; |
||||||
|
import com.jme3.export.Savable; |
||||||
|
import java.io.IOException; |
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
/** |
||||||
|
* A ShaderNode is the unit brick part of a shader program. A shader can be |
||||||
|
* describe with several shader nodes that are plugged together through inputs |
||||||
|
* and outputs. |
||||||
|
* |
||||||
|
* A ShaderNode is based on a definition that has a shader code, inputs and |
||||||
|
* output variables. This node can be activated based on a condition, and has |
||||||
|
* input and ouput mapping. |
||||||
|
* |
||||||
|
* This class is not intended to be used by JME users directly. It's the |
||||||
|
* stucture for loading shader nodes from a J3md ùaterial definition file |
||||||
|
* |
||||||
|
* @author Nehon |
||||||
|
*/ |
||||||
|
public class ShaderNode implements Savable { |
||||||
|
|
||||||
|
private String name; |
||||||
|
private ShaderNodeDefinition definition; |
||||||
|
private String condition; |
||||||
|
private List<VariableMapping> inputMapping = new ArrayList<VariableMapping>(); |
||||||
|
private List<VariableMapping> outputMapping = new ArrayList<VariableMapping>(); |
||||||
|
|
||||||
|
/** |
||||||
|
* creates a ShaderNode |
||||||
|
* |
||||||
|
* @param name the name |
||||||
|
* @param definition the ShaderNodeDefinition |
||||||
|
* @param condition the conditionto activate this node |
||||||
|
*/ |
||||||
|
public ShaderNode(String name, ShaderNodeDefinition definition, String condition) { |
||||||
|
this.name = name; |
||||||
|
this.definition = definition; |
||||||
|
this.condition = condition; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* creates a ShaderNode |
||||||
|
*/ |
||||||
|
public ShaderNode() { |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @return the name of the node |
||||||
|
*/ |
||||||
|
public String getName() { |
||||||
|
return name; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* sets the name of th node |
||||||
|
* |
||||||
|
* @param name the name |
||||||
|
*/ |
||||||
|
public void setName(String name) { |
||||||
|
this.name = name; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* returns the definition |
||||||
|
* |
||||||
|
* @return the ShaderNodeDefinition |
||||||
|
*/ |
||||||
|
public ShaderNodeDefinition getDefinition() { |
||||||
|
return definition; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* sets the definition |
||||||
|
* |
||||||
|
* @param definition the ShaderNodeDefinition |
||||||
|
*/ |
||||||
|
public void setDefinition(ShaderNodeDefinition definition) { |
||||||
|
this.definition = definition; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @return the condition |
||||||
|
*/ |
||||||
|
public String getCondition() { |
||||||
|
return condition; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* sets the ocndition |
||||||
|
* |
||||||
|
* @param condition the condition |
||||||
|
*/ |
||||||
|
public void setCondition(String condition) { |
||||||
|
this.condition = condition; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* return a list of VariableMapping representing the input mappings of this |
||||||
|
* node |
||||||
|
* |
||||||
|
* @return the input mappings |
||||||
|
*/ |
||||||
|
public List<VariableMapping> getInputMapping() { |
||||||
|
return inputMapping; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* sets the input mappings |
||||||
|
* |
||||||
|
* @param inputMapping the input mappings |
||||||
|
*/ |
||||||
|
public void setInputMapping(List<VariableMapping> inputMapping) { |
||||||
|
this.inputMapping = inputMapping; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* return a list of VariableMapping representing the output mappings of this |
||||||
|
* node |
||||||
|
* |
||||||
|
* @return the output mappings |
||||||
|
*/ |
||||||
|
public List<VariableMapping> getOutputMapping() { |
||||||
|
return outputMapping; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* sets the output mappings |
||||||
|
* |
||||||
|
* @param inputMapping the output mappings |
||||||
|
*/ |
||||||
|
public void setOutputMapping(List<VariableMapping> outputMapping) { |
||||||
|
this.outputMapping = outputMapping; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* jme seralization |
||||||
|
* |
||||||
|
* @param ex the exporter |
||||||
|
* @throws IOException |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public void write(JmeExporter ex) throws IOException { |
||||||
|
OutputCapsule oc = (OutputCapsule) ex.getCapsule(this); |
||||||
|
oc.write(name, "name", ""); |
||||||
|
oc.write(definition, "definition", null); |
||||||
|
oc.write(condition, "condition", null); |
||||||
|
oc.writeSavableArrayList((ArrayList) inputMapping, "inputMapping", new ArrayList<VariableMapping>()); |
||||||
|
oc.writeSavableArrayList((ArrayList) outputMapping, "outputMapping", new ArrayList<VariableMapping>()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* jme seralization |
||||||
|
* |
||||||
|
* @param im the importer |
||||||
|
* @throws IOException |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public void read(JmeImporter im) throws IOException { |
||||||
|
InputCapsule ic = (InputCapsule) im.getCapsule(this); |
||||||
|
name = ic.readString("name", ""); |
||||||
|
definition = (ShaderNodeDefinition) ic.readSavable("definition", null); |
||||||
|
condition = ic.readString("condition", null); |
||||||
|
inputMapping = (List<VariableMapping>) ic.readSavableArrayList("inputMapping", new ArrayList<VariableMapping>()); |
||||||
|
outputMapping = (List<VariableMapping>) ic.readSavableArrayList("outputMapping", new ArrayList<VariableMapping>()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* convenience tostring |
||||||
|
* |
||||||
|
* @return a string |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public String toString() { |
||||||
|
return "\nShaderNode{" + "\nname=" + name + ", \ndefinition=" + definition.getName() + ", \ncondition=" + condition + ", \ninputMapping=" + inputMapping + ", \noutputMapping=" + outputMapping + '}'; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,253 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2009-2012 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.shader; |
||||||
|
|
||||||
|
import com.jme3.export.InputCapsule; |
||||||
|
import com.jme3.export.JmeExporter; |
||||||
|
import com.jme3.export.JmeImporter; |
||||||
|
import com.jme3.export.OutputCapsule; |
||||||
|
import com.jme3.export.Savable; |
||||||
|
import com.jme3.shader.Shader.ShaderType; |
||||||
|
import java.io.IOException; |
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.Arrays; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
/** |
||||||
|
* Shader node definition structure meant for holding loaded datat from a |
||||||
|
* material definition j3md file |
||||||
|
* |
||||||
|
* @author Nehon |
||||||
|
*/ |
||||||
|
public class ShaderNodeDefinition implements Savable { |
||||||
|
|
||||||
|
private String name; |
||||||
|
private Shader.ShaderType type; |
||||||
|
private List<String> shadersLanguage = new ArrayList<String>(); |
||||||
|
private List<String> shadersPath = new ArrayList<String>(); |
||||||
|
private String documentation; |
||||||
|
private List<ShaderNodeVariable> inputs = new ArrayList<ShaderNodeVariable>(); |
||||||
|
private List<ShaderNodeVariable> outputs = new ArrayList<ShaderNodeVariable>(); |
||||||
|
private String path = null; |
||||||
|
|
||||||
|
/** |
||||||
|
* creates a ShaderNodeDefinition |
||||||
|
* |
||||||
|
* @param name the name of the definition |
||||||
|
* @param type the type of the shader |
||||||
|
* @param shaderPath the path of the shader |
||||||
|
* @param shaderLanguage the shader language (minimum required for this |
||||||
|
* definition) |
||||||
|
*/ |
||||||
|
public ShaderNodeDefinition(String name, ShaderType type, String shaderPath, String shaderLanguage) { |
||||||
|
this.name = name; |
||||||
|
this.type = type; |
||||||
|
shadersLanguage.add(shaderLanguage); |
||||||
|
shadersPath.add(shaderPath); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* creates a ShaderNodeDefinition |
||||||
|
*/ |
||||||
|
public ShaderNodeDefinition() { |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* returns the name of the definition |
||||||
|
* |
||||||
|
* @return the name |
||||||
|
*/ |
||||||
|
public String getName() { |
||||||
|
return name; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* sets the name of the definition |
||||||
|
* |
||||||
|
* @param name the name |
||||||
|
*/ |
||||||
|
public void setName(String name) { |
||||||
|
this.name = name; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @return the type of shader the definition applies to |
||||||
|
*/ |
||||||
|
public ShaderType getType() { |
||||||
|
return type; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* sets the type of shader this def applies to |
||||||
|
* |
||||||
|
* @param type the type |
||||||
|
*/ |
||||||
|
public void setType(ShaderType type) { |
||||||
|
this.type = type; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @return the docuentation for tthis definition |
||||||
|
*/ |
||||||
|
public String getDocumentation() { |
||||||
|
return documentation; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* sets the dcumentation |
||||||
|
* |
||||||
|
* @param documentation the documentation |
||||||
|
*/ |
||||||
|
public void setDocumentation(String documentation) { |
||||||
|
this.documentation = documentation; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @return the input variables of this definition |
||||||
|
*/ |
||||||
|
public List<ShaderNodeVariable> getInputs() { |
||||||
|
return inputs; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* sets the input variables of this definition |
||||||
|
* |
||||||
|
* @param inputs the inputs |
||||||
|
*/ |
||||||
|
public void setInputs(List<ShaderNodeVariable> inputs) { |
||||||
|
this.inputs = inputs; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @return the output variables of this definition |
||||||
|
*/ |
||||||
|
public List<ShaderNodeVariable> getOutputs() { |
||||||
|
return outputs; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* sets the output variables of this definition |
||||||
|
* |
||||||
|
* @param inputs the output |
||||||
|
*/ |
||||||
|
public void setOutputs(List<ShaderNodeVariable> outputs) { |
||||||
|
this.outputs = outputs; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* retrun the path of this definition |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public String getPath() { |
||||||
|
return path; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* sets the path of this definition |
||||||
|
* @param path |
||||||
|
*/ |
||||||
|
public void setPath(String path) { |
||||||
|
this.path = path; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* jme seralization (not used) |
||||||
|
* |
||||||
|
* @param ex the exporter |
||||||
|
* @throws IOException |
||||||
|
*/ |
||||||
|
public void write(JmeExporter ex) throws IOException { |
||||||
|
OutputCapsule oc = (OutputCapsule) ex.getCapsule(this); |
||||||
|
oc.write(name, "name", ""); |
||||||
|
String[] str = new String[shadersLanguage.size()]; |
||||||
|
oc.write(shadersLanguage.toArray(str), "shadersLanguage", null); |
||||||
|
oc.write(shadersPath.toArray(str), "shadersPath", null); |
||||||
|
oc.write(type, "type", null); |
||||||
|
oc.writeSavableArrayList((ArrayList) inputs, "inputs", new ArrayList<ShaderNodeVariable>()); |
||||||
|
oc.writeSavableArrayList((ArrayList) outputs, "inputs", new ArrayList<ShaderNodeVariable>()); |
||||||
|
} |
||||||
|
|
||||||
|
public List<String> getShadersLanguage() { |
||||||
|
return shadersLanguage; |
||||||
|
} |
||||||
|
|
||||||
|
public List<String> getShadersPath() { |
||||||
|
return shadersPath; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* jme seralization (not used) |
||||||
|
* |
||||||
|
* @param im the importer |
||||||
|
* @throws IOException |
||||||
|
*/ |
||||||
|
public void read(JmeImporter im) throws IOException { |
||||||
|
InputCapsule ic = (InputCapsule) im.getCapsule(this); |
||||||
|
name = ic.readString("name", ""); |
||||||
|
|
||||||
|
String[] str = ic.readStringArray("shadersLanguage", null); |
||||||
|
if (str != null) { |
||||||
|
shadersLanguage = Arrays.asList(str); |
||||||
|
} else { |
||||||
|
shadersLanguage = new ArrayList<String>(); |
||||||
|
} |
||||||
|
|
||||||
|
str = ic.readStringArray("shadersPath", null); |
||||||
|
if (str != null) { |
||||||
|
shadersPath = Arrays.asList(str); |
||||||
|
} else { |
||||||
|
shadersPath = new ArrayList<String>(); |
||||||
|
} |
||||||
|
|
||||||
|
type = ic.readEnum("type", Shader.ShaderType.class, null); |
||||||
|
inputs = (List<ShaderNodeVariable>) ic.readSavableArrayList("inputs", new ArrayList<ShaderNodeVariable>()); |
||||||
|
outputs = (List<ShaderNodeVariable>) ic.readSavableArrayList("outputs", new ArrayList<ShaderNodeVariable>()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* convenience tostring |
||||||
|
* |
||||||
|
* @return a string |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public String toString() { |
||||||
|
return "\nShaderNodeDefinition{\n" + "name=" + name + "\ntype=" + type + "\nshaderPath=" + shadersPath + "\nshaderLanguage=" + shadersLanguage + "\ndocumentation=" + documentation + "\ninputs=" + inputs + ",\noutputs=" + outputs + '}'; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,234 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2009-2012 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.shader; |
||||||
|
|
||||||
|
import com.jme3.export.InputCapsule; |
||||||
|
import com.jme3.export.JmeExporter; |
||||||
|
import com.jme3.export.JmeImporter; |
||||||
|
import com.jme3.export.OutputCapsule; |
||||||
|
import com.jme3.export.Savable; |
||||||
|
import java.io.IOException; |
||||||
|
|
||||||
|
/** |
||||||
|
* A shader node variable |
||||||
|
* |
||||||
|
* @author Nehon |
||||||
|
*/ |
||||||
|
public class ShaderNodeVariable implements Savable, Cloneable { |
||||||
|
|
||||||
|
private String name; |
||||||
|
private String type; |
||||||
|
private String nameSpace; |
||||||
|
private String condition; |
||||||
|
private boolean shaderOutput = false; |
||||||
|
|
||||||
|
/** |
||||||
|
* creates a ShaderNodeVariable |
||||||
|
* |
||||||
|
* @param type the glsl type of the variable |
||||||
|
* @param name the name of the variable |
||||||
|
*/ |
||||||
|
public ShaderNodeVariable(String type, String name) { |
||||||
|
this.name = name; |
||||||
|
this.type = type; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* creates a ShaderNodeVariable |
||||||
|
* |
||||||
|
* @param type the glsl type of the variable |
||||||
|
* @param nameSpace the nameSpace (can be the name of the shaderNode or |
||||||
|
* Globel,Attr,MatParam,WorldParam) |
||||||
|
* @param name the name of the variable |
||||||
|
*/ |
||||||
|
public ShaderNodeVariable(String type, String nameSpace, String name) { |
||||||
|
this.name = name; |
||||||
|
this.nameSpace = nameSpace; |
||||||
|
this.type = type; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* returns the name |
||||||
|
* |
||||||
|
* @return the name |
||||||
|
*/ |
||||||
|
public String getName() { |
||||||
|
return name; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* sets the name |
||||||
|
* |
||||||
|
* @param name the name |
||||||
|
*/ |
||||||
|
public void setName(String name) { |
||||||
|
this.name = name; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @return the glsl type |
||||||
|
*/ |
||||||
|
public String getType() { |
||||||
|
return type; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* sets the glsl type |
||||||
|
* |
||||||
|
* @param type the type |
||||||
|
*/ |
||||||
|
public void setType(String type) { |
||||||
|
this.type = type; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @return the name space (can be the name of the shaderNode or |
||||||
|
* Globel,Attr,MatParam,WorldParam) |
||||||
|
*/ |
||||||
|
public String getNameSpace() { |
||||||
|
return nameSpace; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* sets the nameSpace (can be the name of the shaderNode or |
||||||
|
* Globel,Attr,MatParam,WorldParam) |
||||||
|
* |
||||||
|
* @param nameSpace |
||||||
|
*/ |
||||||
|
public void setNameSpace(String nameSpace) { |
||||||
|
this.nameSpace = nameSpace; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int hashCode() { |
||||||
|
int hash = 5; |
||||||
|
return hash; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean equals(Object obj) { |
||||||
|
if (obj == null) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
if (getClass() != obj.getClass()) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
final ShaderNodeVariable other = (ShaderNodeVariable) obj; |
||||||
|
if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
if ((this.type == null) ? (other.type != null) : !this.type.equals(other.type)) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
if ((this.nameSpace == null) ? (other.nameSpace != null) : !this.nameSpace.equals(other.nameSpace)) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* jme seralization (not used) |
||||||
|
* |
||||||
|
* @param ex the exporter |
||||||
|
* @throws IOException |
||||||
|
*/ |
||||||
|
public void write(JmeExporter ex) throws IOException { |
||||||
|
OutputCapsule oc = (OutputCapsule) ex.getCapsule(this); |
||||||
|
oc.write(name, "name", ""); |
||||||
|
oc.write(type, "type", ""); |
||||||
|
oc.write(nameSpace, "nameSpace", ""); |
||||||
|
oc.write(condition, "condition", null); |
||||||
|
oc.write(shaderOutput, "shaderOutput", false); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* jme seralization (not used) |
||||||
|
* |
||||||
|
* @param im the importer |
||||||
|
* @throws IOException |
||||||
|
*/ |
||||||
|
public void read(JmeImporter im) throws IOException { |
||||||
|
InputCapsule ic = (InputCapsule) im.getCapsule(this); |
||||||
|
name = ic.readString("name", ""); |
||||||
|
type = ic.readString("type", ""); |
||||||
|
nameSpace = ic.readString("nameSpace", ""); |
||||||
|
condition = ic.readString("condition", null); |
||||||
|
shaderOutput = ic.readBoolean("shaderOutput", false); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @return the condition for this variable to be declared |
||||||
|
*/ |
||||||
|
public String getCondition() { |
||||||
|
return condition; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* sets the condition |
||||||
|
* |
||||||
|
* @param condition the condition |
||||||
|
*/ |
||||||
|
public void setCondition(String condition) { |
||||||
|
this.condition = condition; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String toString() { |
||||||
|
return "\n" + type + ' ' + (nameSpace != null ? (nameSpace + '.') : "") + name; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public ShaderNodeVariable clone() { |
||||||
|
return new ShaderNodeVariable(type, nameSpace, name); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @return true if this variable is a shader output |
||||||
|
*/ |
||||||
|
public boolean isShaderOutput() { |
||||||
|
return shaderOutput; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* sets to true if this variable is a shader output |
||||||
|
* |
||||||
|
* @param shaderOutput true if this variable is a shader output |
||||||
|
*/ |
||||||
|
public void setShaderOutput(boolean shaderOutput) { |
||||||
|
this.shaderOutput = shaderOutput; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,196 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2009-2012 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.shader; |
||||||
|
|
||||||
|
import com.jme3.export.InputCapsule; |
||||||
|
import com.jme3.export.JmeExporter; |
||||||
|
import com.jme3.export.JmeImporter; |
||||||
|
import com.jme3.export.OutputCapsule; |
||||||
|
import com.jme3.export.Savable; |
||||||
|
import java.io.IOException; |
||||||
|
|
||||||
|
/** |
||||||
|
* represents a mapping between 2 ShaderNodeVariables |
||||||
|
* |
||||||
|
* @author Nehon |
||||||
|
*/ |
||||||
|
public class VariableMapping implements Savable { |
||||||
|
|
||||||
|
private ShaderNodeVariable leftVariable; |
||||||
|
private ShaderNodeVariable rightVariable; |
||||||
|
private String condition; |
||||||
|
private String leftSwizzling = ""; |
||||||
|
private String rightSwizzling = ""; |
||||||
|
|
||||||
|
/** |
||||||
|
* creates a VariableMapping |
||||||
|
*/ |
||||||
|
public VariableMapping() { |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* creates a VariableMapping |
||||||
|
* |
||||||
|
* @param leftVariable the left hand side variable of the expression |
||||||
|
* @param leftSwizzling the swizzling of the left variable |
||||||
|
* @param rightVariable the right hand side variable of the expression |
||||||
|
* @param rightSwizzling the swizzling of the right variable |
||||||
|
* @param condition the condition for this mapping |
||||||
|
*/ |
||||||
|
public VariableMapping(ShaderNodeVariable leftVariable, String leftSwizzling, ShaderNodeVariable rightVariable, String rightSwizzling, String condition) { |
||||||
|
this.leftVariable = leftVariable; |
||||||
|
this.rightVariable = rightVariable; |
||||||
|
this.condition = condition; |
||||||
|
this.leftSwizzling = leftSwizzling; |
||||||
|
this.rightSwizzling = rightSwizzling; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @return the left variable |
||||||
|
*/ |
||||||
|
public ShaderNodeVariable getLeftVariable() { |
||||||
|
return leftVariable; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* sets the left variable |
||||||
|
* |
||||||
|
* @param leftVariable the left variable |
||||||
|
*/ |
||||||
|
public void setLeftVariable(ShaderNodeVariable leftVariable) { |
||||||
|
this.leftVariable = leftVariable; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @return the right variable |
||||||
|
*/ |
||||||
|
public ShaderNodeVariable getRightVariable() { |
||||||
|
return rightVariable; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* sets the right variable |
||||||
|
* |
||||||
|
* @param leftVariable the right variable |
||||||
|
*/ |
||||||
|
public void setRightVariable(ShaderNodeVariable rightVariable) { |
||||||
|
this.rightVariable = rightVariable; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @return the condition |
||||||
|
*/ |
||||||
|
public String getCondition() { |
||||||
|
return condition; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* sets the condition |
||||||
|
* |
||||||
|
* @param condition the condition |
||||||
|
*/ |
||||||
|
public void setCondition(String condition) { |
||||||
|
this.condition = condition; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @return the left swizzle |
||||||
|
*/ |
||||||
|
public String getLeftSwizzling() { |
||||||
|
return leftSwizzling; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* sets the left swizzle |
||||||
|
* |
||||||
|
* @param leftSwizzling the left swizzle |
||||||
|
*/ |
||||||
|
public void setLeftSwizzling(String leftSwizzling) { |
||||||
|
this.leftSwizzling = leftSwizzling; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @return the right swizzle |
||||||
|
*/ |
||||||
|
public String getRightSwizzling() { |
||||||
|
return rightSwizzling; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* sets the right swizzle |
||||||
|
* |
||||||
|
* @param leftSwizzling the right swizzle |
||||||
|
*/ |
||||||
|
public void setRightSwizzling(String rightSwizzling) { |
||||||
|
this.rightSwizzling = rightSwizzling; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* jme seralization (not used) |
||||||
|
* |
||||||
|
* @param ex the exporter |
||||||
|
* @throws IOException |
||||||
|
*/ |
||||||
|
public void write(JmeExporter ex) throws IOException { |
||||||
|
OutputCapsule oc = (OutputCapsule) ex.getCapsule(this); |
||||||
|
oc.write(leftVariable, "leftVariable", null); |
||||||
|
oc.write(rightVariable, "rightVariable", null); |
||||||
|
oc.write(condition, "condition", ""); |
||||||
|
oc.write(leftSwizzling, "leftSwizzling", ""); |
||||||
|
oc.write(rightSwizzling, "rightSwizzling", ""); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* jme seralization (not used) |
||||||
|
* |
||||||
|
* @param im the importer |
||||||
|
* @throws IOException |
||||||
|
*/ |
||||||
|
public void read(JmeImporter im) throws IOException { |
||||||
|
InputCapsule ic = (InputCapsule) im.getCapsule(this); |
||||||
|
leftVariable = (ShaderNodeVariable) ic.readSavable("leftVariable", null); |
||||||
|
rightVariable = (ShaderNodeVariable) ic.readSavable("rightVariable", null); |
||||||
|
condition = ic.readString("condition", ""); |
||||||
|
leftSwizzling = ic.readString("leftSwizzling", ""); |
||||||
|
rightSwizzling = ic.readString("rightSwizzling", ""); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String toString() { |
||||||
|
return "\n{" + leftVariable.toString() + (leftSwizzling.length() > 0 ? ("." + leftSwizzling) : "") + " = " + rightVariable.getType() + " " + rightVariable.getNameSpace() + "." + rightVariable.getName() + (rightSwizzling.length() > 0 ? ("." + rightSwizzling) : "") + " : " + condition + "}"; |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue