blob: 887ba5e6db53c27b50c3c61d0f32df15f6e0121b [file] [log] [blame]
/*
* Copyright (c) 2009-2010 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);
texKey.setAsCube(cubic);
try {
Texture loadedTexture = assetManager.loadTexture(texKey);
textures[texUnit].setImage(loadedTexture.getImage());
textures[texUnit].setMinFilter(loadedTexture.getMinFilter());
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());
}
}
private void readTextureUnitStatement(Statement statement){
String[] split = statement.getLine().split(" ", 2);
String keyword = split[0];
if (keyword.equals("texture")){
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.Clamp);
}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");
}
if (blend){
RenderState rs = mat.getAdditionalRenderState();
rs.setAlphaTest(true);
rs.setAlphaFallOff(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);
diffuse = null;
specular = null;
shinines = 0f;
vcolor = false;
blend = false;
texUnit = 0;
separateTexCoord = false;
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();
readMaterial(statement);
Material mat = compileMaterial();
list.put(matName, 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();
}
}
}
}