Revert "Locally added removed Forge Methods from 1.7 which allow us to load .obj and Techne Models"
This reverts commit 6712e8c488.
This commit is contained in:
@@ -1,78 +0,0 @@
|
|||||||
package net.minecraftforge.client.model;
|
|
||||||
|
|
||||||
import com.google.common.collect.Maps;
|
|
||||||
import net.minecraft.util.ResourceLocation;
|
|
||||||
import net.minecraftforge.client.model.obj.ObjModelLoader;
|
|
||||||
import net.minecraftforge.client.model.techne.TechneModelLoader;
|
|
||||||
import net.minecraftforge.fml.common.FMLLog;
|
|
||||||
import net.minecraftforge.fml.relauncher.Side;
|
|
||||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DISCLAIMER: This class has been copied from Minecraftforge for 1.7.10 and will be removed
|
|
||||||
* once Forge for 1.8 adds support for .obj model files.
|
|
||||||
*
|
|
||||||
* 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 {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 resource 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(ResourceLocation resource) throws IllegalArgumentException, ModelFormatException
|
|
||||||
{
|
|
||||||
String name = resource.getResourcePath();
|
|
||||||
int i = name.lastIndexOf('.');
|
|
||||||
if (i == -1)
|
|
||||||
{
|
|
||||||
FMLLog.severe("The resource name %s is not valid", resource);
|
|
||||||
throw new IllegalArgumentException("The resource name is not valid");
|
|
||||||
}
|
|
||||||
String suffix = name.substring(i+1);
|
|
||||||
IModelCustomLoader loader = instances.get(suffix);
|
|
||||||
if (loader == null)
|
|
||||||
{
|
|
||||||
FMLLog.severe("The resource name %s is not supported", resource);
|
|
||||||
throw new IllegalArgumentException("The resource name is not supported");
|
|
||||||
}
|
|
||||||
|
|
||||||
return loader.loadInstance(resource);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Collection<String> getSupportedSuffixes()
|
|
||||||
{
|
|
||||||
return instances.keySet();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static
|
|
||||||
{
|
|
||||||
registerModelHandler(new ObjModelLoader());
|
|
||||||
registerModelHandler(new TechneModelLoader());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
package net.minecraftforge.client.model;
|
|
||||||
|
|
||||||
import net.minecraftforge.fml.relauncher.Side;
|
|
||||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DISCLAIMER: This class has been copied from Minecraftforge for 1.7.10 and will be removed
|
|
||||||
* once Forge for 1.8 adds support for .obj model files.
|
|
||||||
*/
|
|
||||||
public interface IModelCustom
|
|
||||||
{
|
|
||||||
String getType();
|
|
||||||
@SideOnly(Side.CLIENT)
|
|
||||||
void renderAll();
|
|
||||||
@SideOnly(Side.CLIENT)
|
|
||||||
void renderOnly(String... groupNames);
|
|
||||||
@SideOnly(Side.CLIENT)
|
|
||||||
void renderPart(String partName);
|
|
||||||
@SideOnly(Side.CLIENT)
|
|
||||||
void renderAllExcept(String... excludedGroupNames);
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
package net.minecraftforge.client.model;
|
|
||||||
|
|
||||||
import net.minecraft.util.ResourceLocation;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DISCLAIMER: This class has been copied from Minecraftforge for 1.7.10 and will be removed
|
|
||||||
* once Forge for 1.8 adds support for .obj model files.
|
|
||||||
*
|
|
||||||
* 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 resource The ResourceLocation of the model
|
|
||||||
* @return A model instance
|
|
||||||
* @throws ModelFormatException if the model format is not correct
|
|
||||||
*/
|
|
||||||
IModelCustom loadInstance(ResourceLocation resource) throws ModelFormatException;
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
package net.minecraftforge.client.model;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DISCLAIMER: This class has been copied from Minecraftforge for 1.7.10 and will be removed
|
|
||||||
* once Forge for 1.8 adds support for .obj model files.
|
|
||||||
*
|
|
||||||
* Thrown if there is a problem parsing the model
|
|
||||||
*
|
|
||||||
* @author cpw
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class ModelFormatException extends RuntimeException {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 2023547503969671835L;
|
|
||||||
|
|
||||||
public ModelFormatException()
|
|
||||||
{
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ModelFormatException(String message, Throwable cause)
|
|
||||||
{
|
|
||||||
super(message, cause);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ModelFormatException(String message)
|
|
||||||
{
|
|
||||||
super(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ModelFormatException(Throwable cause)
|
|
||||||
{
|
|
||||||
super(cause);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,89 +0,0 @@
|
|||||||
package net.minecraftforge.client.model.obj;
|
|
||||||
|
|
||||||
import net.minecraft.client.renderer.WorldRenderer;
|
|
||||||
import net.minecraft.util.Vec3;
|
|
||||||
import net.minecraftforge.fml.relauncher.Side;
|
|
||||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DISCLAIMER: This class has been copied from Minecraftforge for 1.7.10 and will be removed
|
|
||||||
* once Forge for 1.8 adds support for .obj model files.
|
|
||||||
*/
|
|
||||||
public class Face
|
|
||||||
{
|
|
||||||
public Vertex[] vertices;
|
|
||||||
public Vertex[] vertexNormals;
|
|
||||||
public Vertex faceNormal;
|
|
||||||
public TextureCoordinate[] textureCoordinates;
|
|
||||||
|
|
||||||
@SideOnly(Side.CLIENT)
|
|
||||||
public void addFaceForRender(WorldRenderer worldRenderer)
|
|
||||||
{
|
|
||||||
addFaceForRender(worldRenderer, 0.0005F);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SideOnly(Side.CLIENT)
|
|
||||||
public void addFaceForRender(WorldRenderer worldRenderer, float textureOffset)
|
|
||||||
{
|
|
||||||
if (faceNormal == null)
|
|
||||||
{
|
|
||||||
faceNormal = this.calculateFaceNormal();
|
|
||||||
}
|
|
||||||
|
|
||||||
worldRenderer.setNormal(faceNormal.x, faceNormal.y, faceNormal.z);
|
|
||||||
|
|
||||||
float averageU = 0F;
|
|
||||||
float averageV = 0F;
|
|
||||||
|
|
||||||
if ((textureCoordinates != null) && (textureCoordinates.length > 0))
|
|
||||||
{
|
|
||||||
for (int i = 0; i < textureCoordinates.length; ++i)
|
|
||||||
{
|
|
||||||
averageU += textureCoordinates[i].u;
|
|
||||||
averageV += textureCoordinates[i].v;
|
|
||||||
}
|
|
||||||
|
|
||||||
averageU = averageU / textureCoordinates.length;
|
|
||||||
averageV = averageV / textureCoordinates.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
float offsetU, offsetV;
|
|
||||||
|
|
||||||
for (int i = 0; i < vertices.length; ++i)
|
|
||||||
{
|
|
||||||
|
|
||||||
if ((textureCoordinates != null) && (textureCoordinates.length > 0))
|
|
||||||
{
|
|
||||||
offsetU = textureOffset;
|
|
||||||
offsetV = textureOffset;
|
|
||||||
|
|
||||||
if (textureCoordinates[i].u > averageU)
|
|
||||||
{
|
|
||||||
offsetU = -offsetU;
|
|
||||||
}
|
|
||||||
if (textureCoordinates[i].v > averageV)
|
|
||||||
{
|
|
||||||
offsetV = -offsetV;
|
|
||||||
}
|
|
||||||
|
|
||||||
worldRenderer.addVertexWithUV(vertices[i].x, vertices[i].y, vertices[i].z, textureCoordinates[i].u + offsetU,
|
|
||||||
textureCoordinates[i].v + offsetV);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
worldRenderer.addVertex(vertices[i].x, vertices[i].y, vertices[i].z);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vertex calculateFaceNormal()
|
|
||||||
{
|
|
||||||
Vec3 v1 = new Vec3(vertices[1].x - vertices[0].x, vertices[1].y - vertices[0].y, vertices[1].z - vertices[0].z);
|
|
||||||
Vec3 v2 = new Vec3(vertices[2].x - vertices[0].x, vertices[2].y - vertices[0].y, vertices[2].z - vertices[0].z);
|
|
||||||
Vec3 normalVector = null;
|
|
||||||
|
|
||||||
normalVector = v1.crossProduct(v2).normalize();
|
|
||||||
|
|
||||||
return new Vertex((float) normalVector.xCoord, (float) normalVector.yCoord, (float) normalVector.zCoord);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
package net.minecraftforge.client.model.obj;
|
|
||||||
|
|
||||||
import net.minecraft.client.renderer.Tessellator;
|
|
||||||
import net.minecraft.client.renderer.WorldRenderer;
|
|
||||||
import net.minecraftforge.fml.relauncher.Side;
|
|
||||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DISCLAIMER: This class has been copied from Minecraftforge for 1.7.10 and will be removed
|
|
||||||
* once Forge for 1.8 adds support for .obj model files.
|
|
||||||
*/
|
|
||||||
public class GroupObject
|
|
||||||
{
|
|
||||||
public String name;
|
|
||||||
public ArrayList<Face> faces = new ArrayList<Face>();
|
|
||||||
public int glDrawingMode;
|
|
||||||
|
|
||||||
public GroupObject()
|
|
||||||
{
|
|
||||||
this("");
|
|
||||||
}
|
|
||||||
|
|
||||||
public GroupObject(String name)
|
|
||||||
{
|
|
||||||
this(name, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
public GroupObject(String name, int glDrawingMode)
|
|
||||||
{
|
|
||||||
this.name = name;
|
|
||||||
this.glDrawingMode = glDrawingMode;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SideOnly(Side.CLIENT)
|
|
||||||
public void render()
|
|
||||||
{
|
|
||||||
if (faces.size() > 0)
|
|
||||||
{
|
|
||||||
Tessellator tessellator = Tessellator.getInstance();
|
|
||||||
WorldRenderer worldRenderer = tessellator.getWorldRenderer();
|
|
||||||
worldRenderer.startDrawing(glDrawingMode);
|
|
||||||
render(worldRenderer);
|
|
||||||
tessellator.draw();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SideOnly(Side.CLIENT)
|
|
||||||
public void render(WorldRenderer worldRenderer)
|
|
||||||
{
|
|
||||||
if (faces.size() > 0)
|
|
||||||
{
|
|
||||||
for (Face face : faces)
|
|
||||||
{
|
|
||||||
face.addFaceForRender(worldRenderer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
package net.minecraftforge.client.model.obj;
|
|
||||||
|
|
||||||
import net.minecraft.util.ResourceLocation;
|
|
||||||
import net.minecraftforge.client.model.IModelCustom;
|
|
||||||
import net.minecraftforge.client.model.IModelCustomLoader;
|
|
||||||
import net.minecraftforge.client.model.ModelFormatException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DISCLAIMER: This class has been copied from Minecraftforge for 1.7.10 and will be removed
|
|
||||||
* once Forge for 1.8 adds support for .obj model files.
|
|
||||||
*/
|
|
||||||
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(ResourceLocation resource) throws ModelFormatException
|
|
||||||
{
|
|
||||||
return new WavefrontObject(resource);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
package net.minecraftforge.client.model.obj;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DISCLAIMER: This class has been copied from Minecraftforge for 1.7.10 and will be removed
|
|
||||||
* once Forge for 1.8 adds support for .obj model files.
|
|
||||||
*/
|
|
||||||
public class TextureCoordinate
|
|
||||||
{
|
|
||||||
public float u, v, w;
|
|
||||||
|
|
||||||
public TextureCoordinate(float u, float v)
|
|
||||||
{
|
|
||||||
this(u, v, 0F);
|
|
||||||
}
|
|
||||||
|
|
||||||
public TextureCoordinate(float u, float v, float w)
|
|
||||||
{
|
|
||||||
this.u = u;
|
|
||||||
this.v = v;
|
|
||||||
this.w = w;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
package net.minecraftforge.client.model.obj;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DISCLAIMER: This class has been copied from Minecraftforge for 1.7.10 and will be removed
|
|
||||||
* once Forge for 1.8 adds support for .obj model files.
|
|
||||||
*/
|
|
||||||
public class Vertex
|
|
||||||
{
|
|
||||||
public float x, y, z;
|
|
||||||
|
|
||||||
public Vertex(float x, float y)
|
|
||||||
{
|
|
||||||
this(x, y, 0F);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vertex(float x, float y, float z)
|
|
||||||
{
|
|
||||||
this.x = x;
|
|
||||||
this.y = y;
|
|
||||||
this.z = z;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,662 +0,0 @@
|
|||||||
package net.minecraftforge.client.model.obj;
|
|
||||||
|
|
||||||
import net.minecraft.client.Minecraft;
|
|
||||||
import net.minecraft.client.renderer.Tessellator;
|
|
||||||
import net.minecraft.client.renderer.WorldRenderer;
|
|
||||||
import net.minecraft.client.resources.IResource;
|
|
||||||
import net.minecraft.util.ResourceLocation;
|
|
||||||
import net.minecraftforge.client.model.IModelCustom;
|
|
||||||
import net.minecraftforge.client.model.ModelFormatException;
|
|
||||||
import net.minecraftforge.fml.relauncher.Side;
|
|
||||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
|
||||||
import org.lwjgl.opengl.GL11;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DISCLAIMER: This class has been copied from Minecraftforge for 1.7.10 and will be removed
|
|
||||||
* once Forge for 1.8 adds support for .obj model files.
|
|
||||||
*
|
|
||||||
* Wavefront Object importer
|
|
||||||
* Based heavily off of the specifications found at http://en.wikipedia.org/wiki/Wavefront_.obj_file
|
|
||||||
*/
|
|
||||||
public class WavefrontObject implements IModelCustom
|
|
||||||
{
|
|
||||||
private static Pattern vertexPattern = Pattern.compile("(v( (\\-){0,1}\\d+\\.\\d+){3,4} *\\n)|(v( (\\-){0,1}\\d+\\.\\d+){3,4} *$)");
|
|
||||||
private static Pattern vertexNormalPattern = Pattern.compile("(vn( (\\-){0,1}\\d+\\.\\d+){3,4} *\\n)|(vn( (\\-){0,1}\\d+\\.\\d+){3,4} *$)");
|
|
||||||
private static Pattern textureCoordinatePattern = Pattern.compile("(vt( (\\-){0,1}\\d+\\.\\d+){2,3} *\\n)|(vt( (\\-){0,1}\\d+\\.\\d+){2,3} *$)");
|
|
||||||
private static Pattern face_V_VT_VN_Pattern = Pattern.compile("(f( \\d+/\\d+/\\d+){3,4} *\\n)|(f( \\d+/\\d+/\\d+){3,4} *$)");
|
|
||||||
private static Pattern face_V_VT_Pattern = Pattern.compile("(f( \\d+/\\d+){3,4} *\\n)|(f( \\d+/\\d+){3,4} *$)");
|
|
||||||
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;
|
|
||||||
|
|
||||||
public ArrayList<Vertex> vertices = new ArrayList<Vertex>();
|
|
||||||
public ArrayList<Vertex> vertexNormals = new ArrayList<Vertex>();
|
|
||||||
public ArrayList<TextureCoordinate> textureCoordinates = new ArrayList<TextureCoordinate>();
|
|
||||||
public ArrayList<GroupObject> groupObjects = new ArrayList<GroupObject>();
|
|
||||||
private GroupObject currentGroupObject;
|
|
||||||
private String fileName;
|
|
||||||
|
|
||||||
public WavefrontObject(ResourceLocation resource) throws ModelFormatException
|
|
||||||
{
|
|
||||||
this.fileName = resource.toString();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
IResource res = Minecraft.getMinecraft().getResourceManager().getResource(resource);
|
|
||||||
loadObjModel(res.getInputStream());
|
|
||||||
}
|
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
throw new ModelFormatException("IO Exception reading model format", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public WavefrontObject(String filename, InputStream inputStream) throws ModelFormatException
|
|
||||||
{
|
|
||||||
this.fileName = filename;
|
|
||||||
loadObjModel(inputStream);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void loadObjModel(InputStream inputStream) throws ModelFormatException
|
|
||||||
{
|
|
||||||
BufferedReader reader = null;
|
|
||||||
|
|
||||||
String currentLine = null;
|
|
||||||
int lineCount = 0;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
reader = new BufferedReader(new InputStreamReader(inputStream));
|
|
||||||
|
|
||||||
while ((currentLine = reader.readLine()) != null)
|
|
||||||
{
|
|
||||||
lineCount++;
|
|
||||||
currentLine = currentLine.replaceAll("\\s+", " ").trim();
|
|
||||||
|
|
||||||
if (currentLine.startsWith("#") || currentLine.length() == 0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else if (currentLine.startsWith("v "))
|
|
||||||
{
|
|
||||||
Vertex vertex = parseVertex(currentLine, lineCount);
|
|
||||||
if (vertex != null)
|
|
||||||
{
|
|
||||||
vertices.add(vertex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (currentLine.startsWith("vn "))
|
|
||||||
{
|
|
||||||
Vertex vertex = parseVertexNormal(currentLine, lineCount);
|
|
||||||
if (vertex != null)
|
|
||||||
{
|
|
||||||
vertexNormals.add(vertex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (currentLine.startsWith("vt "))
|
|
||||||
{
|
|
||||||
TextureCoordinate textureCoordinate = parseTextureCoordinate(currentLine, lineCount);
|
|
||||||
if (textureCoordinate != null)
|
|
||||||
{
|
|
||||||
textureCoordinates.add(textureCoordinate);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (currentLine.startsWith("f "))
|
|
||||||
{
|
|
||||||
|
|
||||||
if (currentGroupObject == null)
|
|
||||||
{
|
|
||||||
currentGroupObject = new GroupObject("Default");
|
|
||||||
}
|
|
||||||
|
|
||||||
Face face = parseFace(currentLine, lineCount);
|
|
||||||
|
|
||||||
if (face != null)
|
|
||||||
{
|
|
||||||
currentGroupObject.faces.add(face);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (currentLine.startsWith("g ") | currentLine.startsWith("o "))
|
|
||||||
{
|
|
||||||
GroupObject group = parseGroupObject(currentLine, lineCount);
|
|
||||||
|
|
||||||
if (group != null)
|
|
||||||
{
|
|
||||||
if (currentGroupObject != null)
|
|
||||||
{
|
|
||||||
groupObjects.add(currentGroupObject);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
currentGroupObject = group;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
groupObjects.add(currentGroupObject);
|
|
||||||
}
|
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
throw new ModelFormatException("IO Exception reading model format", e);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
reader.close();
|
|
||||||
}
|
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
// hush
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
inputStream.close();
|
|
||||||
}
|
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
// hush
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@SideOnly(Side.CLIENT)
|
|
||||||
public void renderAll()
|
|
||||||
{
|
|
||||||
Tessellator tessellator = Tessellator.getInstance();
|
|
||||||
WorldRenderer worldRenderer = tessellator.getWorldRenderer();
|
|
||||||
if (currentGroupObject != null)
|
|
||||||
{
|
|
||||||
worldRenderer.startDrawing(currentGroupObject.glDrawingMode);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
worldRenderer.startDrawing(GL11.GL_TRIANGLES);
|
|
||||||
}
|
|
||||||
tessellateAll(worldRenderer);
|
|
||||||
|
|
||||||
tessellator.draw();
|
|
||||||
}
|
|
||||||
|
|
||||||
@SideOnly(Side.CLIENT)
|
|
||||||
public void tessellateAll(WorldRenderer worldRenderer)
|
|
||||||
{
|
|
||||||
for (GroupObject groupObject : groupObjects)
|
|
||||||
{
|
|
||||||
groupObject.render(worldRenderer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@SideOnly(Side.CLIENT)
|
|
||||||
public void renderOnly(String... groupNames)
|
|
||||||
{
|
|
||||||
for (GroupObject groupObject : groupObjects)
|
|
||||||
{
|
|
||||||
for (String groupName : groupNames)
|
|
||||||
{
|
|
||||||
if (groupName.equalsIgnoreCase(groupObject.name))
|
|
||||||
{
|
|
||||||
groupObject.render();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SideOnly(Side.CLIENT)
|
|
||||||
public void tessellateOnly(WorldRenderer worldRenderer, String... groupNames) {
|
|
||||||
for (GroupObject groupObject : groupObjects)
|
|
||||||
{
|
|
||||||
for (String groupName : groupNames)
|
|
||||||
{
|
|
||||||
if (groupName.equalsIgnoreCase(groupObject.name))
|
|
||||||
{
|
|
||||||
groupObject.render(worldRenderer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@SideOnly(Side.CLIENT)
|
|
||||||
public void renderPart(String partName)
|
|
||||||
{
|
|
||||||
for (GroupObject groupObject : groupObjects)
|
|
||||||
{
|
|
||||||
if (partName.equalsIgnoreCase(groupObject.name))
|
|
||||||
{
|
|
||||||
groupObject.render();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SideOnly(Side.CLIENT)
|
|
||||||
public void tessellatePart(WorldRenderer worldRenderer, String partName) {
|
|
||||||
for (GroupObject groupObject : groupObjects)
|
|
||||||
{
|
|
||||||
if (partName.equalsIgnoreCase(groupObject.name))
|
|
||||||
{
|
|
||||||
groupObject.render(worldRenderer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@SideOnly(Side.CLIENT)
|
|
||||||
public void renderAllExcept(String... excludedGroupNames)
|
|
||||||
{
|
|
||||||
for (GroupObject groupObject : groupObjects)
|
|
||||||
{
|
|
||||||
boolean skipPart=false;
|
|
||||||
for (String excludedGroupName : excludedGroupNames)
|
|
||||||
{
|
|
||||||
if (excludedGroupName.equalsIgnoreCase(groupObject.name))
|
|
||||||
{
|
|
||||||
skipPart=true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!skipPart)
|
|
||||||
{
|
|
||||||
groupObject.render();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SideOnly(Side.CLIENT)
|
|
||||||
public void tessellateAllExcept(WorldRenderer worldRenderer, String... excludedGroupNames)
|
|
||||||
{
|
|
||||||
boolean exclude;
|
|
||||||
for (GroupObject groupObject : groupObjects)
|
|
||||||
{
|
|
||||||
exclude=false;
|
|
||||||
for (String excludedGroupName : excludedGroupNames)
|
|
||||||
{
|
|
||||||
if (excludedGroupName.equalsIgnoreCase(groupObject.name))
|
|
||||||
{
|
|
||||||
exclude=true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!exclude)
|
|
||||||
{
|
|
||||||
groupObject.render(worldRenderer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Vertex parseVertex(String line, int lineCount) throws ModelFormatException
|
|
||||||
{
|
|
||||||
Vertex vertex = null;
|
|
||||||
|
|
||||||
if (isValidVertexLine(line))
|
|
||||||
{
|
|
||||||
line = line.substring(line.indexOf(" ") + 1);
|
|
||||||
String[] tokens = line.split(" ");
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
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]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (NumberFormatException e)
|
|
||||||
{
|
|
||||||
throw new ModelFormatException(String.format("Number formatting error at line %d",lineCount), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new ModelFormatException("Error parsing entry ('" + line + "'" + ", line " + lineCount + ") in file '" + fileName + "' - Incorrect format");
|
|
||||||
}
|
|
||||||
|
|
||||||
return vertex;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Vertex parseVertexNormal(String line, int lineCount) throws ModelFormatException
|
|
||||||
{
|
|
||||||
Vertex vertexNormal = null;
|
|
||||||
|
|
||||||
if (isValidVertexNormalLine(line))
|
|
||||||
{
|
|
||||||
line = line.substring(line.indexOf(" ") + 1);
|
|
||||||
String[] tokens = line.split(" ");
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (tokens.length == 3)
|
|
||||||
return new Vertex(Float.parseFloat(tokens[0]), Float.parseFloat(tokens[1]), Float.parseFloat(tokens[2]));
|
|
||||||
}
|
|
||||||
catch (NumberFormatException e)
|
|
||||||
{
|
|
||||||
throw new ModelFormatException(String.format("Number formatting error at line %d",lineCount), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new ModelFormatException("Error parsing entry ('" + line + "'" + ", line " + lineCount + ") in file '" + fileName + "' - Incorrect format");
|
|
||||||
}
|
|
||||||
|
|
||||||
return vertexNormal;
|
|
||||||
}
|
|
||||||
|
|
||||||
private TextureCoordinate parseTextureCoordinate(String line, int lineCount) throws ModelFormatException
|
|
||||||
{
|
|
||||||
TextureCoordinate textureCoordinate = null;
|
|
||||||
|
|
||||||
if (isValidTextureCoordinateLine(line))
|
|
||||||
{
|
|
||||||
line = line.substring(line.indexOf(" ") + 1);
|
|
||||||
String[] tokens = line.split(" ");
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (tokens.length == 2)
|
|
||||||
return new TextureCoordinate(Float.parseFloat(tokens[0]), 1 - Float.parseFloat(tokens[1]));
|
|
||||||
else if (tokens.length == 3)
|
|
||||||
return new TextureCoordinate(Float.parseFloat(tokens[0]), 1 - Float.parseFloat(tokens[1]), Float.parseFloat(tokens[2]));
|
|
||||||
}
|
|
||||||
catch (NumberFormatException e)
|
|
||||||
{
|
|
||||||
throw new ModelFormatException(String.format("Number formatting error at line %d",lineCount), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new ModelFormatException("Error parsing entry ('" + line + "'" + ", line " + lineCount + ") in file '" + fileName + "' - Incorrect format");
|
|
||||||
}
|
|
||||||
|
|
||||||
return textureCoordinate;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Face parseFace(String line, int lineCount) throws ModelFormatException
|
|
||||||
{
|
|
||||||
Face face = null;
|
|
||||||
|
|
||||||
if (isValidFaceLine(line))
|
|
||||||
{
|
|
||||||
face = new Face();
|
|
||||||
|
|
||||||
String trimmedLine = line.substring(line.indexOf(" ") + 1);
|
|
||||||
String[] tokens = trimmedLine.split(" ");
|
|
||||||
String[] subTokens = null;
|
|
||||||
|
|
||||||
if (tokens.length == 3)
|
|
||||||
{
|
|
||||||
if (currentGroupObject.glDrawingMode == -1)
|
|
||||||
{
|
|
||||||
currentGroupObject.glDrawingMode = GL11.GL_TRIANGLES;
|
|
||||||
}
|
|
||||||
else if (currentGroupObject.glDrawingMode != GL11.GL_TRIANGLES)
|
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
if (currentGroupObject.glDrawingMode == -1)
|
|
||||||
{
|
|
||||||
currentGroupObject.glDrawingMode = GL11.GL_QUADS;
|
|
||||||
}
|
|
||||||
else if (currentGroupObject.glDrawingMode != GL11.GL_QUADS)
|
|
||||||
{
|
|
||||||
throw new ModelFormatException("Error parsing entry ('" + line + "'" + ", line " + lineCount + ") in file '" + fileName + "' - Invalid number of points for face (expected 3, found " + tokens.length + ")");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// f v1/vt1/vn1 v2/vt2/vn2 v3/vt3/vn3 ...
|
|
||||||
if (isValidFace_V_VT_VN_Line(line))
|
|
||||||
{
|
|
||||||
face.vertices = new Vertex[tokens.length];
|
|
||||||
face.textureCoordinates = new TextureCoordinate[tokens.length];
|
|
||||||
face.vertexNormals = new Vertex[tokens.length];
|
|
||||||
|
|
||||||
for (int i = 0; i < tokens.length; ++i)
|
|
||||||
{
|
|
||||||
subTokens = tokens[i].split("/");
|
|
||||||
|
|
||||||
face.vertices[i] = vertices.get(Integer.parseInt(subTokens[0]) - 1);
|
|
||||||
face.textureCoordinates[i] = textureCoordinates.get(Integer.parseInt(subTokens[1]) - 1);
|
|
||||||
face.vertexNormals[i] = vertexNormals.get(Integer.parseInt(subTokens[2]) - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
face.faceNormal = face.calculateFaceNormal();
|
|
||||||
}
|
|
||||||
// f v1/vt1 v2/vt2 v3/vt3 ...
|
|
||||||
else if (isValidFace_V_VT_Line(line))
|
|
||||||
{
|
|
||||||
face.vertices = new Vertex[tokens.length];
|
|
||||||
face.textureCoordinates = new TextureCoordinate[tokens.length];
|
|
||||||
|
|
||||||
for (int i = 0; i < tokens.length; ++i)
|
|
||||||
{
|
|
||||||
subTokens = tokens[i].split("/");
|
|
||||||
|
|
||||||
face.vertices[i] = vertices.get(Integer.parseInt(subTokens[0]) - 1);
|
|
||||||
face.textureCoordinates[i] = textureCoordinates.get(Integer.parseInt(subTokens[1]) - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
face.faceNormal = face.calculateFaceNormal();
|
|
||||||
}
|
|
||||||
// f v1//vn1 v2//vn2 v3//vn3 ...
|
|
||||||
else if (isValidFace_V_VN_Line(line))
|
|
||||||
{
|
|
||||||
face.vertices = new Vertex[tokens.length];
|
|
||||||
face.vertexNormals = new Vertex[tokens.length];
|
|
||||||
|
|
||||||
for (int i = 0; i < tokens.length; ++i)
|
|
||||||
{
|
|
||||||
subTokens = tokens[i].split("//");
|
|
||||||
|
|
||||||
face.vertices[i] = vertices.get(Integer.parseInt(subTokens[0]) - 1);
|
|
||||||
face.vertexNormals[i] = vertexNormals.get(Integer.parseInt(subTokens[1]) - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
face.faceNormal = face.calculateFaceNormal();
|
|
||||||
}
|
|
||||||
// f v1 v2 v3 ...
|
|
||||||
else if (isValidFace_V_Line(line))
|
|
||||||
{
|
|
||||||
face.vertices = new Vertex[tokens.length];
|
|
||||||
|
|
||||||
for (int i = 0; i < tokens.length; ++i)
|
|
||||||
{
|
|
||||||
face.vertices[i] = vertices.get(Integer.parseInt(tokens[i]) - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
face.faceNormal = face.calculateFaceNormal();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new ModelFormatException("Error parsing entry ('" + line + "'" + ", line " + lineCount + ") in file '" + fileName + "' - Incorrect format");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new ModelFormatException("Error parsing entry ('" + line + "'" + ", line " + lineCount + ") in file '" + fileName + "' - Incorrect format");
|
|
||||||
}
|
|
||||||
|
|
||||||
return face;
|
|
||||||
}
|
|
||||||
|
|
||||||
private GroupObject parseGroupObject(String line, int lineCount) throws ModelFormatException
|
|
||||||
{
|
|
||||||
GroupObject group = null;
|
|
||||||
|
|
||||||
if (isValidGroupObjectLine(line))
|
|
||||||
{
|
|
||||||
String trimmedLine = line.substring(line.indexOf(" ") + 1);
|
|
||||||
|
|
||||||
if (trimmedLine.length() > 0)
|
|
||||||
{
|
|
||||||
group = new GroupObject(trimmedLine);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new ModelFormatException("Error parsing entry ('" + line + "'" + ", line " + lineCount + ") in file '" + fileName + "' - Incorrect format");
|
|
||||||
}
|
|
||||||
|
|
||||||
return group;
|
|
||||||
}
|
|
||||||
|
|
||||||
/***
|
|
||||||
* Verifies that the given line from the model file is a valid vertex
|
|
||||||
* @param line the line being validated
|
|
||||||
* @return true if the line is a valid vertex, false otherwise
|
|
||||||
*/
|
|
||||||
private static boolean isValidVertexLine(String line)
|
|
||||||
{
|
|
||||||
if (vertexMatcher != null)
|
|
||||||
{
|
|
||||||
vertexMatcher.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
vertexMatcher = vertexPattern.matcher(line);
|
|
||||||
return vertexMatcher.matches();
|
|
||||||
}
|
|
||||||
|
|
||||||
/***
|
|
||||||
* Verifies that the given line from the model file is a valid vertex normal
|
|
||||||
* @param line the line being validated
|
|
||||||
* @return true if the line is a valid vertex normal, false otherwise
|
|
||||||
*/
|
|
||||||
private static boolean isValidVertexNormalLine(String line)
|
|
||||||
{
|
|
||||||
if (vertexNormalMatcher != null)
|
|
||||||
{
|
|
||||||
vertexNormalMatcher.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
vertexNormalMatcher = vertexNormalPattern.matcher(line);
|
|
||||||
return vertexNormalMatcher.matches();
|
|
||||||
}
|
|
||||||
|
|
||||||
/***
|
|
||||||
* Verifies that the given line from the model file is a valid texture coordinate
|
|
||||||
* @param line the line being validated
|
|
||||||
* @return true if the line is a valid texture coordinate, false otherwise
|
|
||||||
*/
|
|
||||||
private static boolean isValidTextureCoordinateLine(String line)
|
|
||||||
{
|
|
||||||
if (textureCoordinateMatcher != null)
|
|
||||||
{
|
|
||||||
textureCoordinateMatcher.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
*/
|
|
||||||
private static boolean isValidFace_V_VT_VN_Line(String line)
|
|
||||||
{
|
|
||||||
if (face_V_VT_VN_Matcher != null)
|
|
||||||
{
|
|
||||||
face_V_VT_VN_Matcher.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
*/
|
|
||||||
private static boolean isValidFace_V_VT_Line(String line)
|
|
||||||
{
|
|
||||||
if (face_V_VT_Matcher != null)
|
|
||||||
{
|
|
||||||
face_V_VT_Matcher.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
*/
|
|
||||||
private static boolean isValidFace_V_VN_Line(String line)
|
|
||||||
{
|
|
||||||
if (face_V_VN_Matcher != null)
|
|
||||||
{
|
|
||||||
face_V_VN_Matcher.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
*/
|
|
||||||
private static boolean isValidFace_V_Line(String line)
|
|
||||||
{
|
|
||||||
if (face_V_Matcher != null)
|
|
||||||
{
|
|
||||||
face_V_Matcher.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
face_V_Matcher = face_V_Pattern.matcher(line);
|
|
||||||
return face_V_Matcher.matches();
|
|
||||||
}
|
|
||||||
|
|
||||||
/***
|
|
||||||
* 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
|
|
||||||
*/
|
|
||||||
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
|
|
||||||
*/
|
|
||||||
private static boolean isValidGroupObjectLine(String line)
|
|
||||||
{
|
|
||||||
if (groupObjectMatcher != null)
|
|
||||||
{
|
|
||||||
groupObjectMatcher.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
groupObjectMatcher = groupObjectPattern.matcher(line);
|
|
||||||
return groupObjectMatcher.matches();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getType()
|
|
||||||
{
|
|
||||||
return "obj";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,363 +0,0 @@
|
|||||||
package net.minecraftforge.client.model.techne;
|
|
||||||
|
|
||||||
import net.minecraft.client.Minecraft;
|
|
||||||
import net.minecraft.client.model.ModelBase;
|
|
||||||
import net.minecraft.client.model.ModelRenderer;
|
|
||||||
import net.minecraft.client.resources.IResource;
|
|
||||||
import net.minecraft.util.ResourceLocation;
|
|
||||||
import net.minecraftforge.client.model.IModelCustom;
|
|
||||||
import net.minecraftforge.client.model.ModelFormatException;
|
|
||||||
import net.minecraftforge.fml.common.FMLLog;
|
|
||||||
import net.minecraftforge.fml.relauncher.Side;
|
|
||||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
|
||||||
import org.w3c.dom.Document;
|
|
||||||
import org.w3c.dom.NamedNodeMap;
|
|
||||||
import org.w3c.dom.Node;
|
|
||||||
import org.w3c.dom.NodeList;
|
|
||||||
import org.xml.sax.SAXException;
|
|
||||||
|
|
||||||
import javax.xml.parsers.DocumentBuilder;
|
|
||||||
import javax.xml.parsers.DocumentBuilderFactory;
|
|
||||||
import javax.xml.parsers.ParserConfigurationException;
|
|
||||||
import java.awt.*;
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.zip.ZipEntry;
|
|
||||||
import java.util.zip.ZipException;
|
|
||||||
import java.util.zip.ZipInputStream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DISCLAIMER: This class has been copied from Minecraftforge for 1.7.10 and will be removed
|
|
||||||
* once Forge for 1.8 adds support for .obj model files.
|
|
||||||
*
|
|
||||||
* Techne model importer, based on iChun's Hats importer
|
|
||||||
*/
|
|
||||||
@SideOnly(Side.CLIENT)
|
|
||||||
public class TechneModel extends ModelBase implements IModelCustom {
|
|
||||||
public static final List<String> cubeTypes = Arrays.asList(
|
|
||||||
"d9e621f7-957f-4b77-b1ae-20dcd0da7751",
|
|
||||||
"de81aa14-bd60-4228-8d8d-5238bcd3caaa"
|
|
||||||
);
|
|
||||||
|
|
||||||
private String fileName;
|
|
||||||
private Map<String, byte[]> zipContents = new HashMap<String, byte[]>();
|
|
||||||
|
|
||||||
private Map<String, ModelRenderer> parts = new LinkedHashMap<String, ModelRenderer>();
|
|
||||||
private String texture = null;
|
|
||||||
private Dimension textureDims = null;
|
|
||||||
private int textureName;
|
|
||||||
private boolean textureNameSet = false;
|
|
||||||
|
|
||||||
public TechneModel(ResourceLocation resource) throws ModelFormatException
|
|
||||||
{
|
|
||||||
this.fileName = resource.toString();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
IResource res = Minecraft.getMinecraft().getResourceManager().getResource(resource);
|
|
||||||
loadTechneModel(res.getInputStream());
|
|
||||||
}
|
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
throw new ModelFormatException("IO Exception reading model format", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void loadTechneModel(InputStream stream) throws ModelFormatException
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
ZipInputStream zipInput = new ZipInputStream(stream);
|
|
||||||
|
|
||||||
ZipEntry entry;
|
|
||||||
while ((entry = zipInput.getNextEntry()) != null)
|
|
||||||
{
|
|
||||||
byte[] data = new byte[(int) entry.getSize()];
|
|
||||||
// For some reason, using read(byte[]) makes reading stall upon reaching a 0x1E byte
|
|
||||||
int i = 0;
|
|
||||||
while (zipInput.available() > 0 && i < data.length)
|
|
||||||
{
|
|
||||||
data[i++] = (byte)zipInput.read();
|
|
||||||
}
|
|
||||||
zipContents.put(entry.getName(), data);
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] modelXml = zipContents.get("model.xml");
|
|
||||||
if (modelXml == null)
|
|
||||||
{
|
|
||||||
throw new ModelFormatException("Model " + fileName + " contains no model.xml file");
|
|
||||||
}
|
|
||||||
|
|
||||||
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
|
|
||||||
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
|
|
||||||
Document document = documentBuilder.parse(new ByteArrayInputStream(modelXml));
|
|
||||||
|
|
||||||
NodeList nodeListTechne = document.getElementsByTagName("Techne");
|
|
||||||
if (nodeListTechne.getLength() < 1)
|
|
||||||
{
|
|
||||||
throw new ModelFormatException("Model " + fileName + " contains no Techne tag");
|
|
||||||
}
|
|
||||||
|
|
||||||
NodeList nodeListModel = document.getElementsByTagName("Model");
|
|
||||||
if (nodeListModel.getLength() < 1)
|
|
||||||
{
|
|
||||||
throw new ModelFormatException("Model " + fileName + " contains no Model tag");
|
|
||||||
}
|
|
||||||
|
|
||||||
NamedNodeMap modelAttributes = nodeListModel.item(0).getAttributes();
|
|
||||||
if (modelAttributes == null)
|
|
||||||
{
|
|
||||||
throw new ModelFormatException("Model " + fileName + " contains a Model tag with no attributes");
|
|
||||||
}
|
|
||||||
|
|
||||||
Node modelTexture = modelAttributes.getNamedItem("texture");
|
|
||||||
if (modelTexture != null)
|
|
||||||
{
|
|
||||||
texture = modelTexture.getTextContent();
|
|
||||||
}
|
|
||||||
|
|
||||||
NodeList textureDim = document.getElementsByTagName("TextureSize");
|
|
||||||
if (textureDim.getLength() > 0)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
String[] tmp = textureDim.item(0).getTextContent().split(",");
|
|
||||||
if (tmp.length == 2)
|
|
||||||
{
|
|
||||||
this.textureDims = new Dimension(Integer.parseInt(tmp[0]), Integer.parseInt(tmp[1]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (NumberFormatException e)
|
|
||||||
{
|
|
||||||
throw new ModelFormatException("Model " + fileName + " contains a TextureSize tag with invalid data");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
NodeList shapes = document.getElementsByTagName("Shape");
|
|
||||||
for (int i = 0; i < shapes.getLength(); i++)
|
|
||||||
{
|
|
||||||
Node shape = shapes.item(i);
|
|
||||||
NamedNodeMap shapeAttributes = shape.getAttributes();
|
|
||||||
if (shapeAttributes == null)
|
|
||||||
{
|
|
||||||
throw new ModelFormatException("Shape #" + (i + 1) + " in " + fileName + " has no attributes");
|
|
||||||
}
|
|
||||||
|
|
||||||
Node name = shapeAttributes.getNamedItem("name");
|
|
||||||
String shapeName = null;
|
|
||||||
if (name != null)
|
|
||||||
{
|
|
||||||
shapeName = name.getNodeValue();
|
|
||||||
}
|
|
||||||
if (shapeName == null)
|
|
||||||
{
|
|
||||||
shapeName = "Shape #" + (i + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
String shapeType = null;
|
|
||||||
Node type = shapeAttributes.getNamedItem("type");
|
|
||||||
if (type != null)
|
|
||||||
{
|
|
||||||
shapeType = type.getNodeValue();
|
|
||||||
}
|
|
||||||
if (shapeType != null && !cubeTypes.contains(shapeType))
|
|
||||||
{
|
|
||||||
FMLLog.warning("Model shape [" + shapeName + "] in " + fileName + " is not a cube, ignoring");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
boolean mirrored = false;
|
|
||||||
String[] offset = new String[3];
|
|
||||||
String[] position = new String[3];
|
|
||||||
String[] rotation = new String[3];
|
|
||||||
String[] size = new String[3];
|
|
||||||
String[] textureOffset = new String[2];
|
|
||||||
|
|
||||||
NodeList shapeChildren = shape.getChildNodes();
|
|
||||||
for (int j = 0; j < shapeChildren.getLength(); j++)
|
|
||||||
{
|
|
||||||
Node shapeChild = shapeChildren.item(j);
|
|
||||||
|
|
||||||
String shapeChildName = shapeChild.getNodeName();
|
|
||||||
String shapeChildValue = shapeChild.getTextContent();
|
|
||||||
if (shapeChildValue != null)
|
|
||||||
{
|
|
||||||
shapeChildValue = shapeChildValue.trim();
|
|
||||||
|
|
||||||
if (shapeChildName.equals("IsMirrored"))
|
|
||||||
{
|
|
||||||
mirrored = !shapeChildValue.equals("False");
|
|
||||||
}
|
|
||||||
else if (shapeChildName.equals("Offset"))
|
|
||||||
{
|
|
||||||
offset = shapeChildValue.split(",");
|
|
||||||
}
|
|
||||||
else if (shapeChildName.equals("Position"))
|
|
||||||
{
|
|
||||||
position = shapeChildValue.split(",");
|
|
||||||
}
|
|
||||||
else if (shapeChildName.equals("Rotation"))
|
|
||||||
{
|
|
||||||
rotation = shapeChildValue.split(",");
|
|
||||||
}
|
|
||||||
else if (shapeChildName.equals("Size"))
|
|
||||||
{
|
|
||||||
size = shapeChildValue.split(",");
|
|
||||||
}
|
|
||||||
else if (shapeChildName.equals("TextureOffset"))
|
|
||||||
{
|
|
||||||
textureOffset = shapeChildValue.split(",");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// That's what the ModelBase subclassing is needed for
|
|
||||||
ModelRenderer cube = new ModelRenderer(this, Integer.parseInt(textureOffset[0]), Integer.parseInt(textureOffset[1]));
|
|
||||||
cube.mirror = mirrored;
|
|
||||||
cube.addBox(Float.parseFloat(offset[0]), Float.parseFloat(offset[1]), Float.parseFloat(offset[2]), Integer.parseInt(size[0]), Integer.parseInt(size[1]), Integer.parseInt(size[2]));
|
|
||||||
cube.setRotationPoint(Float.parseFloat(position[0]), Float.parseFloat(position[1]) - 23.4F, Float.parseFloat(position[2]));
|
|
||||||
|
|
||||||
cube.rotateAngleX = (float)Math.toRadians(Float.parseFloat(rotation[0]));
|
|
||||||
cube.rotateAngleY = (float)Math.toRadians(Float.parseFloat(rotation[1]));
|
|
||||||
cube.rotateAngleZ = (float)Math.toRadians(Float.parseFloat(rotation[2]));
|
|
||||||
|
|
||||||
if (this.textureDims != null)
|
|
||||||
{
|
|
||||||
cube.setTextureSize((int)textureDims.getWidth(), (int)textureDims.getHeight());
|
|
||||||
}
|
|
||||||
|
|
||||||
parts.put(shapeName, cube);
|
|
||||||
}
|
|
||||||
catch (NumberFormatException e)
|
|
||||||
{
|
|
||||||
FMLLog.warning("Model shape [" + shapeName + "] in " + fileName + " contains malformed integers within its data, ignoring");
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (ZipException e)
|
|
||||||
{
|
|
||||||
throw new ModelFormatException("Model " + fileName + " is not a valid zip file");
|
|
||||||
}
|
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
throw new ModelFormatException("Model " + fileName + " could not be read", e);
|
|
||||||
}
|
|
||||||
catch (ParserConfigurationException e)
|
|
||||||
{
|
|
||||||
// hush
|
|
||||||
}
|
|
||||||
catch (SAXException e)
|
|
||||||
{
|
|
||||||
throw new ModelFormatException("Model " + fileName + " contains invalid XML", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void bindTexture()
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
if (texture != null)
|
|
||||||
{
|
|
||||||
if (!textureNameSet)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
byte[] textureEntry = zipContents.get(texture);
|
|
||||||
if (textureEntry == null)
|
|
||||||
{
|
|
||||||
throw new ModelFormatException("Model " + fileName + " has no such texture " + texture);
|
|
||||||
}
|
|
||||||
|
|
||||||
BufferedImage image = ImageIO.read(new ByteArrayInputStream(textureEntry));
|
|
||||||
textureName = Minecraft.getMinecraft().renderEngine.allocateAndSetupTexture(image);
|
|
||||||
textureNameSet = true;
|
|
||||||
}
|
|
||||||
catch (ZipException e)
|
|
||||||
{
|
|
||||||
throw new ModelFormatException("Model " + fileName + " is not a valid zip file");
|
|
||||||
}
|
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
throw new ModelFormatException("Texture for model " + fileName + " could not be read", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (textureNameSet)
|
|
||||||
{
|
|
||||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureName);
|
|
||||||
Minecraft.getMinecraft().renderEngine.resetBoundTexture();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getType()
|
|
||||||
{
|
|
||||||
return "tcn";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void renderAll()
|
|
||||||
{
|
|
||||||
bindTexture();
|
|
||||||
|
|
||||||
for (ModelRenderer part : parts.values())
|
|
||||||
{
|
|
||||||
part.renderWithRotation(1.0F);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void renderPart(String partName)
|
|
||||||
{
|
|
||||||
ModelRenderer part = parts.get(partName);
|
|
||||||
if (part != null)
|
|
||||||
{
|
|
||||||
bindTexture();
|
|
||||||
|
|
||||||
part.renderWithRotation(1.0F);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void renderOnly(String... groupNames)
|
|
||||||
{
|
|
||||||
bindTexture();
|
|
||||||
for (ModelRenderer part : parts.values())
|
|
||||||
{
|
|
||||||
for (String groupName : groupNames)
|
|
||||||
{
|
|
||||||
if (groupName.equalsIgnoreCase(part.boxName))
|
|
||||||
{
|
|
||||||
part.render(1.0f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void renderAllExcept(String... excludedGroupNames)
|
|
||||||
{
|
|
||||||
for (ModelRenderer part : parts.values())
|
|
||||||
{
|
|
||||||
boolean skipPart=false;
|
|
||||||
for (String excludedGroupName : excludedGroupNames)
|
|
||||||
{
|
|
||||||
if (excludedGroupName.equalsIgnoreCase(part.boxName))
|
|
||||||
{
|
|
||||||
skipPart=true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!skipPart)
|
|
||||||
{
|
|
||||||
part.render(1.0f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
package net.minecraftforge.client.model.techne;
|
|
||||||
|
|
||||||
import net.minecraft.util.ResourceLocation;
|
|
||||||
import net.minecraftforge.client.model.IModelCustom;
|
|
||||||
import net.minecraftforge.client.model.IModelCustomLoader;
|
|
||||||
import net.minecraftforge.client.model.ModelFormatException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DISCLAIMER: This class has been copied from Minecraftforge for 1.7.10 and will be removed
|
|
||||||
* once Forge for 1.8 adds support for .obj model files.
|
|
||||||
*/
|
|
||||||
public class TechneModelLoader implements IModelCustomLoader {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getType()
|
|
||||||
{
|
|
||||||
return "Techne model";
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final String[] types = { "tcn" };
|
|
||||||
@Override
|
|
||||||
public String[] getSuffixes()
|
|
||||||
{
|
|
||||||
return types;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public IModelCustom loadInstance(ResourceLocation resource) throws ModelFormatException
|
|
||||||
{
|
|
||||||
return new TechneModel(resource);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user