Changes the way a shader is generated to prepare to the new node declaration
This commit is contained in:
parent
d57c362ec3
commit
7055de4531
@ -36,8 +36,9 @@ import com.jme3.material.ShaderGenerationInfo;
|
|||||||
import com.jme3.material.plugins.ConditionParser;
|
import com.jme3.material.plugins.ConditionParser;
|
||||||
import com.jme3.shader.Shader.ShaderType;
|
import com.jme3.shader.Shader.ShaderType;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This shader Generator can generate Vertex and Fragment shaders from
|
* This shader Generator can generate Vertex and Fragment shaders from
|
||||||
@ -51,6 +52,7 @@ public class Glsl100ShaderGenerator extends ShaderGenerator {
|
|||||||
* the indentation characters 1à tabulation characters
|
* the indentation characters 1à tabulation characters
|
||||||
*/
|
*/
|
||||||
private final static String INDENTCHAR = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
|
private final static String INDENTCHAR = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
|
||||||
|
private final static Logger log = Logger.getLogger(Glsl100ShaderGenerator.class.getName());
|
||||||
|
|
||||||
protected ShaderNodeVariable inPosTmp;
|
protected ShaderNodeVariable inPosTmp;
|
||||||
|
|
||||||
@ -116,21 +118,16 @@ public class Glsl100ShaderGenerator extends ShaderGenerator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
protected void generateDeclarationSection(StringBuilder source) {
|
||||||
*
|
for (String defName : declaredNodes.keySet()) {
|
||||||
* if the declaration contains no code nothing is done, else it's appended
|
NodeDeclaration nd = declaredNodes.get(defName);
|
||||||
*/
|
|
||||||
@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");
|
source.append("\n");
|
||||||
unIndent();
|
unIndent();
|
||||||
startCondition(shaderNode.getCondition(), source);
|
startCondition(nd.condition, source);
|
||||||
source.append(nodeSource);
|
source.append(nd.source);
|
||||||
source.append("\n");
|
source.append("\n");
|
||||||
endCondition(shaderNode.getCondition(), source);
|
endCondition(nd.condition, source);
|
||||||
indent();
|
indent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -235,80 +232,111 @@ public class Glsl100ShaderGenerator extends ShaderGenerator {
|
|||||||
@Override
|
@Override
|
||||||
protected void generateNodeMainSection(StringBuilder source, ShaderNode shaderNode, String nodeSource, ShaderGenerationInfo info) {
|
protected void generateNodeMainSection(StringBuilder source, ShaderNode shaderNode, String nodeSource, ShaderGenerationInfo info) {
|
||||||
|
|
||||||
nodeSource = updateDefinesName(nodeSource, shaderNode);
|
|
||||||
source.append("\n");
|
source.append("\n");
|
||||||
comment(source, shaderNode, "Begin");
|
comment(source, shaderNode, "");
|
||||||
startCondition(shaderNode.getCondition(), source);
|
startCondition(shaderNode.getCondition(), source);
|
||||||
|
|
||||||
final List<String> declaredInputs = new ArrayList<>();
|
|
||||||
|
|
||||||
// Decalring variables with default values first
|
|
||||||
final ShaderNodeDefinition definition = shaderNode.getDefinition();
|
final ShaderNodeDefinition definition = shaderNode.getDefinition();
|
||||||
|
|
||||||
for (final ShaderNodeVariable var : definition.getInputs()) {
|
StringBuilder b = new StringBuilder();
|
||||||
|
appendIndent(b);
|
||||||
|
b.append(definition.getName()).append("(");
|
||||||
|
boolean isFirst = true;
|
||||||
|
for (ShaderNodeVariable v : definition.getParams()) {
|
||||||
|
if (!isFirst) {
|
||||||
|
b.append(", ");
|
||||||
|
}
|
||||||
|
if (definition.getInputs().contains(v)) {
|
||||||
|
|
||||||
if (var.getType().startsWith("sampler")) {
|
List<VariableMapping> maps = shaderNode.getInputMapping(v.getName());
|
||||||
continue;
|
|
||||||
|
boolean declared = false;
|
||||||
|
for (VariableMapping m : maps) {
|
||||||
|
// map varyings to their inputs, as the code may not do the mapping.
|
||||||
|
if (isVarying(info, m.getLeftVariable())) {
|
||||||
|
map(m, source, false);
|
||||||
|
declared = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final String fullName = shaderNode.getName() + "_" + var.getName();
|
if (maps.isEmpty()) {
|
||||||
|
//no mapping found
|
||||||
final ShaderNodeVariable variable = new ShaderNodeVariable(var.getType(), shaderNode.getName(),
|
if (v.getDefaultValue() != null) {
|
||||||
var.getName(), var.getMultiplicity());
|
// if there is a default value append it to the function call
|
||||||
|
b.append(v.getDefaultValue());
|
||||||
if (!isVarying(info, variable)) {
|
|
||||||
declareVariable(source, variable, var.getDefaultValue(), true, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
nodeSource = replaceVariableName(nodeSource, variable);
|
|
||||||
declaredInputs.add(fullName);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (VariableMapping mapping : shaderNode.getInputMapping()) {
|
|
||||||
|
|
||||||
final ShaderNodeVariable rightVariable = mapping.getRightVariable();
|
|
||||||
final ShaderNodeVariable leftVariable = mapping.getLeftVariable();
|
|
||||||
|
|
||||||
String newName = shaderNode.getName() + "_" + leftVariable.getName();
|
|
||||||
boolean isDeclared = declaredInputs.contains(newName);
|
|
||||||
//Variables fed with a sampler matparam or world param are replaced by the matparam itself
|
|
||||||
//It avoids issue with samplers that have to be uniforms.
|
|
||||||
if (rightVariable != null && isWorldOrMaterialParam(rightVariable) && rightVariable.getType().startsWith("sampler")) {
|
|
||||||
nodeSource = replace(nodeSource, leftVariable, rightVariable.getPrefix() + rightVariable.getName());
|
|
||||||
} else {
|
} else {
|
||||||
|
// no default value, construct a variable with the proper type and dummy value and raise a warning
|
||||||
if (leftVariable.getType().startsWith("sampler")) {
|
b.append(getConstructor(v.getType()));
|
||||||
throw new IllegalArgumentException("a Sampler must be a uniform");
|
log.log(Level.WARNING, "No input defined for variable " + v.getName() + " on shader node " + shaderNode.getName());
|
||||||
}
|
}
|
||||||
map(mapping, source, !isDeclared);
|
} else if (maps.size() == 1 && !declared) {
|
||||||
|
// one mapping for this variable, directly append the
|
||||||
|
// other variable from the mapping to the function call
|
||||||
|
VariableMapping m = maps.get(0);
|
||||||
|
ShaderNodeVariable v2 = m.getRightVariable();
|
||||||
|
b.append(getAppendableNameSpace(v2))
|
||||||
|
.append(v2.getPrefix())
|
||||||
|
.append(v2.getName());
|
||||||
|
if (m.getRightSwizzling().length() > 0) {
|
||||||
|
b.append(".");
|
||||||
|
b.append(m.getRightSwizzling());
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
if (!isDeclared) {
|
// 2 possible cases here
|
||||||
nodeSource = replace(nodeSource, leftVariable, newName);
|
// the variable is a varrying: we can append it directly
|
||||||
declaredInputs.add(newName);
|
// or
|
||||||
}
|
// several mappings with different conditions: we have to declare the variable and
|
||||||
}
|
// map it properly before appending the variable in the function call
|
||||||
|
for (VariableMapping mapping : maps) {
|
||||||
|
|
||||||
|
|
||||||
for (ShaderNodeVariable var : definition.getOutputs()) {
|
|
||||||
ShaderNodeVariable v = new ShaderNodeVariable(var.getType(), shaderNode.getName(), var.getName(), var.getMultiplicity());
|
|
||||||
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, true);
|
map(mapping, source, true);
|
||||||
}
|
}
|
||||||
endCondition(shaderNode.getCondition(), source);
|
b.append(shaderNode.getName())
|
||||||
comment(source, shaderNode, "End");
|
.append("_")
|
||||||
|
.append(v.getName());
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// outputs
|
||||||
|
String name = shaderNode.getName() + "_" + v.getName();
|
||||||
|
// if the output is not a varying (already declared) we declare it)
|
||||||
|
if (!isVarying(info, name)) {
|
||||||
|
appendIndent(source);
|
||||||
|
source.append(v.getType()).append(" ").append(name).append(";\n");
|
||||||
|
}
|
||||||
|
// append the variable to the function call
|
||||||
|
b.append(shaderNode.getName())
|
||||||
|
.append("_")
|
||||||
|
.append(v.getName());
|
||||||
|
}
|
||||||
|
isFirst = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
b.append(");\n");
|
||||||
|
|
||||||
|
// Map any output to global output.
|
||||||
|
for (VariableMapping mapping : shaderNode.getOutputMapping()) {
|
||||||
|
map(mapping, b, false);
|
||||||
|
}
|
||||||
|
source.append(b);
|
||||||
|
|
||||||
|
endCondition(shaderNode.getCondition(), source);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a proper constructor call for a given type
|
||||||
|
* @param type
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private String getConstructor(String type) {
|
||||||
|
if (type.startsWith("i") || type.startsWith("u")) {
|
||||||
|
return type + "(0)";
|
||||||
|
}
|
||||||
|
if (type.equals("boolean") || type.startsWith("u")) {
|
||||||
|
return "false";
|
||||||
|
}
|
||||||
|
return type + "(0.0)";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* declares a variable, embed in a conditional block if needed
|
* declares a variable, embed in a conditional block if needed
|
||||||
@ -510,6 +538,17 @@ public class Glsl100ShaderGenerator extends ShaderGenerator {
|
|||||||
return isVarying;
|
return isVarying;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected boolean isVarying(ShaderGenerationInfo info, String variableName) {
|
||||||
|
for (ShaderNodeVariable shaderNodeVariable : info.getVaryings()) {
|
||||||
|
String name = shaderNodeVariable.getNameSpace() + "_" + shaderNodeVariable.getName();
|
||||||
|
if (name.equals(variableName)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Appends a comment to the generated code
|
* Appends a comment to the generated code
|
||||||
* @param source the StringBuilder to use
|
* @param source the StringBuilder to use
|
||||||
@ -554,10 +593,10 @@ public class Glsl100ShaderGenerator extends ShaderGenerator {
|
|||||||
String[] lines = nodeSource.split("\\n");
|
String[] lines = nodeSource.split("\\n");
|
||||||
ConditionParser parser = new ConditionParser();
|
ConditionParser parser = new ConditionParser();
|
||||||
for (String line : lines) {
|
for (String line : lines) {
|
||||||
|
line = line.trim();
|
||||||
if (line.trim().startsWith("#if")) {
|
if (line.startsWith("#if")) {
|
||||||
List<String> params = parser.extractDefines(line.trim());
|
List<String> params = parser.extractDefines(line);
|
||||||
String l = line.trim().replaceAll("defined", "").replaceAll("#if ", "").replaceAll("#ifdef", "");//parser.getFormattedExpression();
|
String l = line.replaceAll("defined", "").replaceAll("#if ", "").replaceAll("#ifdef", "");
|
||||||
boolean match = false;
|
boolean match = false;
|
||||||
for (String param : params) {
|
for (String param : params) {
|
||||||
for (VariableMapping map : shaderNode.getInputMapping()) {
|
for (VariableMapping map : shaderNode.getInputMapping()) {
|
||||||
|
@ -34,6 +34,7 @@ package com.jme3.shader;
|
|||||||
import com.jme3.asset.AssetManager;
|
import com.jme3.asset.AssetManager;
|
||||||
import com.jme3.material.ShaderGenerationInfo;
|
import com.jme3.material.ShaderGenerationInfo;
|
||||||
import com.jme3.material.TechniqueDef;
|
import com.jme3.material.TechniqueDef;
|
||||||
|
import com.jme3.material.plugins.ConditionParser;
|
||||||
import com.jme3.shader.Shader.ShaderType;
|
import com.jme3.shader.Shader.ShaderType;
|
||||||
import com.jme3.shader.plugins.ShaderAssetKey;
|
import com.jme3.shader.plugins.ShaderAssetKey;
|
||||||
|
|
||||||
@ -72,7 +73,15 @@ public abstract class ShaderGenerator {
|
|||||||
*/
|
*/
|
||||||
Pattern extensions = Pattern.compile("(#extension.*\\s+)");
|
Pattern extensions = Pattern.compile("(#extension.*\\s+)");
|
||||||
|
|
||||||
private Map<String, String> imports = new LinkedHashMap<>();
|
/**
|
||||||
|
* a set of imports to append to the shader source
|
||||||
|
*/
|
||||||
|
private Set<String> imports = new HashSet<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The nodes function and their condition to be declared in the shader
|
||||||
|
*/
|
||||||
|
protected Map<String, NodeDeclaration> declaredNodes = new LinkedHashMap<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build a shaderGenerator
|
* Build a shaderGenerator
|
||||||
@ -155,12 +164,6 @@ public abstract class ShaderGenerator {
|
|||||||
|
|
||||||
generateEndOfMainSection(source, info, type);
|
generateEndOfMainSection(source, info, type);
|
||||||
|
|
||||||
//insert imports backward
|
|
||||||
int insertIndex = sourceDeclaration.length();
|
|
||||||
for (String importSource : imports.values()) {
|
|
||||||
sourceDeclaration.insert(insertIndex, importSource);
|
|
||||||
}
|
|
||||||
|
|
||||||
sourceDeclaration.append(source);
|
sourceDeclaration.append(source);
|
||||||
|
|
||||||
return moveExtensionsUp(sourceDeclaration);
|
return moveExtensionsUp(sourceDeclaration);
|
||||||
@ -195,56 +198,92 @@ public abstract class ShaderGenerator {
|
|||||||
* @param type the Shader type
|
* @param type the Shader type
|
||||||
*/
|
*/
|
||||||
protected void generateDeclarationAndMainBody(List<ShaderNode> shaderNodes, StringBuilder sourceDeclaration, StringBuilder source, ShaderGenerationInfo info, Shader.ShaderType type) {
|
protected void generateDeclarationAndMainBody(List<ShaderNode> shaderNodes, StringBuilder sourceDeclaration, StringBuilder source, ShaderGenerationInfo info, Shader.ShaderType type) {
|
||||||
|
declaredNodes.clear();
|
||||||
for (ShaderNode shaderNode : shaderNodes) {
|
for (ShaderNode shaderNode : shaderNodes) {
|
||||||
if (info.getUnusedNodes().contains(shaderNode.getName())) {
|
if (info.getUnusedNodes().contains(shaderNode.getName())) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shaderNode.getDefinition().getType() == type) {
|
if (shaderNode.getDefinition().getType() == type) {
|
||||||
int index = findShaderIndexFromVersion(shaderNode, type);
|
int index = findShaderIndexFromVersion(shaderNode, type);
|
||||||
String shaderPath = shaderNode.getDefinition().getShadersPath().get(index);
|
String shaderPath = shaderNode.getDefinition().getShadersPath().get(index);
|
||||||
Map<String, String> sources = (Map<String, String>) assetManager.loadAsset(new ShaderAssetKey(shaderPath, false));
|
Map<String, String> sources = (Map<String, String>) assetManager.loadAsset(new ShaderAssetKey(shaderPath, false));
|
||||||
String loadedSource = sources.get("[main]");
|
String loadedSource = sources.get("[main]");
|
||||||
for (String name : sources.keySet()) {
|
for (String name : sources.keySet()) {
|
||||||
if (!name.equals("[main]")) {
|
if (!name.equals("[main]") && !imports.contains(name)) {
|
||||||
imports.put(name, sources.get(name));
|
imports.add(name);
|
||||||
|
// append the imported file in place if it hasn't been imported already.
|
||||||
|
sourceDeclaration.append(sources.get(name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
appendNodeDeclarationAndMain(loadedSource, sourceDeclaration, source, shaderNode, info, shaderPath);
|
// Nodes are functions added to the declaration part of the shader
|
||||||
|
// Multiple nodes may use the same definition and we don't want to declare it several times.
|
||||||
|
// Also nodes can have #ifdef conditions so we need to properly merge this conditions to declare the Node function.
|
||||||
|
NodeDeclaration nd = declaredNodes.get(shaderNode.getDefinition().getName());
|
||||||
|
loadedSource = functionize(loadedSource, shaderNode.getDefinition());
|
||||||
|
if(nd == null){
|
||||||
|
nd = new NodeDeclaration(shaderNode.getCondition(), loadedSource);
|
||||||
|
declaredNodes.put(shaderNode.getDefinition().getName(), nd);
|
||||||
|
} else {
|
||||||
|
nd.condition = ConditionParser.mergeConditions(nd.condition, shaderNode.getCondition(), "||");
|
||||||
|
}
|
||||||
|
|
||||||
|
generateNodeMainSection(source, shaderNode, loadedSource, info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
generateDeclarationSection(sourceDeclaration);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Appends declaration and main part of a node to the shader declaration and
|
* Tuns old style shader node code into a proper function so that it can be appended to the declarative sectio.
|
||||||
* main part. the loadedSource is split by "void main(){" to split
|
* Note that this only needed for nodes coming from a j3sn file.
|
||||||
* declaration from main part of the node source code.The trailing "}" is
|
* @param source
|
||||||
* removed from the main part. Each part is then respectively passed to
|
* @param def
|
||||||
* generateDeclarativeSection and generateNodeMainSection.
|
* @return
|
||||||
*
|
|
||||||
* @see ShaderGenerator#generateDeclarativeSection
|
|
||||||
* @see ShaderGenerator#generateNodeMainSection
|
|
||||||
*
|
|
||||||
* @param loadedSource the actual source code loaded for this node.
|
|
||||||
* @param shaderPath path to the shader file
|
|
||||||
* @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, String shaderPath) {
|
public static String functionize(String source, ShaderNodeDefinition def){
|
||||||
if (loadedSource.length() > 1) {
|
StringBuffer signature = new StringBuffer();
|
||||||
loadedSource = loadedSource.substring(0, loadedSource.lastIndexOf("}"));
|
def.setReturnType("void");
|
||||||
String[] sourceParts = loadedSource.split("\\s*void\\s*main\\s*\\(\\s*\\)\\s*\\{");
|
signature.append("void ").append(def.getName()).append("(");
|
||||||
if(sourceParts.length<2){
|
boolean addParam = false;
|
||||||
throw new IllegalArgumentException("Syntax error in "+ shaderPath +". Cannot find 'void main(){' in \n"+ loadedSource);
|
if(def.getParams().isEmpty()){
|
||||||
}
|
addParam = true;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean isFirst = true;
|
||||||
|
for (ShaderNodeVariable v : def.getInputs()) {
|
||||||
|
if(!isFirst){
|
||||||
|
signature.append(", ");
|
||||||
|
}
|
||||||
|
String qualifier;
|
||||||
|
qualifier = "const in";
|
||||||
|
signature.append(qualifier).append(" ").append(v.getType()).append(" ").append(v.getName());
|
||||||
|
isFirst = false;
|
||||||
|
if(addParam) {
|
||||||
|
def.getParams().add(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ShaderNodeVariable v : def.getOutputs()) {
|
||||||
|
if(def.getInputs().contains(v)){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(!isFirst){
|
||||||
|
signature.append(", ");
|
||||||
|
}
|
||||||
|
signature.append("out ").append(v.getType()).append(" ").append(v.getName());
|
||||||
|
isFirst = false;
|
||||||
|
if(addParam) {
|
||||||
|
def.getParams().add(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
signature.append("){");
|
||||||
|
|
||||||
|
source = source.replaceAll("\\s*void\\s*main\\s*\\(\\s*\\)\\s*\\{", signature.toString());
|
||||||
|
|
||||||
|
return source;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -287,19 +326,12 @@ public abstract class ShaderGenerator {
|
|||||||
protected abstract void generateVaryings(StringBuilder source, ShaderGenerationInfo info, ShaderType type);
|
protected abstract void generateVaryings(StringBuilder source, ShaderGenerationInfo info, ShaderType type);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Appends the given shaderNode declarative part to the shader declarative
|
* Appends the shaderNodes function to the shader declarative
|
||||||
* part. If needed the shader type can be determined by fetching the
|
* part.
|
||||||
* shaderNode's definition type.
|
|
||||||
*
|
*
|
||||||
* @see ShaderNode#getDefinition()
|
|
||||||
* @see ShaderNodeDefinition#getType()
|
|
||||||
*
|
|
||||||
* @param nodeDecalarationSource the declaration part of the node
|
|
||||||
* @param source the StringBuilder to append generated code.
|
* @param source the StringBuilder to append generated code.
|
||||||
* @param shaderNode the shaderNode.
|
|
||||||
* @param info the ShaderGenerationInfo.
|
|
||||||
*/
|
*/
|
||||||
protected abstract void generateDeclarativeSection(StringBuilder source, ShaderNode shaderNode, String nodeDecalarationSource, ShaderGenerationInfo info);
|
protected abstract void generateDeclarationSection(StringBuilder source);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* generates the start of the shader main section. this method is
|
* generates the start of the shader main section. this method is
|
||||||
@ -363,4 +395,15 @@ public abstract class ShaderGenerator {
|
|||||||
}
|
}
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected class NodeDeclaration{
|
||||||
|
String condition;
|
||||||
|
String source;
|
||||||
|
|
||||||
|
public NodeDeclaration(String condition, String source) {
|
||||||
|
this.condition = condition;
|
||||||
|
this.source = source;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -143,6 +143,21 @@ public class ShaderNode implements Savable, Cloneable {
|
|||||||
return inputMapping;
|
return inputMapping;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of variable mapping for the given node input.
|
||||||
|
*
|
||||||
|
* @return the input mappings.
|
||||||
|
*/
|
||||||
|
public List<VariableMapping> getInputMapping(String varName) {
|
||||||
|
List<VariableMapping> list = new ArrayList<>();
|
||||||
|
for (VariableMapping v : inputMapping) {
|
||||||
|
if (v.getLeftVariable().getName().equals(varName)){
|
||||||
|
list.add(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the input mappings.
|
* Sets the input mappings.
|
||||||
*
|
*
|
||||||
|
@ -57,8 +57,10 @@ public class ShaderNodeDefinition implements Savable {
|
|||||||
private String documentation;
|
private String documentation;
|
||||||
private List<ShaderNodeVariable> inputs = new ArrayList<ShaderNodeVariable>();
|
private List<ShaderNodeVariable> inputs = new ArrayList<ShaderNodeVariable>();
|
||||||
private List<ShaderNodeVariable> outputs = new ArrayList<ShaderNodeVariable>();
|
private List<ShaderNodeVariable> outputs = new ArrayList<ShaderNodeVariable>();
|
||||||
|
private List<ShaderNodeVariable> params = new ArrayList<>();
|
||||||
private String path = null;
|
private String path = null;
|
||||||
private boolean noOutput = false;
|
private boolean noOutput = false;
|
||||||
|
private String returnType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* creates a ShaderNodeDefinition
|
* creates a ShaderNodeDefinition
|
||||||
@ -184,7 +186,21 @@ public class ShaderNodeDefinition implements Savable {
|
|||||||
this.path = path;
|
this.path = path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getReturnType() {
|
||||||
|
return returnType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setReturnType(String returnType) {
|
||||||
|
this.returnType = returnType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ShaderNodeVariable> getParams() {
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setParams(List<ShaderNodeVariable> params) {
|
||||||
|
this.params = params;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* jme serialization (not used)
|
* jme serialization (not used)
|
||||||
@ -194,14 +210,15 @@ public class ShaderNodeDefinition implements Savable {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void write(JmeExporter ex) throws IOException {
|
public void write(JmeExporter ex) throws IOException {
|
||||||
OutputCapsule oc = (OutputCapsule) ex.getCapsule(this);
|
OutputCapsule oc = ex.getCapsule(this);
|
||||||
oc.write(name, "name", "");
|
oc.write(name, "name", "");
|
||||||
String[] str = new String[shadersLanguage.size()];
|
String[] str = new String[shadersLanguage.size()];
|
||||||
oc.write(shadersLanguage.toArray(str), "shadersLanguage", null);
|
oc.write(shadersLanguage.toArray(str), "shadersLanguage", null);
|
||||||
oc.write(shadersPath.toArray(str), "shadersPath", null);
|
oc.write(shadersPath.toArray(str), "shadersPath", null);
|
||||||
oc.write(type, "type", null);
|
oc.write(type, "type", null);
|
||||||
oc.writeSavableArrayList((ArrayList) inputs, "inputs", new ArrayList<ShaderNodeVariable>());
|
oc.writeSavableArrayList((ArrayList) inputs, "inputs", new ArrayList<ShaderNodeVariable>());
|
||||||
oc.writeSavableArrayList((ArrayList) outputs, "inputs", new ArrayList<ShaderNodeVariable>());
|
oc.writeSavableArrayList((ArrayList) outputs, "outputs", new ArrayList<ShaderNodeVariable>());
|
||||||
|
oc.writeSavableArrayList((ArrayList) params, "params", new ArrayList<ShaderNodeVariable>());
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<String> getShadersLanguage() {
|
public List<String> getShadersLanguage() {
|
||||||
@ -250,6 +267,8 @@ public class ShaderNodeDefinition implements Savable {
|
|||||||
type = ic.readEnum("type", Shader.ShaderType.class, null);
|
type = ic.readEnum("type", Shader.ShaderType.class, null);
|
||||||
inputs = (List<ShaderNodeVariable>) ic.readSavableArrayList("inputs", new ArrayList<ShaderNodeVariable>());
|
inputs = (List<ShaderNodeVariable>) ic.readSavableArrayList("inputs", new ArrayList<ShaderNodeVariable>());
|
||||||
outputs = (List<ShaderNodeVariable>) ic.readSavableArrayList("outputs", new ArrayList<ShaderNodeVariable>());
|
outputs = (List<ShaderNodeVariable>) ic.readSavableArrayList("outputs", new ArrayList<ShaderNodeVariable>());
|
||||||
|
params = (List<ShaderNodeVariable>) ic.readSavableArrayList("params", new ArrayList<ShaderNodeVariable>());
|
||||||
|
im.getAssetManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
|
#import "Common/ShaderLib/Skinning.glsllib"
|
||||||
|
|
||||||
void main(){
|
void main(){
|
||||||
modModelPosition = (mat4(0.0) +
|
#ifdef NUM_BONES
|
||||||
boneMatrices[int(boneIndex.x)] * boneWeight.x +
|
modModelPosition = modelPosition;
|
||||||
boneMatrices[int(boneIndex.y)] * boneWeight.y +
|
Skinning_Compute(modModelPosition);
|
||||||
boneMatrices[int(boneIndex.z)] * boneWeight.z +
|
#endif
|
||||||
boneMatrices[int(boneIndex.w)] * boneWeight.w) * vec4(modelPosition.xyz,1.0);
|
|
||||||
}
|
}
|
@ -1,12 +1,10 @@
|
|||||||
|
#import "Common/ShaderLib/Skinning.glsllib"
|
||||||
|
|
||||||
void main(){
|
void main(){
|
||||||
modModelPosition = (mat4(0.0) +
|
#ifdef NUM_BONES
|
||||||
boneMatrices[int(boneIndex.x)] * boneWeight.x +
|
modModelPosition = modelPosition;
|
||||||
boneMatrices[int(boneIndex.y)] * boneWeight.y +
|
modModelNormal = modelNormal;
|
||||||
boneMatrices[int(boneIndex.z)] * boneWeight.z +
|
modModelTangents = modelTangents;
|
||||||
boneMatrices[int(boneIndex.w)] * boneWeight.w) * modelPosition;
|
Skinning_Compute(modModelPosition, modModelNormal, modModelTangents);
|
||||||
|
#endif
|
||||||
mat3 rotMat = mat3(mat[0].xyz, mat[1].xyz, mat[2].xyz);
|
|
||||||
modModelTangent = rotMat * modelTangent;
|
|
||||||
modModelNormal = rotMat * modelNormal;
|
|
||||||
}
|
}
|
@ -104,6 +104,28 @@ public class ConditionParser {
|
|||||||
return defines;
|
return defines;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 static String mergeConditions(String condition1, String condition2, String operator) {
|
||||||
|
if (condition1 != null) {
|
||||||
|
if (condition2 == null) {
|
||||||
|
return condition1;
|
||||||
|
} else {
|
||||||
|
String mergedCondition = "(" + condition1 + ") " + operator + " (" + condition2 + ")";
|
||||||
|
return mergedCondition;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return condition2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @return the formatted expression previously updated by extractDefines
|
* @return the formatted expression previously updated by extractDefines
|
||||||
|
@ -580,7 +580,7 @@ public class ShaderNodeLoaderDelegate {
|
|||||||
multiplicity = multiplicity.toUpperCase();
|
multiplicity = multiplicity.toUpperCase();
|
||||||
left.setMultiplicity(multiplicity);
|
left.setMultiplicity(multiplicity);
|
||||||
// only declare the variable if the define is defined.
|
// only declare the variable if the define is defined.
|
||||||
left.setCondition(mergeConditions(left.getCondition(), "defined(" + multiplicity + ")", "||"));
|
left.setCondition(ConditionParser.mergeConditions(left.getCondition(), "defined(" + multiplicity + ")", "||"));
|
||||||
} else {
|
} else {
|
||||||
throw new MatParseException("Wrong multiplicity for variable" + left.getName() + ". " +
|
throw new MatParseException("Wrong multiplicity for variable" + left.getName() + ". " +
|
||||||
multiplicity + " should be an int or a declared material parameter.", statement);
|
multiplicity + " should be an int or a declared material parameter.", statement);
|
||||||
@ -1057,26 +1057,6 @@ public class ShaderNodeLoaderDelegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 (condition1 != null) {
|
|
||||||
if (condition2 == null) {
|
|
||||||
return condition1;
|
|
||||||
} else {
|
|
||||||
String mergedCondition = "(" + condition1 + ") " + operator + " (" + condition2 + ")";
|
|
||||||
return mergedCondition;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return condition2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Searches a variable in a list from its name and merges the conditions of the
|
* Searches a variable in a list from its name and merges the conditions of the
|
||||||
|
@ -4,7 +4,7 @@ import com.jme3.app.SimpleApplication;
|
|||||||
import com.jme3.material.Material;
|
import com.jme3.material.Material;
|
||||||
import com.jme3.material.Technique;
|
import com.jme3.material.Technique;
|
||||||
import com.jme3.material.TechniqueDef;
|
import com.jme3.material.TechniqueDef;
|
||||||
import com.jme3.math.ColorRGBA;
|
import com.jme3.math.*;
|
||||||
import com.jme3.scene.Geometry;
|
import com.jme3.scene.Geometry;
|
||||||
import com.jme3.scene.shape.Box;
|
import com.jme3.scene.shape.Box;
|
||||||
import com.jme3.shader.Shader;
|
import com.jme3.shader.Shader;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user