diff --git a/jme3-core/src/plugins/java/com/jme3/material/plugins/J3MLoader.java b/jme3-core/src/plugins/java/com/jme3/material/plugins/J3MLoader.java index 23310f12f..609245e8d 100644 --- a/jme3-core/src/plugins/java/com/jme3/material/plugins/J3MLoader.java +++ b/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; @@ -48,8 +49,10 @@ import com.jme3.texture.image.ColorSpace; import com.jme3.util.PlaceholderAssets; 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; @@ -57,10 +60,10 @@ import java.util.logging.Logger; public class J3MLoader implements AssetLoader { private static final Logger logger = Logger.getLogger(J3MLoader.class.getName()); - // private ErrorLogger errors; + // private ErrorLogger errors; private ShaderNodeLoaderDelegate nodesLoaderDelegate; boolean isUseNodes = false; - + private AssetManager assetManager; private AssetKey key; @@ -68,16 +71,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 shaderLanguage; + private EnumMap shaderName; + private static final String whitespacePattern = "\\p{javaWhitespace}+"; - public J3MLoader(){ + public J3MLoader() { + shaderLanguage = new EnumMap(Shader.ShaderType.class); + shaderName = new EnumMap(Shader.ShaderType.class); } @@ -91,20 +93,25 @@ 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) { + System.out.println(shaderType); + System.out.println(name); + shaderName.put(shaderType, name); + shaderLanguage.put(shaderType, language); + } + // LightMode - private void readLightMode(String statement) throws IOException{ + private void readLightMode(String statement) throws IOException { String[] split = statement.split(whitespacePattern); - if (split.length != 2){ + if (split.length != 2) { throw new IOException("LightMode statement syntax incorrect"); } LightMode lm = LightMode.valueOf(split[1]); @@ -112,29 +119,29 @@ public class J3MLoader implements AssetLoader { } // ShadowMode - private void readShadowMode(String statement) throws IOException{ + private void readShadowMode(String statement) throws IOException { String[] split = statement.split(whitespacePattern); - if (split.length != 2){ + if (split.length != 2) { throw new IOException("ShadowMode statement syntax incorrect"); } ShadowMode sm = ShadowMode.valueOf(split[1]); technique.setShadowMode(sm); } - private Object readValue(VarType type, String value) throws IOException{ - if (type.isTextureType()){ + private Object readValue(VarType type, String value) throws IOException { + if (type.isTextureType()) { // String texturePath = readString("[\n;(//)(\\})]"); String texturePath = value.trim(); boolean flipY = false; boolean repeat = false; - if (texturePath.startsWith("Flip Repeat ")){ + if (texturePath.startsWith("Flip Repeat ")) { texturePath = texturePath.substring(12).trim(); flipY = true; repeat = true; - }else if (texturePath.startsWith("Flip ")){ + } else if (texturePath.startsWith("Flip ")) { texturePath = texturePath.substring(5).trim(); flipY = true; - }else if (texturePath.startsWith("Repeat ")){ + } else if (texturePath.startsWith("Repeat ")) { texturePath = texturePath.substring(7).trim(); repeat = true; } @@ -156,270 +163,273 @@ public class J3MLoader implements AssetLoader { Texture tex; try { tex = assetManager.loadTexture(texKey); - } catch (AssetNotFoundException ex){ + } catch (AssetNotFoundException ex) { logger.log(Level.WARNING, "Cannot locate {0} for material {1}", new Object[]{texKey, key}); tex = null; } - if (tex != null){ - if (repeat){ + if (tex != null) { + if (repeat) { tex.setWrap(WrapMode.Repeat); - } - }else{ + } + } else { tex = new Texture2D(PlaceholderAssets.getPlaceholderImage(assetManager)); - if (repeat){ + if (repeat) { tex.setWrap(WrapMode.Repeat); } tex.setKey(texKey); - } + } return tex; - }else{ + } else { String[] split = value.trim().split(whitespacePattern); - switch (type){ + switch (type) { case Float: - if (split.length != 1){ + if (split.length != 1) { throw new IOException("Float value parameter must have 1 entry: " + value); } - return Float.parseFloat(split[0]); + return Float.parseFloat(split[0]); case Vector2: - if (split.length != 2){ + if (split.length != 2) { throw new IOException("Vector2 value parameter must have 2 entries: " + value); } return new Vector2f(Float.parseFloat(split[0]), - Float.parseFloat(split[1])); + Float.parseFloat(split[1])); case Vector3: - if (split.length != 3){ + if (split.length != 3) { throw new IOException("Vector3 value parameter must have 3 entries: " + value); } return new Vector3f(Float.parseFloat(split[0]), - Float.parseFloat(split[1]), - Float.parseFloat(split[2])); + Float.parseFloat(split[1]), + Float.parseFloat(split[2])); case Vector4: - if (split.length != 4){ + if (split.length != 4) { throw new IOException("Vector4 value parameter must have 4 entries: " + value); } return new ColorRGBA(Float.parseFloat(split[0]), - Float.parseFloat(split[1]), - Float.parseFloat(split[2]), - Float.parseFloat(split[3])); + Float.parseFloat(split[1]), + Float.parseFloat(split[2]), + Float.parseFloat(split[3])); case Int: - if (split.length != 1){ + if (split.length != 1) { throw new IOException("Int value parameter must have 1 entry: " + value); } return Integer.parseInt(split[0]); case Boolean: - if (split.length != 1){ + if (split.length != 1) { throw new IOException("Boolean value parameter must have 1 entry: " + value); } return Boolean.parseBoolean(split[0]); default: - throw new UnsupportedOperationException("Unknown type: "+type); + throw new UnsupportedOperationException("Unknown type: " + type); } } } - + // [ "(" ")" ] [ ":" ] [-LINEAR] - private void readParam(String statement) throws IOException{ + 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")){ + if (split.length > 1) { + if (split[1].equalsIgnoreCase("LINEAR")) { colorSpace = ColorSpace.Linear; } statement = split[0].trim(); } - + split = statement.split(":"); - + // Parse default val - if (split.length == 1){ + if (split.length == 1) { // Doesn't contain default value - }else{ - if (split.length != 2){ + } else { + if (split.length != 2) { 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){ + if (startParen != -1) { // get content inside parentheses int endParen = statement.indexOf(")", startParen); - String bindingStr = statement.substring(startParen+1, endParen).trim(); + String bindingStr = statement.substring(startParen + 1, endParen).trim(); // don't care about bindingStr statement = statement.substring(0, startParen); } - + // Parse type + name split = statement.split(whitespacePattern); - if (split.length != 2){ + if (split.length != 2) { throw new IOException("Parameter statement syntax incorrect"); } - + VarType type; - if (split[0].equals("Color")){ + if (split[0].equals("Color")) { type = VarType.Vector4; - }else{ + } 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); - }else{ + if (type.isTextureType()) { + materialDef.addMaterialParamTexture(type, name, colorSpace); + } else { materialDef.addMaterialParam(type, name, defaultValObj); } - + } - private void readValueParam(String statement) throws IOException{ + private void readValueParam(String statement) throws IOException { // Use limit=1 incase filename contains colons String[] split = statement.split(":", 2); - if (split.length != 2){ + if (split.length != 2) { throw new IOException("Value parameter statement syntax incorrect"); } String name = split[0].trim(); // parse value MatParam p = material.getMaterialDef().getMaterialParam(name); - if (p == null){ - throw new IOException("The material parameter: "+name+" is undefined."); + if (p == null) { + throw new IOException("The material parameter: " + name + " is undefined."); } Object valueObj = readValue(p.getVarType(), split[1]); - if (p.getVarType().isTextureType()){ + if (p.getVarType().isTextureType()) { material.setTextureParam(name, p.getVarType(), (Texture) valueObj); - }else{ + } else { material.setParam(name, p.getVarType(), valueObj); } } - private void readMaterialParams(List paramsList) throws IOException{ - for (Statement statement : paramsList){ + private void readMaterialParams(List paramsList) throws IOException { + for (Statement statement : paramsList) { readParam(statement.getLine()); } } - private void readExtendingMaterialParams(List paramsList) throws IOException{ - for (Statement statement : paramsList){ + private void readExtendingMaterialParams(List paramsList) throws IOException { + for (Statement statement : paramsList) { readValueParam(statement.getLine()); } } - private void readWorldParams(List worldParams) throws IOException{ - for (Statement statement : worldParams){ + private void readWorldParams(List worldParams) throws IOException { + for (Statement statement : worldParams) { technique.addWorldParam(statement.getLine()); } } - private boolean parseBoolean(String word){ + private boolean parseBoolean(String word) { return word != null && word.equals("On"); } - private void readRenderStateStatement(Statement statement) throws IOException{ + private void readRenderStateStatement(Statement statement) throws IOException { String[] split = statement.getLine().split(whitespacePattern); - if (split[0].equals("Wireframe")){ + if (split[0].equals("Wireframe")) { renderState.setWireframe(parseBoolean(split[1])); - }else if (split[0].equals("FaceCull")){ + } else if (split[0].equals("FaceCull")) { renderState.setFaceCullMode(FaceCullMode.valueOf(split[1])); - }else if (split[0].equals("DepthWrite")){ + } else if (split[0].equals("DepthWrite")) { renderState.setDepthWrite(parseBoolean(split[1])); - }else if (split[0].equals("DepthTest")){ + } else if (split[0].equals("DepthTest")) { renderState.setDepthTest(parseBoolean(split[1])); - }else if (split[0].equals("Blend")){ + } else if (split[0].equals("Blend")) { renderState.setBlendMode(BlendMode.valueOf(split[1])); - }else if (split[0].equals("AlphaTestFalloff")){ + } else if (split[0].equals("AlphaTestFalloff")) { renderState.setAlphaTest(true); renderState.setAlphaFallOff(Float.parseFloat(split[1])); - }else if (split[0].equals("PolyOffset")){ + } else if (split[0].equals("PolyOffset")) { float factor = Float.parseFloat(split[1]); float units = Float.parseFloat(split[2]); renderState.setPolyOffset(factor, units); - }else if (split[0].equals("ColorWrite")){ + } else if (split[0].equals("ColorWrite")) { renderState.setColorWrite(parseBoolean(split[1])); - }else if (split[0].equals("PointSprite")){ + } else if (split[0].equals("PointSprite")) { renderState.setPointSprite(parseBoolean(split[1])); - }else if (split[0].equals("DepthFunc")){ + } else if (split[0].equals("DepthFunc")) { renderState.setDepthFunc(RenderState.TestFunction.valueOf(split[1])); - }else if (split[0].equals("AlphaFunc")){ + } else if (split[0].equals("AlphaFunc")) { renderState.setAlphaFunc(RenderState.TestFunction.valueOf(split[1])); } else { throw new MatParseException(null, split[0], statement); } } - private void readAdditionalRenderState(List renderStates) throws IOException{ + private void readAdditionalRenderState(List renderStates) throws IOException { renderState = material.getAdditionalRenderState(); - for (Statement statement : renderStates){ + for (Statement statement : renderStates) { readRenderStateStatement(statement); } renderState = null; } - private void readRenderState(List renderStates) throws IOException{ + private void readRenderState(List renderStates) throws IOException { renderState = new RenderState(); - for (Statement statement : renderStates){ + for (Statement statement : renderStates) { readRenderStateStatement(statement); } technique.setRenderState(renderState); renderState = null; } - - private void readForcedRenderState(List renderStates) throws IOException{ + + private void readForcedRenderState(List renderStates) throws IOException { renderState = new RenderState(); - for (Statement statement : renderStates){ + for (Statement statement : renderStates) { readRenderStateStatement(statement); } technique.setForcedRenderState(renderState); renderState = null; } - + // [ ":" ] - private void readDefine(String statement) throws IOException{ + private void readDefine(String statement) throws IOException { String[] split = statement.split(":"); - if (split.length == 1){ + if (split.length == 1) { // add preset define technique.addShaderPresetDefine(split[0].trim(), VarType.Boolean, true); - }else if (split.length == 2){ + } else if (split.length == 2) { technique.addShaderParamDefine(split[1].trim(), split[0].trim()); - }else{ + } else { throw new IOException("Define syntax incorrect"); } } - private void readDefines(List defineList) throws IOException{ - for (Statement statement : defineList){ + private void readDefines(List defineList) throws IOException { + for (Statement statement : defineList) { readDefine(statement.getLine()); } } - - private void readTechniqueStatement(Statement statement) throws IOException{ - String[] split = statement.getLine().split("[ \\{]"); + + private void readTechniqueStatement(Statement statement) throws IOException { + String[] split = statement.getLine().split("[ \\{]"); if (split[0].equals("VertexShader") || - split[0].equals("FragmentShader")){ + split[0].equals("FragmentShader") || + split[0].equals("GeometryShader") || + split[0].equals("TesselationControlShader") || + split[0].equals("TesselationEvaluationShader")) { readShaderStatement(statement.getLine()); - }else if (split[0].equals("LightMode")){ + } else if (split[0].equals("LightMode")) { readLightMode(statement.getLine()); - }else if (split[0].equals("ShadowMode")){ + } else if (split[0].equals("ShadowMode")) { readShadowMode(statement.getLine()); - }else if (split[0].equals("WorldParameters")){ + } 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,23 +442,23 @@ 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{ + + private void readTransparentStatement(String statement) throws IOException { String[] split = statement.split(whitespacePattern); - if (split.length != 2){ + if (split.length != 2) { throw new IOException("Transparent statement syntax incorrect"); } material.setTransparent(parseBoolean(split[1])); } - private void readTechnique(Statement techStat) throws IOException{ + private void readTechnique(Statement techStat) throws IOException { isUseNodes = false; String[] split = techStat.getLine().split(whitespacePattern); if (split.length == 1) { @@ -459,64 +469,62 @@ public class J3MLoader implements AssetLoader { } else { throw new IOException("Technique statement syntax incorrect"); } - - for (Statement statement : techStat.getContents()){ + + for (Statement statement : techStat.getContents()) { readTechniqueStatement(statement); } - - if(isUseNodes){ + + 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 roots) throws IOException{ - if (roots.size() == 2){ + private void loadFromRoot(List roots) throws IOException { + if (roots.size() == 2) { Statement exception = roots.get(0); String line = exception.getLine(); - if (line.startsWith("Exception")){ + if (line.startsWith("Exception")) { throw new AssetLoadException(line.substring("Exception ".length())); - }else{ + } else { throw new IOException("In multiroot material, expected first statement to be 'Exception'"); } - }else if (roots.size() != 1){ + } 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(); - if (materialName.startsWith("MaterialDef")){ + if (materialName.startsWith("MaterialDef")) { materialName = materialName.substring("MaterialDef ".length()).trim(); extending = false; - }else if (materialName.startsWith("Material")){ + } else if (materialName.startsWith("Material")) { materialName = materialName.substring("Material ".length()).trim(); extending = true; - }else{ + } 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); + + if (materialName.equals("")) { + throw new MatParseException("Material name cannot be empty", materialStat); } - if (split.length == 2){ - if (!extending){ - throw new MatParseException("Must use 'Material' when extending.", materialStat); + if (split.length == 2) { + if (!extending) { + throw new MatParseException("Must use 'Material' when extending.", materialStat); } String extendedMat = split[1].trim(); @@ -529,65 +537,65 @@ public class J3MLoader implements AssetLoader { material = new Material(def); material.setKey(key); // material.setAssetName(fileName); - }else if (split.length == 1){ - if (extending){ - throw new MatParseException("Expected ':', got '{'", materialStat); + } else if (split.length == 1) { + if (extending) { + 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); + } else { + throw new MatParseException("Cannot use colon in material name/path", materialStat); } - - for (Statement statement : materialStat.getContents()){ + + for (Statement statement : materialStat.getContents()) { split = statement.getLine().split("[ \\{]"); String statType = split[0]; - if (extending){ - if (statType.equals("MaterialParameters")){ + if (extending) { + if (statType.equals("MaterialParameters")) { readExtendingMaterialParams(statement.getContents()); - }else if (statType.equals("AdditionalRenderState")){ + } else if (statType.equals("AdditionalRenderState")) { readAdditionalRenderState(statement.getContents()); - }else if (statType.equals("Transparent")){ + } else if (statType.equals("Transparent")) { readTransparentStatement(statement.getLine()); } - }else{ - if (statType.equals("Technique")){ + } else { + if (statType.equals("Technique")) { readTechnique(statement); - }else if (statType.equals("MaterialParameters")){ + } else if (statType.equals("MaterialParameters")) { readMaterialParams(statement.getContents()); - }else{ - throw new MatParseException("Expected material statement, got '"+statType+"'", statement); + } else { + 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){ + if (in != null) { in.close(); } } - - if (material != null){ - if (!(info.getKey() instanceof MaterialKey)){ + + if (material != null) { + if (!(info.getKey() instanceof MaterialKey)) { throw new IOException("Material instances must be loaded via MaterialKey"); } // material implementation return material; - }else{ + } else { // material definition return materialDef; } } - + public MaterialDef loadMaterialDef(List roots, AssetManager manager, AssetKey key) throws IOException { this.key = key; this.assetManager = manager; @@ -597,11 +605,11 @@ public class J3MLoader implements AssetLoader { protected void initNodesLoader() { if (!isUseNodes) { - isUseNodes = fragName == null && vertName == null; - if (isUseNodes) { - if(nodesLoaderDelegate == null){ + isUseNodes = shaderName.get(Shader.ShaderType.Vertex) == null && shaderName.get(Shader.ShaderType.Fragment) == null; + if (isUseNodes) { + if (nodesLoaderDelegate == null) { nodesLoaderDelegate = new ShaderNodeLoaderDelegate(); - }else{ + } else { nodesLoaderDelegate.clear(); } nodesLoaderDelegate.setTechniqueDef(technique); @@ -609,6 +617,6 @@ public class J3MLoader implements AssetLoader { nodesLoaderDelegate.setAssetManager(assetManager); } } - } + } }