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.
native-compilation-test
Nehon 8 years ago
parent 4777c591b1
commit 12a2f0f63c
  1. 34
      jme3-core/src/main/java/com/jme3/material/ShaderGenerationInfo.java
  2. 59
      jme3-core/src/main/java/com/jme3/material/TechniqueDef.java
  3. 22
      jme3-core/src/main/java/com/jme3/shader/ShaderNode.java
  4. 10
      jme3-core/src/main/java/com/jme3/shader/ShaderNodeVariable.java
  5. 12
      jme3-core/src/main/java/com/jme3/shader/VariableMapping.java
  6. 97
      jme3-core/src/plugins/java/com/jme3/material/plugins/J3MLoader.java

@ -48,7 +48,7 @@ import java.util.List;
* *
* @author Nehon * @author Nehon
*/ */
public class ShaderGenerationInfo implements Savable { public class ShaderGenerationInfo implements Savable, Cloneable {
/** /**
* the list of attributes of the vertex shader * the list of attributes of the vertex shader
@ -187,4 +187,36 @@ public class ShaderGenerationInfo implements Savable {
vertexGlobal = (ShaderNodeVariable) ic.readSavable("vertexGlobal", null); 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 com.jme3.shader.Shader.ShaderType;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.*; import java.util.*;
/** /**
@ -46,7 +47,7 @@ import java.util.*;
* *
* @author Kirill Vainer * @author Kirill Vainer
*/ */
public class TechniqueDef implements Savable { public class TechniqueDef implements Savable, Cloneable {
/** /**
* Version #1: Separate shader language for each shader source. * 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) { public void setShaderFile(EnumMap<Shader.ShaderType, String> shaderNames, EnumMap<Shader.ShaderType, String> shaderLanguages) {
requiredCaps.clear(); requiredCaps.clear();
int maxCap = 0; weight = 0;
for (Shader.ShaderType shaderType : shaderNames.keySet()) { for (Shader.ShaderType shaderType : shaderNames.keySet()) {
String language = shaderLanguages.get(shaderType); String language = shaderLanguages.get(shaderType);
String shaderFile = shaderNames.get(shaderType); String shaderFile = shaderNames.get(shaderType);
@ -549,7 +550,7 @@ public class TechniqueDef implements Savable {
Caps cap = Caps.valueOf(language); Caps cap = Caps.valueOf(language);
requiredCaps.add(cap); requiredCaps.add(cap);
maxCap = Math.max(maxCap, cap.ordinal()); weight = Math.max(weight, cap.ordinal());
if (shaderType.equals(Shader.ShaderType.Geometry)) { if (shaderType.equals(Shader.ShaderType.Geometry)) {
requiredCaps.add(Caps.GeometryShader); requiredCaps.add(Caps.GeometryShader);
@ -557,7 +558,6 @@ public class TechniqueDef implements Savable {
requiredCaps.add(Caps.TesselationShader); requiredCaps.add(Caps.TesselationShader);
} }
} }
weight = maxCap;
} }
/** /**
@ -776,4 +776,55 @@ public class TechniqueDef implements Savable {
public void setLightSpace(LightSpace lightSpace) { public void setLightSpace(LightSpace lightSpace) {
this.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 * @author Nehon
*/ */
public class ShaderNode implements Savable { public class ShaderNode implements Savable, Cloneable {
private String name; private String name;
private ShaderNodeDefinition definition; private ShaderNodeDefinition definition;
@ -212,4 +212,24 @@ public class ShaderNode implements Savable {
public String toString() { public String toString() {
return "\nShaderNode{" + "\nname=" + name + ", \ndefinition=" + definition.getName() + ", \ncondition=" + condition + ", \ninputMapping=" + inputMapping + ", \noutputMapping=" + outputMapping + '}'; 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; 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 * @return true if this variable is a shader output
@ -282,5 +277,8 @@ public class ShaderNodeVariable implements Savable, Cloneable {
this.multiplicity = multiplicity; this.multiplicity = multiplicity;
} }
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
} }

@ -43,7 +43,7 @@ import java.io.IOException;
* *
* @author Nehon * @author Nehon
*/ */
public class VariableMapping implements Savable { public class VariableMapping implements Savable, Cloneable {
private ShaderNodeVariable leftVariable; private ShaderNodeVariable leftVariable;
private ShaderNodeVariable rightVariable; private ShaderNodeVariable rightVariable;
@ -195,4 +195,14 @@ public class VariableMapping implements Savable {
public String toString() { public String toString() {
return "\n{" + leftVariable.toString() + (leftSwizzling.length() > 0 ? ("." + leftSwizzling) : "") + " = " + rightVariable.getType() + " " + rightVariable.getNameSpace() + "." + rightVariable.getName() + (rightSwizzling.length() > 0 ? ("." + rightSwizzling) : "") + " : " + condition + "}"; 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.ColorRGBA;
import com.jme3.math.Vector2f; import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f; import com.jme3.math.Vector3f;
import com.jme3.shader.DefineList; import com.jme3.shader.*;
import com.jme3.shader.Shader;
import com.jme3.shader.VarType;
import com.jme3.texture.Texture; import com.jme3.texture.Texture;
import com.jme3.texture.Texture2D; import com.jme3.texture.Texture2D;
import com.jme3.texture.image.ColorSpace; import com.jme3.texture.image.ColorSpace;
import com.jme3.util.PlaceholderAssets; import com.jme3.util.PlaceholderAssets;
import com.jme3.util.blockparser.BlockLanguageParser; import com.jme3.util.blockparser.BlockLanguageParser;
import com.jme3.util.blockparser.Statement; import com.jme3.util.blockparser.Statement;
import com.jme3.util.clone.Cloner;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.ArrayList; import java.util.*;
import java.util.EnumMap;
import java.util.List;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import java.util.regex.Matcher; import java.util.regex.Matcher;
@ -69,6 +66,7 @@ public class J3MLoader implements AssetLoader {
// private ErrorLogger errors; // private ErrorLogger errors;
private ShaderNodeLoaderDelegate nodesLoaderDelegate; private ShaderNodeLoaderDelegate nodesLoaderDelegate;
boolean isUseNodes = false; boolean isUseNodes = false;
int langSize = 0;
private AssetManager assetManager; private AssetManager assetManager;
private AssetKey key; private AssetKey key;
@ -79,13 +77,13 @@ public class J3MLoader implements AssetLoader {
private RenderState renderState; private RenderState renderState;
private ArrayList<String> presetDefines = new ArrayList<String>(); 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 EnumMap<Shader.ShaderType, String> shaderNames;
private static final String whitespacePattern = "\\p{javaWhitespace}+"; private static final String whitespacePattern = "\\p{javaWhitespace}+";
public J3MLoader() { public J3MLoader() {
shaderLanguages = new EnumMap<>(Shader.ShaderType.class); shaderLanguages = new ArrayList<>();// EnumMap<>(Shader.ShaderType.class);
shaderNames = new 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); throw new IOException("Shader statement syntax incorrect" + statement);
} }
String[] typeAndLang = split[0].split(whitespacePattern); 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()) { for (Shader.ShaderType shaderType : Shader.ShaderType.values()) {
if (typeAndLang[0].equals(shaderType.toString() + "Shader")) { 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); 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> // LightMode <MODE>
@ -608,6 +615,7 @@ public class J3MLoader implements AssetLoader {
private void readTechnique(Statement techStat) throws IOException{ private void readTechnique(Statement techStat) throws IOException{
isUseNodes = false; isUseNodes = false;
String[] split = techStat.getLine().split(whitespacePattern); String[] split = techStat.getLine().split(whitespacePattern);
Cloner cloner = new Cloner();
String name; String name;
if (split.length == 1) { if (split.length == 1) {
@ -625,6 +633,30 @@ public class J3MLoader implements AssetLoader {
readTechniqueStatement(statement); readTechniqueStatement(statement);
} }
technique.setShaderPrologue(createShaderPrologue(presetDefines));
switch (technique.getLightMode()) {
case Disable:
technique.setLogic(new DefaultTechniqueDefLogic(technique));
break;
case MultiPass:
technique.setLogic(new MultiPassLightingLogic(technique));
break;
case SinglePass:
technique.setLogic(new SinglePassLightingLogic(technique));
break;
case StaticPass:
technique.setLogic(new StaticPassLightingLogic(technique));
break;
case SinglePassAndImageBased:
technique.setLogic(new SinglePassAndImageBasedLightingLogic(technique));
break;
default:
throw new UnsupportedOperationException();
}
List<TechniqueDef> techniqueDefs = new ArrayList<>();
if(isUseNodes){ if(isUseNodes){
nodesLoaderDelegate.computeConditions(); nodesLoaderDelegate.computeConditions();
@ -634,43 +666,36 @@ public class J3MLoader implements AssetLoader {
// Not sure if this is needed anymore, since shader caching // Not sure if this is needed anymore, since shader caching
// is now done by TechniqueDef. // is now done by TechniqueDef.
technique.setShaderFile(technique.hashCode() + "", technique.hashCode() + "", "GLSL100", "GLSL100"); technique.setShaderFile(technique.hashCode() + "", technique.hashCode() + "", "GLSL100", "GLSL100");
techniqueDefs.add(technique);
}else if (shaderNames.containsKey(Shader.ShaderType.Vertex) && shaderNames.containsKey(Shader.ShaderType.Fragment)) { }else if (shaderNames.containsKey(Shader.ShaderType.Vertex) && shaderNames.containsKey(Shader.ShaderType.Fragment)) {
technique.setShaderFile(shaderNames, shaderLanguages); 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 { } else {
technique = null; technique = null;
shaderLanguages.clear(); shaderLanguages.clear();
shaderNames.clear(); shaderNames.clear();
presetDefines.clear(); presetDefines.clear();
langSize = 0;
logger.log(Level.WARNING, "Fixed function technique was ignored"); logger.log(Level.WARNING, "Fixed function technique was ignored");
logger.log(Level.WARNING, "Fixed function technique ''{0}'' was ignored for material {1}", logger.log(Level.WARNING, "Fixed function technique ''{0}'' was ignored for material {1}",
new Object[]{name, key}); new Object[]{name, key});
return; return;
} }
technique.setShaderPrologue(createShaderPrologue(presetDefines)); for (TechniqueDef techniqueDef : techniqueDefs) {
materialDef.addTechniqueDef(techniqueDef);
switch (technique.getLightMode()) {
case Disable:
technique.setLogic(new DefaultTechniqueDefLogic(technique));
break;
case MultiPass:
technique.setLogic(new MultiPassLightingLogic(technique));
break;
case SinglePass:
technique.setLogic(new SinglePassLightingLogic(technique));
break;
case StaticPass:
technique.setLogic(new StaticPassLightingLogic(technique));
break;
case SinglePassAndImageBased:
technique.setLogic(new SinglePassAndImageBasedLightingLogic(technique));
break;
default:
throw new UnsupportedOperationException();
} }
materialDef.addTechniqueDef(technique);
technique = null; technique = null;
langSize = 0;
shaderLanguages.clear(); shaderLanguages.clear();
shaderNames.clear(); shaderNames.clear();
presetDefines.clear(); presetDefines.clear();

Loading…
Cancel
Save