One can now define several versions for the shader in a Technique in a J3md file, ie:

VertexShader GLSL150 GLSL110 : "path/to/shader/file.vert"
FragmentShader GLSL150 GLSL110 : "path/to/shader/file.frag"

Versions must be separated with spaces. They will be matched together when creating the technique so they have to follow the same order for different shaders.
This commit is contained in:
Nehon 2017-01-15 18:57:53 +01:00
parent 4777c591b1
commit 12a2f0f63c
6 changed files with 188 additions and 52 deletions

View File

@ -48,7 +48,7 @@ import java.util.List;
*
* @author Nehon
*/
public class ShaderGenerationInfo implements Savable {
public class ShaderGenerationInfo implements Savable, Cloneable {
/**
* the list of attributes of the vertex shader
@ -187,4 +187,36 @@ public class ShaderGenerationInfo implements Savable {
vertexGlobal = (ShaderNodeVariable) ic.readSavable("vertexGlobal", null);
}
@Override
protected Object clone() throws CloneNotSupportedException {
ShaderGenerationInfo clone = (ShaderGenerationInfo) super.clone();
for (ShaderNodeVariable attribute : attributes) {
clone.attributes.add((ShaderNodeVariable) attribute.clone());
}
for (ShaderNodeVariable uniform : vertexUniforms) {
clone.vertexUniforms.add((ShaderNodeVariable) uniform.clone());
}
clone.vertexGlobal = (ShaderNodeVariable) vertexGlobal.clone();
for (ShaderNodeVariable varying : varyings) {
clone.varyings.add((ShaderNodeVariable) varying.clone());
}
for (ShaderNodeVariable uniform : fragmentUniforms) {
clone.fragmentUniforms.add((ShaderNodeVariable) uniform.clone());
}
for (ShaderNodeVariable globals : fragmentGlobals) {
clone.fragmentGlobals.add((ShaderNodeVariable) globals.clone());
}
clone.unusedNodes.addAll(unusedNodes);
return clone;
}
}

View File

@ -39,6 +39,7 @@ import com.jme3.shader.*;
import com.jme3.shader.Shader.ShaderType;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
/**
@ -46,7 +47,7 @@ import java.util.*;
*
* @author Kirill Vainer
*/
public class TechniqueDef implements Savable {
public class TechniqueDef implements Savable, Cloneable {
/**
* Version #1: Separate shader language for each shader source.
@ -539,7 +540,7 @@ public class TechniqueDef implements Savable {
public void setShaderFile(EnumMap<Shader.ShaderType, String> shaderNames, EnumMap<Shader.ShaderType, String> shaderLanguages) {
requiredCaps.clear();
int maxCap = 0;
weight = 0;
for (Shader.ShaderType shaderType : shaderNames.keySet()) {
String language = shaderLanguages.get(shaderType);
String shaderFile = shaderNames.get(shaderType);
@ -549,7 +550,7 @@ public class TechniqueDef implements Savable {
Caps cap = Caps.valueOf(language);
requiredCaps.add(cap);
maxCap = Math.max(maxCap, cap.ordinal());
weight = Math.max(weight, cap.ordinal());
if (shaderType.equals(Shader.ShaderType.Geometry)) {
requiredCaps.add(Caps.GeometryShader);
@ -557,7 +558,6 @@ public class TechniqueDef implements Savable {
requiredCaps.add(Caps.TesselationShader);
}
}
weight = maxCap;
}
/**
@ -776,4 +776,55 @@ public class TechniqueDef implements Savable {
public void setLightSpace(LightSpace lightSpace) {
this.lightSpace = lightSpace;
}
@Override
public Object clone() throws CloneNotSupportedException {
//cannot use super.clone because of the final fields instance that would be shared by the clones.
TechniqueDef clone = new TechniqueDef(name, sortId);
clone.noRender = noRender;
clone.lightMode = lightMode;
clone.shadowMode = shadowMode;
clone.lightSpace = lightSpace;
clone.usesNodes = usesNodes;
clone.shaderPrologue = shaderPrologue;
clone.setShaderFile(shaderNames, shaderLanguages);
clone.defineNames = new ArrayList<>(defineNames.size());
clone.defineNames.addAll(defineNames);
clone.defineTypes = new ArrayList<>(defineTypes.size());
clone.defineTypes.addAll(defineTypes);
clone.paramToDefineId = new HashMap<>(paramToDefineId.size());
clone.paramToDefineId.putAll(paramToDefineId);
if (shaderNodes != null) {
for (ShaderNode shaderNode : shaderNodes) {
clone.shaderNodes.add((ShaderNode) shaderNode.clone());
}
clone.shaderGenerationInfo = (ShaderGenerationInfo) shaderGenerationInfo.clone();
}
if (renderState != null) {
clone.setRenderState(renderState.clone());
}
if (forcedRenderState != null) {
clone.setForcedRenderState(forcedRenderState.clone());
}
try {
clone.logic = logic.getClass().getConstructor(TechniqueDef.class).newInstance(clone);
} catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
e.printStackTrace();
}
if (worldBinds != null) {
clone.worldBinds = new ArrayList<>(worldBinds.size());
clone.worldBinds.addAll(worldBinds);
}
return clone;
}
}

View File

@ -54,7 +54,7 @@ import java.util.List;
*
* @author Nehon
*/
public class ShaderNode implements Savable {
public class ShaderNode implements Savable, Cloneable {
private String name;
private ShaderNodeDefinition definition;
@ -212,4 +212,24 @@ public class ShaderNode implements Savable {
public String toString() {
return "\nShaderNode{" + "\nname=" + name + ", \ndefinition=" + definition.getName() + ", \ncondition=" + condition + ", \ninputMapping=" + inputMapping + ", \noutputMapping=" + outputMapping + '}';
}
@Override
public Object clone() throws CloneNotSupportedException {
ShaderNode clone = (ShaderNode) super.clone();
//No need to clone the definition.
clone.definition = definition;
clone.inputMapping = new ArrayList<>();
for (VariableMapping variableMapping : inputMapping) {
clone.inputMapping.add((VariableMapping) variableMapping.clone());
}
clone.outputMapping = new ArrayList<>();
for (VariableMapping variableMapping : outputMapping) {
clone.outputMapping.add((VariableMapping) variableMapping.clone());
}
return clone;
}
}

View File

@ -243,11 +243,6 @@ public class ShaderNodeVariable implements Savable, Cloneable {
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
@ -281,6 +276,9 @@ public class ShaderNodeVariable implements Savable, Cloneable {
public void setMultiplicity(String multiplicity) {
this.multiplicity = multiplicity;
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}

View File

@ -43,7 +43,7 @@ import java.io.IOException;
*
* @author Nehon
*/
public class VariableMapping implements Savable {
public class VariableMapping implements Savable, Cloneable {
private ShaderNodeVariable leftVariable;
private ShaderNodeVariable rightVariable;
@ -195,4 +195,14 @@ public class VariableMapping implements Savable {
public String toString() {
return "\n{" + leftVariable.toString() + (leftSwizzling.length() > 0 ? ("." + leftSwizzling) : "") + " = " + rightVariable.getType() + " " + rightVariable.getNameSpace() + "." + rightVariable.getName() + (rightSwizzling.length() > 0 ? ("." + rightSwizzling) : "") + " : " + condition + "}";
}
@Override
protected Object clone() throws CloneNotSupportedException {
VariableMapping clone = (VariableMapping) super.clone();
clone.leftVariable = (ShaderNodeVariable) leftVariable.clone();
clone.rightVariable = (ShaderNodeVariable) rightVariable.clone();
return clone;
}
}

View File

@ -43,21 +43,18 @@ import com.jme3.material.logic.StaticPassLightingLogic;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.shader.DefineList;
import com.jme3.shader.Shader;
import com.jme3.shader.VarType;
import com.jme3.shader.*;
import com.jme3.texture.Texture;
import com.jme3.texture.Texture2D;
import com.jme3.texture.image.ColorSpace;
import com.jme3.util.PlaceholderAssets;
import com.jme3.util.blockparser.BlockLanguageParser;
import com.jme3.util.blockparser.Statement;
import com.jme3.util.clone.Cloner;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.List;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
@ -69,6 +66,7 @@ public class J3MLoader implements AssetLoader {
// private ErrorLogger errors;
private ShaderNodeLoaderDelegate nodesLoaderDelegate;
boolean isUseNodes = false;
int langSize = 0;
private AssetManager assetManager;
private AssetKey key;
@ -79,13 +77,13 @@ public class J3MLoader implements AssetLoader {
private RenderState renderState;
private ArrayList<String> presetDefines = new ArrayList<String>();
private EnumMap<Shader.ShaderType, String> shaderLanguages;
private List<EnumMap<Shader.ShaderType, String>> shaderLanguages;
private EnumMap<Shader.ShaderType, String> shaderNames;
private static final String whitespacePattern = "\\p{javaWhitespace}+";
public J3MLoader() {
shaderLanguages = new EnumMap<>(Shader.ShaderType.class);
shaderLanguages = new ArrayList<>();// EnumMap<>(Shader.ShaderType.class);
shaderNames = new EnumMap<>(Shader.ShaderType.class);
}
@ -97,20 +95,29 @@ public class J3MLoader implements AssetLoader {
throw new IOException("Shader statement syntax incorrect" + statement);
}
String[] typeAndLang = split[0].split(whitespacePattern);
if (typeAndLang.length != 2) {
throw new IOException("Shader statement syntax incorrect: " + statement);
}
for (Shader.ShaderType shaderType : Shader.ShaderType.values()) {
if (typeAndLang[0].equals(shaderType.toString() + "Shader")) {
readShaderDefinition(shaderType, split[1].trim(), typeAndLang[1]);
readShaderDefinition(shaderType, split[1].trim(), Arrays.copyOfRange(typeAndLang, 1, typeAndLang.length));
}
}
}
private void readShaderDefinition(Shader.ShaderType shaderType, String name, String language) {
private void readShaderDefinition(Shader.ShaderType shaderType, String name, String... languages) {
shaderNames.put(shaderType, name);
shaderLanguages.put(shaderType, language);
if (langSize != 0 && langSize != languages.length) {
throw new AssetLoadException("Technique " + technique.getName() + " must have the same number of languages for each shader type.");
}
langSize = languages.length;
for (int i = 0; i < languages.length; i++) {
if (i >= shaderLanguages.size()) {
shaderLanguages.add(new EnumMap<Shader.ShaderType, String>(Shader.ShaderType.class));
}
shaderLanguages.get(i).put(shaderType, languages[i]);
}
}
// LightMode <MODE>
@ -608,6 +615,7 @@ public class J3MLoader implements AssetLoader {
private void readTechnique(Statement techStat) throws IOException{
isUseNodes = false;
String[] split = techStat.getLine().split(whitespacePattern);
Cloner cloner = new Cloner();
String name;
if (split.length == 1) {
@ -625,30 +633,8 @@ public class J3MLoader implements AssetLoader {
readTechniqueStatement(statement);
}
if(isUseNodes){
nodesLoaderDelegate.computeConditions();
//used for caching later, the shader here is not a file.
// KIRILL 9/19/2015
// Not sure if this is needed anymore, since shader caching
// is now done by TechniqueDef.
technique.setShaderFile(technique.hashCode() + "", technique.hashCode() + "", "GLSL100", "GLSL100");
}else if (shaderNames.containsKey(Shader.ShaderType.Vertex) && shaderNames.containsKey(Shader.ShaderType.Fragment)) {
technique.setShaderFile(shaderNames, shaderLanguages);
} else {
technique = null;
shaderLanguages.clear();
shaderNames.clear();
presetDefines.clear();
logger.log(Level.WARNING, "Fixed function technique was ignored");
logger.log(Level.WARNING, "Fixed function technique ''{0}'' was ignored for material {1}",
new Object[]{name, key});
return;
}
technique.setShaderPrologue(createShaderPrologue(presetDefines));
switch (technique.getLightMode()) {
case Disable:
technique.setLogic(new DefaultTechniqueDefLogic(technique));
@ -669,8 +655,47 @@ public class J3MLoader implements AssetLoader {
throw new UnsupportedOperationException();
}
materialDef.addTechniqueDef(technique);
List<TechniqueDef> techniqueDefs = new ArrayList<>();
if(isUseNodes){
nodesLoaderDelegate.computeConditions();
//used for caching later, the shader here is not a file.
// KIRILL 9/19/2015
// Not sure if this is needed anymore, since shader caching
// is now done by TechniqueDef.
technique.setShaderFile(technique.hashCode() + "", technique.hashCode() + "", "GLSL100", "GLSL100");
techniqueDefs.add(technique);
}else if (shaderNames.containsKey(Shader.ShaderType.Vertex) && shaderNames.containsKey(Shader.ShaderType.Fragment)) {
if (shaderLanguages.size() > 1) {
for (int i = 1; i < shaderLanguages.size(); i++) {
TechniqueDef td = cloner.clone(technique);
td.setShaderFile(shaderNames, shaderLanguages.get(i));
techniqueDefs.add(td);
}
}
technique.setShaderFile(shaderNames, shaderLanguages.get(0));
techniqueDefs.add(technique);
} else {
technique = null;
shaderLanguages.clear();
shaderNames.clear();
presetDefines.clear();
langSize = 0;
logger.log(Level.WARNING, "Fixed function technique was ignored");
logger.log(Level.WARNING, "Fixed function technique ''{0}'' was ignored for material {1}",
new Object[]{name, key});
return;
}
for (TechniqueDef techniqueDef : techniqueDefs) {
materialDef.addTechniqueDef(techniqueDef);
}
technique = null;
langSize = 0;
shaderLanguages.clear();
shaderNames.clear();
presetDefines.clear();