package com.hbm.render.loader; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.URL; import java.util.ArrayList; import java.util.regex.Matcher; import java.util.regex.Pattern; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.resources.IResource; import net.minecraft.util.ResourceLocation; import net.minecraftforge.client.model.ModelFormatException; import net.minecraftforge.client.model.obj.TextureCoordinate; import net.minecraftforge.client.model.obj.Vertex; @SideOnly(Side.CLIENT) public class S_WavefrontObject extends S_ModelCustom { 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; private static Matcher vertexNormalMatcher; private static Matcher textureCoordinateMatcher; private static Matcher face_V_VT_VN_Matcher; private static Matcher face_V_VT_Matcher; private static Matcher face_V_VN_Matcher; private static Matcher face_V_Matcher; private static Matcher groupObjectMatcher; public ArrayList vertices = new ArrayList(); public ArrayList vertexNormals = new ArrayList(); public ArrayList textureCoordinates = new ArrayList(); public ArrayList groupObjects = new ArrayList(); private S_GroupObject currentS_GroupObject; private String fileName; public S_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 S_WavefrontObject(String fileName, URL resource) throws ModelFormatException { this.fileName = fileName; try { loadObjModel(resource.openStream()); } catch (IOException e) { throw new ModelFormatException("IO Exception reading model format", e); } } public S_WavefrontObject(String filename, InputStream inputStream) throws ModelFormatException { this.fileName = filename; loadObjModel(inputStream); } public boolean containsPart(String partName) { for (S_GroupObject groupObject : this.groupObjects) { if (partName.equalsIgnoreCase(groupObject.name)) { return true; } } return false; } 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)) { if (currentLine.startsWith("v ")) { Vertex vertex = parseVertex(currentLine, lineCount); if (vertex != null) { checkMinMax(vertex); this.vertices.add(vertex); } } else if (currentLine.startsWith("vn ")) { Vertex vertex = parseVertexNormal(currentLine, lineCount); if (vertex != null) { this.vertexNormals.add(vertex); } } else if (currentLine.startsWith("vt ")) { TextureCoordinate textureCoordinate = parseTextureCoordinate(currentLine, lineCount); if (textureCoordinate != null) { this.textureCoordinates.add(textureCoordinate); } } else if (currentLine.startsWith("f ")) { if (this.currentS_GroupObject == null) { this.currentS_GroupObject = new S_GroupObject("Default"); } S_Face face = parseFace(currentLine, lineCount); if (face != null) { this.currentS_GroupObject.faces.add(face); } } else if (((currentLine.startsWith("g ") | currentLine.startsWith("o "))) && (currentLine.charAt(2) == '$')) { S_GroupObject group = parseS_GroupObject(currentLine, lineCount); if (group != null) { if (this.currentS_GroupObject != null) { this.groupObjects.add(this.currentS_GroupObject); } } this.currentS_GroupObject = group; } } } this.groupObjects.add(this.currentS_GroupObject); return; } catch (IOException e) { throw new ModelFormatException("IO Exception reading model format", e); } finally { checkMinMaxFinal(); try { reader.close(); } catch (IOException e) {} try { inputStream.close(); } catch (IOException e) {} } } public void renderAll() { Tessellator tessellator = Tessellator.instance; if (this.currentS_GroupObject != null) { tessellator.startDrawing(this.currentS_GroupObject.glDrawingMode); } else { tessellator.startDrawing(4); } tessellateAll(tessellator); tessellator.draw(); } public void tessellateAll(Tessellator tessellator) { for (S_GroupObject groupObject : this.groupObjects) { groupObject.render(tessellator); } } public void renderOnly(String... groupNames) { for (S_GroupObject groupObject : this.groupObjects) { for (String groupName : groupNames) { if (groupName.equalsIgnoreCase(groupObject.name)) { groupObject.render(); } } } } public void tessellateOnly(Tessellator tessellator, String... groupNames) { for (S_GroupObject groupObject : this.groupObjects) { for (String groupName : groupNames) { if (groupName.equalsIgnoreCase(groupObject.name)) { groupObject.render(tessellator); } } } } public void renderPart(String partName) { for (S_GroupObject groupObject : this.groupObjects) { if (partName.equalsIgnoreCase(groupObject.name)) { groupObject.render(); } } } public void tessellatePart(Tessellator tessellator, String partName) { for (S_GroupObject groupObject : this.groupObjects) { if (partName.equalsIgnoreCase(groupObject.name)) { groupObject.render(tessellator); } } } public void renderAllExcept(String... excludedGroupNames) { for (S_GroupObject groupObject : this.groupObjects) { boolean skipPart = false; for (String excludedGroupName : excludedGroupNames) { if (excludedGroupName.equalsIgnoreCase(groupObject.name)) { skipPart = true; } } if (!skipPart) { groupObject.render(); } } } public void tessellateAllExcept(Tessellator tessellator, String... excludedGroupNames) { for (S_GroupObject groupObject : this.groupObjects) { boolean exclude = false; for (String excludedGroupName : excludedGroupNames) { if (excludedGroupName.equalsIgnoreCase(groupObject.name)) { exclude = true; } } if (!exclude) { groupObject.render(tessellator); } } } 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])); } 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", new Object[] { Integer.valueOf(lineCount) }), e); } } else { throw new ModelFormatException("Error parsing entry ('" + line + "'" + ", line " + lineCount + ") in file '" + this.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", new Object[] { Integer.valueOf(lineCount) }), e); } } else { throw new ModelFormatException("Error parsing entry ('" + line + "'" + ", line " + lineCount + ") in file '" + this.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.0F - Float.parseFloat(tokens[1])); } if (tokens.length == 3) { return new TextureCoordinate(Float.parseFloat(tokens[0]), 1.0F - Float.parseFloat(tokens[1]), Float.parseFloat(tokens[2])); } } catch (NumberFormatException e) { throw new ModelFormatException(String.format("Number formatting error at line %d", new Object[] { Integer.valueOf(lineCount) }), e); } } else { throw new ModelFormatException("Error parsing entry ('" + line + "'" + ", line " + lineCount + ") in file '" + this.fileName + "' - Incorrect format"); } return textureCoordinate; } private S_Face parseFace(String line, int lineCount) throws ModelFormatException { S_Face face = null; if (isValidFaceLine(line)) { face = new S_Face(); String trimmedLine = line.substring(line.indexOf(" ") + 1); String[] tokens = trimmedLine.split(" "); String[] subTokens = null; if (tokens.length == 3) { if (this.currentS_GroupObject.glDrawingMode == -1) { this.currentS_GroupObject.glDrawingMode = 4; } else if (this.currentS_GroupObject.glDrawingMode != 4) { throw new ModelFormatException("Error parsing entry ('" + line + "'" + ", line " + lineCount + ") in file '" + this.fileName + "' - Invalid number of points for face (expected 4, found " + tokens.length + ")"); } } else if (tokens.length == 4) { if (this.currentS_GroupObject.glDrawingMode == -1) { this.currentS_GroupObject.glDrawingMode = 7; } else if (this.currentS_GroupObject.glDrawingMode != 7) { throw new ModelFormatException("Error parsing entry ('" + line + "'" + ", line " + lineCount + ") in file '" + this.fileName + "' - Invalid number of points for face (expected 3, found " + tokens.length + ")"); } } 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] = ((Vertex)this.vertices.get(Integer.parseInt(subTokens[0]) - 1)); face.textureCoordinates[i] = ((TextureCoordinate)this.textureCoordinates.get(Integer.parseInt(subTokens[1]) - 1)); face.vertexNormals[i] = ((Vertex)this.vertexNormals.get(Integer.parseInt(subTokens[2]) - 1)); } face.faceNormal = face.calculateFaceNormal(); } 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] = ((Vertex)this.vertices.get(Integer.parseInt(subTokens[0]) - 1)); face.textureCoordinates[i] = ((TextureCoordinate)this.textureCoordinates.get(Integer.parseInt(subTokens[1]) - 1)); } face.faceNormal = face.calculateFaceNormal(); } 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] = ((Vertex)this.vertices.get(Integer.parseInt(subTokens[0]) - 1)); face.vertexNormals[i] = ((Vertex)this.vertexNormals.get(Integer.parseInt(subTokens[1]) - 1)); } face.faceNormal = face.calculateFaceNormal(); } else if (isValidFace_V_Line(line)) { face.vertices = new Vertex[tokens.length]; for (int i = 0; i < tokens.length; i++) { face.vertices[i] = ((Vertex)this.vertices.get(Integer.parseInt(tokens[i]) - 1)); } face.faceNormal = face.calculateFaceNormal(); } else { throw new ModelFormatException("Error parsing entry ('" + line + "'" + ", line " + lineCount + ") in file '" + this.fileName + "' - Incorrect format"); } } else { throw new ModelFormatException("Error parsing entry ('" + line + "'" + ", line " + lineCount + ") in file '" + this.fileName + "' - Incorrect format"); } return face; } private S_GroupObject parseS_GroupObject(String line, int lineCount) throws ModelFormatException { S_GroupObject group = null; if (isValidS_GroupObjectLine(line)) { String trimmedLine = line.substring(line.indexOf(" ") + 1); if (trimmedLine.length() > 0) { group = new S_GroupObject(trimmedLine); } } else { throw new ModelFormatException("Error parsing entry ('" + line + "'" + ", line " + lineCount + ") in file '" + this.fileName + "' - Incorrect format"); } return group; } private static boolean isValidVertexLine(String line) { if (vertexMatcher != null) { vertexMatcher.reset(); } vertexMatcher = vertexPattern.matcher(line); return vertexMatcher.matches(); } private static boolean isValidVertexNormalLine(String line) { if (vertexNormalMatcher != null) { vertexNormalMatcher.reset(); } vertexNormalMatcher = vertexNormalPattern.matcher(line); return vertexNormalMatcher.matches(); } private static boolean isValidTextureCoordinateLine(String line) { if (textureCoordinateMatcher != null) { textureCoordinateMatcher.reset(); } textureCoordinateMatcher = textureCoordinatePattern.matcher(line); return textureCoordinateMatcher.matches(); } 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(); } 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(); } 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(); } 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(); } 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)); } private static boolean isValidS_GroupObjectLine(String line) { if (groupObjectMatcher != null) { groupObjectMatcher.reset(); } groupObjectMatcher = groupObjectPattern.matcher(line); return groupObjectMatcher.matches(); } public String getType() { return "obj"; } public void renderAllLine(int startLine, int maxLine) { Tessellator tessellator = Tessellator.instance; tessellator.startDrawing(1); renderAllLine(tessellator, startLine, maxLine); tessellator.draw(); } public void renderAllLine(Tessellator tessellator, int startLine, int maxLine) { int lineCnt = 0; for (S_GroupObject groupObject : this.groupObjects) { if (groupObject.faces.size() > 0) { for (S_Face face : groupObject.faces) { for (int i = 0; i < face.vertices.length / 3; i++) { Vertex v1 = face.vertices[(i * 3 + 0)]; Vertex v2 = face.vertices[(i * 3 + 1)]; Vertex v3 = face.vertices[(i * 3 + 2)]; lineCnt++; if (lineCnt > maxLine) { return; } tessellator.addVertex(v1.x, v1.y, v1.z); tessellator.addVertex(v2.x, v2.y, v2.z); lineCnt++; if (lineCnt > maxLine) { return; } tessellator.addVertex(v2.x, v2.y, v2.z); tessellator.addVertex(v3.x, v3.y, v3.z); lineCnt++; if (lineCnt > maxLine) { return; } tessellator.addVertex(v3.x, v3.y, v3.z); tessellator.addVertex(v1.x, v1.y, v1.z); } } } } } public int getVertexNum() { return this.vertices.size(); } public int getFaceNum() { return getVertexNum() / 3; } public void renderAll(int startFace, int maxFace) { if (startFace < 0) { startFace = 0; } Tessellator tessellator = Tessellator.instance; tessellator.startDrawing(4); renderAll(tessellator, startFace, maxFace); tessellator.draw(); } public void renderAll(Tessellator tessellator, int startFace, int maxLine) { int faceCnt = 0; for (S_GroupObject groupObject : this.groupObjects) { if (groupObject.faces.size() > 0) { for (S_Face face : groupObject.faces) { faceCnt++; if (faceCnt >= startFace) { if (faceCnt > maxLine) { return; } face.addFaceForRender(tessellator); } } } } } }