package com.mrcrayfish.skateboarding.util;
import java.util.ArrayList;
import java.util.List;
import com.mrcrayfish.skateboarding.util.StateHelper.RelativeFacing;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.client.renderer.vertex.VertexFormat;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumFacing.Axis;
import net.minecraft.util.math.Vec3d;
import net.minecraftforge.client.model.pipeline.UnpackedBakedQuad;
public class QuadHelper
{
private VertexFormat format;
private TextureAtlasSprite sprite;
private EnumFacing facing = EnumFacing.EAST;
public QuadHelper(VertexFormat format, TextureAtlasSprite sprite)
{
this.format = format;
this.sprite = sprite;
}
public List<BakedQuad> createCuboid(Vec3d v1, Vec3d v2)
{
List<BakedQuad> quads = new ArrayList<BakedQuad>();
float width = (float) (v2.xCoord - v1.xCoord) * 16F;
float height = (float) (v2.yCoord - v1.yCoord) * 16F;
float depth = (float) (v2.zCoord - v1.zCoord) * 16F;
// Front
quads.add(createQuad(new Vertex(v1.xCoord, v1.yCoord, v2.zCoord, 0F, 0F),
new Vertex(v1.xCoord, v2.yCoord, v2.zCoord, 0F, height),
new Vertex(v1.xCoord, v2.yCoord, v1.zCoord, depth, height),
new Vertex(v1.xCoord, v1.yCoord, v1.zCoord, depth, 0F),
EnumFacing.WEST));
// Back
quads.add(createQuad(new Vertex(v2.xCoord, v1.yCoord, v1.zCoord, 0F, 0F),
new Vertex(v2.xCoord, v2.yCoord, v1.zCoord, 0F, height),
new Vertex(v2.xCoord, v2.yCoord, v2.zCoord, depth, height),
new Vertex(v2.xCoord, v1.yCoord, v2.zCoord, depth, 0F),
EnumFacing.EAST));
// Left
quads.add(createQuad(new Vertex(v1.xCoord, v1.yCoord, v1.zCoord, 0F, 0F),
new Vertex(v1.xCoord, v2.yCoord, v1.zCoord, 0F, height),
new Vertex(v2.xCoord, v2.yCoord, v1.zCoord, width, height),
new Vertex(v2.xCoord, v1.yCoord, v1.zCoord, width, 0F),
EnumFacing.NORTH));
// Right
quads.add(createQuad(new Vertex(v2.xCoord, v1.yCoord, v2.zCoord, 0F, 0F),
new Vertex(v2.xCoord, v2.yCoord, v2.zCoord, 0F, height),
new Vertex(v1.xCoord, v2.yCoord, v2.zCoord, width, height),
new Vertex(v1.xCoord, v1.yCoord, v2.zCoord, width, 0F),
EnumFacing.SOUTH));
// Bottom
quads.add(createQuad(new Vertex(v1.xCoord, v1.yCoord, v2.zCoord, 0F, 0F),
new Vertex(v1.xCoord, v1.yCoord, v1.zCoord, 0F, depth),
new Vertex(v2.xCoord, v1.yCoord, v1.zCoord, width, depth),
new Vertex(v2.xCoord, v1.yCoord, v2.zCoord, width, 0F),
EnumFacing.DOWN));
// Top
quads.add(createQuad(new Vertex(v1.xCoord, v2.yCoord, v1.zCoord, 0F, 0F),
new Vertex(v1.xCoord, v2.yCoord, v2.zCoord, 0F, depth),
new Vertex(v2.xCoord, v2.yCoord, v2.zCoord, width, depth),
new Vertex(v2.xCoord, v2.yCoord, v1.zCoord, width, 0F),
EnumFacing.UP));
return quads;
}
public List<BakedQuad> createAngledCuboid(Vec3d v1, Vec3d v2, double heightOffset)
{
List<BakedQuad> quads = new ArrayList<BakedQuad>();
float width = (float) (v2.xCoord - v1.xCoord) * 16F;
float height = (float) (v2.yCoord - v1.yCoord) * 16F;
float depth = (float) (v2.zCoord - v1.zCoord) * 16F;
// Front
quads.add(createQuad(new Vertex(v1.xCoord, v1.yCoord, v2.zCoord, 0F, 0F),
new Vertex(v1.xCoord, v2.yCoord, v2.zCoord, 0F, height),
new Vertex(v1.xCoord, v2.yCoord, v1.zCoord, depth, height),
new Vertex(v1.xCoord, v1.yCoord, v1.zCoord, depth, 0F),
EnumFacing.WEST));
// Back
quads.add(createQuad(new Vertex(v2.xCoord, v1.yCoord + heightOffset, v1.zCoord, 0F, 0F),
new Vertex(v2.xCoord, v2.yCoord + heightOffset, v1.zCoord, 0F, height),
new Vertex(v2.xCoord, v2.yCoord + heightOffset, v2.zCoord, depth, height),
new Vertex(v2.xCoord, v1.yCoord + heightOffset, v2.zCoord, depth, 0F),
EnumFacing.EAST));
// Left
quads.add(createQuad(new Vertex(v1.xCoord, v1.yCoord, v1.zCoord, 0F, 0F),
new Vertex(v1.xCoord, v2.yCoord, v1.zCoord, 0F, height),
new Vertex(v2.xCoord, v2.yCoord + heightOffset, v1.zCoord, width, height),
new Vertex(v2.xCoord, v1.yCoord + heightOffset, v1.zCoord, width, 0F),
EnumFacing.NORTH));
// Right
quads.add(createQuad(new Vertex(v2.xCoord, v1.yCoord + heightOffset, v2.zCoord, 0F, 0F),
new Vertex(v2.xCoord, v2.yCoord + heightOffset, v2.zCoord, 0F, height),
new Vertex(v1.xCoord, v2.yCoord, v2.zCoord, width, height),
new Vertex(v1.xCoord, v1.yCoord, v2.zCoord, width, 0F),
EnumFacing.SOUTH));
// Bottom
quads.add(createQuad(new Vertex(v1.xCoord, v1.yCoord, v2.zCoord, 0F, 0F),
new Vertex(v1.xCoord, v1.yCoord, v1.zCoord, 0F, depth),
new Vertex(v2.xCoord, v1.yCoord + heightOffset, v1.zCoord, width, depth),
new Vertex(v2.xCoord, v1.yCoord + heightOffset, v2.zCoord, width, 0F),
EnumFacing.DOWN));
// Top
quads.add(createQuad(new Vertex(v1.xCoord, v2.yCoord, v1.zCoord, 0F, 0F),
new Vertex(v1.xCoord, v2.yCoord, v2.zCoord, 0F, depth),
new Vertex(v2.xCoord, v2.yCoord + heightOffset, v2.zCoord, width, depth),
new Vertex(v2.xCoord, v2.yCoord + heightOffset, v1.zCoord, width, 0F),
EnumFacing.UP));
return quads;
}
public BakedQuad createQuad(Vertex v1, Vertex v2, Vertex v3, Vertex v4, EnumFacing face)
{
v1 = rotate(v1, facing);
v2 = rotate(v2, facing);
v3 = rotate(v3, facing);
v4 = rotate(v4, facing);
face = rotateFacing(face);
Vec3d normal = v1.getVec3d().subtract(v2.getVec3d()).crossProduct(v3.getVec3d().subtract(v2.getVec3d()));
UnpackedBakedQuad.Builder builder = new UnpackedBakedQuad.Builder(format);
builder.setTexture(sprite);
builder.setQuadOrientation(face);
putVertex(builder, face, normal, v1.x, v1.y, v1.z, v1.u, v1.v);
putVertex(builder, face, normal, v2.x, v2.y, v2.z, v2.u, v2.v);
putVertex(builder, face, normal, v3.x, v3.y, v3.z, v3.u, v3.v);
putVertex(builder, face, normal, v4.x, v4.y, v4.z, v4.u, v4.v);
return builder.build();
}
private void putVertex(UnpackedBakedQuad.Builder builder, EnumFacing side, Vec3d normal, double x, double y, double z, float u, float v)
{
for (int i = 0; i < format.getElementCount(); i++)
{
switch (format.getElement(i).getUsage())
{
case POSITION:
builder.put(i, (float) x, (float) y, (float) z, 1.0F);
break;
case COLOR:
builder.put(i, 1.0F, 1.0F, 1.0F, 1.0F);
break;
case UV: if (format.getElement(i).getIndex() == 0)
{
u = sprite.getInterpolatedU(u);
v = sprite.getInterpolatedV(v);
builder.put(i, u, v, 0.0F, 1.0F);
break;
}
case NORMAL:
builder.put(i, (float) side.getFrontOffsetX(), (float) side.getFrontOffsetY(), (float) side.getFrontOffsetZ(), 0.0F);
break;
default:
builder.put(i);
break;
}
}
}
public void setSprite(TextureAtlasSprite sprite)
{
this.sprite = sprite;
}
public void setFacing(EnumFacing facing)
{
if(facing == null) return;
this.facing = facing;
}
public static class Vertex
{
public double x;
public double y;
public double z;
public float u;
public float v;
public Vertex(double x, double y, double z)
{
this.x = x;
this.y = y;
this.z = z;
}
public Vertex(double x, double y, double z, float u, float v)
{
this.x = x;
this.y = y;
this.z = z;
this.u = u;
this.v = v;
}
public Vec3d getVec3d()
{
return new Vec3d(x, y, z);
}
}
public static Vertex rotate(Vertex vertex, EnumFacing facing)
{
switch (facing)
{
case WEST:
vertex.x = 1.0 - vertex.x;
vertex.z = 1.0 - vertex.z;
break;
case NORTH:
vertex.x = 1.0 - vertex.x;
double temp_1 = vertex.x;
vertex.x = vertex.z;
vertex.z = temp_1;
break;
case SOUTH:
vertex.z = 1.0 - vertex.z;
double temp_2 = vertex.z;
vertex.z = vertex.x;
vertex.x = temp_2;
break;
default:
break;
}
return vertex;
}
/**
* Get the index of this horizontal facing (0-3). The order is S0-W1-N2-E3
*/
public EnumFacing rotateFacing(EnumFacing side)
{
if(side.getAxis() == Axis.Y) return side;
switch(facing)
{
case NORTH:
return side.rotateYCCW();
case WEST:
return side.getOpposite();
case SOUTH:
return side.rotateY();
default:
return side;
}
}
}