Add in a generic factory interface, allowing for additional model support
to be added at runtime.
This commit is contained in:
parent
d4b71ef964
commit
1ae7fa0080
|
@ -0,0 +1,82 @@
|
|||
package net.minecraftforge.client.model;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
import net.minecraftforge.client.model.obj.ObjModelLoader;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import cpw.mods.fml.common.FMLLog;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
|
||||
/**
|
||||
* Common interface for advanced model loading from files, based on file suffix
|
||||
* Model support can be queried through the {@link #getSupportedSuffixes()} method.
|
||||
* Instances can be created by calling {@link #loadModel(String)} with a class-loadable-path
|
||||
*
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
@SideOnly(Side.CLIENT)
|
||||
public class AdvancedModelLoader {
|
||||
private static Map<String, IModelCustomLoader> instances = Maps.newHashMap();
|
||||
|
||||
/**
|
||||
* Register a new model handler
|
||||
* @param modelHandler The model handler to register
|
||||
*/
|
||||
public static void registerModelHandler(IModelCustomLoader modelHandler)
|
||||
{
|
||||
for (String suffix : modelHandler.getSuffixes())
|
||||
{
|
||||
instances.put(suffix, modelHandler);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the model from the supplied classpath resolvable resource name
|
||||
* @param resourceName The resource name
|
||||
* @return A model
|
||||
* @throws IllegalArgumentException if the resource name cannot be understood
|
||||
* @throws ModelFormatException if the underlying model handler cannot parse the model format
|
||||
*/
|
||||
public static IModelCustom loadModel(String resourceName) throws IllegalArgumentException, ModelFormatException
|
||||
{
|
||||
int i = resourceName.lastIndexOf('.');
|
||||
if (i == -1)
|
||||
{
|
||||
FMLLog.severe("The resource name %s is not valid", resourceName);
|
||||
throw new IllegalArgumentException("The resource name is not valid");
|
||||
}
|
||||
String suffix = resourceName.substring(i);
|
||||
IModelCustomLoader loader = instances.get(suffix);
|
||||
if (loader == null)
|
||||
{
|
||||
FMLLog.severe("The resource name %s is not supported", resourceName);
|
||||
throw new IllegalArgumentException("The resource name is not supported");
|
||||
}
|
||||
|
||||
URL resource = AdvancedModelLoader.class.getResource(resourceName);
|
||||
if (resource == null)
|
||||
{
|
||||
FMLLog.severe("The resource name %s could not be found", resourceName);
|
||||
throw new IllegalArgumentException("The resource name could not be found");
|
||||
}
|
||||
return loader.loadInstance(resourceName, resource);
|
||||
}
|
||||
|
||||
public static Collection<String> getSupportedSuffixes()
|
||||
{
|
||||
return instances.keySet();
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
{
|
||||
registerModelHandler(new ObjModelLoader());
|
||||
}
|
||||
}
|
|
@ -3,11 +3,7 @@ package net.minecraftforge.client.model;
|
|||
|
||||
|
||||
public interface IModelCustom {
|
||||
|
||||
public abstract IModelCustom load(String fileName);
|
||||
|
||||
public abstract void renderAll();
|
||||
|
||||
public abstract void renderPart(String partName);
|
||||
|
||||
String getType();
|
||||
void renderAll();
|
||||
void renderPart(String partName);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
package net.minecraftforge.client.model;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* Instances of this class act as factories for their model type
|
||||
*
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
public interface IModelCustomLoader {
|
||||
/**
|
||||
* Get the main type name for this loader
|
||||
* @return the type name
|
||||
*/
|
||||
String getType();
|
||||
/**
|
||||
* Get resource suffixes this model loader recognizes
|
||||
* @return a list of suffixes
|
||||
*/
|
||||
String[] getSuffixes();
|
||||
/**
|
||||
* Load a model instance from the supplied path
|
||||
* @param resourceName The resource name to load
|
||||
* @param resource The URL associated with the classloader resource
|
||||
* @return A model instance
|
||||
* @throws ModelFormatException if the model format is not correct
|
||||
*/
|
||||
IModelCustom loadInstance(String resourceName, URL resource) throws ModelFormatException;
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package net.minecraftforge.client.model;
|
||||
|
||||
/**
|
||||
* Thrown if there is a problem parsing the model
|
||||
*
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
public class ModelFormatException extends RuntimeException {
|
||||
|
||||
public ModelFormatException()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public ModelFormatException(String message, Throwable cause)
|
||||
{
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public ModelFormatException(String message)
|
||||
{
|
||||
super(message);
|
||||
}
|
||||
|
||||
public ModelFormatException(Throwable cause)
|
||||
{
|
||||
super(cause);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package net.minecraftforge.client.model.obj;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
|
||||
import net.minecraftforge.client.model.IModelCustom;
|
||||
import net.minecraftforge.client.model.IModelCustomLoader;
|
||||
import net.minecraftforge.client.model.ModelFormatException;
|
||||
|
||||
public class ObjModelLoader implements IModelCustomLoader {
|
||||
|
||||
@Override
|
||||
public String getType()
|
||||
{
|
||||
return "OBJ model";
|
||||
}
|
||||
|
||||
private static final String[] types = { "obj" };
|
||||
@Override
|
||||
public String[] getSuffixes()
|
||||
{
|
||||
return types;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IModelCustom loadInstance(String resourceName, URL resource) throws ModelFormatException
|
||||
{
|
||||
return new WavefrontObject(resourceName, resource);
|
||||
}
|
||||
|
||||
}
|
|
@ -8,10 +8,10 @@ import java.net.URL;
|
|||
import java.util.ArrayList;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.zip.DataFormatException;
|
||||
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraftforge.client.model.IModelCustom;
|
||||
import net.minecraftforge.client.model.ModelFormatException;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
|
@ -34,7 +34,7 @@ public class WavefrontObject implements IModelCustom
|
|||
private static Pattern face_V_VN_Pattern = Pattern.compile("(f( \\d+//\\d+){3,4} *\\n)|(f( \\d+//\\d+){3,4} *$)");
|
||||
private static Pattern face_V_Pattern = Pattern.compile("(f( \\d+){3,4} *\\n)|(f( \\d+){3,4} *$)");
|
||||
private static Pattern groupObjectPattern = Pattern.compile("([go]( [\\w\\d]+) *\\n)|([go]( [\\w\\d]+) *$)");
|
||||
|
||||
|
||||
private static Matcher vertexMatcher, vertexNormalMatcher, textureCoordinateMatcher;
|
||||
private static Matcher face_V_VT_VN_Matcher, face_V_VT_Matcher, face_V_VN_Matcher, face_V_Matcher;
|
||||
private static Matcher groupObjectMatcher;
|
||||
|
@ -46,42 +46,17 @@ public class WavefrontObject implements IModelCustom
|
|||
private GroupObject currentGroupObject;
|
||||
private String fileName;
|
||||
|
||||
public WavefrontObject(String fileName)
|
||||
public WavefrontObject(String fileName, URL resource) throws ModelFormatException
|
||||
{
|
||||
this.fileName = fileName;
|
||||
|
||||
try
|
||||
{
|
||||
loadObjModel(this.getClass().getResource(fileName));
|
||||
}
|
||||
catch (DataFormatException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public IModelCustom load(String fileName)
|
||||
{
|
||||
return new WavefrontObject(fileName);
|
||||
}
|
||||
|
||||
public void load()
|
||||
{
|
||||
try
|
||||
{
|
||||
loadObjModel(this.getClass().getResource(fileName));
|
||||
}
|
||||
catch (DataFormatException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
loadObjModel(resource);
|
||||
}
|
||||
|
||||
private void loadObjModel(URL fileURL) throws DataFormatException
|
||||
private void loadObjModel(URL fileURL) throws ModelFormatException
|
||||
{
|
||||
BufferedReader reader = null;
|
||||
InputStream inputStream = null;
|
||||
|
||||
|
||||
String currentLine = null;
|
||||
int lineCount = 0;
|
||||
|
||||
|
@ -158,7 +133,7 @@ public class WavefrontObject implements IModelCustom
|
|||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
throw new ModelFormatException("IO Exception reading model format", e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -168,16 +143,16 @@ public class WavefrontObject implements IModelCustom
|
|||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
// hush
|
||||
}
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
inputStream.close();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
// hush
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -216,7 +191,7 @@ public class WavefrontObject implements IModelCustom
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void renderPart(String partName)
|
||||
{
|
||||
for (GroupObject groupObject : groupObjects)
|
||||
|
@ -242,7 +217,7 @@ public class WavefrontObject implements IModelCustom
|
|||
}
|
||||
}
|
||||
|
||||
private Vertex parseVertex(String line, int lineCount) throws DataFormatException
|
||||
private Vertex parseVertex(String line, int lineCount) throws ModelFormatException
|
||||
{
|
||||
Vertex vertex = null;
|
||||
|
||||
|
@ -253,29 +228,29 @@ public class WavefrontObject implements IModelCustom
|
|||
|
||||
try
|
||||
{
|
||||
if (tokens.length == 3)
|
||||
if (tokens.length == 2)
|
||||
{
|
||||
return new Vertex(Float.parseFloat(tokens[0]), Float.parseFloat(tokens[1]));
|
||||
}
|
||||
else if (tokens.length == 3)
|
||||
{
|
||||
return new Vertex(Float.parseFloat(tokens[0]), Float.parseFloat(tokens[1]), Float.parseFloat(tokens[2]));
|
||||
}
|
||||
else if (tokens.length == 4)
|
||||
{
|
||||
return new Vertex(Float.parseFloat(tokens[0]), Float.parseFloat(tokens[1]), Float.parseFloat(tokens[2]), Float.parseFloat(tokens[3]));
|
||||
}
|
||||
}
|
||||
catch (NumberFormatException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
throw new ModelFormatException(String.format("Number formatting error at line %d",lineCount), e);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new DataFormatException("Error parsing entry ('" + line + "'" + ", line " + lineCount + ") in file '" + fileName + "' - Incorrect format");
|
||||
throw new ModelFormatException("Error parsing entry ('" + line + "'" + ", line " + lineCount + ") in file '" + fileName + "' - Incorrect format");
|
||||
}
|
||||
|
||||
return vertex;
|
||||
}
|
||||
|
||||
private Vertex parseVertexNormal(String line, int lineCount) throws DataFormatException
|
||||
private Vertex parseVertexNormal(String line, int lineCount) throws ModelFormatException
|
||||
{
|
||||
Vertex vertexNormal = null;
|
||||
|
||||
|
@ -291,18 +266,18 @@ public class WavefrontObject implements IModelCustom
|
|||
}
|
||||
catch (NumberFormatException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
throw new ModelFormatException(String.format("Number formatting error at line %d",lineCount), e);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new DataFormatException("Error parsing entry ('" + line + "'" + ", line " + lineCount + ") in file '" + fileName + "' - Incorrect format");
|
||||
throw new ModelFormatException("Error parsing entry ('" + line + "'" + ", line " + lineCount + ") in file '" + fileName + "' - Incorrect format");
|
||||
}
|
||||
|
||||
return vertexNormal;
|
||||
}
|
||||
|
||||
private TextureCoordinate parseTextureCoordinate(String line, int lineCount) throws DataFormatException
|
||||
private TextureCoordinate parseTextureCoordinate(String line, int lineCount) throws ModelFormatException
|
||||
{
|
||||
TextureCoordinate textureCoordinate = null;
|
||||
|
||||
|
@ -320,18 +295,18 @@ public class WavefrontObject implements IModelCustom
|
|||
}
|
||||
catch (NumberFormatException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
throw new ModelFormatException(String.format("Number formatting error at line %d",lineCount), e);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new DataFormatException("Error parsing entry ('" + line + "'" + ", line " + lineCount + ") in file '" + fileName + "' - Incorrect format");
|
||||
throw new ModelFormatException("Error parsing entry ('" + line + "'" + ", line " + lineCount + ") in file '" + fileName + "' - Incorrect format");
|
||||
}
|
||||
|
||||
return textureCoordinate;
|
||||
}
|
||||
|
||||
private Face parseFace(String line, int lineCount) throws DataFormatException
|
||||
private Face parseFace(String line, int lineCount) throws ModelFormatException
|
||||
{
|
||||
Face face = null;
|
||||
|
||||
|
@ -351,7 +326,7 @@ public class WavefrontObject implements IModelCustom
|
|||
}
|
||||
else if (currentGroupObject.glDrawingMode != GL11.GL_TRIANGLES)
|
||||
{
|
||||
throw new DataFormatException("Error parsing entry ('" + line + "'" + ", line " + lineCount + ") in file '" + fileName + "' - Invalid number of points for face (expected 4, found " + tokens.length + ")");
|
||||
throw new ModelFormatException("Error parsing entry ('" + line + "'" + ", line " + lineCount + ") in file '" + fileName + "' - Invalid number of points for face (expected 4, found " + tokens.length + ")");
|
||||
}
|
||||
}
|
||||
else if (tokens.length == 4)
|
||||
|
@ -362,7 +337,7 @@ public class WavefrontObject implements IModelCustom
|
|||
}
|
||||
else if (currentGroupObject.glDrawingMode != GL11.GL_QUADS)
|
||||
{
|
||||
throw new DataFormatException("Error parsing entry ('" + line + "'" + ", line " + lineCount + ") in file '" + fileName + "' - Invalid number of points for face (expected 3, found " + tokens.length + ")");
|
||||
throw new ModelFormatException("Error parsing entry ('" + line + "'" + ", line " + lineCount + ") in file '" + fileName + "' - Invalid number of points for face (expected 3, found " + tokens.length + ")");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -422,18 +397,18 @@ public class WavefrontObject implements IModelCustom
|
|||
}
|
||||
else
|
||||
{
|
||||
throw new DataFormatException("Error parsing entry ('" + line + "'" + ", line " + lineCount + ") in file '" + fileName + "' - Incorrect format");
|
||||
throw new ModelFormatException("Error parsing entry ('" + line + "'" + ", line " + lineCount + ") in file '" + fileName + "' - Incorrect format");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new DataFormatException("Error parsing entry ('" + line + "'" + ", line " + lineCount + ") in file '" + fileName + "' - Incorrect format");
|
||||
throw new ModelFormatException("Error parsing entry ('" + line + "'" + ", line " + lineCount + ") in file '" + fileName + "' - Incorrect format");
|
||||
}
|
||||
|
||||
return face;
|
||||
}
|
||||
|
||||
private GroupObject parseGroupObject(String line, int lineCount) throws DataFormatException
|
||||
private GroupObject parseGroupObject(String line, int lineCount) throws ModelFormatException
|
||||
{
|
||||
GroupObject group = null;
|
||||
|
||||
|
@ -448,7 +423,7 @@ public class WavefrontObject implements IModelCustom
|
|||
}
|
||||
else
|
||||
{
|
||||
throw new DataFormatException("Error parsing entry ('" + line + "'" + ", line " + lineCount + ") in file '" + fileName + "' - Incorrect format");
|
||||
throw new ModelFormatException("Error parsing entry ('" + line + "'" + ", line " + lineCount + ") in file '" + fileName + "' - Incorrect format");
|
||||
}
|
||||
|
||||
return group;
|
||||
|
@ -465,7 +440,7 @@ public class WavefrontObject implements IModelCustom
|
|||
{
|
||||
vertexMatcher.reset();
|
||||
}
|
||||
|
||||
|
||||
vertexMatcher = vertexPattern.matcher(line);
|
||||
return vertexMatcher.matches();
|
||||
}
|
||||
|
@ -501,11 +476,11 @@ public class WavefrontObject implements IModelCustom
|
|||
textureCoordinateMatcher = textureCoordinatePattern.matcher(line);
|
||||
return textureCoordinateMatcher.matches();
|
||||
}
|
||||
|
||||
|
||||
/***
|
||||
* Verifies that the given line from the model file is a valid face that is described by vertices, texture coordinates, and vertex normals
|
||||
* @param line the line being validated
|
||||
* @return true if the line is a valid face that matches the format "f v1/vt1/vn1 ..." (with a minimum of 3 points in the face, and a maximum of 4), false otherwise
|
||||
* @return true if the line is a valid face that matches the format "f v1/vt1/vn1 ..." (with a minimum of 3 points in the face, and a maximum of 4), false otherwise
|
||||
*/
|
||||
private static boolean isValidFace_V_VT_VN_Line(String line)
|
||||
{
|
||||
|
@ -517,11 +492,11 @@ public class WavefrontObject implements IModelCustom
|
|||
face_V_VT_VN_Matcher = face_V_VT_VN_Pattern.matcher(line);
|
||||
return face_V_VT_VN_Matcher.matches();
|
||||
}
|
||||
|
||||
|
||||
/***
|
||||
* Verifies that the given line from the model file is a valid face that is described by vertices and texture coordinates
|
||||
* @param line the line being validated
|
||||
* @return true if the line is a valid face that matches the format "f v1/vt1 ..." (with a minimum of 3 points in the face, and a maximum of 4), false otherwise
|
||||
* @return true if the line is a valid face that matches the format "f v1/vt1 ..." (with a minimum of 3 points in the face, and a maximum of 4), false otherwise
|
||||
*/
|
||||
private static boolean isValidFace_V_VT_Line(String line)
|
||||
{
|
||||
|
@ -533,11 +508,11 @@ public class WavefrontObject implements IModelCustom
|
|||
face_V_VT_Matcher = face_V_VT_Pattern.matcher(line);
|
||||
return face_V_VT_Matcher.matches();
|
||||
}
|
||||
|
||||
|
||||
/***
|
||||
* Verifies that the given line from the model file is a valid face that is described by vertices and vertex normals
|
||||
* @param line the line being validated
|
||||
* @return true if the line is a valid face that matches the format "f v1//vn1 ..." (with a minimum of 3 points in the face, and a maximum of 4), false otherwise
|
||||
* @return true if the line is a valid face that matches the format "f v1//vn1 ..." (with a minimum of 3 points in the face, and a maximum of 4), false otherwise
|
||||
*/
|
||||
private static boolean isValidFace_V_VN_Line(String line)
|
||||
{
|
||||
|
@ -549,11 +524,11 @@ public class WavefrontObject implements IModelCustom
|
|||
face_V_VN_Matcher = face_V_VN_Pattern.matcher(line);
|
||||
return face_V_VN_Matcher.matches();
|
||||
}
|
||||
|
||||
|
||||
/***
|
||||
* Verifies that the given line from the model file is a valid face that is described by only vertices
|
||||
* @param line the line being validated
|
||||
* @return true if the line is a valid face that matches the format "f v1 ..." (with a minimum of 3 points in the face, and a maximum of 4), false otherwise
|
||||
* @return true if the line is a valid face that matches the format "f v1 ..." (with a minimum of 3 points in the face, and a maximum of 4), false otherwise
|
||||
*/
|
||||
private static boolean isValidFace_V_Line(String line)
|
||||
{
|
||||
|
@ -569,17 +544,17 @@ public class WavefrontObject implements IModelCustom
|
|||
/***
|
||||
* Verifies that the given line from the model file is a valid face of any of the possible face formats
|
||||
* @param line the line being validated
|
||||
* @return true if the line is a valid face that matches any of the valid face formats, false otherwise
|
||||
* @return true if the line is a valid face that matches any of the valid face formats, false otherwise
|
||||
*/
|
||||
private static boolean isValidFaceLine(String line)
|
||||
{
|
||||
{
|
||||
return isValidFace_V_VT_VN_Line(line) || isValidFace_V_VT_Line(line) || isValidFace_V_VN_Line(line) || isValidFace_V_Line(line);
|
||||
}
|
||||
|
||||
/***
|
||||
* Verifies that the given line from the model file is a valid group (or object)
|
||||
* @param line the line being validated
|
||||
* @return true if the line is a valid group (or object), false otherwise
|
||||
* @return true if the line is a valid group (or object), false otherwise
|
||||
*/
|
||||
private static boolean isValidGroupObjectLine(String line)
|
||||
{
|
||||
|
@ -591,4 +566,10 @@ public class WavefrontObject implements IModelCustom
|
|||
groupObjectMatcher = groupObjectPattern.matcher(line);
|
||||
return groupObjectMatcher.matches();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType()
|
||||
{
|
||||
return "obj";
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue