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:
parent
4777c591b1
commit
12a2f0f63c
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
Loading…
x
Reference in New Issue
Block a user