Skip to content

Instantly share code, notes, and snippets.

@StillManic
Created June 14, 2015 20:43
Show Gist options
  • Save StillManic/2b3bde2d96ede8fad6f8 to your computer and use it in GitHub Desktop.
Save StillManic/2b3bde2d96ede8fad6f8 to your computer and use it in GitHub Desktop.
package net.minecraftforge.client.model.obj;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
import javax.vecmath.Matrix4f;
import javax.vecmath.Quat4f;
import javax.vecmath.Vector2f;
import javax.vecmath.Vector3f;
import javax.vecmath.Vector4f;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.renderer.block.model.ItemCameraTransforms;
import net.minecraft.client.renderer.block.model.ItemCameraTransforms.TransformType;
import net.minecraft.client.renderer.block.model.ItemTransformVec3f;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.vertex.VertexFormat;
import net.minecraft.client.renderer.vertex.VertexFormatElement;
import net.minecraft.client.resources.IResource;
import net.minecraft.client.resources.IResourceManager;
import net.minecraft.client.resources.model.IBakedModel;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.model.Attributes;
import net.minecraftforge.client.model.IColoredBakedQuad.ColoredBakedQuad;
import net.minecraftforge.client.model.IFlexibleBakedModel;
import net.minecraftforge.client.model.IModel;
import net.minecraftforge.client.model.IModelPart;
import net.minecraftforge.client.model.IModelState;
import net.minecraftforge.client.model.IPerspectiveAwareModel;
import net.minecraftforge.client.model.ISmartBlockModel;
import net.minecraftforge.client.model.ISmartItemModel;
import net.minecraftforge.client.model.ModelLoader;
import net.minecraftforge.client.model.TRSRTransformation;
import net.minecraftforge.common.property.IExtendedBlockState;
import net.minecraftforge.common.property.IUnlistedProperty;
import org.apache.commons.lang3.tuple.Pair;
import org.lwjgl.BufferUtils;
import com.google.common.base.Charsets;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
public class OBJModel implements IModel {
static final Set<String> unknownObjectCommands = new HashSet<String>();
private MaterialLibrary matLib;
private IModelState state;
public OBJModel(MaterialLibrary matLib) {
this.matLib = matLib;
}
private void setModelState(IModelState state) {
this.state = state;
}
@Override
public Collection<ResourceLocation> getDependencies()
{
return Collections.emptyList();
}
@Override
public Collection<ResourceLocation> getTextures()
{
Iterator<Material> materialIterator = this.matLib.materials.values().iterator();
List<ResourceLocation> textures = new ArrayList<ResourceLocation>();
while (materialIterator.hasNext()) {
Material mat = materialIterator.next();
ResourceLocation textureLoc = new ResourceLocation(mat.getTexture().getPath());
if (!textures.contains(textureLoc)) textures.add(textureLoc);
}
return textures;
}
@Override
public IFlexibleBakedModel bake(IModelState state, VertexFormat format, Function<ResourceLocation, TextureAtlasSprite> bakedTextureGetter)
{
ImmutableMap.Builder<String, TextureAtlasSprite> builder = ImmutableMap.builder();
Iterator<Material> materialIterator = this.matLib.library.values().iterator();
while (materialIterator.hasNext()) {
Material mat = materialIterator.next();
builder.put(mat.texture.path, bakedTextureGetter.apply(new ResourceLocation(mat.getTexture().getPath())));
builder.put("missingno", bakedTextureGetter.apply(new ResourceLocation("missingno")));
}
return new OBJBakedModel(this, state, format, bakedTextureGetter);
}
public OBJState getDefaultState()
{
return new OBJState(null, ItemCameraTransforms.DEFAULT);
}
public MaterialLibrary getMatLib() {
return this.matLib;
}
public static class Parser
{
public MaterialLibrary materialLibrary = new MaterialLibrary();
private IResourceManager manager;
private InputStreamReader objStream;
private BufferedReader objReader;
private ResourceLocation objFrom;
private List<String> elementList = new ArrayList<String>();
private List<Vertex> vertices = new ArrayList<Vertex>();
private List<Normal> normals = new ArrayList<Normal>();
private List<TextureCoordinate> texCoords = new ArrayList<TextureCoordinate>();
public Parser(IResource from, IResourceManager manager) throws IOException
{
this.manager = manager;
this.objFrom = from.getResourceLocation();
this.objStream = new InputStreamReader(from.getInputStream(), Charsets.UTF_8);
this.objReader = new BufferedReader(objStream);
}
public List<String> getElements() {
return this.elementList;
}
public OBJModel parse() throws IOException
{
String currentLine = "";
String nextLine = "";
String nextKey = "";
String nextData = "";
Material material = new Material();
for (;;)
{
currentLine = nextLine;
nextLine = objReader.readLine();
if (currentLine == null) break;
if (currentLine.isEmpty() || currentLine.startsWith("#")) continue;
if (nextLine != null && !nextLine.isEmpty() && !nextLine.startsWith("#"))
{
String[] nextFields = nextLine.split(" ", 2);
nextKey = nextFields[0];
nextData = nextFields[1];
}
String[] fields = currentLine.split(" ", 2);
String key = fields[0];
String data = fields[1];
if (key.equalsIgnoreCase("mtllib")) materialLibrary.parseMaterials(manager, data, objFrom);
else if (key.equalsIgnoreCase("usemtl")) material = materialLibrary.materials.get(data);
else if (key.equalsIgnoreCase("v")) {
String[] splitData = data.split(" ");
float[] floatSplitData = new float[splitData.length];
for (int i = 0; i < splitData.length; i++) floatSplitData[i] = Float.parseFloat(splitData[i]);
Vector4f pos = new Vector4f(floatSplitData[0], floatSplitData[1], floatSplitData[2], floatSplitData.length == 4 ? floatSplitData[3] : 1);
Vertex vertex = new Vertex(pos, new Vector4f(0.5f, 0.5f, 0.5f, 1.0f));
this.vertices.add(vertex);
}
else if (key.equalsIgnoreCase("vn")) {
String[] splitData = data.split(" ");
float[] floatSplitData = new float[splitData.length];
for (int i = 0; i < splitData.length; i++) floatSplitData[i] = Float.parseFloat(splitData[i]);
Normal normal = new Normal(new Vector3f(floatSplitData[0], floatSplitData[1], floatSplitData[2]));
this.normals.add(normal);
}
else if (key.equalsIgnoreCase("vt")) {
String[] splitData = data.split(" ");
float[] floatSplitData = new float[splitData.length];
for (int i = 0; i < splitData.length; i++) floatSplitData[i] = Float.parseFloat(splitData[i]);
TextureCoordinate texCoord = new TextureCoordinate(new Vector3f(floatSplitData[0], floatSplitData[1], floatSplitData.length == 3 ? floatSplitData[2] : 1));
this.texCoords.add(texCoord);
}
else if (key.equalsIgnoreCase("f")) {
String[] splitSpace = data.split(" ");
String[][] splitSlash = new String[splitSpace.length][];
int[] verts = new int[splitSpace.length];
int[] texCoords = new int[splitSpace.length];
int[] norms = new int[splitSpace.length];
List<Vertex> v = new ArrayList<Vertex>(verts.length);
List<TextureCoordinate> t = new ArrayList<TextureCoordinate>(texCoords.length);
List<Normal> n = new ArrayList<Normal>(norms.length);
for (int i = 0; i < splitSpace.length; i++) {
if (splitSpace[i].contains("//")) {
splitSlash[i] = splitSpace[i].split("//");
verts[i] = Integer.parseInt(splitSlash[i][0]);
verts[i] = verts[i] < 0 ? verts[i] = this.vertices.size() - 1 : verts[i] - 1;
norms[i] = Integer.parseInt(splitSlash[i][1]);
norms[i] = norms[i] < 0 ? norms[i] = this.normals.size() - 1 : norms[i] - 1;
v.add(this.vertices.get(verts[i]));
n.add(this.normals.get(norms[i]));
} else if (splitSpace[i].contains("/")) {
splitSlash[i] = splitSpace[i].split("/");
verts[i] = Integer.parseInt(splitSlash[i][0]);
verts[i] = verts[i] < 0 ? this.vertices.size() - 1 : verts[i] - 1;
texCoords[i] = Integer.parseInt(splitSlash[i][1]);
texCoords[i] = texCoords[i] < 0 ? this.texCoords.size() - 1 : texCoords[i] - 1;
if (splitSlash[i].length > 2) {
norms[i] = Integer.parseInt(splitSlash[i][2]);
norms[i] = norms[i] < 0 ? this.normals.size() - 1 : norms[i] - 1;
}
v.add(this.vertices.get(verts[i]));
t.add(this.texCoords.get(texCoords[i]));
if (splitSlash[i].length > 2) n.add(this.normals.get(norms[i]));
} else {
splitSlash[i] = splitSpace[i].split("");
verts[i] = Integer.parseInt(splitSlash[i][0]);
verts[i] = verts[i] < 0 ? this.vertices.size() - 1 : verts[i] - 1;
v.add(this.vertices.get(verts[i]));
}
}
Vertex[] va = new Vertex[v.size()];
v.toArray(va);
TextureCoordinate[] ta = new TextureCoordinate[t.size()];
t.toArray(ta);
Normal[] na = new Normal[n.size()];
n.toArray(na);
Face face = new Face(va, ta, na);
this.materialLibrary.library.put(face, material);
if (elementList.isEmpty()) {
this.materialLibrary.elements.put("default", face);
} else {
for (String s : elementList) {
this.materialLibrary.elements.put(s, face);
}
}
} else if (key.equalsIgnoreCase("g") || key.equalsIgnoreCase("o")) {
elementList.clear();
if (key.equalsIgnoreCase("g")) {
String[] splitSpace = data.split(" ");
for (String s : splitSpace) elementList.add(s);
} else {
elementList.add(data);
}
}
}
return new OBJModel(this.materialLibrary);
}
}
public static class MaterialLibrary
{
private Map<String, Material> materials = new HashMap<String, Material>();
private Map<Face, Material> library = new HashMap<Face, Material>();
private Map<String, Face> elements = new HashMap<String, Face>();
private InputStreamReader mtlStream;
private BufferedReader mtlReader;
private List<String> materialCommands = new ArrayList<String>();
public MaterialLibrary() {}
public void parseMaterials(IResourceManager manager, String path, ResourceLocation from) throws IOException
{
String domain = from.getResourceDomain();
mtlStream = new InputStreamReader(manager.getResource(new ResourceLocation(domain, path)).getInputStream(), Charsets.UTF_8);
mtlReader = new BufferedReader(mtlStream);
for (;;)
{
String currentLine = mtlReader.readLine();
if (currentLine == null) break;
if (currentLine.isEmpty() || currentLine.startsWith("#")) continue;
materialCommands.add(currentLine);
}
for (String command : materialCommands) {
String[] fields = command.split(" ", 2);
String key = fields[0];
String data = fields[1];
if (key.equalsIgnoreCase("newmtl")) {
this.materials.put(data, Material.parseMaterial(materialCommands));
}
}
}
public Map<String, Face> getElements() {
return this.elements;
}
}
public static class Material
{
private Vector4f color;
private Texture texture = Texture.White;
public Material()
{
this(Texture.White);
}
public Material(Vector4f color)
{
this(color, Texture.White);
}
public Material(Texture texture)
{
this(new Vector4f(1, 1, 1, 1), texture);
}
public Material(Vector4f color, Texture texture)
{
this.color = color;
this.texture = texture;
}
public void setColor(Vector4f color)
{
this.color = color;
}
public Vector4f getColor()
{
return this.color;
}
public void setTexture(Texture texture)
{
this.texture = texture;
}
public Texture getTexture()
{
return this.texture;
}
public static Material parseMaterial(List<String> commands)
{
Material material = new Material(null, null);
ListIterator<String> commandIterator = commands.listIterator();
while (commandIterator.hasNext())
{
String currentLine = commandIterator.next();
String[] fields = currentLine.split(" ", 2);
String key = fields[0];
String data = fields[1];
if (key.equalsIgnoreCase("newmtl")) continue;
else if (key.equalsIgnoreCase("Ka") || key.equalsIgnoreCase("Kd") || key.equalsIgnoreCase("Ks"))
{
String[] rgbStrings = data.split(" ", 3);
Vector4f color = new Vector4f(Float.parseFloat(rgbStrings[0]), Float.parseFloat(rgbStrings[1]), Float.parseFloat(rgbStrings[2]), 1.0f);
material.setColor(color);
}
else if (key.equalsIgnoreCase("illum")) ; //TODO: implement illumination models?
else if (key.equalsIgnoreCase("map_Ka") || key.equalsIgnoreCase("map_Kd") || key.equalsIgnoreCase("map_Ks"))
{
if (data.contains(" "))
{
String[] mapStrings = data.split(" ");
String texturePath = mapStrings[mapStrings.length - 1];
Texture texture = new Texture(texturePath);
material.setTexture(texture);
}
else
{
Texture texture = new Texture(data);
material.setTexture(texture);
}
}
else if (key.equalsIgnoreCase("d") || key.equalsIgnoreCase("Tr")) ; //TODO: transparency?
else if (key.equalsIgnoreCase("map_d")) ; //TODO: alpha map?
}
if (material.getTexture() == null) material.setTexture(Texture.White);
return material;
}
}
public static class Texture
{
public static Texture White = new Texture("builtin/white", new Vector2f(0, 0), new Vector2f(1, 1), 0);
private String path;
private Vector2f position;
private Vector2f scale;
private float rotation;
public Texture(String path)
{
this(path, new Vector2f(0, 0), new Vector2f(1, 1), 0);
}
public Texture(String path, Vector2f position, Vector2f scale, float rotation)
{
this.path = path;
this.position = position;
this.scale = scale;
this.rotation = rotation;
}
public ResourceLocation getTextureLocation()
{
ResourceLocation loc = new ResourceLocation(this.path);
return loc;
}
public void setPath(String path)
{
this.path = path;
}
public String getPath()
{
return this.path;
}
public void setPosition(Vector2f position)
{
this.position = position;
}
public Vector2f getPosition()
{
return this.position;
}
public void setScale(Vector2f scale)
{
this.scale = scale;
}
public Vector2f getScale()
{
return this.scale;
}
public void setRotation(float rotation)
{
this.rotation = rotation;
}
public float getRotation()
{
return this.rotation;
}
}
public static class Face
{
private Vertex[] verts = new Vertex[4];
private Normal[] norms = new Normal[4];
private TextureCoordinate[] texCoords = new TextureCoordinate[4];
public Face(Vertex[] verts)
{
this(verts, null, null);
}
public Face(Vertex[] verts, Normal[] norms)
{
this(verts, null, norms);
}
public Face(Vertex[] verts, TextureCoordinate[] texCoords)
{
this(verts, texCoords, null);
}
public Face(Vertex[] verts, TextureCoordinate[] texCoords, Normal[] norms)
{
this.verts = verts;
this.verts = this.verts.length > 0 ? this.verts : null;
this.norms = norms;
this.norms = this.norms.length > 0 ? this.norms : null;
this.texCoords = texCoords;
this.texCoords = this.texCoords.length > 0 ? this.texCoords : null;
}
public void setVertices(Vertex[] verts)
{
this.verts = verts;
}
public Vertex[] getVertices()
{
return this.verts;
}
public void setNormals(Normal[] norms)
{
this.norms = norms;
}
public Normal[] getNormals()
{
return this.norms;
}
public void setTextureCoordinates(TextureCoordinate[] texCoords)
{
this.texCoords = texCoords;
}
public TextureCoordinate[] getTextureCoordinates()
{
return this.texCoords;
}
public Normal getNormal() {
if (norms == null) { //use vertices to calculate normal
Vector3f v1 = new Vector3f(this.verts[0].getPosition().x, this.verts[0].getPosition().y, this.verts[0].getPosition().z);
Vector3f v2 = new Vector3f(this.verts[1].getPosition().x, this.verts[1].getPosition().y, this.verts[1].getPosition().z);
Vector3f v3 = new Vector3f(this.verts[2].getPosition().x, this.verts[2].getPosition().y, this.verts[2].getPosition().z);
Vector3f v4 = this.verts.length > 3 ? new Vector3f(this.verts[3].getPosition().x, this.verts[3].getPosition().y, this.verts[3].getPosition().z) : null;
if (v4 == null) {
Vector3f v2c = new Vector3f(v2.x, v2.y, v2.z);
Vector3f v1c = new Vector3f(v1.x, v1.y, v1.z);
v1c.sub(v2c);
Vector3f v3c = new Vector3f(v3.x, v3.y, v3.z);
v3c.sub(v2c);
Vector3f c = new Vector3f();
c.cross(v1c, v3c);
c.normalize();
Normal normal = new Normal(c);
return normal;
} else {
Vector3f v2c = new Vector3f(v2.x, v2.y, v2.z);
Vector3f v1c = new Vector3f(v1.x, v1.y, v1.z);
v1c.sub(v2c);
Vector3f v3c = new Vector3f(v3.x, v3.y, v3.z);
v3c.sub(v2c);
Vector3f c = new Vector3f();
c.cross(v1c, v3c);
c.normalize();
v1c = new Vector3f(v1.x, v1.y, v1.z);
v3c = new Vector3f(v3.x, v3.y, v3.z);
Vector3f v4c = new Vector3f(v4.x, v4.y, v4.z);
v1c.sub(v4c);
v3c.sub(v4c);
Vector3f d = new Vector3f();
d.cross(v1c, v3c);
d.normalize();
Vector3f avg = new Vector3f();
avg.x = (c.x + d.x) * 0.5f;
avg.y = (c.y + d.y) * 0.5f;
avg.z = (c.z + d.z) * 0.5f;
avg.normalize();
Normal normal = new Normal(avg);
return normal;
}
} else { //use normals to calculate normal
Vector3f n1 = this.norms[0].getNormal();
Vector3f n2 = this.norms[1].getNormal();
Vector3f n3 = this.norms[2].getNormal();
Vector3f n4 = this.norms.length > 3 ? this.norms[3].getNormal() : null;
if (n4 == null) {
Vector3f n2c = new Vector3f(n2.x, n2.y, n2.z);
Vector3f n1c = new Vector3f(n1.x, n1.y, n1.z);
n1c.sub(n2c);
Vector3f n3c = new Vector3f(n3.x, n3.y, n3.z);
n3c.sub(n2c);
Vector3f c = new Vector3f();
c.cross(n1c, n3c);
c.normalize();
Normal normal = new Normal(c);
return normal;
} else {
Vector3f n2c = new Vector3f(n2.x, n2.y, n2.z);
Vector3f n1c = new Vector3f(n1.x, n1.y, n1.z);
n1c.sub(n2c);
Vector3f n3c = new Vector3f(n3.x, n3.y, n3.z);
n3c.sub(n2c);
Vector3f c = new Vector3f();
c.cross(n1c, n3c);
c.normalize();
n1c = new Vector3f(n1.x, n1.y, n1.z);
n3c = new Vector3f(n3.x, n3.y, n3.z);
Vector3f n4c = new Vector3f(n4.x, n4.y, n4.z);
n1c.sub(n4c);
n3c.sub(n4c);
Vector3f d = new Vector3f();
d.cross(n1c, n3c);
d.normalize();
Vector3f avg = new Vector3f();
avg.x = (c.x + d.x) * 0.5f;
avg.y = (c.y + d.y) * 0.5f;
avg.z = (c.z + d.z) * 0.5f;
avg.normalize();
Normal normal = new Normal(avg);
return normal;
}
}
}
}
public static class Vertex
{
private Vector4f position;
private Vector4f color;
public Vertex(Vector4f position, Vector4f color)
{
this.position = position;
this.color = color;
}
public void setPos(Vector4f position)
{
this.position = position;
}
public Vector4f getPosition()
{
return this.position;
}
public void setColor(Vector4f color)
{
this.color = color;
}
public Vector4f getColor()
{
return this.color;
}
@Override
public String toString()
{
StringBuilder builder = new StringBuilder();
builder.append(String.format("v:%n"));
builder.append(String.format(" position: %s %s %s%n", position.x, position.y, position.z));
builder.append(String.format(" color: %s %s %s %s%n", color.x, color.y, color.z, color.w));
return builder.toString();
}
}
public static class Normal
{
private Vector3f normal;
public Normal(Vector3f normal)
{
this.normal = normal;
}
public void setNormal(Vector3f normal)
{
this.normal = normal;
}
public Vector3f getNormal()
{
return this.normal;
}
}
public static class TextureCoordinate
{
private Vector3f position;
public TextureCoordinate(Vector3f position)
{
this.position = position;
}
public void setPosition(Vector3f position)
{
this.position = position;
}
public Vector3f getPosition()
{
return this.position;
}
}
public class OBJState implements IModelState {
private List<String> visibleElements = new ArrayList<String>();
private ItemCameraTransforms transforms = ItemCameraTransforms.DEFAULT;
public OBJState(List<String> visibleElements, ItemCameraTransforms transforms) {
this.visibleElements = visibleElements;
this.transforms = transforms;
}
public void setVisibleElements(List<String> visibleElements) {
this.visibleElements = visibleElements;
}
public List<String> getVisibleElements() {
return this.visibleElements;
}
public void setTransforms(ItemCameraTransforms transforms) {
this.transforms = transforms;
}
public ItemCameraTransforms getTransforms() {
return this.transforms;
}
@Override
public TRSRTransformation apply(IModelPart part)
{
TRSRTransformation ret = TRSRTransformation.identity();
if (part instanceof Element) {
Element element = (Element) part;
ret = ret.compose(new TRSRTransformation(element.getPos(), element.getRot(), element.getScale(), null));
Matrix4f matrix = ret.getMatrix();
matrix.invert();
ret = ret.compose(new TRSRTransformation(matrix));
}
return ret;
}
}
public static enum OBJModelProperty implements IUnlistedProperty<OBJState> {
instance;
public String getName() {
return "OBJModel";
}
@Override
public boolean isValid(OBJState value)
{
return value instanceof OBJState;
}
@Override
public Class<OBJState> getType()
{
return OBJState.class;
}
@Override
public String valueToString(OBJState value)
{
return value.toString();
}
}
public class Element implements IModelPart {
private final String name;
private final Vector3f pos;
private final Vector3f scale;
private final Quat4f rot;
private final ImmutableList<Face> faces;
public Element(String name, Vector3f pos, Vector3f scale, Quat4f rot, List<Face> faces) {
this.name = name;
this.pos = pos;
this.scale = scale;
this.rot = rot;
this.faces = ImmutableList.copyOf(faces);
}
public ImmutableList<Face> bake() {
ImmutableList.Builder<Face> builder = ImmutableList.builder();
for (Face f : faces) {
builder.add(f);
}
return builder.build();
}
public String getName() {
return this.name;
}
public Vector3f getPos() {
return this.pos;
}
public Vector3f getScale() {
return this.scale;
}
public Quat4f getRot() {
return this.rot;
}
public List<Face> getFaces() {
return this.faces;
}
}
private class OBJBakedModel implements IFlexibleBakedModel, ISmartBlockModel, ISmartItemModel, IPerspectiveAwareModel
{
private final OBJModel model;
private final IModelState state;
private final VertexFormat format;
private final ByteBuffer buffer;
private ImmutableList<BakedQuad> quads;
private static final int BYTES_IN_INT = Integer.SIZE / Byte.SIZE;
private static final int VERTICES_IN_QUAD = 4;
private Function<ResourceLocation, TextureAtlasSprite> bakedTextureGetter;
private ImmutableMap<String, TextureAtlasSprite> textures;
public OBJBakedModel(OBJModel model, IModelState state, VertexFormat format, Function<ResourceLocation, TextureAtlasSprite> bakedTextureGetter)
{
this.model = model;
this.state = state;
this.format = format;
this.bakedTextureGetter = bakedTextureGetter;
buffer = BufferUtils.createByteBuffer(VERTICES_IN_QUAD * format.getNextOffset());
model.setModelState(state);
}
@Override
public List<BakedQuad> getFaceQuads(EnumFacing side)
{
return Collections.emptyList();
}
@Override
public List<BakedQuad> getGeneralQuads()
{
if (quads == null) {
ImmutableList.Builder<BakedQuad> builder = ImmutableList.builder();
ImmutableMap.Builder<String, TextureAtlasSprite> texBuilder = ImmutableMap.builder();
List<Face> faces = new ArrayList<Face>();
List<ResourceLocation> texturesAdded = new ArrayList<ResourceLocation>();
Iterator<Map.Entry<Face, Material>> faceIterator = model.matLib.library.entrySet().iterator();
while (faceIterator.hasNext()) {
Map.Entry<Face, Material> entry = faceIterator.next();
faces.add(entry.getKey());
if (!texturesAdded.contains(entry.getValue().getTexture().getTextureLocation())) texturesAdded.add(entry.getValue().getTexture().getTextureLocation());
// texBuilder.put(entry.getValue().texture.path, bakedTextureGetter.apply(new ResourceLocation(entry.getValue().texture.path)));
}
for (ResourceLocation r : texturesAdded) texBuilder.put(r.getResourceDomain() + ":" + r.getResourcePath(), bakedTextureGetter.apply(r));
this.textures = texBuilder.build();
for (Face f : faces) {
buffer.clear();
List<Texture> textures = new ArrayList<Texture>();
textures.add(model.matLib.library.get(f).texture);
TextureAtlasSprite sprite;
if (textures.isEmpty()) sprite = this.textures.get("missingno");
else if (textures.get(0) == OBJModel.Texture.White) sprite = ModelLoader.White.instance;
else sprite = this.textures.get(textures.get(0).getPath());
putVertexData(f.verts[0], sprite, f.norms != null ? f.norms[0] : f.getNormal());
putVertexData(f.verts[1], sprite, f.norms != null ? f.norms[1] : f.getNormal());
putVertexData(f.verts[2], sprite, f.norms != null ? f.norms[2] : f.getNormal());
putVertexData(f.verts[3], sprite, f.norms != null ? f.norms[3] : f.getNormal());
buffer.flip();
int[] data = new int[VERTICES_IN_QUAD * format.getNextOffset() / BYTES_IN_INT];
buffer.asIntBuffer().get(data);
builder.add(new ColoredBakedQuad(data, -1, EnumFacing.getFacingFromVector(f.getNormal().normal.x, f.getNormal().normal.y, f.getNormal().normal.z)));
}
quads = builder.build();
}
return quads;
}
private void put(VertexFormatElement e, Float... fs) {
Attributes.put(buffer, e, true, 0f, fs);
}
@SuppressWarnings("unchecked")
private final void putVertexData(Vertex v, TextureAtlasSprite sprite, Normal n) {
int oldPos = buffer.position();
Number[] ns = new Number[16];
for (int i = 0; i < ns.length; i++) ns[i] = 0f;
for (VertexFormatElement e : (List<VertexFormatElement>) format.getElements()) {
switch (e.getUsage()) {
case POSITION:
put(e, v.position.x, v.position.y, v.position.z, 1f);
break;
case COLOR:
if (v.color != null) put(e, v.color.x, v.color.y, v.color.z, v.color.w);
else put(e, 1f, 1f, 1f, 1f);
break;
case NORMAL:
put(e, n.normal.x, n.normal.y, n.normal.z, 1f);
break;
case GENERIC:
put(e, 0f, 0f, 0f, 0f);
break;
default:
break;
}
}
buffer.position(oldPos + format.getNextOffset());
}
@Override
public boolean isAmbientOcclusion()
{
return true;
}
@Override
public boolean isGui3d()
{
return true;
}
@Override
public boolean isBuiltInRenderer()
{
return false;
}
@Override
public TextureAtlasSprite getTexture()
{
return this.textures.get(0);
// return bakedTextureGetter.apply(new ResourceLocation("forgedebugmodelloaderregistry", "texture.png"));
}
@Override
public ItemCameraTransforms getItemCameraTransforms()
{
if (this.state instanceof IExtendedBlockState) {
IExtendedBlockState exState = (IExtendedBlockState) this.state;
if (exState.getUnlistedNames().contains(OBJModelProperty.instance)) {
OBJState s = exState.getValue(OBJModelProperty.instance);
return s.getTransforms();
}
}
return ItemCameraTransforms.DEFAULT;
}
@Override
public VertexFormat getFormat()
{
return format;
}
@Override
public Pair<IBakedModel, Matrix4f> handlePerspective(TransformType cameraTransformType)
{
//FIXME figure out where to get matrices for the different camera transform types
// if (this.state instanceof IExtendedBlockState) {
// IExtendedBlockState exState = (IExtendedBlockState) this.state;
// if (exState.getUnlistedNames().contains(OBJModelProperty.instance)) {
// OBJState s = (OBJState) exState.getValue(OBJModelProperty.instance);
// Matrix4f matrix = new Matrix4f();
// switch (cameraTransformType) {
// case THIRD_PERSON:
// break;
// case FIRST_PERSON:
// break;
// case HEAD:
// break;
// case GUI:
// break;
// case NONE:
// default:
// matrix.setIdentity();
// return Pair.of((IBakedModel) this, matrix);
// }
// }
// }
Matrix4f matrix = new Matrix4f();
matrix.setIdentity();
return Pair.of((IBakedModel) this, matrix);
}
@Override
public IBakedModel handleItemState(ItemStack stack)
{
return this;
}
@Override
public IBakedModel handleBlockState(IBlockState state)
{
if (state instanceof IExtendedBlockState) {
IExtendedBlockState exState = (IExtendedBlockState) state;
if (exState.getUnlistedNames().contains(OBJModelProperty.instance)) {
OBJState s = (OBJState) exState.getValue(OBJModelProperty.instance);
if (s != null) {
return getModel(s.getVisibleElements(), s.getTransforms());
}
}
}
return this;
}
public OBJBakedModel getModel(List<String> visibleElements, ItemCameraTransforms transforms) {
return new OBJBakedModel(model, new OBJState(visibleElements, transforms), format, bakedTextureGetter);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment