Shader Nodes implementation :
Core system git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@10432 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
This commit is contained in:
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;
|
||||||
|
}
|
||||||
|
}
|
@ -56,6 +56,9 @@ import java.util.logging.Logger;
|
|||||||
public class J3MLoader implements AssetLoader {
|
public class J3MLoader implements AssetLoader {
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(J3MLoader.class.getName());
|
private static final Logger logger = Logger.getLogger(J3MLoader.class.getName());
|
||||||
|
// private ErrorLogger errors;
|
||||||
|
private ShaderNodeLoaderDelegate nodesLoaderDelegate;
|
||||||
|
boolean isUseNodes = false;
|
||||||
|
|
||||||
private AssetManager assetManager;
|
private AssetManager assetManager;
|
||||||
private AssetKey key;
|
private AssetKey key;
|
||||||
@ -76,13 +79,6 @@ public class J3MLoader implements AssetLoader {
|
|||||||
public J3MLoader(){
|
public J3MLoader(){
|
||||||
}
|
}
|
||||||
|
|
||||||
private void throwIfNequal(String expected, String got) throws IOException {
|
|
||||||
if (expected == null)
|
|
||||||
throw new IOException("Expected a statement, got '"+got+"'!");
|
|
||||||
|
|
||||||
if (!expected.equals(got))
|
|
||||||
throw new IOException("Expected '"+expected+"', got '"+got+"'!");
|
|
||||||
}
|
|
||||||
|
|
||||||
// <TYPE> <LANG> : <SOURCE>
|
// <TYPE> <LANG> : <SOURCE>
|
||||||
private void readShaderStatement(String statement) throws IOException {
|
private void readShaderStatement(String statement) throws IOException {
|
||||||
@ -311,8 +307,8 @@ public class J3MLoader implements AssetLoader {
|
|||||||
return word != null && word.equals("On");
|
return word != null && word.equals("On");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readRenderStateStatement(String statement) throws IOException{
|
private void readRenderStateStatement(Statement statement) throws IOException{
|
||||||
String[] split = statement.split(whitespacePattern);
|
String[] split = statement.getLine().split(whitespacePattern);
|
||||||
if (split[0].equals("Wireframe")){
|
if (split[0].equals("Wireframe")){
|
||||||
renderState.setWireframe(parseBoolean(split[1]));
|
renderState.setWireframe(parseBoolean(split[1]));
|
||||||
}else if (split[0].equals("FaceCull")){
|
}else if (split[0].equals("FaceCull")){
|
||||||
@ -335,14 +331,14 @@ public class J3MLoader implements AssetLoader {
|
|||||||
}else if (split[0].equals("PointSprite")){
|
}else if (split[0].equals("PointSprite")){
|
||||||
renderState.setPointSprite(parseBoolean(split[1]));
|
renderState.setPointSprite(parseBoolean(split[1]));
|
||||||
} else {
|
} else {
|
||||||
throwIfNequal(null, split[0]);
|
throw new MatParseException(null, split[0], statement);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readAdditionalRenderState(List<Statement> renderStates) throws IOException{
|
private void readAdditionalRenderState(List<Statement> renderStates) throws IOException{
|
||||||
renderState = material.getAdditionalRenderState();
|
renderState = material.getAdditionalRenderState();
|
||||||
for (Statement statement : renderStates){
|
for (Statement statement : renderStates){
|
||||||
readRenderStateStatement(statement.getLine());
|
readRenderStateStatement(statement);
|
||||||
}
|
}
|
||||||
renderState = null;
|
renderState = null;
|
||||||
}
|
}
|
||||||
@ -350,7 +346,7 @@ public class J3MLoader implements AssetLoader {
|
|||||||
private void readRenderState(List<Statement> renderStates) throws IOException{
|
private void readRenderState(List<Statement> renderStates) throws IOException{
|
||||||
renderState = new RenderState();
|
renderState = new RenderState();
|
||||||
for (Statement statement : renderStates){
|
for (Statement statement : renderStates){
|
||||||
readRenderStateStatement(statement.getLine());
|
readRenderStateStatement(statement);
|
||||||
}
|
}
|
||||||
technique.setRenderState(renderState);
|
technique.setRenderState(renderState);
|
||||||
renderState = null;
|
renderState = null;
|
||||||
@ -359,7 +355,7 @@ public class J3MLoader implements AssetLoader {
|
|||||||
private void readForcedRenderState(List<Statement> renderStates) throws IOException{
|
private void readForcedRenderState(List<Statement> renderStates) throws IOException{
|
||||||
renderState = new RenderState();
|
renderState = new RenderState();
|
||||||
for (Statement statement : renderStates){
|
for (Statement statement : renderStates){
|
||||||
readRenderStateStatement(statement.getLine());
|
readRenderStateStatement(statement);
|
||||||
}
|
}
|
||||||
technique.setForcedRenderState(renderState);
|
technique.setForcedRenderState(renderState);
|
||||||
renderState = null;
|
renderState = null;
|
||||||
@ -402,8 +398,23 @@ public class J3MLoader implements AssetLoader {
|
|||||||
readForcedRenderState(statement.getContents());
|
readForcedRenderState(statement.getContents());
|
||||||
}else if (split[0].equals("Defines")){
|
}else if (split[0].equals("Defines")){
|
||||||
readDefines(statement.getContents());
|
readDefines(statement.getContents());
|
||||||
|
} else if (split[0].equals("ShaderNodesDefinitions")) {
|
||||||
|
initNodesLoader();
|
||||||
|
if (isUseNodes) {
|
||||||
|
nodesLoaderDelegate.readNodesDefinitions(statement.getContents());
|
||||||
|
}
|
||||||
|
} else if (split[0].equals("VertexShaderNodes")) {
|
||||||
|
initNodesLoader();
|
||||||
|
if (isUseNodes) {
|
||||||
|
nodesLoaderDelegate.readVertexShaderNodes(statement.getContents());
|
||||||
|
}
|
||||||
|
} else if (split[0].equals("FragmentShaderNodes")) {
|
||||||
|
initNodesLoader();
|
||||||
|
if (isUseNodes) {
|
||||||
|
nodesLoaderDelegate.readFragmentShaderNodes(statement.getContents());
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
throwIfNequal(null, split[0]);
|
throw new MatParseException(null, split[0], statement);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -448,6 +459,7 @@ public class J3MLoader implements AssetLoader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void loadFromRoot(List<Statement> roots) throws IOException{
|
private void loadFromRoot(List<Statement> roots) throws IOException{
|
||||||
|
isUseNodes = false;
|
||||||
if (roots.size() == 2){
|
if (roots.size() == 2){
|
||||||
Statement exception = roots.get(0);
|
Statement exception = roots.get(0);
|
||||||
String line = exception.getLine();
|
String line = exception.getLine();
|
||||||
@ -476,32 +488,33 @@ public class J3MLoader implements AssetLoader {
|
|||||||
String[] split = materialName.split(":", 2);
|
String[] split = materialName.split(":", 2);
|
||||||
|
|
||||||
if (materialName.equals("")){
|
if (materialName.equals("")){
|
||||||
throw new IOException("Material name cannot be empty");
|
throw new MatParseException("Material name cannot be empty", materialStat);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (split.length == 2){
|
if (split.length == 2){
|
||||||
if (!extending){
|
if (!extending){
|
||||||
throw new IOException("Must use 'Material' when extending.");
|
throw new MatParseException("Must use 'Material' when extending.", materialStat);
|
||||||
}
|
}
|
||||||
|
|
||||||
String extendedMat = split[1].trim();
|
String extendedMat = split[1].trim();
|
||||||
|
|
||||||
MaterialDef def = (MaterialDef) assetManager.loadAsset(new AssetKey(extendedMat));
|
MaterialDef def = (MaterialDef) assetManager.loadAsset(new AssetKey(extendedMat));
|
||||||
if (def == null)
|
if (def == null) {
|
||||||
throw new IOException("Extended material "+extendedMat+" cannot be found.");
|
throw new MatParseException("Extended material " + extendedMat + " cannot be found.", materialStat);
|
||||||
|
}
|
||||||
|
|
||||||
material = new Material(def);
|
material = new Material(def);
|
||||||
material.setKey(key);
|
material.setKey(key);
|
||||||
// material.setAssetName(fileName);
|
// material.setAssetName(fileName);
|
||||||
}else if (split.length == 1){
|
}else if (split.length == 1){
|
||||||
if (extending){
|
if (extending){
|
||||||
throw new IOException("Expected ':', got '{'");
|
throw new MatParseException("Expected ':', got '{'", materialStat);
|
||||||
}
|
}
|
||||||
materialDef = new MaterialDef(assetManager, materialName);
|
materialDef = new MaterialDef(assetManager, materialName);
|
||||||
// NOTE: pass file name for defs so they can be loaded later
|
// NOTE: pass file name for defs so they can be loaded later
|
||||||
materialDef.setAssetName(key.getName());
|
materialDef.setAssetName(key.getName());
|
||||||
}else{
|
}else{
|
||||||
throw new IOException("Cannot use colon in material name/path");
|
throw new MatParseException("Cannot use colon in material name/path", materialStat);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Statement statement : materialStat.getContents()){
|
for (Statement statement : materialStat.getContents()){
|
||||||
@ -521,7 +534,7 @@ public class J3MLoader implements AssetLoader {
|
|||||||
}else if (statType.equals("MaterialParameters")){
|
}else if (statType.equals("MaterialParameters")){
|
||||||
readMaterialParams(statement.getContents());
|
readMaterialParams(statement.getContents());
|
||||||
}else{
|
}else{
|
||||||
throw new IOException("Expected material statement, got '"+statType+"'");
|
throw new MatParseException("Expected material statement, got '"+statType+"'", statement);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -552,4 +565,23 @@ public class J3MLoader implements AssetLoader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MaterialDef loadMaterialDef(List<Statement> roots, AssetManager manager, AssetKey key) throws IOException {
|
||||||
|
this.key = key;
|
||||||
|
this.assetManager = manager;
|
||||||
|
loadFromRoot(roots);
|
||||||
|
return materialDef;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void initNodesLoader() {
|
||||||
|
if (!isUseNodes) {
|
||||||
|
isUseNodes = fragName == null && vertName == null;
|
||||||
|
if (isUseNodes) {
|
||||||
|
nodesLoaderDelegate = new ShaderNodeLoaderDelegate();
|
||||||
|
nodesLoaderDelegate.setTechniqueDef(technique);
|
||||||
|
nodesLoaderDelegate.setMaterialDef(materialDef);
|
||||||
|
nodesLoaderDelegate.setAssetManager(assetManager);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -38,12 +38,15 @@ import com.jme3.audio.AudioKey;
|
|||||||
import com.jme3.font.BitmapFont;
|
import com.jme3.font.BitmapFont;
|
||||||
import com.jme3.material.Material;
|
import com.jme3.material.Material;
|
||||||
import com.jme3.post.FilterPostProcessor;
|
import com.jme3.post.FilterPostProcessor;
|
||||||
|
import com.jme3.renderer.Caps;
|
||||||
import com.jme3.scene.Spatial;
|
import com.jme3.scene.Spatial;
|
||||||
import com.jme3.scene.plugins.OBJLoader;
|
import com.jme3.scene.plugins.OBJLoader;
|
||||||
import com.jme3.shader.Shader;
|
import com.jme3.shader.Shader;
|
||||||
|
import com.jme3.shader.ShaderGenerator;
|
||||||
import com.jme3.shader.ShaderKey;
|
import com.jme3.shader.ShaderKey;
|
||||||
import com.jme3.texture.Texture;
|
import com.jme3.texture.Texture;
|
||||||
import com.jme3.texture.plugins.TGALoader;
|
import com.jme3.texture.plugins.TGALoader;
|
||||||
|
import java.util.EnumSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -364,4 +367,17 @@ public interface AssetManager {
|
|||||||
* @see AssetManager#loadAsset(com.jme3.asset.AssetKey)
|
* @see AssetManager#loadAsset(com.jme3.asset.AssetKey)
|
||||||
*/
|
*/
|
||||||
public FilterPostProcessor loadFilter(String name);
|
public FilterPostProcessor loadFilter(String name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the shaderGenerator to generate shaders based on shaderNodes.
|
||||||
|
* @param generator the shaderGenerator
|
||||||
|
*/
|
||||||
|
public void setShaderGenerator(ShaderGenerator generator);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the shaderGenerator responsible for generating the shaders
|
||||||
|
* @return the shaderGenerator
|
||||||
|
*/
|
||||||
|
public ShaderGenerator getShaderGenerator(EnumSet<Caps> caps);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ LOADER com.jme3.audio.plugins.OGGLoader : ogg
|
|||||||
LOADER com.jme3.cursors.plugins.CursorLoader : ani, cur, ico
|
LOADER com.jme3.cursors.plugins.CursorLoader : ani, cur, ico
|
||||||
LOADER com.jme3.material.plugins.J3MLoader : j3m
|
LOADER com.jme3.material.plugins.J3MLoader : j3m
|
||||||
LOADER com.jme3.material.plugins.J3MLoader : j3md
|
LOADER com.jme3.material.plugins.J3MLoader : j3md
|
||||||
|
LOADER com.jme3.material.plugins.ShaderNodeDefinitionLoader : j3sn
|
||||||
LOADER com.jme3.font.plugins.BitmapFontLoader : fnt
|
LOADER com.jme3.font.plugins.BitmapFontLoader : fnt
|
||||||
LOADER com.jme3.texture.plugins.DDSLoader : dds
|
LOADER com.jme3.texture.plugins.DDSLoader : dds
|
||||||
LOADER com.jme3.texture.plugins.PFMLoader : pfm
|
LOADER com.jme3.texture.plugins.PFMLoader : pfm
|
||||||
|
@ -38,8 +38,12 @@ import com.jme3.audio.AudioKey;
|
|||||||
import com.jme3.font.BitmapFont;
|
import com.jme3.font.BitmapFont;
|
||||||
import com.jme3.material.Material;
|
import com.jme3.material.Material;
|
||||||
import com.jme3.post.FilterPostProcessor;
|
import com.jme3.post.FilterPostProcessor;
|
||||||
|
import com.jme3.renderer.Caps;
|
||||||
import com.jme3.scene.Spatial;
|
import com.jme3.scene.Spatial;
|
||||||
|
import com.jme3.shader.Glsl100ShaderGenerator;
|
||||||
|
import com.jme3.shader.Glsl150ShaderGenerator;
|
||||||
import com.jme3.shader.Shader;
|
import com.jme3.shader.Shader;
|
||||||
|
import com.jme3.shader.ShaderGenerator;
|
||||||
import com.jme3.shader.ShaderKey;
|
import com.jme3.shader.ShaderKey;
|
||||||
import com.jme3.texture.Texture;
|
import com.jme3.texture.Texture;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -48,6 +52,7 @@ import java.net.URL;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.EnumSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
@ -62,6 +67,7 @@ import java.util.logging.Logger;
|
|||||||
public class DesktopAssetManager implements AssetManager {
|
public class DesktopAssetManager implements AssetManager {
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(AssetManager.class.getName());
|
private static final Logger logger = Logger.getLogger(AssetManager.class.getName());
|
||||||
|
private ShaderGenerator shaderGenerator;
|
||||||
|
|
||||||
private final ImplHandler handler = new ImplHandler(this);
|
private final ImplHandler handler = new ImplHandler(this);
|
||||||
|
|
||||||
@ -407,4 +413,29 @@ public class DesktopAssetManager implements AssetManager {
|
|||||||
}
|
}
|
||||||
return shader;
|
return shader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public ShaderGenerator getShaderGenerator(EnumSet<Caps> caps) {
|
||||||
|
if (shaderGenerator == null) {
|
||||||
|
if(caps.contains(Caps.GLSL150)){
|
||||||
|
shaderGenerator = new Glsl150ShaderGenerator(this);
|
||||||
|
}else{
|
||||||
|
shaderGenerator = new Glsl100ShaderGenerator(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return shaderGenerator;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void setShaderGenerator(ShaderGenerator shaderGenerator) {
|
||||||
|
this.shaderGenerator = shaderGenerator;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
89
engine/src/core/com/jme3/asset/ShaderNodeDefinitionKey.java
Normal file
89
engine/src/core/com/jme3/asset/ShaderNodeDefinitionKey.java
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -873,10 +873,10 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
|
|||||||
public void selectTechnique(String name, RenderManager renderManager) {
|
public void selectTechnique(String name, RenderManager renderManager) {
|
||||||
// check if already created
|
// check if already created
|
||||||
Technique tech = techniques.get(name);
|
Technique tech = techniques.get(name);
|
||||||
if (tech == null) {
|
|
||||||
// When choosing technique, we choose one that
|
// When choosing technique, we choose one that
|
||||||
// supports all the caps.
|
// supports all the caps.
|
||||||
EnumSet<Caps> rendererCaps = renderManager.getRenderer().getCaps();
|
EnumSet<Caps> rendererCaps = renderManager.getRenderer().getCaps();
|
||||||
|
if (tech == null) {
|
||||||
|
|
||||||
if (name.equals("Default")) {
|
if (name.equals("Default")) {
|
||||||
List<TechniqueDef> techDefs = def.getDefaultTechniques();
|
List<TechniqueDef> techDefs = def.getDefaultTechniques();
|
||||||
@ -923,7 +923,7 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
technique = tech;
|
technique = tech;
|
||||||
tech.makeCurrent(def.getAssetManager(), true);
|
tech.makeCurrent(def.getAssetManager(), true, rendererCaps);
|
||||||
|
|
||||||
// shader was changed
|
// shader was changed
|
||||||
sortingId = -1;
|
sortingId = -1;
|
||||||
@ -933,7 +933,7 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
|
|||||||
if (technique == null) {
|
if (technique == null) {
|
||||||
selectTechnique("Default", rm);
|
selectTechnique("Default", rm);
|
||||||
} else {
|
} else {
|
||||||
technique.makeCurrent(def.getAssetManager(), false);
|
technique.makeCurrent(def.getAssetManager(), false, rm.getRenderer().getCaps());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
190
engine/src/core/com/jme3/material/ShaderGenerationInfo.java
Normal file
190
engine/src/core/com/jme3/material/ShaderGenerationInfo.java
Normal file
@ -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);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -32,9 +32,11 @@
|
|||||||
package com.jme3.material;
|
package com.jme3.material;
|
||||||
|
|
||||||
import com.jme3.asset.AssetManager;
|
import com.jme3.asset.AssetManager;
|
||||||
|
import com.jme3.renderer.Caps;
|
||||||
import com.jme3.shader.*;
|
import com.jme3.shader.*;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.EnumSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
@ -170,7 +172,7 @@ public class Technique /* implements Savable */ {
|
|||||||
*
|
*
|
||||||
* @param assetManager The asset manager to use for loading shaders.
|
* @param assetManager The asset manager to use for loading shaders.
|
||||||
*/
|
*/
|
||||||
public void makeCurrent(AssetManager assetManager, boolean techniqueSwitched) {
|
public void makeCurrent(AssetManager assetManager, boolean techniqueSwitched, EnumSet<Caps> rendererCaps) {
|
||||||
if (!def.isUsingShaders()) {
|
if (!def.isUsingShaders()) {
|
||||||
// No shaders are used, no processing is neccessary.
|
// No shaders are used, no processing is neccessary.
|
||||||
return;
|
return;
|
||||||
@ -197,23 +199,23 @@ public class Technique /* implements Savable */ {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (needReload) {
|
if (needReload) {
|
||||||
loadShader(assetManager);
|
loadShader(assetManager,rendererCaps);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadShader(AssetManager manager) {
|
private void loadShader(AssetManager manager,EnumSet<Caps> rendererCaps) {
|
||||||
// recompute define list
|
|
||||||
DefineList allDefines = new DefineList();
|
|
||||||
allDefines.addFrom(def.getShaderPresetDefines());
|
|
||||||
allDefines.addFrom(defines);
|
|
||||||
|
|
||||||
|
if (getDef().isUsingShaderNodes()) {
|
||||||
|
shader = manager.getShaderGenerator(rendererCaps).generateShader(this);
|
||||||
|
} else {
|
||||||
ShaderKey key = new ShaderKey(def.getVertexShaderName(),
|
ShaderKey key = new ShaderKey(def.getVertexShaderName(),
|
||||||
def.getFragmentShaderName(),
|
def.getFragmentShaderName(),
|
||||||
allDefines,
|
getAllDefines(),
|
||||||
def.getVertexShaderLanguage(),
|
def.getVertexShaderLanguage(),
|
||||||
def.getFragmentShaderLanguage());
|
def.getFragmentShaderLanguage());
|
||||||
shader = manager.loadShader(key);
|
shader = manager.loadShader(key);
|
||||||
|
|
||||||
|
}
|
||||||
// register the world bound uniforms
|
// register the world bound uniforms
|
||||||
worldBindUniforms.clear();
|
worldBindUniforms.clear();
|
||||||
if (def.getWorldBindings() != null) {
|
if (def.getWorldBindings() != null) {
|
||||||
@ -228,6 +230,17 @@ public class Technique /* implements Savable */ {
|
|||||||
needReload = false;
|
needReload = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes the define list
|
||||||
|
* @return the complete define list
|
||||||
|
*/
|
||||||
|
public DefineList getAllDefines() {
|
||||||
|
DefineList allDefines = new DefineList();
|
||||||
|
allDefines.addFrom(def.getShaderPresetDefines());
|
||||||
|
allDefines.addFrom(defines);
|
||||||
|
return allDefines;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
public void write(JmeExporter ex) throws IOException {
|
public void write(JmeExporter ex) throws IOException {
|
||||||
OutputCapsule oc = ex.getCapsule(this);
|
OutputCapsule oc = ex.getCapsule(this);
|
||||||
|
@ -35,6 +35,7 @@ import com.jme3.export.*;
|
|||||||
import com.jme3.renderer.Caps;
|
import com.jme3.renderer.Caps;
|
||||||
import com.jme3.renderer.Renderer;
|
import com.jme3.renderer.Renderer;
|
||||||
import com.jme3.shader.DefineList;
|
import com.jme3.shader.DefineList;
|
||||||
|
import com.jme3.shader.ShaderNode;
|
||||||
import com.jme3.shader.UniformBinding;
|
import com.jme3.shader.UniformBinding;
|
||||||
import com.jme3.shader.VarType;
|
import com.jme3.shader.VarType;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -110,6 +111,9 @@ public class TechniqueDef implements Savable {
|
|||||||
|
|
||||||
private DefineList presetDefines;
|
private DefineList presetDefines;
|
||||||
private boolean usesShaders;
|
private boolean usesShaders;
|
||||||
|
private boolean usesNodes = false;
|
||||||
|
private List<ShaderNode> shaderNodes;
|
||||||
|
private ShaderGenerationInfo shaderGenerationInfo;
|
||||||
|
|
||||||
private RenderState renderState;
|
private RenderState renderState;
|
||||||
private RenderState forcedRenderState;
|
private RenderState forcedRenderState;
|
||||||
@ -218,6 +222,16 @@ public class TechniqueDef implements Savable {
|
|||||||
return usesShaders;
|
return usesShaders;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if this technique uses Shader Nodes, false otherwise.
|
||||||
|
*
|
||||||
|
* @return true if this technique uses Shader Nodes, false otherwise.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public boolean isUsingShaderNodes(){
|
||||||
|
return usesNodes;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the {@link Caps renderer capabilities} that are required
|
* Gets the {@link Caps renderer capabilities} that are required
|
||||||
* by this technique.
|
* by this technique.
|
||||||
@ -408,6 +422,9 @@ public class TechniqueDef implements Savable {
|
|||||||
oc.write(shadowMode, "shadowMode", ShadowMode.Disable);
|
oc.write(shadowMode, "shadowMode", ShadowMode.Disable);
|
||||||
oc.write(renderState, "renderState", null);
|
oc.write(renderState, "renderState", null);
|
||||||
oc.write(usesShaders, "usesShaders", false);
|
oc.write(usesShaders, "usesShaders", false);
|
||||||
|
oc.write(usesNodes, "usesNodes", false);
|
||||||
|
oc.writeSavableArrayList((ArrayList)shaderNodes,"shaderNodes", null);
|
||||||
|
oc.write(shaderGenerationInfo, "shaderGenerationInfo", null);
|
||||||
|
|
||||||
// TODO: Finish this when Map<String, String> export is available
|
// TODO: Finish this when Map<String, String> export is available
|
||||||
// oc.write(defineParams, "defineParams", null);
|
// oc.write(defineParams, "defineParams", null);
|
||||||
@ -435,6 +452,32 @@ public class TechniqueDef implements Savable {
|
|||||||
vertLanguage = ic.readString("vertLanguage", null);
|
vertLanguage = ic.readString("vertLanguage", null);
|
||||||
fragLanguage = ic.readString("fragLanguage", null);;
|
fragLanguage = ic.readString("fragLanguage", null);;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
usesNodes = ic.readBoolean("usesNodes", false);
|
||||||
|
shaderNodes = ic.readSavableArrayList("shaderNodes", null);
|
||||||
|
shaderGenerationInfo = (ShaderGenerationInfo) ic.readSavable("shaderGenerationInfo", null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<ShaderNode> getShaderNodes() {
|
||||||
|
return shaderNodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setShaderNodes(List<ShaderNode> shaderNodes) {
|
||||||
|
this.shaderNodes = shaderNodes;
|
||||||
|
usesNodes = true;
|
||||||
|
usesShaders = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ShaderGenerationInfo getShaderGenerationInfo() {
|
||||||
|
return shaderGenerationInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setShaderGenerationInfo(ShaderGenerationInfo shaderGenerationInfo) {
|
||||||
|
this.shaderGenerationInfo = shaderGenerationInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "TechniqueDef{" + "requiredCaps=" + requiredCaps + ", name=" + name + ", vertName=" + vertName + ", fragName=" + fragName + ", vertLanguage=" + vertLanguage + ", fragLanguage=" + fragLanguage + ", presetDefines=" + presetDefines + ", usesShaders=" + usesShaders + ", usesNodes=" + usesNodes + ", shaderNodes=" + shaderNodes + ", shaderGenerationInfo=" + shaderGenerationInfo + ", renderState=" + renderState + ", forcedRenderState=" + forcedRenderState + ", lightMode=" + lightMode + ", shadowMode=" + shadowMode + ", defineParams=" + defineParams + ", worldBinds=" + worldBinds + '}';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,7 @@ package com.jme3.renderer.queue;
|
|||||||
|
|
||||||
import com.jme3.renderer.Camera;
|
import com.jme3.renderer.Camera;
|
||||||
import com.jme3.scene.Geometry;
|
import com.jme3.scene.Geometry;
|
||||||
|
import com.jme3.util.ListSort;
|
||||||
import com.jme3.util.SortUtil;
|
import com.jme3.util.SortUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -48,10 +49,16 @@ public class GeometryList {
|
|||||||
private static final int DEFAULT_SIZE = 32;
|
private static final int DEFAULT_SIZE = 32;
|
||||||
|
|
||||||
private Geometry[] geometries;
|
private Geometry[] geometries;
|
||||||
private Geometry[] geometries2;
|
// private Geometry[] geometries2;
|
||||||
|
private ListSort listSort;
|
||||||
private int size;
|
private int size;
|
||||||
private GeometryComparator comparator;
|
private GeometryComparator comparator;
|
||||||
|
|
||||||
|
/*static private int count =0;
|
||||||
|
static private int cpt =0;
|
||||||
|
static private long time = 0;
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the GeometryList to use the given {@link GeometryComparator}
|
* Initializes the GeometryList to use the given {@link GeometryComparator}
|
||||||
* to use for comparing geometries.
|
* to use for comparing geometries.
|
||||||
@ -61,8 +68,9 @@ public class GeometryList {
|
|||||||
public GeometryList(GeometryComparator comparator) {
|
public GeometryList(GeometryComparator comparator) {
|
||||||
size = 0;
|
size = 0;
|
||||||
geometries = new Geometry[DEFAULT_SIZE];
|
geometries = new Geometry[DEFAULT_SIZE];
|
||||||
geometries2 = new Geometry[DEFAULT_SIZE];
|
// geometries2 = new Geometry[DEFAULT_SIZE];
|
||||||
this.comparator = comparator;
|
this.comparator = comparator;
|
||||||
|
listSort = new ListSort<Geometry>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -115,7 +123,7 @@ public class GeometryList {
|
|||||||
System.arraycopy(geometries, 0, temp, 0, size);
|
System.arraycopy(geometries, 0, temp, 0, size);
|
||||||
geometries = temp; // original list replaced by double-size list
|
geometries = temp; // original list replaced by double-size list
|
||||||
|
|
||||||
geometries2 = new Geometry[size * 2];
|
// geometries2 = new Geometry[size * 2];
|
||||||
}
|
}
|
||||||
geometries[size++] = g;
|
geometries[size++] = g;
|
||||||
}
|
}
|
||||||
@ -137,14 +145,34 @@ public class GeometryList {
|
|||||||
public void sort() {
|
public void sort() {
|
||||||
if (size > 1) {
|
if (size > 1) {
|
||||||
// sort the spatial list using the comparator
|
// sort the spatial list using the comparator
|
||||||
|
// count++;
|
||||||
|
// long t = System.nanoTime();
|
||||||
|
|
||||||
// SortUtil.qsort(geometries, 0, size, comparator);
|
if(listSort.getLength() != size){
|
||||||
|
listSort.allocateStack(size);
|
||||||
|
}
|
||||||
|
listSort.sort(geometries,comparator);
|
||||||
|
|
||||||
|
// time += System.nanoTime() - t;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// count++;
|
||||||
|
// long t = System.nanoTime();
|
||||||
|
// System.arraycopy(geometries, 0, geometries2, 0, size);
|
||||||
|
// SortUtil.msort(geometries2, geometries, 0, size-1, comparator);
|
||||||
|
// time += System.nanoTime() - t;
|
||||||
|
//
|
||||||
|
// count++;
|
||||||
|
// long t = System.nanoTime();
|
||||||
// Arrays.sort(geometries,0,size, comparator);
|
// Arrays.sort(geometries,0,size, comparator);
|
||||||
|
// time += System.nanoTime() - t;
|
||||||
|
}
|
||||||
|
|
||||||
System.arraycopy(geometries, 0, geometries2, 0, size);
|
// if( count>50){
|
||||||
SortUtil.msort(geometries2, geometries, 0, size-1, comparator);
|
// count = 0;
|
||||||
|
// cpt++;
|
||||||
|
// System.err.println(50*cpt+"\t"+time/1000000);
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
572
engine/src/core/com/jme3/shader/Glsl100ShaderGenerator.java
Normal file
572
engine/src/core/com/jme3/shader/Glsl100ShaderGenerator.java
Normal file
@ -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);
|
||||||
|
}
|
||||||
|
}
|
146
engine/src/core/com/jme3/shader/Glsl150ShaderGenerator.java
Normal file
146
engine/src/core/com/jme3/shader/Glsl150ShaderGenerator.java
Normal file
@ -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");
|
||||||
|
}
|
||||||
|
}
|
290
engine/src/core/com/jme3/shader/ShaderGenerator.java
Normal file
290
engine/src/core/com/jme3/shader/ShaderGenerator.java
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
215
engine/src/core/com/jme3/shader/ShaderNode.java
Normal file
215
engine/src/core/com/jme3/shader/ShaderNode.java
Normal file
@ -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 + '}';
|
||||||
|
}
|
||||||
|
}
|
253
engine/src/core/com/jme3/shader/ShaderNodeDefinition.java
Normal file
253
engine/src/core/com/jme3/shader/ShaderNodeDefinition.java
Normal file
@ -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 + '}';
|
||||||
|
}
|
||||||
|
}
|
234
engine/src/core/com/jme3/shader/ShaderNodeVariable.java
Normal file
234
engine/src/core/com/jme3/shader/ShaderNodeVariable.java
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -46,4 +46,71 @@ public class ShaderUtils {
|
|||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a mapping is valid by checking the types and swizzle of both of
|
||||||
|
* the variables
|
||||||
|
*
|
||||||
|
* @param mapping the mapping
|
||||||
|
* @return true if this mapping is valid
|
||||||
|
*/
|
||||||
|
public static boolean typesMatch(VariableMapping mapping) {
|
||||||
|
String leftType = mapping.getLeftVariable().getType();
|
||||||
|
String rightType = mapping.getRightVariable().getType();
|
||||||
|
String leftSwizzling = mapping.getLeftSwizzling();
|
||||||
|
String rightSwizzling = mapping.getRightSwizzling();
|
||||||
|
|
||||||
|
//types match : no error
|
||||||
|
if (leftType.equals(rightType) && leftSwizzling.length() == rightSwizzling.length()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (isSwizzlable(leftType) && isSwizzlable(rightType)) {
|
||||||
|
if (getCardinality(leftType, leftSwizzling) == getCardinality(rightType, rightSwizzling)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return the cardinality of a type and a swizzle example : vec4 cardinality
|
||||||
|
* is 4 float cardinality is 1 vec4.xyz cardinality is 3. sampler2D
|
||||||
|
* cardinality is 0
|
||||||
|
*
|
||||||
|
* @param type the glsl type
|
||||||
|
* @param swizzling the swizzling of a variable
|
||||||
|
* @return the cardinality
|
||||||
|
*/
|
||||||
|
public static int getCardinality(String type, String swizzling) {
|
||||||
|
int card = 0;
|
||||||
|
if (isSwizzlable(type)) {
|
||||||
|
if (type.equals("float")) {
|
||||||
|
card = 1;
|
||||||
|
if (swizzling.length() != 0) {
|
||||||
|
card = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
card = Integer.parseInt(type.replaceAll("vec", ""));
|
||||||
|
|
||||||
|
if (swizzling.length() > 0) {
|
||||||
|
if (card >= swizzling.length()) {
|
||||||
|
card = swizzling.length();
|
||||||
|
} else {
|
||||||
|
card = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return card;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns true if a variable of the given type can have a swizzle
|
||||||
|
*
|
||||||
|
* @param type the glsl type
|
||||||
|
* @return true if a variable of the given type can have a swizzle
|
||||||
|
*/
|
||||||
|
public static boolean isSwizzlable(String type) {
|
||||||
|
return type.equals("vec4") || type.equals("vec3") || type.equals("vec2") || type.equals("float");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,63 +37,63 @@ public enum UniformBinding {
|
|||||||
* The world matrix. Converts Model space to World space.
|
* The world matrix. Converts Model space to World space.
|
||||||
* Type: mat4
|
* Type: mat4
|
||||||
*/
|
*/
|
||||||
WorldMatrix,
|
WorldMatrix("mat4"),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The view matrix. Converts World space to View space.
|
* The view matrix. Converts World space to View space.
|
||||||
* Type: mat4
|
* Type: mat4
|
||||||
*/
|
*/
|
||||||
ViewMatrix,
|
ViewMatrix("mat4"),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The projection matrix. Converts View space to Clip/Projection space.
|
* The projection matrix. Converts View space to Clip/Projection space.
|
||||||
* Type: mat4
|
* Type: mat4
|
||||||
*/
|
*/
|
||||||
ProjectionMatrix,
|
ProjectionMatrix("mat4"),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The world view matrix. Converts Model space to View space.
|
* The world view matrix. Converts Model space to View space.
|
||||||
* Type: mat4
|
* Type: mat4
|
||||||
*/
|
*/
|
||||||
WorldViewMatrix,
|
WorldViewMatrix("mat4"),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The normal matrix. The inverse transpose of the worldview matrix.
|
* The normal matrix. The inverse transpose of the worldview matrix.
|
||||||
* Converts normals from model space to view space.
|
* Converts normals from model space to view space.
|
||||||
* Type: mat3
|
* Type: mat3
|
||||||
*/
|
*/
|
||||||
NormalMatrix,
|
NormalMatrix("mat3"),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The world view projection matrix. Converts Model space to Clip/Projection
|
* The world view projection matrix. Converts Model space to Clip/Projection
|
||||||
* space.
|
* space.
|
||||||
* Type: mat4
|
* Type: mat4
|
||||||
*/
|
*/
|
||||||
WorldViewProjectionMatrix,
|
WorldViewProjectionMatrix("mat4"),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The view projection matrix. Converts World space to Clip/Projection
|
* The view projection matrix. Converts World space to Clip/Projection
|
||||||
* space.
|
* space.
|
||||||
* Type: mat4
|
* Type: mat4
|
||||||
*/
|
*/
|
||||||
ViewProjectionMatrix,
|
ViewProjectionMatrix("mat4"),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The world matrix inverse transpose. Converts a normals from Model space
|
* The world matrix inverse transpose. Converts a normals from Model space
|
||||||
* to world space.
|
* to world space.
|
||||||
* Type: mat3
|
* Type: mat3
|
||||||
*/
|
*/
|
||||||
WorldMatrixInverseTranspose,
|
WorldMatrixInverseTranspose("mat3"),
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
WorldMatrixInverse,
|
WorldMatrixInverse("mat4"),
|
||||||
ViewMatrixInverse,
|
ViewMatrixInverse("mat4"),
|
||||||
ProjectionMatrixInverse,
|
ProjectionMatrixInverse("mat4"),
|
||||||
ViewProjectionMatrixInverse,
|
ViewProjectionMatrixInverse("mat4"),
|
||||||
WorldViewMatrixInverse,
|
WorldViewMatrixInverse("mat4"),
|
||||||
NormalMatrixInverse,
|
NormalMatrixInverse("mat3"),
|
||||||
WorldViewProjectionMatrixInverse,
|
WorldViewProjectionMatrixInverse("mat4"),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains the four viewport parameters in this order:
|
* Contains the four viewport parameters in this order:
|
||||||
@ -103,7 +103,7 @@ public enum UniformBinding {
|
|||||||
* W = Bottom.
|
* W = Bottom.
|
||||||
* Type: vec4
|
* Type: vec4
|
||||||
*/
|
*/
|
||||||
ViewPort,
|
ViewPort("vec4"),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The near and far values for the camera frustum.
|
* The near and far values for the camera frustum.
|
||||||
@ -111,65 +111,80 @@ public enum UniformBinding {
|
|||||||
* Y = Far.
|
* Y = Far.
|
||||||
* Type: vec2
|
* Type: vec2
|
||||||
*/
|
*/
|
||||||
FrustumNearFar,
|
FrustumNearFar("vec2"),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The width and height of the camera.
|
* The width and height of the camera.
|
||||||
* Type: vec2
|
* Type: vec2
|
||||||
*/
|
*/
|
||||||
Resolution,
|
Resolution("vec2"),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The inverse of the resolution, 1/width and 1/height.
|
* The inverse of the resolution, 1/width and 1/height.
|
||||||
* Type: vec2
|
* Type: vec2
|
||||||
*/
|
*/
|
||||||
ResolutionInverse,
|
ResolutionInverse("vec2"),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Aspect ratio of the resolution currently set. Width/Height.
|
* Aspect ratio of the resolution currently set. Width/Height.
|
||||||
* Type: float
|
* Type: float
|
||||||
*/
|
*/
|
||||||
Aspect,
|
Aspect("float"),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Camera position in world space.
|
* Camera position in world space.
|
||||||
* Type: vec3
|
* Type: vec3
|
||||||
*/
|
*/
|
||||||
CameraPosition,
|
CameraPosition("vec3"),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Direction of the camera.
|
* Direction of the camera.
|
||||||
* Type: vec3
|
* Type: vec3
|
||||||
*/
|
*/
|
||||||
CameraDirection,
|
CameraDirection("vec3"),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Left vector of the camera.
|
* Left vector of the camera.
|
||||||
* Type: vec3
|
* Type: vec3
|
||||||
*/
|
*/
|
||||||
CameraLeft,
|
CameraLeft("vec3"),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Up vector of the camera.
|
* Up vector of the camera.
|
||||||
* Type: vec3
|
* Type: vec3
|
||||||
*/
|
*/
|
||||||
CameraUp,
|
CameraUp("vec3"),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Time in seconds since the application was started.
|
* Time in seconds since the application was started.
|
||||||
* Type: float
|
* Type: float
|
||||||
*/
|
*/
|
||||||
Time,
|
Time("float"),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Time in seconds that the last frame took.
|
* Time in seconds that the last frame took.
|
||||||
* Type: float
|
* Type: float
|
||||||
*/
|
*/
|
||||||
Tpf,
|
Tpf("float"),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Frames per second.
|
* Frames per second.
|
||||||
* Type: float
|
* Type: float
|
||||||
*/
|
*/
|
||||||
FrameRate,
|
FrameRate("float");
|
||||||
|
|
||||||
|
String glslType;
|
||||||
|
|
||||||
|
private UniformBinding() {
|
||||||
|
}
|
||||||
|
|
||||||
|
private UniformBinding(String glslType) {
|
||||||
|
this.glslType = glslType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getGlslType() {
|
||||||
|
return glslType;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -33,40 +33,44 @@ package com.jme3.shader;
|
|||||||
|
|
||||||
public enum VarType {
|
public enum VarType {
|
||||||
|
|
||||||
Float,
|
Float("float"),
|
||||||
Vector2,
|
Vector2("vec2"),
|
||||||
Vector3,
|
Vector3("vec3"),
|
||||||
Vector4,
|
Vector4("vec4"),
|
||||||
|
|
||||||
FloatArray(true,false),
|
FloatArray(true,false,"float[]"),
|
||||||
Vector2Array(true,false),
|
Vector2Array(true,false,"vec2[]"),
|
||||||
Vector3Array(true,false),
|
Vector3Array(true,false,"vec3[]"),
|
||||||
Vector4Array(true,false),
|
Vector4Array(true,false,"vec4[]"),
|
||||||
|
|
||||||
Boolean,
|
Boolean("bool"),
|
||||||
|
|
||||||
Matrix3(true,false),
|
Matrix3(true,false,"mat3"),
|
||||||
Matrix4(true,false),
|
Matrix4(true,false,"mat4"),
|
||||||
|
|
||||||
Matrix3Array(true,false),
|
Matrix3Array(true,false,"mat3[]"),
|
||||||
Matrix4Array(true,false),
|
Matrix4Array(true,false,"mat4[]"),
|
||||||
|
|
||||||
TextureBuffer(false,true),
|
TextureBuffer(false,true,"sampler1D|sampler1DShadow"),
|
||||||
Texture2D(false,true),
|
Texture2D(false,true,"sampler2D|sampler2DShadow"),
|
||||||
Texture3D(false,true),
|
Texture3D(false,true,"sampler3D"),
|
||||||
TextureArray(false,true),
|
TextureArray(false,true,"sampler2DArray"),
|
||||||
TextureCubeMap(false,true),
|
TextureCubeMap(false,true,"samplerCube"),
|
||||||
Int;
|
Int("int");
|
||||||
|
|
||||||
private boolean usesMultiData = false;
|
private boolean usesMultiData = false;
|
||||||
private boolean textureType = false;
|
private boolean textureType = false;
|
||||||
|
private String glslType;
|
||||||
|
|
||||||
VarType(){
|
|
||||||
|
VarType(String glslType){
|
||||||
|
this.glslType = glslType;
|
||||||
}
|
}
|
||||||
|
|
||||||
VarType(boolean multiData, boolean textureType){
|
VarType(boolean multiData, boolean textureType,String glslType){
|
||||||
usesMultiData = multiData;
|
usesMultiData = multiData;
|
||||||
this.textureType = textureType;
|
this.textureType = textureType;
|
||||||
|
this.glslType = glslType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isTextureType() {
|
public boolean isTextureType() {
|
||||||
@ -77,4 +81,8 @@ public enum VarType {
|
|||||||
return usesMultiData;
|
return usesMultiData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getGlslType() {
|
||||||
|
return glslType;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
196
engine/src/core/com/jme3/shader/VariableMapping.java
Normal file
196
engine/src/core/com/jme3/shader/VariableMapping.java
Normal file
@ -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 + "}";
|
||||||
|
}
|
||||||
|
}
|
@ -36,22 +36,23 @@ import java.util.List;
|
|||||||
|
|
||||||
public class Statement {
|
public class Statement {
|
||||||
|
|
||||||
private int lineNumber;
|
protected int lineNumber;
|
||||||
private String line;
|
protected String line;
|
||||||
private List<Statement> contents = new ArrayList<Statement>();
|
protected List<Statement> contents = new ArrayList<Statement>();
|
||||||
|
|
||||||
Statement(int lineNumber, String line) {
|
protected Statement(int lineNumber, String line) {
|
||||||
this.lineNumber = lineNumber;
|
this.lineNumber = lineNumber;
|
||||||
this.line = line;
|
this.line = line;
|
||||||
}
|
}
|
||||||
|
|
||||||
void addStatement(Statement statement){
|
protected void addStatement(Statement statement) {
|
||||||
// if (contents == null){
|
|
||||||
// contents = new ArrayList<Statement>();
|
|
||||||
// }
|
|
||||||
contents.add(statement);
|
contents.add(statement);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void addStatement(int index, Statement statement) {
|
||||||
|
contents.add(index, statement);
|
||||||
|
}
|
||||||
|
|
||||||
public int getLineNumber() {
|
public int getLineNumber() {
|
||||||
return lineNumber;
|
return lineNumber;
|
||||||
}
|
}
|
||||||
@ -64,11 +65,11 @@ public class Statement {
|
|||||||
return contents;
|
return contents;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getIndent(int indent){
|
protected String getIndent(int indent) {
|
||||||
return " ".substring(0, indent);
|
return " ".substring(0, indent);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String toString(int indent){
|
protected String toString(int indent) {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.append(getIndent(indent));
|
sb.append(getIndent(indent));
|
||||||
sb.append(line);
|
sb.append(line);
|
||||||
@ -88,5 +89,4 @@ public class Statement {
|
|||||||
public String toString() {
|
public String toString() {
|
||||||
return toString(0);
|
return toString(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user