/* * Copyright (c) 2009-2012 jMonkeyEngine * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name of 'jMonkeyEngine' nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package com.jme3.scene.plugins.ogre; import com.jme3.asset.*; import com.jme3.material.Material; import com.jme3.material.MaterialList; import com.jme3.material.RenderState; import com.jme3.math.ColorRGBA; import com.jme3.scene.plugins.ogre.matext.MaterialExtensionLoader; import com.jme3.scene.plugins.ogre.matext.MaterialExtensionSet; import com.jme3.scene.plugins.ogre.matext.OgreMaterialKey; import com.jme3.texture.Texture; import com.jme3.texture.Texture.WrapMode; import com.jme3.texture.Texture2D; 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.Arrays; import java.util.List; import java.util.Scanner; import java.util.logging.Level; import java.util.logging.Logger; public class MaterialLoader implements AssetLoader { private static final Logger logger = Logger.getLogger(MaterialLoader.class.getName()); private String folderName; private AssetManager assetManager; private ColorRGBA ambient, diffuse, specular, emissive; private Texture[] textures = new Texture[4]; private String texName; private String matName; private float shinines; private boolean vcolor = false; private boolean blend = false; private boolean twoSide = false; private boolean noLight = false; private boolean separateTexCoord = false; private int texUnit = 0; private ColorRGBA readColor(String content){ String[] split = content.split("\\s"); ColorRGBA color = new ColorRGBA(); color.r = Float.parseFloat(split[0]); color.g = Float.parseFloat(split[1]); color.b = Float.parseFloat(split[2]); if (split.length >= 4){ color.a = Float.parseFloat(split[3]); } return color; } private void readTextureImage(String content){ // texture image def String path = null; // find extension int extStart = content.lastIndexOf("."); for (int i = extStart; i < content.length(); i++){ char c = content.charAt(i); if (Character.isWhitespace(c)){ // extension ends here path = content.substring(0, i).trim(); content = content.substring(i+1).trim(); break; } } if (path == null){ path = content.trim(); content = ""; } Scanner lnScan = new Scanner(content); String mips = null; String type = null; if (lnScan.hasNext()){ // more params type = lnScan.next(); // if (!lnScan.hasNext("\n") && lnScan.hasNext()){ // mips = lnScan.next(); // if (lnScan.hasNext()){ // even more params.. // will have to ignore // } // } } boolean genMips = true; boolean cubic = false; if (type != null && type.equals("0")) genMips = false; if (type != null && type.equals("cubic")){ cubic = true; } TextureKey texKey = new TextureKey(folderName + path, false); texKey.setGenerateMips(genMips); if (cubic) { texKey.setTextureTypeHint(Texture.Type.CubeMap); } try { Texture loadedTexture = assetManager.loadTexture(texKey); textures[texUnit].setImage(loadedTexture.getImage()); textures[texUnit].setMinFilter(loadedTexture.getMinFilter()); textures[texUnit].setMagFilter(loadedTexture.getMagFilter()); textures[texUnit].setAnisotropicFilter(loadedTexture.getAnisotropicFilter()); textures[texUnit].setKey(loadedTexture.getKey()); // XXX: Is this really neccessary? textures[texUnit].setWrap(WrapMode.Repeat); if (texName != null){ textures[texUnit].setName(texName); texName = null; }else{ textures[texUnit].setName(texKey.getName()); } } catch (AssetNotFoundException ex){ logger.log(Level.WARNING, "Cannot locate {0} for material {1}", new Object[]{texKey, matName}); textures[texUnit].setImage(PlaceholderAssets.getPlaceholderImage(assetManager)); textures[texUnit].setKey(texKey); } } private void readTextureUnitStatement(Statement statement){ String[] split = statement.getLine().split(" ", 2); String keyword = split[0]; if (keyword.equals("texture")){ if (split.length < 2) { logger.log(Level.WARNING, "Invalid texture directive, no image specified at [{0}]", statement.getLineNumber()); return; } readTextureImage(split[1]); }else if (keyword.equals("tex_address_mode")){ String mode = split[1]; if (mode.equals("wrap")){ textures[texUnit].setWrap(WrapMode.Repeat); }else if (mode.equals("clamp")){ textures[texUnit].setWrap(WrapMode.EdgeClamp); }else if (mode.equals("mirror")){ textures[texUnit].setWrap(WrapMode.MirroredRepeat); }else if (mode.equals("border")){ textures[texUnit].setWrap(WrapMode.BorderClamp); } }else if (keyword.equals("filtering")){ // ignored.. only anisotropy is considered }else if (keyword.equals("tex_coord_set")){ int texCoord = Integer.parseInt(split[1]); if (texCoord == 1){ separateTexCoord = true; } }else if (keyword.equals("max_anisotropy")){ int amount = Integer.parseInt(split[1]); textures[texUnit].setAnisotropicFilter(amount); }else{ logger.log(Level.WARNING, "Unsupported texture_unit directive: {0}", keyword); } } private void readTextureUnit(Statement statement){ String[] split = statement.getLine().split(" ", 2); // name is optional if (split.length == 2){ texName = split[1]; }else{ texName = null; } textures[texUnit] = new Texture2D(); for (Statement texUnitStat : statement.getContents()){ readTextureUnitStatement(texUnitStat); } if (textures[texUnit].getImage() != null){ texUnit++; }else{ // no image was loaded, ignore textures[texUnit] = null; } } private void readPassStatement(Statement statement){ // read until newline String[] split = statement.getLine().split(" ", 2); String keyword = split[0]; if (keyword.equals("diffuse")){ if (split[1].equals("vertexcolour")){ // use vertex colors diffuse = ColorRGBA.White; vcolor = true; }else{ diffuse = readColor(split[1]); } }else if(keyword.equals("ambient")) { if (split[1].equals("vertexcolour")){ // use vertex colors ambient = ColorRGBA.White; }else{ ambient = readColor(split[1]); } }else if (keyword.equals("emissive")){ emissive = readColor(split[1]); }else if (keyword.equals("specular")){ String[] subsplit = split[1].split("\\s"); specular = new ColorRGBA(); specular.r = Float.parseFloat(subsplit[0]); specular.g = Float.parseFloat(subsplit[1]); specular.b = Float.parseFloat(subsplit[2]); float unknown = Float.parseFloat(subsplit[3]); if (subsplit.length >= 5){ // using 5 float values specular.a = unknown; shinines = Float.parseFloat(subsplit[4]); }else{ // using 4 float values specular.a = 1f; shinines = unknown; } }else if (keyword.equals("texture_unit")){ readTextureUnit(statement); }else if (keyword.equals("scene_blend")){ String mode = split[1]; if (mode.equals("alpha_blend")){ blend = true; } }else if (keyword.equals("cull_hardware")){ String mode = split[1]; if (mode.equals("none")){ twoSide = true; } }else if (keyword.equals("cull_software")){ // ignore }else if (keyword.equals("lighting")){ String isOn = split[1]; if (isOn.equals("on")){ noLight = false; }else if (isOn.equals("off")){ noLight = true; } }else{ logger.log(Level.WARNING, "Unsupported pass directive: {0}", keyword); } } private void readPass(Statement statement){ String name; String[] split = statement.getLine().split(" ", 2); if (split.length == 1){ // no name name = null; }else{ name = split[1]; } for (Statement passStat : statement.getContents()){ readPassStatement(passStat); } texUnit = 0; } private void readTechnique(Statement statement){ String[] split = statement.getLine().split(" ", 2); String name; if (split.length == 1){ // no name name = null; }else{ name = split[1]; } for (Statement techStat : statement.getContents()){ readPass(techStat); } } private void readMaterialStatement(Statement statement){ if (statement.getLine().startsWith("technique")){ readTechnique(statement); }else if (statement.getLine().startsWith("receive_shadows")){ String isOn = statement.getLine().split("\\s")[1]; if (isOn != null && isOn.equals("true")){ } } } @SuppressWarnings("empty-statement") private void readMaterial(Statement statement){ for (Statement materialStat : statement.getContents()){ readMaterialStatement(materialStat); } } private Material compileMaterial(){ Material mat; if (noLight){ mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); }else{ mat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); } mat.setName(matName); if (blend){ RenderState rs = mat.getAdditionalRenderState(); mat.setFloat("AlphaDiscardThreshold", 0.01f); rs.setBlendMode(RenderState.BlendMode.Alpha); if (twoSide){ rs.setFaceCullMode(RenderState.FaceCullMode.Off); } // rs.setDepthWrite(false); mat.setTransparent(true); if (!noLight){ // mat.setBoolean("UseAlpha", true); } }else{ if (twoSide){ RenderState rs = mat.getAdditionalRenderState(); rs.setFaceCullMode(RenderState.FaceCullMode.Off); } } if (!noLight){ if (shinines > 0f) { mat.setFloat("Shininess", shinines); } else { mat.setFloat("Shininess", 16f); // set shininess to some value anyway.. } if (vcolor) mat.setBoolean("UseVertexColor", true); if (textures[0] != null) mat.setTexture("DiffuseMap", textures[0]); mat.setBoolean("UseMaterialColors", true); if(diffuse != null){ mat.setColor("Diffuse", diffuse); }else{ mat.setColor("Diffuse", ColorRGBA.White); } if(ambient != null){ mat.setColor("Ambient", ambient); }else{ mat.setColor("Ambient", ColorRGBA.DarkGray); } if(specular != null){ mat.setColor("Specular", specular); }else{ mat.setColor("Specular", ColorRGBA.Black); } if (emissive != null){ mat.setColor("GlowColor", emissive); } }else{ if (vcolor) { mat.setBoolean("VertexColor", true); } if (textures[0] != null && textures[1] == null){ if (separateTexCoord){ mat.setTexture("LightMap", textures[0]); mat.setBoolean("SeparateTexCoord", true); }else{ mat.setTexture("ColorMap", textures[0]); } }else if (textures[1] != null){ mat.setTexture("ColorMap", textures[0]); mat.setTexture("LightMap", textures[1]); if (separateTexCoord){ mat.setBoolean("SeparateTexCoord", true); } } if(diffuse != null){ mat.setColor("Color", diffuse); } if (emissive != null){ mat.setColor("GlowColor", emissive); } } noLight = false; Arrays.fill(textures, null); ambient = null; diffuse = null; specular = null; emissive = null; shinines = 0f; vcolor = false; blend = false; texUnit = 0; separateTexCoord = false; twoSide = false; matName = null; texName = null; return mat; } private MaterialList load(AssetManager assetManager, AssetKey key, InputStream in) throws IOException{ folderName = key.getFolder(); this.assetManager = assetManager; MaterialList list = null; List<Statement> statements = BlockLanguageParser.parse(in); for (Statement statement : statements){ if (statement.getLine().startsWith("import")){ MaterialExtensionSet matExts = null; if (key instanceof OgreMaterialKey){ matExts = ((OgreMaterialKey)key).getMaterialExtensionSet(); } if (matExts == null){ throw new IOException("Must specify MaterialExtensionSet when loading\n"+ "Ogre3D materials with extended materials"); } list = new MaterialExtensionLoader().load(assetManager, key, matExts, statements); break; }else if (statement.getLine().startsWith("material")){ if (list == null){ list = new MaterialList(); } String[] split = statement.getLine().split(" ", 2); matName = split[1].trim(); if (matName.startsWith("\"") && matName.endsWith("\"")) { matName = matName.substring(1, matName.length() - 1); } readMaterial(statement); Material mat = compileMaterial(); list.put(mat.getName(), mat); } } return list; } public Object load(AssetInfo info) throws IOException { InputStream in = null; try { in = info.openStream(); return load(info.getManager(), info.getKey(), in); } finally { if (in != null){ in.close(); } } } }