package codechicken.lib.render; import codechicken.lib.lighting.LC; import codechicken.lib.render.CCRenderState.VertexAttribute; import codechicken.lib.vec.Cuboid6; import net.minecraft.client.renderer.block.model.ItemCameraTransforms; import net.minecraft.client.renderer.block.model.ItemTransformVec3f; import org.lwjgl.util.vector.Vector3f; public class BlockRenderer { public static class BlockFace implements CCRenderState.IVertexSource { public Vertex5[] verts = new Vertex5[] { new Vertex5(), new Vertex5(), new Vertex5(), new Vertex5() }; public LC[] lightCoords = new LC[] { new LC(), new LC(), new LC(), new LC() }; public boolean lcComputed = false; public int side; @Override public Vertex5[] getVertices() { return verts; } @Override public <T> T getAttributes(CCRenderState.VertexAttribute<T> attr) { return attr == CCRenderState.lightCoordAttrib && lcComputed ? (T) lightCoords : null; } @Override public boolean hasAttribute(CCRenderState.VertexAttribute<?> attr) { return attr == CCRenderState.sideAttrib || attr == CCRenderState.lightCoordAttrib && lcComputed; } @Override public void prepareVertex() { CCRenderState.side = side; } public BlockFace computeLightCoords() { if (!lcComputed) { for (int i = 0; i < 4; i++) { lightCoords[i].compute(verts[i].vec, side); } lcComputed = true; } return this; } public BlockFace loadCuboidFace(Cuboid6 c, int side) { double x1 = c.min.x; double x2 = c.max.x; double y1 = c.min.y; double y2 = c.max.y; double z1 = c.min.z; double z2 = c.max.z; double u1; double u2; double v1; double v2; this.side = side; lcComputed = false; switch (side) { case 0: u1 = x1; v1 = z1; u2 = x2; v2 = z2; verts[0].set(x1, y1, z2, u1, v2, 0); verts[1].set(x1, y1, z1, u1, v1, 0); verts[2].set(x2, y1, z1, u2, v1, 0); verts[3].set(x2, y1, z2, u2, v2, 0); break; case 1: u1 = x1; v1 = z1; u2 = x2; v2 = z2; verts[0].set(x2, y2, z2, u2, v2, 1); verts[1].set(x2, y2, z1, u2, v1, 1); verts[2].set(x1, y2, z1, u1, v1, 1); verts[3].set(x1, y2, z2, u1, v2, 1); break; case 2: u1 = 1 - x1; v1 = 1 - y2; u2 = 1 - x2; v2 = 1 - y1; verts[0].set(x1, y1, z1, u1, v2, 2); verts[1].set(x1, y2, z1, u1, v1, 2); verts[2].set(x2, y2, z1, u2, v1, 2); verts[3].set(x2, y1, z1, u2, v2, 2); break; case 3: u1 = x1; v1 = 1 - y2; u2 = x2; v2 = 1 - y1; verts[0].set(x2, y1, z2, u2, v2, 3); verts[1].set(x2, y2, z2, u2, v1, 3); verts[2].set(x1, y2, z2, u1, v1, 3); verts[3].set(x1, y1, z2, u1, v2, 3); break; case 4: u1 = z1; v1 = 1 - y2; u2 = z2; v2 = 1 - y1; verts[0].set(x1, y1, z2, u2, v2, 4); verts[1].set(x1, y2, z2, u2, v1, 4); verts[2].set(x1, y2, z1, u1, v1, 4); verts[3].set(x1, y1, z1, u1, v2, 4); break; case 5: u1 = 1 - z1; v1 = 1 - y2; u2 = 1 - z2; v2 = 1 - y1; verts[0].set(x2, y1, z1, u1, v2, 5); verts[1].set(x2, y2, z1, u1, v1, 5); verts[2].set(x2, y2, z2, u2, v1, 5); verts[3].set(x2, y1, z2, u2, v2, 5); } return this; } } public static class FullBlock implements CCRenderState.IVertexSource { public Vertex5[] verts = CCModel.quadModel(24).generateBlock(0, Cuboid6.full).verts; public LC[] lightCoords = new LC[24]; public FullBlock() { for (int i = 0; i < 24; i++) { lightCoords[i] = new LC().compute(verts[i].vec, i / 4); } } @Override public Vertex5[] getVertices() { return verts; } @Override public <T> T getAttributes(VertexAttribute<T> attr) { return attr == CCRenderState.lightCoordAttrib ? (T) lightCoords : null; } @Override public boolean hasAttribute(VertexAttribute<?> attr) { return attr == CCRenderState.sideAttrib || attr == CCRenderState.lightCoordAttrib; } @Override public void prepareVertex() { CCRenderState.side = CCRenderState.vertexIndex >> 2; } } public static ItemTransformVec3f thirdPersonTransform = new ItemTransformVec3f(new Vector3f(10, -45, 170), new Vector3f(0, 1.5F / 16F, -2.75F / 16F), new Vector3f(0.375F, 0.375F, 0.375F)); public static ItemCameraTransforms blockCameraTransform = new ItemCameraTransforms(thirdPersonTransform, ItemTransformVec3f.DEFAULT, ItemTransformVec3f.DEFAULT, ItemTransformVec3f.DEFAULT, ItemTransformVec3f.DEFAULT, ItemTransformVec3f.DEFAULT); public static FullBlock fullBlock = new FullBlock(); public static void renderFullBlock(int sideMask) { CCRenderState.setModel(fullBlock); renderFaces(sideMask); } /** * Renders faces of a block-like model based on a sideMask. Eg for side 2, verts 8-11 will be rendered * * @param sideMask A mask of faces not to render */ public static void renderFaces(int sideMask) { if (sideMask == 0x3F) { return; } for (int s = 0; s < 6; s++) { if ((sideMask & 1 << s) == 0) { CCRenderState.setVertexRange(s * 4, (s + 1) * 4); CCRenderState.render(); } } } private static BlockFace face = new BlockFace(); /** * Renders faces of a cuboid with texture coordinates mapped to match a standard minecraft block * * @param bounds The bounding cuboid to render * @param sideMask A mask of faces not to render */ public static void renderCuboid(Cuboid6 bounds, int sideMask) { if (sideMask == 0x3F) { return; } CCRenderState.setModel(face); for (int s = 0; s < 6; s++) { if ((sideMask & 1 << s) == 0) { face.loadCuboidFace(bounds, s); CCRenderState.render(); } } } }