Просмотр исходного кода

Refactoring of the shader system to allow addition of new shaderstages

michael 10 лет назад
Родитель
Сommit
0d3292c83a

+ 1 - 0
jme3-core/src/main/java/com/jme3/asset/DesktopAssetManager.java

@@ -402,6 +402,7 @@ public class DesktopAssetManager implements AssetManager {
                 }
                 shader = shaderGenerator.generateShader();
             } else {
+
                 String vertName = key.getVertName();
                 String fragName = key.getFragName();
 

+ 1 - 5
jme3-core/src/main/java/com/jme3/material/Technique.java

@@ -190,11 +190,7 @@ public class Technique /* implements Savable */ {
 
     private void loadShader(AssetManager manager,EnumSet<Caps> rendererCaps) {
         
-        ShaderKey key = new ShaderKey(def.getVertexShaderName(),
-                    def.getFragmentShaderName(),
-                    getAllDefines(),
-                    def.getVertexShaderLanguage(),
-                    def.getFragmentShaderLanguage());
+        ShaderKey key = new ShaderKey(getAllDefines(),def.getShaderProgramLanguages(),def.getShaderProgramNames());
         
         if (getDef().isUsingShaderNodes()) {                 
            manager.getShaderGenerator(rendererCaps).initialize(this);           

+ 89 - 34
jme3-core/src/main/java/com/jme3/material/TechniqueDef.java

@@ -34,15 +34,10 @@ package com.jme3.material;
 import com.jme3.export.*;
 import com.jme3.renderer.Caps;
 import com.jme3.renderer.Renderer;
-import com.jme3.shader.DefineList;
-import com.jme3.shader.ShaderNode;
-import com.jme3.shader.UniformBinding;
-import com.jme3.shader.VarType;
+import com.jme3.shader.*;
+
 import java.io.IOException;
-import java.util.ArrayList;
-import java.util.EnumSet;
-import java.util.HashMap;
-import java.util.List;
+import java.util.*;
 
 /**
  * Describes a technique definition.
@@ -55,7 +50,9 @@ public class TechniqueDef implements Savable {
      * Version #1: Separate shader language for each shader source.
      */
     public static final int SAVABLE_VERSION = 1;
-    
+
+
+
     /**
      * Describes light rendering mode.
      */
@@ -100,10 +97,8 @@ public class TechniqueDef implements Savable {
     private EnumSet<Caps> requiredCaps = EnumSet.noneOf(Caps.class);
     private String name;
 
-    private String vertName;
-    private String fragName;
-    private String vertLanguage;
-    private String fragLanguage;
+    private EnumMap<Shader.ShaderType,String> shaderLanguage;
+    private EnumMap<Shader.ShaderType,String> shaderName;
     
     private DefineList presetDefines;
     private boolean usesShaders;
@@ -129,6 +124,7 @@ public class TechniqueDef implements Savable {
      * for default techniques.
      */
     public TechniqueDef(String name){
+        this();
         this.name = name == null ? "Default" : name;
     }
 
@@ -136,6 +132,8 @@ public class TechniqueDef implements Savable {
      * Serialization only. Do not use.
      */
     public TechniqueDef(){
+        shaderLanguage=new EnumMap<Shader.ShaderType, String>(Shader.ShaderType.class);
+        shaderName=new EnumMap<Shader.ShaderType, String>(Shader.ShaderType.class);
     }
 
     /**
@@ -244,11 +242,10 @@ public class TechniqueDef implements Savable {
      * @param fragLanguage The fragment shader language
      */
     public void setShaderFile(String vertexShader, String fragmentShader, String vertLanguage, String fragLanguage){
-        this.vertName = vertexShader;
-        this.fragName = fragmentShader;
-        this.vertLanguage = vertLanguage;
-        this.fragLanguage = fragLanguage;
-
+        this.shaderLanguage.put(Shader.ShaderType.Vertex,shaderLanguage.get(vertLanguage));
+        this.shaderName.put(Shader.ShaderType.Vertex,shaderName.get(vertexShader));
+        this.shaderLanguage.put(Shader.ShaderType.Fragment,shaderLanguage.get(fragLanguage));
+        this.shaderName.put(Shader.ShaderType.Fragment,shaderName.get(fragmentShader));
         Caps vertCap = Caps.valueOf(vertLanguage);
         requiredCaps.add(vertCap);
         Caps fragCap = Caps.valueOf(fragLanguage);
@@ -257,6 +254,26 @@ public class TechniqueDef implements Savable {
         usesShaders = true;
     }
 
+
+    /**
+     * Sets the shaders that this technique definition will use.
+     *
+     * @param shaderName EnumMap containing all shader names for this stage
+     * @param shaderLanguage EnumMap containing all shader languages for this stage
+     */
+    public void setShaderFile(EnumMap<Shader.ShaderType, String> shaderName, EnumMap<Shader.ShaderType, String> shaderLanguage) {
+        for (Shader.ShaderType shaderType : shaderName.keySet()) {
+            this.shaderLanguage.put(shaderType,shaderLanguage.get(shaderType));
+            this.shaderName.put(shaderType,shaderName.get(shaderType));
+            if(shaderType.equals(Shader.ShaderType.Geometry)){
+                requiredCaps.add(Caps.GeometryShader);
+            }else if(shaderType.equals(Shader.ShaderType.TesselationControl)){
+                requiredCaps.add(Caps.TesselationShader);
+            }
+        }
+        usesShaders=true;
+    }
+
     /**
      * Returns the define name which the given material parameter influences.
      * 
@@ -329,7 +346,7 @@ public class TechniqueDef implements Savable {
      * @return the name of the fragment shader to be used.
      */
     public String getFragmentShaderName() {
-        return fragName;
+        return shaderName.get(Shader.ShaderType.Fragment);
     }
 
     
@@ -340,7 +357,7 @@ public class TechniqueDef implements Savable {
      * @return the name of the vertex shader to be used.
      */
     public String getVertexShaderName() {
-        return vertName;
+        return shaderName.get(Shader.ShaderType.Vertex);
     }
 
     /**
@@ -348,21 +365,34 @@ public class TechniqueDef implements Savable {
      */
     @Deprecated
     public String getShaderLanguage() {
-        return vertLanguage;
+        return shaderLanguage.get(Shader.ShaderType.Vertex);
     }
 
     /**
      * Returns the language of the fragment shader used in this technique.
      */
     public String getFragmentShaderLanguage() {
-        return fragLanguage;
+        return shaderLanguage.get(Shader.ShaderType.Fragment);
     }
     
     /**
      * Returns the language of the vertex shader used in this technique.
      */
     public String getVertexShaderLanguage() {
-        return vertLanguage;
+        return shaderLanguage.get(Shader.ShaderType.Vertex);
+    }
+
+    /**Returns the language for each shader program
+     * @param shaderType
+     */
+    public String getShaderProgramLanguage(Shader.ShaderType shaderType){
+        return shaderLanguage.get(shaderType);
+    }
+    /**Returns the name for each shader program
+     * @param shaderType
+     */
+    public String getShaderProgramName(Shader.ShaderType shaderType){
+        return shaderName.get(shaderType);
     }
     
     /**
@@ -406,10 +436,18 @@ public class TechniqueDef implements Savable {
     public void write(JmeExporter ex) throws IOException{
         OutputCapsule oc = ex.getCapsule(this);
         oc.write(name, "name", null);
-        oc.write(vertName, "vertName", null);
-        oc.write(fragName, "fragName", null);
-        oc.write(vertLanguage, "vertLanguage", null);
-        oc.write(vertLanguage, "fragLanguage", null);
+
+        oc.write(shaderName.get(Shader.ShaderType.Vertex), "vertName", null);
+        oc.write(shaderName.get(Shader.ShaderType.Fragment), "fragName", null);
+        oc.write(shaderName.get(Shader.ShaderType.Geometry), "geomName", null);
+        oc.write(shaderName.get(Shader.ShaderType.TesselationControl), "tsctrlName", null);
+        oc.write(shaderName.get(Shader.ShaderType.TesselationEvaluation), "tsevalName", null);
+        oc.write(shaderLanguage.get(Shader.ShaderType.Vertex), "vertLanguage", null);
+        oc.write(shaderLanguage.get(Shader.ShaderType.Fragment), "fragLanguage", null);
+        oc.write(shaderLanguage.get(Shader.ShaderType.Geometry), "geomLanguage", null);
+        oc.write(shaderLanguage.get(Shader.ShaderType.TesselationControl), "tsctrlLanguage", null);
+        oc.write(shaderLanguage.get(Shader.ShaderType.TesselationEvaluation), "tsevalLanguage", null);
+
         oc.write(presetDefines, "presetDefines", null);
         oc.write(lightMode, "lightMode", LightMode.Disable);
         oc.write(shadowMode, "shadowMode", ShadowMode.Disable);
@@ -428,8 +466,11 @@ public class TechniqueDef implements Savable {
     public void read(JmeImporter im) throws IOException{
         InputCapsule ic = im.getCapsule(this);
         name = ic.readString("name", null);
-        vertName = ic.readString("vertName", null);
-        fragName = ic.readString("fragName", null);
+        shaderName.put(Shader.ShaderType.Vertex,ic.readString("vertName", null));
+        shaderName.put(Shader.ShaderType.Fragment,ic.readString("fragName", null));
+        shaderName.put(Shader.ShaderType.Geometry,ic.readString("geomName", null));
+        shaderName.put(Shader.ShaderType.TesselationControl,ic.readString("tsctrlName", null));
+        shaderName.put(Shader.ShaderType.TesselationEvaluation,ic.readString("tsevalName", null));
         presetDefines = (DefineList) ic.readSavable("presetDefines", null);
         lightMode = ic.readEnum("lightMode", LightMode.class, LightMode.Disable);
         shadowMode = ic.readEnum("shadowMode", ShadowMode.class, ShadowMode.Disable);
@@ -438,12 +479,15 @@ public class TechniqueDef implements Savable {
         
         if (ic.getSavableVersion(TechniqueDef.class) == 0) {
             // Old version
-            vertLanguage = ic.readString("shaderLang", null);
-            fragLanguage = vertLanguage;
+            shaderLanguage.put(Shader.ShaderType.Vertex,ic.readString("shaderLang", null));
+            shaderLanguage.put(Shader.ShaderType.Fragment,shaderLanguage.get(Shader.ShaderType.Vertex));
         } else {
             // New version
-            vertLanguage = ic.readString("vertLanguage", null);
-            fragLanguage = ic.readString("fragLanguage", null);;
+            shaderLanguage.put(Shader.ShaderType.Vertex,ic.readString("vertLanguage", null));
+            shaderLanguage.put(Shader.ShaderType.Fragment,ic.readString("fragLanguage", null));
+            shaderLanguage.put(Shader.ShaderType.Geometry,ic.readString("geomLanguage", null));
+            shaderLanguage.put(Shader.ShaderType.TesselationControl,ic.readString("tsctrlLanguage", null));
+            shaderLanguage.put(Shader.ShaderType.TesselationEvaluation,ic.readString("tsevalLanguage", null));
         }
         
         usesNodes = ic.readBoolean("usesNodes", false);
@@ -461,6 +505,16 @@ public class TechniqueDef implements Savable {
         usesShaders = true;
     }
 
+    //todo: add javadoc
+    public EnumMap<Shader.ShaderType, String> getShaderProgramNames() {
+        return shaderName;
+    }
+
+    //todo: add javadoc
+    public EnumMap<Shader.ShaderType, String> getShaderProgramLanguages() {
+        return shaderLanguage;
+    }
+
     public ShaderGenerationInfo getShaderGenerationInfo() {
         return shaderGenerationInfo;
     }
@@ -469,8 +523,9 @@ public class TechniqueDef implements Savable {
         this.shaderGenerationInfo = shaderGenerationInfo;
     }
 
+    //todo: make toString return something usefull
     @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 + '}';
+        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 + '}';
     }    
 }

+ 43 - 22
jme3-core/src/main/java/com/jme3/shader/ShaderKey.java

@@ -37,25 +37,30 @@ import com.jme3.export.JmeExporter;
 import com.jme3.export.JmeImporter;
 import com.jme3.export.OutputCapsule;
 import java.io.IOException;
+import java.util.EnumMap;
 
 public class ShaderKey extends AssetKey<Shader> {
 
-    protected String fragName;
+    protected EnumMap<Shader.ShaderType,String> shaderLanguage;
+    protected EnumMap<Shader.ShaderType,String> shaderName;
     protected DefineList defines;
-    protected String vertLanguage;
-    protected String fragLanguage;
     protected int cachedHashedCode = 0;
     protected boolean usesShaderNodes = false;
 
     public ShaderKey(){
+        shaderLanguage=new EnumMap<Shader.ShaderType, String>(Shader.ShaderType.class);
+        shaderName=new EnumMap<Shader.ShaderType, String>(Shader.ShaderType.class);
     }
 
-    public ShaderKey(String vertName, String fragName, DefineList defines, String vertLanguage, String fragLanguage){
-        super(vertName);
-        this.fragName = fragName;
+    public ShaderKey(DefineList defines, EnumMap<Shader.ShaderType,String> shaderLanguage,EnumMap<Shader.ShaderType,String> shaderName){
+        super(shaderName.get(Shader.ShaderType.Vertex));
+        this.shaderLanguage=new EnumMap<Shader.ShaderType, String>(Shader.ShaderType.class);
+        this.shaderName=new EnumMap<Shader.ShaderType, String>(Shader.ShaderType.class);
         this.defines = defines;
-        this.vertLanguage = vertLanguage;
-        this.fragLanguage = fragLanguage;
+        for (Shader.ShaderType shaderType : shaderName.keySet()) {
+            this.shaderName.put(shaderType,shaderName.get(shaderType));
+            this.shaderLanguage.put(shaderType,shaderLanguage.get(shaderType));
+        }
     }
     
     @Override
@@ -68,13 +73,15 @@ public class ShaderKey extends AssetKey<Shader> {
     
     @Override
     public String toString(){
-        return "V="+name + " F=" + fragName + (defines != null ? defines : "");
+        //todo:
+        return "V="+name+";";
     }
 
+    //todo: make equals and hashCode work
     @Override
     public boolean equals(Object obj) {
         final ShaderKey other = (ShaderKey) obj;
-        if (name.equals(other.name) && fragName.equals(other.fragName)){
+        if (name.equals(other.name) && shaderName.get(Shader.ShaderType.Fragment).equals(other.shaderName.get(Shader.ShaderType.Fragment))){
             if (defines != null && other.defines != null) {
                 return defines.equals(other.defines);
             } else if (defines != null || other.defines != null) {
@@ -91,7 +98,7 @@ public class ShaderKey extends AssetKey<Shader> {
         if (cachedHashedCode == 0) {
             int hash = 7;
             hash = 41 * hash + name.hashCode();
-            hash = 41 * hash + fragName.hashCode();
+            hash = 41 * hash + shaderName.get(Shader.ShaderType.Fragment).hashCode();
             hash = 41 * hash + (defines != null ? defines.hashCode() : 0);
             cachedHashedCode = hash;
         }
@@ -103,11 +110,11 @@ public class ShaderKey extends AssetKey<Shader> {
     }
 
     public String getVertName(){
-        return name;
+        return shaderName.get(Shader.ShaderType.Vertex);
     }
 
     public String getFragName() {
-        return fragName;
+        return shaderName.get(Shader.ShaderType.Fragment);
     }
 
     /**
@@ -115,15 +122,15 @@ public class ShaderKey extends AssetKey<Shader> {
      */
     @Deprecated
     public String getLanguage() {
-        return vertLanguage;
+        return shaderLanguage.get(Shader.ShaderType.Vertex);
     }
     
     public String getVertexShaderLanguage() { 
-        return vertLanguage;
+        return shaderLanguage.get(Shader.ShaderType.Vertex);
     }
     
     public String getFragmentShaderLanguage() {
-        return fragLanguage;
+        return shaderLanguage.get(Shader.ShaderType.Vertex);
     }
 
     public boolean isUsesShaderNodes() {
@@ -138,18 +145,32 @@ public class ShaderKey extends AssetKey<Shader> {
     public void write(JmeExporter ex) throws IOException{
         super.write(ex);
         OutputCapsule oc = ex.getCapsule(this);
-        oc.write(fragName, "fragment_name", null);
-        oc.write(vertLanguage, "language", null);
-        oc.write(fragLanguage, "frag_language", null);
+        oc.write(shaderName.get(Shader.ShaderType.Fragment), "fragment_name", null);
+        oc.write(shaderName.get(Shader.ShaderType.Geometry), "geometry_name", null);
+        oc.write(shaderName.get(Shader.ShaderType.TesselationControl), "tessControl_name", null);
+        oc.write(shaderName.get(Shader.ShaderType.TesselationEvaluation), "tessEval_name", null);
+        oc.write(shaderLanguage.get(Shader.ShaderType.Vertex), "language", null);
+        oc.write(shaderLanguage.get(Shader.ShaderType.Fragment), "frag_language", null);
+        oc.write(shaderLanguage.get(Shader.ShaderType.Geometry), "geom_language", null);
+        oc.write(shaderLanguage.get(Shader.ShaderType.TesselationControl), "tsctrl_language", null);
+        oc.write(shaderLanguage.get(Shader.ShaderType.TesselationEvaluation), "tseval_language", null);
+
     }
 
     @Override
     public void read(JmeImporter im) throws IOException{
         super.read(im);
         InputCapsule ic = im.getCapsule(this);
-        fragName = ic.readString("fragment_name", null);
-        vertLanguage = ic.readString("language", null);
-        fragLanguage = ic.readString("frag_language", null);
+        shaderName.put(Shader.ShaderType.Vertex,name);
+        shaderName.put(Shader.ShaderType.Fragment,ic.readString("fragment_name", null));
+        shaderName.put(Shader.ShaderType.Geometry,ic.readString("geometry_name", null));
+        shaderName.put(Shader.ShaderType.TesselationControl,ic.readString("tessControl_name", null));
+        shaderName.put(Shader.ShaderType.TesselationEvaluation,ic.readString("tessEval_name", null));
+        shaderLanguage.put(Shader.ShaderType.Vertex,ic.readString("language", null));
+        shaderLanguage.put(Shader.ShaderType.Fragment,ic.readString("frag_language", null));
+        shaderLanguage.put(Shader.ShaderType.Geometry,ic.readString("geom_language", null));
+        shaderLanguage.put(Shader.ShaderType.TesselationControl,ic.readString("tsctrl_language", null));
+        shaderLanguage.put(Shader.ShaderType.TesselationEvaluation,ic.readString("tseval_language", null));
     }
 
 }

+ 69 - 67
jme3-core/src/plugins/java/com/jme3/material/plugins/J3MLoader.java

@@ -40,6 +40,7 @@ import com.jme3.material.TechniqueDef.ShadowMode;
 import com.jme3.math.ColorRGBA;
 import com.jme3.math.Vector2f;
 import com.jme3.math.Vector3f;
+import com.jme3.shader.Shader;
 import com.jme3.shader.VarType;
 import com.jme3.texture.Texture;
 import com.jme3.texture.Texture.WrapMode;
@@ -50,6 +51,7 @@ import com.jme3.util.blockparser.BlockLanguageParser;
 import com.jme3.util.blockparser.Statement;
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.EnumMap;
 import java.util.List;
 import java.util.logging.Level;
 import java.util.logging.Logger;
@@ -60,7 +62,7 @@ public class J3MLoader implements AssetLoader {
    // private ErrorLogger errors;
     private ShaderNodeLoaderDelegate nodesLoaderDelegate;
     boolean isUseNodes = false;
-    
+
     private AssetManager assetManager;
     private AssetKey key;
 
@@ -68,16 +70,15 @@ public class J3MLoader implements AssetLoader {
     private Material material;
     private TechniqueDef technique;
     private RenderState renderState;
-    
-    private String vertLanguage;
-    private String fragLanguage;
-    
-    private String vertName;
-    private String fragName;
-    
+
+    private EnumMap<Shader.ShaderType,String> shaderLanguage;
+    private EnumMap<Shader.ShaderType,String> shaderName;
+
     private static final String whitespacePattern = "\\p{javaWhitespace}+";
 
     public J3MLoader(){
+        shaderLanguage=new EnumMap<Shader.ShaderType, String>(Shader.ShaderType.class);
+        shaderName=new EnumMap<Shader.ShaderType, String>(Shader.ShaderType.class);
     }
 
 
@@ -91,16 +92,19 @@ public class J3MLoader implements AssetLoader {
         if (typeAndLang.length != 2) {
             throw new IOException("Shader statement syntax incorrect: " + statement);
         }
-        
-        if (typeAndLang[0].equals("VertexShader")) {
-            vertName = split[1].trim();
-            vertLanguage = typeAndLang[1];
-        } else if (typeAndLang[0].equals("FragmentShader")) {
-            fragName = split[1].trim();
-            fragLanguage = typeAndLang[1];
+
+        for (Shader.ShaderType shaderType : Shader.ShaderType.values()) {
+            if(typeAndLang[0].equals(shaderType.toString()+"Shader")){
+                readShaderDefinition(shaderType,split[1].trim(),typeAndLang[1]);
+            }
         }
     }
 
+    private void readShaderDefinition(Shader.ShaderType shaderType,String name,String language){
+        shaderName.put(shaderType,name);
+        shaderLanguage.put(shaderType,language);
+    }
+
     // LightMode <MODE>
     private void readLightMode(String statement) throws IOException{
         String[] split = statement.split(whitespacePattern);
@@ -163,14 +167,14 @@ public class J3MLoader implements AssetLoader {
             if (tex != null){
                 if (repeat){
                     tex.setWrap(WrapMode.Repeat);
-                }                
+                }
             }else{
                 tex = new Texture2D(PlaceholderAssets.getPlaceholderImage(assetManager));
                 if (repeat){
                     tex.setWrap(WrapMode.Repeat);
                 }
                 tex.setKey(texKey);
-            }         
+            }
             return tex;
         }else{
             String[] split = value.trim().split(whitespacePattern);
@@ -216,13 +220,13 @@ public class J3MLoader implements AssetLoader {
             }
         }
     }
-    
+
     // <TYPE> <NAME> [ "(" <FFBINDING> ")" ] [ ":" <DEFAULTVAL> ] [-LINEAR]
     private void readParam(String statement) throws IOException{
         String name;
         String defaultVal = null;
         ColorSpace colorSpace = null;
-        
+
         String[] split = statement.split("-");
         if(split.length>1){
             if(split[1].equalsIgnoreCase("LINEAR")){
@@ -230,9 +234,9 @@ public class J3MLoader implements AssetLoader {
             }
             statement = split[0].trim();
         }
-        
+
         split = statement.split(":");
-        
+
         // Parse default val
         if (split.length == 1){
             // Doesn't contain default value
@@ -241,9 +245,9 @@ public class J3MLoader implements AssetLoader {
                 throw new IOException("Parameter statement syntax incorrect");
             }
             statement = split[0].trim();
-            defaultVal = split[1].trim();           
+            defaultVal = split[1].trim();
         }
-        
+
         // Parse ffbinding
         int startParen = statement.indexOf("(");
         if (startParen != -1){
@@ -253,32 +257,32 @@ public class J3MLoader implements AssetLoader {
             // don't care about bindingStr
             statement = statement.substring(0, startParen);
         }
-        
+
         // Parse type + name
         split = statement.split(whitespacePattern);
         if (split.length != 2){
             throw new IOException("Parameter statement syntax incorrect");
         }
-        
+
         VarType type;
         if (split[0].equals("Color")){
             type = VarType.Vector4;
         }else{
             type = VarType.valueOf(split[0]);
         }
-        
+
         name = split[1];
-        
+
         Object defaultValObj = null;
-        if (defaultVal != null){ 
+        if (defaultVal != null){
             defaultValObj = readValue(type, defaultVal);
         }
         if(type.isTextureType()){
-            materialDef.addMaterialParamTexture(type, name, colorSpace);    
+            materialDef.addMaterialParamTexture(type, name, colorSpace);
         }else{
             materialDef.addMaterialParam(type, name, defaultValObj);
         }
-        
+
     }
 
     private void readValueParam(String statement) throws IOException{
@@ -373,7 +377,7 @@ public class J3MLoader implements AssetLoader {
         technique.setRenderState(renderState);
         renderState = null;
     }
-    
+
     private void readForcedRenderState(List<Statement> renderStates) throws IOException{
         renderState = new RenderState();
         for (Statement statement : renderStates){
@@ -382,7 +386,7 @@ public class J3MLoader implements AssetLoader {
         technique.setForcedRenderState(renderState);
         renderState = null;
     }
-    
+
     // <DEFINENAME> [ ":" <PARAMNAME> ]
     private void readDefine(String statement) throws IOException{
         String[] split = statement.split(":");
@@ -402,9 +406,9 @@ public class J3MLoader implements AssetLoader {
         }
 
     }
-    
+
     private void readTechniqueStatement(Statement statement) throws IOException{
-        String[] split = statement.getLine().split("[ \\{]");       
+        String[] split = statement.getLine().split("[ \\{]");
         if (split[0].equals("VertexShader") ||
             split[0].equals("FragmentShader")){
             readShaderStatement(statement.getLine());
@@ -414,12 +418,12 @@ public class J3MLoader implements AssetLoader {
             readShadowMode(statement.getLine());
         }else if (split[0].equals("WorldParameters")){
             readWorldParams(statement.getContents());
-        }else if (split[0].equals("RenderState")){  
+        }else if (split[0].equals("RenderState")){
             readRenderState(statement.getContents());
-        }else if (split[0].equals("ForcedRenderState")){  
+        }else if (split[0].equals("ForcedRenderState")){
             readForcedRenderState(statement.getContents());
-        }else if (split[0].equals("Defines")){           
-            readDefines(statement.getContents());         
+        }else if (split[0].equals("Defines")){
+            readDefines(statement.getContents());
         } else if (split[0].equals("ShaderNodesDefinitions")) {
             initNodesLoader();
             if (isUseNodes) {
@@ -432,14 +436,14 @@ public class J3MLoader implements AssetLoader {
             }
         } else if (split[0].equals("FragmentShaderNodes")) {
             initNodesLoader();
-            if (isUseNodes) {                
+            if (isUseNodes) {
                 nodesLoaderDelegate.readFragmentShaderNodes(statement.getContents());
             }
         } else {
             throw new MatParseException(null, split[0], statement);
         }
     }
-    
+
     private void readTransparentStatement(String statement) throws IOException{
         String[] split = statement.split(whitespacePattern);
         if (split.length != 2){
@@ -459,30 +463,28 @@ public class J3MLoader implements AssetLoader {
         } else {
             throw new IOException("Technique statement syntax incorrect");
         }
-        
+
         for (Statement statement : techStat.getContents()){
             readTechniqueStatement(statement);
         }
-        
+
         if(isUseNodes){
             nodesLoaderDelegate.computeConditions();
             //used for caching later, the shader here is not a file.
             technique.setShaderFile(technique.hashCode() + "", technique.hashCode() + "", "GLSL100", "GLSL100");
         }
 
-        if (vertName != null && fragName != null){
-            technique.setShaderFile(vertName, fragName, vertLanguage, fragLanguage);
+        if(shaderName.containsKey(Shader.ShaderType.Vertex) && shaderName.containsKey(Shader.ShaderType.Fragment)){
+            technique.setShaderFile(shaderName,shaderLanguage);
         }
-        
+
         materialDef.addTechniqueDef(technique);
         technique = null;
-        vertName = null;
-        fragName = null;
-        vertLanguage = null;
-        fragLanguage = null;
+        shaderLanguage.clear();
+        shaderName.clear();
     }
 
-    private void loadFromRoot(List<Statement> roots) throws IOException{       
+    private void loadFromRoot(List<Statement> roots) throws IOException{
         if (roots.size() == 2){
             Statement exception = roots.get(0);
             String line = exception.getLine();
@@ -494,7 +496,7 @@ public class J3MLoader implements AssetLoader {
         }else if (roots.size() != 1){
             throw new IOException("Too many roots in J3M/J3MD file");
         }
-               
+
         boolean extending = false;
         Statement materialStat = roots.get(0);
         String materialName = materialStat.getLine();
@@ -507,16 +509,16 @@ public class J3MLoader implements AssetLoader {
         }else{
             throw new IOException("Specified file is not a Material file");
         }
-        
+
         String[] split = materialName.split(":", 2);
-        
+
         if (materialName.equals("")){
-            throw new MatParseException("Material name cannot be empty", materialStat);         
+            throw new MatParseException("Material name cannot be empty", materialStat);
         }
 
         if (split.length == 2){
             if (!extending){
-                throw new MatParseException("Must use 'Material' when extending.", materialStat); 
+                throw new MatParseException("Must use 'Material' when extending.", materialStat);
             }
 
             String extendedMat = split[1].trim();
@@ -531,15 +533,15 @@ public class J3MLoader implements AssetLoader {
 //            material.setAssetName(fileName);
         }else if (split.length == 1){
             if (extending){
-                throw new MatParseException("Expected ':', got '{'", materialStat);               
+                throw new MatParseException("Expected ':', got '{'", materialStat);
             }
             materialDef = new MaterialDef(assetManager, materialName);
             // NOTE: pass file name for defs so they can be loaded later
             materialDef.setAssetName(key.getName());
         }else{
-            throw new MatParseException("Cannot use colon in material name/path", materialStat);   
+            throw new MatParseException("Cannot use colon in material name/path", materialStat);
         }
-        
+
         for (Statement statement : materialStat.getContents()){
             split = statement.getLine().split("[ \\{]");
             String statType = split[0];
@@ -557,25 +559,25 @@ public class J3MLoader implements AssetLoader {
                 }else if (statType.equals("MaterialParameters")){
                     readMaterialParams(statement.getContents());
                 }else{
-                    throw new MatParseException("Expected material statement, got '"+statType+"'", statement);                       
+                    throw new MatParseException("Expected material statement, got '"+statType+"'", statement);
                 }
             }
         }
     }
 
-    public Object load(AssetInfo info) throws IOException {       
+    public Object load(AssetInfo info) throws IOException {
         this.assetManager = info.getManager();
 
-        InputStream in = info.openStream();        
+        InputStream in = info.openStream();
         try {
-            key = info.getKey();            
+            key = info.getKey();
             loadFromRoot(BlockLanguageParser.parse(in));
         } finally {
             if (in != null){
                 in.close();
             }
         }
-        
+
         if (material != null){
             if (!(info.getKey() instanceof MaterialKey)){
                 throw new IOException("Material instances must be loaded via MaterialKey");
@@ -587,7 +589,7 @@ public class J3MLoader implements AssetLoader {
             return materialDef;
         }
     }
-    
+
     public MaterialDef loadMaterialDef(List<Statement> roots, AssetManager manager, AssetKey key) throws IOException {
         this.key = key;
         this.assetManager = manager;
@@ -597,8 +599,8 @@ public class J3MLoader implements AssetLoader {
 
     protected void initNodesLoader() {
         if (!isUseNodes) {
-            isUseNodes = fragName == null && vertName == null;
-            if (isUseNodes) { 
+            isUseNodes = shaderName.get(Shader.ShaderType.Vertex) == null && shaderName.get(Shader.ShaderType.Fragment) == null;
+            if (isUseNodes) {
                 if(nodesLoaderDelegate == null){
                     nodesLoaderDelegate = new ShaderNodeLoaderDelegate();
                 }else{
@@ -609,6 +611,6 @@ public class J3MLoader implements AssetLoader {
                 nodesLoaderDelegate.setAssetManager(assetManager);
             }
         }
-    }   
+    }
 
 }

+ 2 - 5
jme3-core/src/tools/java/jme3tools/shadercheck/ShaderCheck.java

@@ -38,11 +38,8 @@ public class ShaderCheck {
         for (TechniqueDef techDef : def.getDefaultTechniques()){
             DefineList dl = new DefineList();
             dl.addFrom(techDef.getShaderPresetDefines());
-            ShaderKey shaderKey = new ShaderKey(techDef.getVertexShaderName(),
-                                                techDef.getFragmentShaderName(),
-                                                dl,
-                                                techDef.getVertexShaderLanguage(),
-                                                techDef.getFragmentShaderLanguage());
+            ShaderKey shaderKey = new ShaderKey(dl,techDef.getShaderProgramLanguages(),techDef.getShaderProgramNames());
+
             Shader shader = assetManager.loadShader(shaderKey);
 
             for (Validator validator : validators){