/*******************************************************************************
* Copyright 2011 See AUTHORS file.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
******************************************************************************/
package com.badlogic.gdx.graphics.g3d.loaders;
import java.util.HashMap;
import java.util.Map;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.g3d.ModelLoaderHints;
import com.badlogic.gdx.graphics.g3d.loaders.g3d.G3dLoader.G3dKeyframedModelLoader;
import com.badlogic.gdx.graphics.g3d.loaders.g3d.G3dLoader.G3dStillModelLoader;
import com.badlogic.gdx.graphics.g3d.loaders.g3d.G3dLoader.G3dSkeletonModelLoader;
import com.badlogic.gdx.graphics.g3d.loaders.g3d.G3dtLoader.G3dtKeyframedModelLoader;
import com.badlogic.gdx.graphics.g3d.loaders.g3d.G3dtLoader.G3dtStillModelLoader;
import com.badlogic.gdx.graphics.g3d.loaders.md2.MD2Loader;
import com.badlogic.gdx.graphics.g3d.loaders.md2.MD2Loader.MD2LoaderHints;
import com.badlogic.gdx.graphics.g3d.loaders.wavefront.ObjLoader;
import com.badlogic.gdx.graphics.g3d.model.Model;
import com.badlogic.gdx.graphics.g3d.model.keyframe.KeyframedModel;
import com.badlogic.gdx.graphics.g3d.model.skeleton.SkeletonModel;
import com.badlogic.gdx.graphics.g3d.model.still.StillModel;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.GdxRuntimeException;
/**
* Simple "pluggable" class for loading models. Keeps a list of {@link ModelLoader} instances on a per file suffix
* basis. Use one of the static methods to load a {@link Model}. The registry will then try out all the registered
* loaders for that extension and eventually return a Model or throw a {@link GdxRuntimeException}.
*
* @author mzechner
*/
public class ModelLoaderRegistry {
private static Map<String, Array<ModelLoader>> loaders = new HashMap<String, Array<ModelLoader>>();
private static Map<String, Array<ModelLoaderHints>> defaultHints = new HashMap<String, Array<ModelLoaderHints>>();
// registering the default loaders here
static {
/* TODO: Move/Drop support
registerLoader("dae", new ColladaLoader(), new ModelLoaderHints(false));
registerLoader("dae", new ColladaLoaderSkeleton(), new ModelLoaderHints(false));
*/
registerLoader("obj", new ObjLoader(), new ModelLoaderHints(false));
registerLoader("md2", new MD2Loader(), new MD2LoaderHints(0.2f));
registerLoader("g3dt", new G3dtStillModelLoader(), new ModelLoaderHints(true));
registerLoader("g3dt", new G3dtKeyframedModelLoader(), new ModelLoaderHints(true));
registerLoader("g3d", new G3dStillModelLoader(), new ModelLoaderHints(false));
registerLoader("g3d", new G3dKeyframedModelLoader(), new ModelLoaderHints(false));
registerLoader("g3d", new G3dSkeletonModelLoader(), new ModelLoaderHints(false));
/*
registerLoader("ctm", new CtmModelLoader(), new ModelLoaderHints(false));
*/
}
/**
* Registers a new loader with the registry. The extension will be used to match the loader against a file to be
* loaded. The extension will be compared case insensitive. If multiple loaders are registered per extension they
* will be tried on a file in the sequence they have been registered until one succeeds or none succeed.
*
* @param extension
* the extension string, e.g. "dae" or "obj"
* @param loader
* the {@link ModelLoader}
* @param defaultHints
* the default {@link ModelLoaderHints} to be used with this loader.
*/
public static void registerLoader(String extension, ModelLoader loader, ModelLoaderHints defaultHints) {
Array<ModelLoader> loaders = ModelLoaderRegistry.loaders.get(extension);
if (loaders == null) {
loaders = new Array<ModelLoader>();
ModelLoaderRegistry.loaders.put(extension.toLowerCase(), loaders);
}
loaders.add(loader);
Array<ModelLoaderHints> hints = ModelLoaderRegistry.defaultHints.get(extension);
if (hints == null) {
hints = new Array<ModelLoaderHints>();
ModelLoaderRegistry.defaultHints.put(extension.toLowerCase(), hints);
}
hints.add(defaultHints);
}
/**
* Loads the specified file with one of the loaders registered with this ModelLoaderRegistry. Uses the extension to
* determine which loader to use. The comparison of extensions is done case insensitive.
*
* @param file
* the file to be loaded
* @return the {@link Model}
* @throws GdxRuntimeException
* in case the model could not be loaded.
*/
public static Model load(FileHandle file) {
String name = file.name();
int dotIndex = name.lastIndexOf('.');
if (dotIndex == -1)
throw new GdxRuntimeException("file '" + file.name()
+ "' does not have an extension that can be matched to a ModelLoader");
String extension = name.substring(dotIndex + 1).toLowerCase();
Array<ModelLoader> loaders = ModelLoaderRegistry.loaders.get(extension);
Array<ModelLoaderHints> hints = ModelLoaderRegistry.defaultHints.get(extension);
if (loaders == null)
throw new GdxRuntimeException("no loaders for extension '" + extension + "'");
if (hints == null)
throw new GdxRuntimeException("no default hints for extension '" + extension + "'");
Model model = null;
StringBuilder errors = new StringBuilder();
for (int i = 0; i < loaders.size; i++) {
ModelLoader loader = loaders.get(i);
ModelLoaderHints hint = hints.get(i);
try {
model = loader.load(file, hint);
} catch (GdxRuntimeException e) {
errors.append("Couldn't load '" + file.name() + "' with loader of type " + loader.getClass().getName()
+ ": " + e.getMessage() + "\n");
}
}
if (model == null)
throw new GdxRuntimeException(errors.toString());
else
return model;
}
/**
* Loads the specified file with one of the loaders registered with this ModelLoaderRegistry. Uses the extension to
* determine which loader to use. The comparison of extensions is done case insensitive.
*
* @param file
* the file to be loaded
* @param hints
* the {@link ModelLoaderHints} to use
* @return the {@link Model}
* @throws GdxRuntimeException
* in case the model could not be loaded.
*/
public static Model load(FileHandle file, ModelLoaderHints hints) {
String name = file.name();
int dotIndex = name.lastIndexOf('.');
if (dotIndex == -1)
throw new GdxRuntimeException("file '" + file.name()
+ "' does not have an extension that can be matched to a ModelLoader");
String extension = name.substring(dotIndex + 1).toLowerCase();
Array<ModelLoader> loaders = ModelLoaderRegistry.loaders.get(extension);
if (loaders == null)
throw new GdxRuntimeException("no loaders for extension '" + extension + "'");
Model model = null;
StringBuilder errors = new StringBuilder();
for (int i = 0; i < loaders.size; i++) {
ModelLoader loader = loaders.get(i);
try {
model = loader.load(file, hints);
} catch (GdxRuntimeException e) {
errors.append("Couldn't load '" + file.name() + "' with loader of type " + loader.getClass().getName()
+ ": " + e.getMessage() + "\n");
}
}
if (model == null)
throw new GdxRuntimeException(errors.toString());
else
return model;
}
/**
* Loads the specified file with one of the loaders registered with this ModelLoaderRegistry. Uses the extension to
* determine which loader to use. The comparison of extensions is done case insensitive. Uses only
* {@link StillModelLoader} instances.
*
* @param file
* the file to be loaded
* @return the {@link Model}
* @throws GdxRuntimeException
* in case the model could not be loaded.
*/
public static StillModel loadStillModel(FileHandle file) {
String name = file.name();
int dotIndex = name.lastIndexOf('.');
if (dotIndex == -1)
throw new GdxRuntimeException("file '" + file.name()
+ "' does not have an extension that can be matched to a ModelLoader");
String extension = name.substring(dotIndex + 1).toLowerCase();
Array<ModelLoader> loaders = ModelLoaderRegistry.loaders.get(extension);
Array<ModelLoaderHints> hints = ModelLoaderRegistry.defaultHints.get(extension);
if (loaders == null)
throw new GdxRuntimeException("no loaders for extension '" + extension + "'");
if (hints == null)
throw new GdxRuntimeException("no default hints for extension '" + extension + "'");
StillModel model = null;
StringBuilder errors = new StringBuilder();
for (int i = 0; i < loaders.size; i++) {
ModelLoader loader = loaders.get(i);
ModelLoaderHints hint = hints.get(i);
try {
if (loader instanceof StillModelLoader) {
model = ((StillModelLoader) loader).load(file, hint);
}
} catch (GdxRuntimeException e) {
errors.append("Couldn't load '" + file.name() + "' with loader of type " + loader.getClass().getName()
+ ": " + e.getMessage() + "\n");
}
}
if (model == null)
throw new GdxRuntimeException("Couldn't load model '" + file.name() + "', " + errors.toString());
else
return model;
}
/**
* Loads the specified file with one of the loaders registered with this ModelLoaderRegistry. Uses the extension to
* determine which loader to use. The comparison of extensions is done case insensitive. Uses only
* {@link StillModelLoader} instances.
*
* @param file
* the file to be loaded
* @param hints
* the ModelLoaderHints to be used.
* @return the {@link Model}
* @throws GdxRuntimeException
* in case the model could not be loaded.
*/
public static StillModel loadStillModel(FileHandle file, ModelLoaderHints hints) {
String name = file.name();
int dotIndex = name.lastIndexOf('.');
if (dotIndex == -1)
throw new GdxRuntimeException("file '" + file.name()
+ "' does not have an extension that can be matched to a ModelLoader");
String extension = name.substring(dotIndex + 1).toLowerCase();
Array<ModelLoader> loaders = ModelLoaderRegistry.loaders.get(extension);
if (loaders == null)
throw new GdxRuntimeException("no loaders for extension '" + extension + "'");
StillModel model = null;
StringBuilder errors = new StringBuilder();
for (int i = 0; i < loaders.size; i++) {
ModelLoader loader = loaders.get(i);
try {
if (loader instanceof StillModelLoader) {
model = ((StillModelLoader) loader).load(file, hints);
}
} catch (GdxRuntimeException e) {
errors.append("Couldn't load '" + file.name() + "' with loader of type " + loader.getClass().getName()
+ ": " + e.getMessage() + "\n");
}
}
if (model == null)
throw new GdxRuntimeException("Couldn't load model '" + file.name() + "', " + errors.toString());
else
return model;
}
/**
* Loads the specified file with one of the loaders registered with this ModelLoaderRegistry. Uses the extension to
* determine which loader to use. The comparison of extensions is done case insensitive. Uses only
* {@link KeyframedModelLoader} instances.
*
* @param file
* the file to be loaded
* @return the {@link Model}
* @throws GdxRuntimeException
* in case the model could not be loaded.
*/
public static KeyframedModel loadKeyframedModel(FileHandle file) {
String name = file.name();
int dotIndex = name.lastIndexOf('.');
if (dotIndex == -1)
throw new GdxRuntimeException("file '" + file.name()
+ "' does not have an extension that can be matched to a ModelLoader");
String extension = name.substring(dotIndex + 1).toLowerCase();
Array<ModelLoader> loaders = ModelLoaderRegistry.loaders.get(extension);
Array<ModelLoaderHints> hints = ModelLoaderRegistry.defaultHints.get(extension);
if (loaders == null)
throw new GdxRuntimeException("no loaders for extension '" + extension + "'");
if (hints == null)
throw new GdxRuntimeException("no default hints for extension '" + extension + "'");
KeyframedModel model = null;
StringBuilder errors = new StringBuilder();
for (int i = 0; i < loaders.size; i++) {
ModelLoader loader = loaders.get(i);
ModelLoaderHints hint = hints.get(i);
try {
if (loader instanceof KeyframedModelLoader) {
model = ((KeyframedModelLoader) loader).load(file, hint);
}
} catch (GdxRuntimeException e) {
errors.append("Couldn't load '" + file.name() + "' with loader of type " + loader.getClass().getName()
+ ": " + e.getMessage() + "\n");
}
}
if (model == null)
throw new GdxRuntimeException(errors.toString());
else
return model;
}
/**
* Loads the specified file with one of the loaders registered with this ModelLoaderRegistry. Uses the extension to
* determine which loader to use. The comparison of extensions is done case insensitive. Uses only
* {@link KeyframedModelLoader} instances.
*
* @param file
* the file to be loaded
* @param hints
* the Model
* @return the {@link Model}
* @throws GdxRuntimeException
* in case the model could not be loaded.
*/
public static KeyframedModel loadKeyframedModel(FileHandle file, ModelLoaderHints hints) {
String name = file.name();
int dotIndex = name.lastIndexOf('.');
if (dotIndex == -1)
throw new GdxRuntimeException("file '" + file.name()
+ "' does not have an extension that can be matched to a ModelLoader");
String extension = name.substring(dotIndex + 1).toLowerCase();
Array<ModelLoader> loaders = ModelLoaderRegistry.loaders.get(extension);
if (loaders == null)
throw new GdxRuntimeException("no loaders for extension '" + extension + "'");
KeyframedModel model = null;
StringBuilder errors = new StringBuilder();
for (int i = 0; i < loaders.size; i++) {
ModelLoader loader = loaders.get(i);
try {
if (loader instanceof KeyframedModelLoader) {
model = ((KeyframedModelLoader) loader).load(file, hints);
}
} catch (GdxRuntimeException e) {
errors.append("Couldn't load '" + file.name() + "' with loader of type " + loader.getClass().getName()
+ ": " + e.getMessage() + "\n");
}
}
if (model == null)
throw new GdxRuntimeException(errors.toString());
else
return model;
}
/**
* Loads the specified file with one of the loaders registered with this ModelLoaderRegistry. Uses the extension to
* determine which loader to use. The comparison of extensions is done case insensitive. Uses only
* {@link SkeletonModelLoader} instances.
*
* @param file
* the file to be loaded
* @return the {@link Model}
* @throws GdxRuntimeException
* in case the model could not be loaded.
*/
public static SkeletonModel loadSkeletonModel(FileHandle file) {
String name = file.name();
int dotIndex = name.lastIndexOf('.');
if (dotIndex == -1)
throw new GdxRuntimeException("file '" + file.name()
+ "' does not have an extension that can be matched to a ModelLoader");
String extension = name.substring(dotIndex + 1).toLowerCase();
Array<ModelLoader> loaders = ModelLoaderRegistry.loaders.get(extension);
Array<ModelLoaderHints> hints = ModelLoaderRegistry.defaultHints.get(extension);
if (loaders == null)
throw new GdxRuntimeException("no loaders for extension '" + extension + "'");
if (hints == null)
throw new GdxRuntimeException("no default hints for extension '" + extension + "'");
SkeletonModel model = null;
StringBuilder errors = new StringBuilder();
for (int i = 0; i < loaders.size; i++) {
ModelLoader loader = loaders.get(i);
ModelLoaderHints hint = hints.get(i);
try {
if (loader instanceof SkeletonModelLoader) {
model = ((SkeletonModelLoader) loader).load(file, hint);
}
} catch (GdxRuntimeException e) {
errors.append("Couldn't load '" + file.name() + "' with loader of type " + loader.getClass().getName()
+ ": " + e.getMessage());
}
}
if (model == null)
throw new GdxRuntimeException(errors.toString());
else
return model;
}
/**
* Loads the specified file with one of the loaders registered with this ModelLoaderRegistry. Uses the extension to
* determine which loader to use. The comparison of extensions is done case insensitive. Uses only
* {@link SkeletonModelLoader} instances.
*
* @param file
* the file to be loaded
* @param hints
* the ModelLoaderHints to use
* @return the {@link Model}
* @throws GdxRuntimeException
* in case the model could not be loaded.
*/
public static SkeletonModel loadSkeletonModel(FileHandle file, ModelLoaderHints hints) {
String name = file.name();
int dotIndex = name.lastIndexOf('.');
if (dotIndex == -1)
throw new GdxRuntimeException("file '" + file.name()
+ "' does not have an extension that can be matched to a ModelLoader");
String extension = name.substring(dotIndex + 1).toLowerCase();
Array<ModelLoader> loaders = ModelLoaderRegistry.loaders.get(extension);
if (loaders == null)
throw new GdxRuntimeException("no loaders for extension '" + extension + "'");
SkeletonModel model = null;
StringBuilder errors = new StringBuilder();
for (int i = 0; i < loaders.size; i++) {
ModelLoader loader = loaders.get(i);
try {
if (loader instanceof SkeletonModelLoader) {
model = ((SkeletonModelLoader) loader).load(file, hints);
}
} catch (GdxRuntimeException e) {
errors.append("Couldn't load '" + file.name() + "' with loader of type " + loader.getClass().getName()
+ ": " + e.getMessage());
}
}
if (model == null)
throw new GdxRuntimeException(errors.toString());
else
return model;
}
}