/***********************************************************************
* mt4j Copyright (c) 2008 - 2009 C.Ruff, Fraunhofer-Gesellschaft All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
***********************************************************************/
package org.mt4j.util.modelImporter;
import java.io.FileNotFoundException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;
import org.mt4j.components.visibleComponents.shapes.mesh.MTTriangleMesh;
import org.mt4j.util.modelImporter.file3ds.Model3dsFileFactory;
import org.mt4j.util.modelImporter.fileObj.ModelObjFileFactory;
import processing.core.PApplet;
/**
* A factory for creating ModelImporter objects.
* @author Christopher Ruff
*/
public abstract class ModelImporterFactory {
/** The suffix to factory. */
private static HashMap<String, Class<? extends ModelImporterFactory>> suffixToFactory;
static {
suffixToFactory = new HashMap<String, Class<? extends ModelImporterFactory>>();
//Add default factories for .3ds and for .obj files
registerModelImporterFactory(".3ds", Model3dsFileFactory.class);
registerModelImporterFactory(".obj", ModelObjFileFactory.class);
}
/**
* Gets the appropriate class for suffix.
*
* @param fileSuffix the file suffix
*
* @return the appropriate class for suffix
*/
private static Class<? extends ModelImporterFactory> getAppropriateClassForSuffix(String fileSuffix){
return suffixToFactory.get(fileSuffix);
}
/**
* Registers a ModelImporterFactory with this class.
* The registered class has to extend the abstract ModelImporterFactory class!
*
* @param fileSuffix the suffix of the files to be loaded by this factory (e.g. ".obj" or ".3ds")
* @param factory the factory to load the models with the specified suffix with. The factory has to be derived from ModelImporterFactory!
*/
public static void registerModelImporterFactory(String fileSuffix, Class<? extends ModelImporterFactory> factory){
suffixToFactory.put(fileSuffix, factory);
}
/**
* Unregister a importer factory class for a file type.
*
* @param factory the factory to load the models with the specified suffix with. The factory has to be derived from ModelImporterFactory!
*/
public static void unregisterModelImporterFactory(Class<? extends ModelImporterFactory> factory){
Set<String> suffixesInHashMap = suffixToFactory.keySet();
for (Iterator<String> iter = suffixesInHashMap.iterator(); iter.hasNext();) {
String suffix = (String) iter.next();
if (suffixToFactory.get(suffix).equals(factory)){
suffixToFactory.remove(suffix);
}
}
}
/**
* Loads a model from a file and creates an array of meshes.
* <p>
* Some models store the texture information flipped on the y-Axis.
* This can be solved by setting <code>flipTextureY</code> to true.
* <br>Vertex normals will be created for the geometry according to the crease angle.
* <br>A crease angle of 180 will result in an all smoothed model, creating a vertex normal
* that is interpolated from all neighbor faces normals.
* <br>A crease angle of zero (0) will result in a flat shaded geometry. Only face normals will
* be used then.
* <br>A crease angle of 89 will create hard edges at 90 degree angle faces and smooth faces with
* less then 90 degree normals. This would be ideal to generate normals for cubes and models with
* many sharp 90 degree angles.
* <br>The best crease angle for a model has to be found by testing different crease angles.
*
* @param pa the parent processing applet
* @param pathToModel the absolute path of the model file
* @param creaseAngle the crease angle, see method description for info
* @param flipTextureY flag whether or not to flip the texture vertical
* @param flipTextureX flag whether or not to flip the texture horizontal
*
* @return the MT triangle mesh[]
*
* @throws FileNotFoundException the file not found exception
*
* an array filled with the meshes created during the loading process
*/
public static MTTriangleMesh[] loadModel(PApplet pa, String pathToModel, float creaseAngle, boolean flipTextureY, boolean flipTextureX){
try {
String suffix = getFileSuffix(pathToModel);
ModelImporterFactory factory = getFactory(suffix);
if (factory != null){
return factory.loadModelImpl(pa, pathToModel, creaseAngle, flipTextureY, flipTextureX);
}
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return new MTTriangleMesh[]{};
}
/**
* Gets the factory.
*
* @param fileSuffix the suffix of the file to be loaded by the factory (e.g. ".obj" or ".3ds")
*
* @return the factory
*
* @throws IllegalAccessException the illegal access exception
* @throws InstantiationException the instantiation exception
* @throws RuntimeException the runtime exception
*
* the factory to load the model with if a appropriate factory was found
*/
private static ModelImporterFactory getFactory(String fileSuffix) throws IllegalAccessException, InstantiationException{
Class<? extends ModelImporterFactory> modelFactoryClass = getAppropriateClassForSuffix(fileSuffix);
//Get, create instance and return a appropriate factory object if found
if (modelFactoryClass != null){
try {
ModelImporterFactory modelFactory = modelFactoryClass.newInstance();
System.out.println("Found and created model factory for handling files: \"" + fileSuffix + "\"" + " Factory: " + modelFactory.getClass().getName());
return modelFactory;
}catch (InstantiationException e) {
throw new InstantiationException("The ModelImporterFactory \"" + modelFactoryClass.getName() + "\" has to have a constructor without any parameters!");
} catch (IllegalAccessException e) {
throw new IllegalAccessException();
}
}else{
throw new RuntimeException("No appropriate factory class was found for handling files: \"" + fileSuffix + "\"");
}
}
/**
* Gets the file suffix.
*
* @param pathToFile the path to file
*
* @return the file suffix
*/
private static String getFileSuffix(String pathToFile){
int indexOfPoint = pathToFile.lastIndexOf(".");
String suffix;
if (indexOfPoint != -1){
suffix = pathToFile.substring(indexOfPoint, pathToFile.length());
suffix.toLowerCase();
}else{
suffix = "";
}
return suffix;
}
/**
* The model loading will put out debug information if set to true.
*
* @param debug the debug
*/
public abstract void setDebug(boolean debug);
/**
* Loads a model from a file and creates an array of meshes.
* <p>
* Some models store the texture information flipped on the y-Axis.
* This can be solved by setting <code>flipTextureY</code> to true.
* <br>Vertex normals will be created for the geometry according to the crease angle.
* <br>A crease angle of 180 will result in an all smoothed model, creating a vertex normal
* that is interpolated from all neighbor faces normals.
* <br>A crease angle of zero (0) will result in a flat shaded geometry. Only face normals will
* be used then.
* <br>A crease angle of 89 will create hard edges at 90 degree angle faces and smooth faces with
* less then 90 degree normals. This would be ideal to generate normals for cubes and models with
* many sharp 90 degree angles.
* <br>The best crease angle for a model has to be found by testing different crease angles.
*
* @param pa the parent processing applet
* @param pathToModel the absolute path of the model file
* @param creaseAngle the crease angle, see method description for info
* @param flipTextureY flag whether or not to flip the texture vertical
* @param flipTextureX flag whether or not to flip the texture horizontal
*
* @return the MT triangle mesh[]
*
* @throws FileNotFoundException the file not found exception
*
* an array filled with the meshes created during the loading process
*/
public abstract MTTriangleMesh[] loadModelImpl(PApplet pa, String pathToModel, float creaseAngle, boolean flipTextureY, boolean flipTextureX) throws FileNotFoundException;
}