Created
May 29, 2015 18:41
-
-
Save FyiurAmron/89523fa43cc3b624038d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package vax.libgdx; | |
import java.io.*; | |
import com.badlogic.gdx.Gdx; | |
import com.badlogic.gdx.files.FileHandle; | |
import com.badlogic.gdx.graphics.Color; | |
import com.badlogic.gdx.graphics.g3d.model.data.ModelMaterial; | |
import com.badlogic.gdx.graphics.g3d.model.data.ModelTexture; | |
import com.badlogic.gdx.utils.Array; | |
import com.badlogic.gdx.utils.ObjectMap; | |
import com.badlogic.gdx.utils.ObjectSet; | |
import vax.sys.MainLogger; | |
import java.net.URI; | |
import java.net.URISyntaxException; | |
import java.util.logging.Level; | |
import java.util.logging.Logger; | |
/** | |
* A dedicated, stand-alone Wavefront MTL (.mtl) parser/loader, intended for use with ObjLoader. | |
* <p> | |
* Currently supports all of most common MTL parameters. Note that you have to have a shader capable of processing the | |
* various Texture map/color attributes to be actually able to benefit from it. | |
* | |
* @author vaxquis | |
*/ | |
public class MtlLoader { | |
public static interface MtlProvider { | |
ObjectMap<String, ModelMaterial> get( FileHandle fileHandle ); | |
} | |
/** | |
* An MTL provider allowing to ignore explicit MTL naming in mtllib statements, providing all materials from a | |
* single file. | |
*/ | |
public static class SingleFileMtlProvider implements MtlProvider { | |
private final ObjectMap<String, ModelMaterial> singleMtl; | |
public SingleFileMtlProvider( String filename ) { | |
singleMtl = MtlLoader.load( filename ); | |
} | |
public SingleFileMtlProvider( FileHandle fileHandle ) { | |
singleMtl = MtlLoader.load( fileHandle ); | |
} | |
@Override | |
public ObjectMap<String, ModelMaterial> get( FileHandle fileHandle ) { | |
return singleMtl; | |
} | |
} | |
/** | |
* Default MTL provider; simply loads an MTL file from a requested handle. Suppresses all exceptions, but emits | |
* Gdx.app.error() warnings on them if logWarnings is set. | |
*/ | |
public static MtlProvider DEFAULT_MTL_PROVIDER = new MtlProvider() { | |
@Override | |
public ObjectMap<String, ModelMaterial> get( FileHandle fileHandle ) { | |
return MtlLoader.load( fileHandle ); | |
} | |
}; | |
private static ObjectMap<String, Integer> usageMap; | |
private static ObjectSet<String> unsupportedSet; | |
private static ModelMaterial DEFAULT_MATERIAL; | |
static final String DEFAULT_MATERIAL_NAME = "default"; | |
public static boolean logWarnings = true; | |
private static void initStaticData() { | |
if ( usageMap != null ) { | |
return; | |
} | |
usageMap = new ObjectMap<String, Integer>( 10 ); | |
usageMap.put( "map_ka", ModelTexture.USAGE_AMBIENT ); | |
usageMap.put( "map_kd", ModelTexture.USAGE_DIFFUSE ); | |
usageMap.put( "map_ks", ModelTexture.USAGE_SPECULAR ); | |
usageMap.put( "map_ke", ModelTexture.USAGE_EMISSIVE ); // popular extension | |
usageMap.put( "map_ns", ModelTexture.USAGE_SHININESS ); | |
usageMap.put( "map_d", ModelTexture.USAGE_TRANSPARENCY ); | |
usageMap.put( "map_bump", ModelTexture.USAGE_BUMP ); // popular extension | |
usageMap.put( "bump", ModelTexture.USAGE_BUMP ); | |
usageMap.put( "refl", ModelTexture.USAGE_REFLECTION ); | |
usageMap.put( "disp", ModelTexture.USAGE_NORMAL ); | |
unsupportedSet = new ObjectSet<String>( 6 ); | |
unsupportedSet.add( "illum" ); // illumination model - unsupported | |
unsupportedSet.add( "tf" ); // transmission filter - currently unsupported | |
unsupportedSet.add( "ni" ); // optical density - currently unsupported | |
unsupportedSet.add( "sharpness" ); // reflection sharpness - currently unsupported | |
unsupportedSet.add( "map_aat" ); // per-texture antialiasing - currently unsupported | |
unsupportedSet.add( "decal" ); // decal scalar texture - currently unsupported | |
} | |
private MtlLoader() { | |
throw new UnsupportedOperationException(); | |
} | |
private static Color parseColor( String[] tokens ) { | |
float r = Float.parseFloat( tokens[1] ); | |
float g = Float.parseFloat( tokens[2] ); | |
float b = Float.parseFloat( tokens[3] ); | |
float a = ( tokens.length <= 4 ) | |
? 1 | |
: Float.parseFloat( tokens[4] ); | |
return new Color( r, g, b, a ); | |
} | |
private static ModelMaterial createMaterial( String name ) { | |
ModelMaterial mat = new ModelMaterial(); | |
mat.diffuse = new Color( Color.WHITE ); | |
mat.specular = new Color( Color.WHITE ); | |
mat.id = name; | |
return mat; | |
} | |
static ModelMaterial getDefaultMaterial() { | |
if ( DEFAULT_MATERIAL == null ) { | |
DEFAULT_MATERIAL = createMaterial( DEFAULT_MATERIAL_NAME ); | |
} | |
return DEFAULT_MATERIAL; | |
} | |
/** | |
* Loads a Wavefront MTL material file from an internal file with a given name. | |
* | |
* @param filename | |
* @return | |
*/ | |
public static ObjectMap<String, ModelMaterial> load( String filename ) { | |
return load( Gdx.files.internal( filename ) ); | |
} | |
/** | |
* Loads a Wavefront MTL material file for a file handle. | |
* | |
* @param file | |
* @return | |
*/ | |
@SuppressWarnings( "AssignmentToForLoopParameter" ) | |
public static ObjectMap<String, ModelMaterial> load( FileHandle file ) { | |
if ( !file.exists() ) { | |
throw new IllegalArgumentException( "file '" + file + "' doesn't exist" ); | |
} | |
initStaticData(); | |
ObjectMap<String, ModelMaterial> materials = new ObjectMap<String, ModelMaterial>(); | |
ModelMaterial mat = getDefaultMaterial(); // to allow parsing slightly malformed MTL files (no newmtl statement) | |
BufferedReader reader = null; | |
try { | |
reader = new BufferedReader( new InputStreamReader( file.read() ), 4096 ); | |
for( String line = reader.readLine(); line != null; line = reader.readLine() ) { | |
line = line.trim(); | |
String[] tokens = line.split( "\\s+" ); | |
if ( tokens[0].length() == 0 || tokens[0].charAt( 0 ) == '#' ) { // line comment or empty line | |
continue; | |
} | |
final String key = tokens[0].toLowerCase(); | |
if ( key.equals( "newmtl" ) ) { // new material | |
mat = ( tokens.length <= 1 ) | |
? getDefaultMaterial() | |
: createMaterial( tokens[1].replace( '.', '_' ) ); | |
materials.put( mat.id, mat ); | |
} else if ( key.equals( "ka" ) ) { // ambient color | |
mat.ambient = parseColor( tokens ); | |
} else if ( key.equals( "kd" ) ) { // diffuse color | |
mat.diffuse = parseColor( tokens ); | |
} else if ( key.equals( "ks" ) ) { // specular color | |
mat.specular = parseColor( tokens ); | |
} else if ( key.equals( "ke" ) ) { // emissive color | |
mat.emissive = parseColor( tokens ); | |
} else if ( key.equals( "tr" ) || key.equals( "d" ) ) { // transmission/dissolve (alpha) | |
mat.opacity = Float.parseFloat( tokens[1] ); | |
} else if ( key.equals( "ns" ) ) { // shininess exponent | |
mat.shininess = Float.parseFloat( tokens[1] ); | |
} else if ( unsupportedSet.contains( key ) ) { | |
// Gdx.app.error( "MtlLoader", "unsupported MTL statement '" + tokens[0] + "'" ); | |
} else { | |
Integer usage = usageMap.get( key ); | |
if ( usage != null ) { | |
ModelTexture tex = new ModelTexture(); | |
tex.usage = usage; | |
MainLogger.info( "pre-normalize:", file.parent().child( tokens[1] ) ); // debug | |
//tex.fileName = VaxApp.getPathProvider().normalize( file.parent().child( tokens[1] ).path() ); | |
try { | |
tex.fileName = new URI( file.parent().child( tokens[1] ).path() ).normalize().getPath(); | |
} catch ( Exception ex ) { | |
throw new RuntimeException(ex); | |
} | |
MainLogger.info( "post-normalize:", tex.fileName ); // debug | |
if ( mat.textures == null ) { | |
mat.textures = new Array<ModelTexture>( 1 ); | |
} | |
mat.textures.add( tex ); | |
} else if ( logWarnings ) { | |
Gdx.app.error( "MtlLoader.load()", "unknown MTL statement '" + tokens[0] + "'" ); | |
} | |
} | |
} | |
} catch ( IOException ex ) { | |
if ( logWarnings ) { | |
Gdx.app.error( "MtlLoader.load()", ex.toString() ); | |
} | |
return null; | |
} finally { | |
if ( reader != null ) { | |
try { | |
reader.close(); | |
} catch ( IOException ex ) { | |
Gdx.app.error( "MtlLoader.load()", ex.toString() ); | |
} | |
} | |
} | |
return materials; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment