/** * Copyright (c) 2003-2009, Xith3D Project Group all rights reserved. * * Portions based on the Java3D interface, Copyright by Sun Microsystems. * Many thanks to the developers of Java3D and Sun Microsystems for their * innovation and design. * * 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 the 'Xith3D Project Group' 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) A * RISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE */ package org.xith3d.loaders.models; import java.io.File; import java.io.IOException; import java.net.URL; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import org.jagatoo.datatypes.NamedObject; import org.jagatoo.loaders.IncorrectFormatException; import org.jagatoo.loaders.ParsingException; import org.jagatoo.loaders.models._util.AnimationFactory; import org.jagatoo.loaders.models._util.AppearanceFactory; import org.jagatoo.loaders.models._util.GeometryFactory; import org.jagatoo.loaders.models._util.GroupType; import org.jagatoo.loaders.models._util.LoaderUtils; import org.jagatoo.loaders.models._util.NodeFactory; import org.jagatoo.loaders.models._util.SpecialItemsHandler; import org.jagatoo.loaders.models.ac3d.AC3DPrototypeLoader; import org.jagatoo.loaders.models.ase.AseReader; import org.jagatoo.loaders.models.bsp.BSPPrototypeLoader; import org.jagatoo.loaders.models.bsp.BSPTextureAnimator; import org.jagatoo.loaders.models.md2.MD2File; import org.jagatoo.loaders.models.md3.MD3File; import org.jagatoo.loaders.models.md5.MD5AnimationReader; import org.jagatoo.loaders.models.md5.MD5MeshReader; import org.jagatoo.loaders.models.obj.OBJPrototypeLoader; import org.jagatoo.loaders.models.tds.TDSFile; import org.openmali.vecmath2.Matrix4f; import org.xith3d.loaders.models.animations.ModelAnimation; import org.xith3d.loaders.models.conversion.XithAnimationFactory; import org.xith3d.loaders.models.conversion.XithAppearanceFactory; import org.xith3d.loaders.models.conversion.XithGeometryFactory; import org.xith3d.loaders.models.conversion.XithNodeFactory; import org.xith3d.loaders.models.util.specific.bsp.BSPTextureAnimatedShape; import org.xith3d.resources.ResourceLocator; import org.xith3d.scenegraph.Fog; import org.xith3d.scenegraph.GroupNode; import org.xith3d.scenegraph.Light; import org.xith3d.scenegraph.Shape3D; import org.xith3d.scenegraph.Sound; import org.xith3d.scenegraph.TransformGroup; import org.xith3d.scenegraph.View; import org.xith3d.scenegraph.Geometry.Optimization; import org.xith3d.scenegraph.primitives.SkyBox; /** * The abstract Loader class is used to specify the location * and elements of a file format to load. * The class is used to give loaders of various * file formats a common public interface. * * Ideally the Scene and Model classes will be extended * to give the user a consistent interface to extract the * data. * * @see org.xith3d.loaders.models.base.LoadedGraph * @see org.xith3d.loaders.models.base.Scene * @see org.xith3d.loaders.models.Model * * @author Amos Wenger (aka BlueSky) * @author Marvin Froehlich (aka Qudus) * @author Andrew Hanson (aka Patheros) added canLoad */ public class ModelLoader { protected static final class SpecialItemsHandlerImpl implements SpecialItemsHandler { private final Model model; private ArrayList<TransformGroup> nestedTransforms = null; private HashSet<TransformGroup> nestedTransformsSet = null; private ArrayList<Shape3D> shapes = new ArrayList<Shape3D>(); private ArrayList<Light> lights = null; private ArrayList<Fog> fogs = null; private ArrayList<Sound> sounds = null; private ArrayList<View> cameras = null; private ArrayList<Matrix4f> spawnTransforms = null; private ArrayList<TransformGroup> mountTransforms = null; private ArrayList<ModelAnimation> animations = null; public void addSpecialItem( SpecialItemType type, String name, Object item ) { switch ( type ) { case MAIN_GROUP: model.setMainGroup( (GroupNode)item ); //( (GroupNode)item ).setRenderable( false ); if ( ( name != null ) && ( name.length() > 0 ) ) model.addNamedObject( name, (NamedObject)item ); break; case SHAPE: shapes.add( (Shape3D)item ); if ( ( name != null ) && ( name.length() > 0 ) ) model.addNamedObject( name, (NamedObject)item ); break; case SPAWN_TRANSFORM: if ( spawnTransforms == null ) spawnTransforms = new ArrayList<Matrix4f>(); spawnTransforms.add( (Matrix4f)item ); break; case MOUNT_TRANSFORM: TransformGroup mt = new TransformGroup( (Matrix4f)item ); mt.setName( name ); if ( mountTransforms == null ) mountTransforms = new ArrayList<TransformGroup>(); mountTransforms.add( mt ); break; case NESTED_TRANSFORM: if ( nestedTransformsSet == null ) nestedTransformsSet = new HashSet<TransformGroup>(); if ( nestedTransforms == null ) nestedTransforms = new ArrayList<TransformGroup>(); if ( !nestedTransformsSet.contains( item ) ) { nestedTransformsSet.add( (TransformGroup)item ); nestedTransforms.add( (TransformGroup)item ); if ( ( name != null ) && ( name.length() > 0 ) ) model.addNamedObject( name, (NamedObject)item ); } break; case ITEM: break; case SUB_MODEL: /* try { Model model = modelsCache.get( name ); if ( model == null ) { model = ModelLoader.getInstance().loadModel( new URL( name ), "", worldScale ); modelsCache.put( name, model ); } TransformGroup tg = new TransformGroup(); tg.getTransform().set( (Matrix4f)item ); tg.updateTransform(); model = model.getSharedInstance(); //model.setShowBounds( true ); tg.addChild( model ); scene.addChild( tg ); //model.updateBounds( true ); } catch ( Exception e ) { e.printStackTrace(); } */ break; case LIGHT: if ( lights == null ) lights = new ArrayList<Light>(); lights.add( (Light)item ); if ( ( name != null ) && ( name.length() > 0 ) ) model.addNamedObject( name, (NamedObject)item ); break; case FOG: if ( fogs == null ) fogs = new ArrayList<Fog>(); fogs.add( (Fog)item ); if ( ( name != null ) && ( name.length() > 0 ) ) model.addNamedObject( name, (NamedObject)item ); break; case SOUND: if ( sounds == null ) sounds = new ArrayList<Sound>(); sounds.add( (Sound)item ); if ( ( name != null ) && ( name.length() > 0 ) ) model.addNamedObject( name, (NamedObject)item ); break; case SKYBOX: model.setSkyBox( (SkyBox)item ); if ( ( name != null ) && ( name.length() > 0 ) ) model.addNamedObject( name, (NamedObject)item ); break; case NAMED_OBJECT: model.addNamedObject( name, (NamedObject)item ); break; } } public NamedObject createTextureAnimator( BSPTextureAnimator animator, NamedObject shapeObj ) { Shape3D shape = (Shape3D)shapeObj; BSPTextureAnimatedShape animatedShape = new BSPTextureAnimatedShape( shape.getGeometry(), shape.getAppearance(), animator ); animatedShape.setName( shape.getName() ); return ( animatedShape ); } public void addAnimation( Object animation ) { if ( animations == null ) animations = new ArrayList<ModelAnimation>(); animations.add( (ModelAnimation)animation ); } public void flush() { if ( nestedTransforms != null ) { model.setNestedTransforms( nestedTransforms.toArray( new TransformGroup[ nestedTransforms.size() ] ) ); nestedTransforms = null; nestedTransformsSet = null; } model.setShapes( shapes.toArray( new Shape3D[ shapes.size() ] ) ); shapes.clear(); if ( lights != null ) { model.setLights( lights.toArray( new Light[ lights.size() ] ) ); lights = null; } if ( fogs != null ) { model.setFogs( fogs.toArray( new Fog[ fogs.size() ] ) ); fogs = null; } if ( sounds != null ) { model.setSounds( sounds.toArray( new Sound[ sounds.size() ] ) ); sounds = null; } if ( cameras != null ) { model.setCameras( cameras.toArray( new View[ cameras.size() ] ) ); cameras = null; } if ( animations != null ) { model.setAnimations( animations.toArray( new ModelAnimation[ animations.size() ] ) ); animations = null; } if ( mountTransforms != null ) { model.setMountTransforms( mountTransforms.toArray( new TransformGroup[ mountTransforms.size() ] ) ); mountTransforms = null; } if ( spawnTransforms != null ) { model.setSpawnTransforms( spawnTransforms.toArray( new Matrix4f[ spawnTransforms.size() ] ) ); spawnTransforms = null; } } public SpecialItemsHandlerImpl( Model model ) { this.model = model; } } public static final float SCALE = 1.0f; public static final String STANDARD_MODEL_FILE_EXTENSION = "md3"; private static final XithAppearanceFactory appFactory = new XithAppearanceFactory(); private static final XithNodeFactory nodeFactory = new XithNodeFactory(); private static final XithAnimationFactory animFactory = new XithAnimationFactory(); private static ModelLoader singletonInstance = null; /** * This flag enables the loading of light objects into the scene. */ public static final int LOAD_LIGHT_NODES = 1; /** * This flag enables the loading of fog objects into the scene. */ public static final int LOAD_FOG_NODES = 2; /** * This flag enables the loading of sound objects into the scene. */ public static final int LOAD_SOUND_NODES = 4; /** * This flag enables the loading of camera (view) objects into the scene. */ public static final int LOAD_CAMERAS = 8; /** * This flag enables the loading of camera (view) objects into the scene. */ public static final int LOAD_SUB_MODELS = 16; /** * This flag makes the loader to convert the model from z-up * to y-up if the source model format is known to use z-up * by default (like 3DS, MD2, MD3, MD5 and BSP). */ public static final int CONVERT_Z_UP_TO_Y_UP_IF_EXPECTED = 32; /** * This flag forces the conversion from Z-up to Y-up for all model types. */ public static final int ALWAYS_CONVERT_Z_UP_TO_Y_UP = 64; public static final int DEFAULT_FLAGS = ~0 & ~ALWAYS_CONVERT_Z_UP_TO_Y_UP; protected static enum SourceModelType { AC3D( false, Optimization.USE_DISPLAY_LISTS ), ASE( true, Optimization.USE_DISPLAY_LISTS ), BSP( true, Optimization.USE_DISPLAY_LISTS ), CAL3D( false, Optimization.NONE ), COLLADA( false, Optimization.NONE ), MD2( true, Optimization.NONE ), MD3( true, Optimization.NONE ), MD5( true, Optimization.NONE ), MS3D( false, Optimization.NONE ), OBJ( false, Optimization.USE_DISPLAY_LISTS ), TDS( true, Optimization.USE_DISPLAY_LISTS ), ; private final boolean hasDefaultZUp; private final Optimization defaultOptimization; public final boolean hasDefaultZUp() { return ( hasDefaultZUp ); } public final boolean getConvertFlag( int flags ) { if ( ( flags & ALWAYS_CONVERT_Z_UP_TO_Y_UP ) != 0 ) { return ( true ); } else if ( ( flags & CONVERT_Z_UP_TO_Y_UP_IF_EXPECTED ) != 0 ) { return ( hasDefaultZUp ); } else { return ( false ); } } public final Optimization getDefaultOptimization() { return ( defaultOptimization ); } private SourceModelType( boolean hasDefaultZUp, Optimization defaultOptimization ) { this.hasDefaultZUp = hasDefaultZUp; this.defaultOptimization = defaultOptimization; } } /** Stores the types of objects that the user wishes to load.*/ private int loadFlags; /** * This method sets the load flags for the file. The flags should * equal 0 by default (which tells the loader to only load geometry). */ public final void setFlags( int flags ) { loadFlags = flags; } /** * @return the current loading flags setting. */ public final int getFlags() { return ( loadFlags ); } /** * This method sets the specified load flag for the file. * The flags should equal 0 by default (which tells the loader to only load geometry). * * @param flag the flag to set/reset * @param enable true to enable the flag */ public final void setFlag( int flag, boolean enable ) { if ( enable ) loadFlags |= flag; else loadFlags &= ~flag; } /** * @return the current loading flag setting. */ public final boolean getFlag( int flag ) { return ( ( loadFlags & flag ) > 0 ); } protected SourceModelType extractModelType( URL url, String filename ) { if ( filename.endsWith( ".ac" ) ) return ( SourceModelType.AC3D ); if ( filename.endsWith( ".ase" ) ) return ( SourceModelType.ASE ); if ( filename.endsWith( ".bsp" ) ) return ( SourceModelType.BSP ); if ( filename.endsWith( ".cfg" ) ) return ( SourceModelType.CAL3D ); if ( filename.endsWith( ".dae" ) ) return ( SourceModelType.COLLADA ); if ( filename.endsWith( ".md2" ) ) return ( SourceModelType.MD2 ); if ( filename.endsWith( ".md2" ) ) return ( SourceModelType.MD2 ); if ( filename.endsWith( ".md3" ) ) return ( SourceModelType.MD3 ); if ( filename.endsWith( ".md5mesh" ) ) return ( SourceModelType.MD5 ); if ( filename.endsWith( ".obj" ) ) return ( SourceModelType.OBJ ); if ( filename.endsWith( ".3ds" ) ) return ( SourceModelType.TDS ); if ( url == null ) throw new Error( "Can't load the model file \"" + filename + "\"." ); throw new Error( "Can't load the model file \"" + url.toString() + "\"." ); } protected final SourceModelType extractModelType( URL url ) { return ( extractModelType( url, url.getFile().toLowerCase() ) ); } protected final SourceModelType extractModelType( String filename ) { return ( extractModelType( null, filename ) ); } protected Model loadModel( URL url, String filenameBase, SourceModelType modelType, URL baseURL, String skin, float scale, int flags, AppearanceFactory appFactory, GeometryFactory geomFactory, NodeFactory nodeFactory, AnimationFactory animFactory, SpecialItemsHandler siHandler, Model model ) throws IOException, IncorrectFormatException, ParsingException { boolean convertZup2Yup = modelType.getConvertFlag( flags ); switch ( modelType ) { case AC3D: AC3DPrototypeLoader.load( url.openStream(), baseURL, appFactory, geomFactory, nodeFactory, true, model, siHandler ); break; case ASE: AseReader.load( url.openStream(), baseURL, appFactory, geomFactory, convertZup2Yup, scale, nodeFactory, animFactory, siHandler, model ); break; case BSP: BSPPrototypeLoader.load( url.openStream(), filenameBase, baseURL, geomFactory, true, 0.03f, appFactory, nodeFactory, model, GroupType.BSP_TREE, siHandler ); break; case CAL3D: break; case COLLADA: break; case MD2: MD2File.load( url.openStream(), baseURL, appFactory, skin, geomFactory, convertZup2Yup, scale, nodeFactory, animFactory, siHandler, model ); break; case MD3: MD3File.load( url.openStream(), baseURL, appFactory, geomFactory, convertZup2Yup, scale, nodeFactory, animFactory, siHandler, model ); break; case MD5: { Object[][][] boneWeights = MD5MeshReader.load( url.openStream(), baseURL, appFactory, skin, geomFactory, convertZup2Yup, scale, nodeFactory, animFactory, siHandler, model ); ( (SpecialItemsHandlerImpl)siHandler ).flush(); List< URL > animResources = new ResourceLocator( baseURL ).findAllResources( "md5anim", true, false ); for ( URL animURL: animResources ) { String filename = LoaderUtils.extractFilenameWithoutExt( animURL ); MD5AnimationReader.load( animURL.openStream(), filename, baseURL, appFactory, geomFactory, convertZup2Yup, scale, nodeFactory, model.getShapes(), boneWeights, animFactory, siHandler, model ); } } break; case MS3D: break; case OBJ: // TODO: Implement direct scaling! GroupNode rootGroup = model; if ( scale != 1.0f ) { TransformGroup scaleGroup = new TransformGroup(); scaleGroup.getTransform().setScale( scale ); model.addChild( scaleGroup ); model.setMainGroup( scaleGroup ); rootGroup = scaleGroup; } OBJPrototypeLoader.load( url.openStream(), baseURL, appFactory, skin, geomFactory, convertZup2Yup, scale, nodeFactory, siHandler, rootGroup ); break; case TDS: TDSFile.load( url.openStream(), baseURL, appFactory, geomFactory, convertZup2Yup, nodeFactory, animFactory, siHandler, model ); } return ( model ); } public Model loadModel( URL url, String filenameBase, URL baseURL, String skin, float scale, int flags ) throws IOException, IncorrectFormatException, ParsingException { SourceModelType modelType = extractModelType( url ); Model model = new Model(); model.setName( filenameBase ); XithGeometryFactory geomFactory = new XithGeometryFactory( modelType.getDefaultOptimization() ); SpecialItemsHandlerImpl siHandler = new SpecialItemsHandlerImpl( model ); model = loadModel( url, filenameBase, modelType, baseURL, skin, scale, flags, appFactory, geomFactory, nodeFactory, animFactory, siHandler, model ); siHandler.flush(); model.updateBounds( false ); return ( model ); } /** * This method loads the Model from a URL. * Any data files referenced by the model file are searched in the * following locations in the following order: * <ol> * <li>By absolute path as referenced in the model file</li> * <li>By relative filename (relative to the baseURL)</li> * <li>In case of textures see TextureLoader's TextureStreamLocator architecture</li> * </ol> * * @param url the URL to load the Model from. * @param skin the skin resource name * @param scale pre-scaling factor * @param flags loading flags */ public final Model loadModel( URL url, String skin, float scale, int flags ) throws IOException, IncorrectFormatException, ParsingException { return ( loadModel( url, LoaderUtils.extractFilenameWithoutExt( url ), LoaderUtils.extractBaseURL( url ), skin, scale, flags ) ); } /** * This method loads the Model from a URL. * Any data files referenced by the model file are searched in the * following locations in the following order: * <ol> * <li>By absolute path as referenced in the model file</li> * <li>By relative filename (relative to the baseURL)</li> * <li>In case of textures see TextureLoader's TextureStreamLocator architecture</li> * </ol> * * @param url the URL to load the Model from. * @param scale pre-scaling factor * @param flags loading flags */ public final Model loadModel( URL url, float scale, int flags ) throws IOException, IncorrectFormatException, ParsingException { return ( loadModel( url, null, scale, flags ) ); } /** * This method loads the Model from a URL. * Any data files referenced by the model file are searched in the * following locations in the following order: * <ol> * <li>By absolute path as referenced in the model file</li> * <li>By relative filename (relative to the baseURL)</li> * <li>In case of textures see TextureLoader's TextureStreamLocator architecture</li> * </ol> * * @param filename the filename to load the Model from * @param skin the skin resource name * @param scale pre-scaling factor * @param flags loading flags */ public final Model loadModel( String filename, String skin, float scale, int flags ) throws IOException, IncorrectFormatException, ParsingException { File file = new File( filename ); if ( !file.isAbsolute() ) file = file.getAbsoluteFile(); return ( loadModel( file.toURI().toURL(), skin, scale, flags ) ); } /** * This method loads the Model from a URL. * Any data files referenced by the model file are searched in the * following locations in the following order: * <ol> * <li>By absolute path as referenced in the model file</li> * <li>By relative filename (relative to the baseURL)</li> * <li>In case of textures see TextureLoader's TextureStreamLocator architecture</li> * </ol> * * @param filename the filename to load the Model from * @param scale pre-scaling factor * @param flags loading flags */ public final Model loadModel( String filename, float scale, int flags ) throws IOException, IncorrectFormatException, ParsingException { return ( loadModel( filename, null, scale, flags ) ); } /** * This method loads the Model from a URL. * Any data files referenced by the model file are searched in the * following locations in the following order: * <ol> * <li>By absolute path as referenced in the model file</li> * <li>By relative filename (relative to the baseURL)</li> * <li>In case of textures see TextureLoader's TextureStreamLocator architecture</li> * </ol> * * @param url the URL to load the Model from. * @param skin the skin resource name * @param scale pre-scaling factor */ public final Model loadModel( URL url, String skin, float scale ) throws IOException, IncorrectFormatException, ParsingException { return ( loadModel( url, skin, scale, getFlags() ) ); } /** * This method loads the Model from a URL. * Any data files referenced by the model file are searched in the * following locations in the following order: * <ol> * <li>By absolute path as referenced in the model file</li> * <li>By relative filename (relative to the baseURL)</li> * <li>In case of textures see TextureLoader's TextureStreamLocator architecture</li> * </ol> * * @param url the URL to load the Model from. * @param scale pre-scaling factor * @param flags loading flags */ public final Model loadModel( URL url, float scale ) throws IOException, IncorrectFormatException, ParsingException { return ( loadModel( url, scale, getFlags() ) ); } /** * This method loads the Model from a URL. * Any data files referenced by the model file are searched in the * following locations in the following order: * <ol> * <li>By absolute path as referenced in the model file</li> * <li>By relative filename (relative to the baseURL)</li> * <li>In case of textures see TextureLoader's TextureStreamLocator architecture</li> * </ol> * * @param filename the filename to load the Model from * @param skin the skin resource name * @param scale pre-scaling factor */ public final Model loadModel( String filename, String skin, float scale ) throws IOException, IncorrectFormatException, ParsingException { return ( loadModel( filename, skin, scale, getFlags() ) ); } /** * This method loads the Model from a URL. * Any data files referenced by the model file are searched in the * following locations in the following order: * <ol> * <li>By absolute path as referenced in the model file</li> * <li>By relative filename (relative to the baseURL)</li> * <li>In case of textures see TextureLoader's TextureStreamLocator architecture</li> * </ol> * * @param filename the filename to load the Model from * @param scale pre-scaling factor */ public final Model loadModel( String filename, float scale ) throws IOException, IncorrectFormatException, ParsingException { return ( loadModel( filename, null, scale, getFlags() ) ); } /** * This method loads the Model from a URL. * Any data files referenced by the model file are searched in the * following locations in the following order: * <ol> * <li>By absolute path as referenced in the model file</li> * <li>By relative filename (relative to the baseURL)</li> * <li>In case of textures see TextureLoader's TextureStreamLocator architecture</li> * </ol> * * @param url the URL to load the Model from. * @param skin the skin resource name */ public final Model loadModel( URL url, String skin ) throws IOException, IncorrectFormatException, ParsingException { return ( loadModel( url, skin, 1.0f, getFlags() ) ); } /** * This method loads the Model from a URL. * Any data files referenced by the model file are searched in the * following locations in the following order: * <ol> * <li>By absolute path as referenced in the model file</li> * <li>By relative filename (relative to the baseURL)</li> * <li>In case of textures see TextureLoader's TextureStreamLocator architecture</li> * </ol> * * @param url the URL to load the Model from. */ public final Model loadModel( URL url ) throws IOException, IncorrectFormatException, ParsingException { return ( loadModel( url, null ) ); } /** * This method loads the Model from a URL. * Any data files referenced by the model file are searched in the * following locations in the following order: * <ol> * <li>By absolute path as referenced in the model file</li> * <li>By relative filename (relative to the baseURL)</li> * <li>In case of textures see TextureLoader's TextureStreamLocator architecture</li> * </ol> * * @param filename the filename to load the Model from * @param skin the skin resource name */ public final Model loadModel( String filename, String skin ) throws IOException, IncorrectFormatException, ParsingException { return ( loadModel( filename, skin, 1.0f, getFlags() ) ); } /** * This method loads the Model from a URL. * Any data files referenced by the model file are searched in the * following locations in the following order: * <ol> * <li>By absolute path as referenced in the model file</li> * <li>By relative filename (relative to the baseURL)</li> * <li>In case of textures see TextureLoader's TextureStreamLocator architecture</li> * </ol> * * @param filename the filename to load the Model from */ public final Model loadModel( String filename ) throws IOException, IncorrectFormatException, ParsingException { return ( loadModel( filename, null ) ); } /** * Constructs a ModelLoader with the specified flags word. * * @param flags */ protected ModelLoader( int flags ) { this.loadFlags = flags; } /** * Constructs a ModelLoader with default flags. */ protected ModelLoader() { this( DEFAULT_FLAGS ); } /** * If you decide to use the Loader as a singleton, here is the method to * get the instance from. * * @return a singleton instance of the Loader */ public static ModelLoader getInstance() { if ( singletonInstance == null ) singletonInstance = new ModelLoader(); return ( singletonInstance ); } }