package com.jaquadro.minecraft.gardencore.util; import net.minecraft.client.renderer.Tessellator; import net.minecraft.util.IIcon; public class RenderHelperLL { private static final int TL = 0; private static final int BL = 1; private static final int BR = 2; private static final int TR = 3; private static final int MINX = 0; private static final int MAXX = 1; private static final int MINY = 2; private static final int MAXY = 3; private static final int MINZ = 4; private static final int MAXZ = 5; private static final int xyzuvMap[][][] = { { // Y-NEG { 0, 2, 5, 0, 3 }, { 0, 2, 4, 0, 2 }, { 1, 2, 4, 1, 2 }, { 1, 2, 5, 1, 3 } }, { // Y-POS { 1, 3, 5, 1, 3 }, { 1, 3, 4, 1, 2 }, { 0, 3, 4, 0, 2 }, { 0, 3, 5, 0, 3 } }, { // Z-NEG { 0, 3, 4, 1, 2 }, { 1, 3, 4, 0, 2 }, { 1, 2, 4, 0, 3 }, { 0, 2, 4, 1, 3 } }, { // Z-POS { 0, 3, 5, 0, 2 }, { 0, 2, 5, 0, 3 }, { 1, 2, 5, 1, 3 }, { 1, 3, 5, 1, 2 } }, { // X-NEG { 0, 3, 5, 1, 2 }, { 0, 3, 4, 0, 2 }, { 0, 2, 4, 0, 3 }, { 0, 2, 5, 1, 3 } }, { // X-POS { 1, 2, 5, 0, 3 }, { 1, 2, 4, 1, 3 }, { 1, 3, 4, 1, 2 }, { 1, 3, 5, 0, 2 } }, }; private RenderHelperState state; private double[] minUDiv = new double[24]; private double[] maxUDiv = new double[24]; private double[] minVDiv = new double[24]; private double[] maxVDiv = new double[24]; private int[][] brightnessLerp = new int[10][10]; // u-min, u-max, v-min, v-max private double[] uv = new double[4]; // x-min, x-max, y-min, y-max, z-min, z-max private double[] xyz = new double[6]; public RenderHelperLL (RenderHelperState state) { this.state = state; } public void drawFace (int face, double x, double y, double z, IIcon icon) { boolean flip = state.flipTexture; switch (face) { case RenderHelper.YNEG: case RenderHelper.YPOS: drawFaceY(face, x, y, z, icon); break; case RenderHelper.ZNEG: case RenderHelper.ZPOS: if (state.rotateTransform == RenderHelperState.ROTATE180 || state.rotateTransform == RenderHelperState.ROTATE90) state.flipTexture = !state.flipTexture; drawFaceZ(face, x, y, z, icon); break; case RenderHelper.XNEG: case RenderHelper.XPOS: if (state.rotateTransform == RenderHelperState.ROTATE180 || state.rotateTransform == RenderHelperState.ROTATE270) state.flipTexture = !state.flipTexture; drawFaceX(face, x, y, z, icon); break; } state.flipTexture = flip; } private void drawFaceY (int face, double x, double y, double z, IIcon icon) { int rangeX = (int)(Math.ceil(state.renderMaxX + state.shiftU) - Math.floor(state.renderMinX + state.shiftU)); int rangeZ = (int)(Math.ceil(state.renderMaxZ + state.shiftV) - Math.floor(state.renderMinZ + state.shiftV)); setXYZ(x, y, z); if (state.renderFromInside) { xyz[MINX] = z + state.renderMaxX; xyz[MAXX] = z + state.renderMinX; } if (rangeX <= 1 && rangeZ <= 1) { setUV(icon, state.renderMinX + state.shiftU, state.renderMinZ + state.shiftV, state.renderMaxX + state.shiftU, state.renderMaxZ + state.shiftV); if (state.enableAO) renderXYZUVAO(xyzuvMap[face]); else renderXYZUV(xyzuvMap[face]); return; } double uStart = (state.renderMinX + state.shiftU + rangeX) % 1.0; double uStop = (state.renderMaxX + state.shiftU + rangeX) % 1.0; double vStart = (state.renderMinZ + state.shiftV + rangeZ) % 1.0; double vStop = (state.renderMaxZ + state.shiftV + rangeZ) % 1.0; setupUVPoints(uStart, vStart, uStop, vStop, rangeX, rangeZ, icon); setupAOBrightnessLerp(state.renderMinX, state.renderMaxX, state.renderMinZ, state.renderMaxZ, rangeX, rangeZ); int rotate = (face == 0) ? state.uvRotate[0] : state.uvRotate[1]; for (int ix = 0; ix < rangeX; ix++) { xyz[MAXX] = xyz[MINX] + maxUDiv[ix] - minUDiv[ix]; xyz[MINZ] = z + state.renderMinZ; for (int iz = 0; iz < rangeZ; iz++) { xyz[MAXZ] = xyz[MINZ] + maxVDiv[iz] - minVDiv[iz]; state.brightnessTopLeft = brightnessLerp[ix][iz]; state.brightnessTopRight = brightnessLerp[ix + 1][iz]; state.brightnessBottomLeft = brightnessLerp[ix][iz + 1]; state.brightnessBottomRight = brightnessLerp[ix + 1][iz + 1]; switch (rotate) { case RenderHelperState.ROTATE90: setUV(icon, maxVDiv[ix], minUDiv[iz], minVDiv[ix], maxUDiv[iz]); break; case RenderHelperState.ROTATE180: setUV(icon, maxUDiv[ix], maxVDiv[iz], minUDiv[ix], minVDiv[iz]); break; case RenderHelperState.ROTATE270: setUV(icon, minVDiv[ix], maxUDiv[iz], maxVDiv[ix], minUDiv[iz]); break; default: setUV(icon, minUDiv[ix], minVDiv[iz], maxUDiv[ix], maxVDiv[iz]); break; } renderXYZUVAO(xyzuvMap[face]); xyz[MINZ] = xyz[MAXZ]; } xyz[MINX] = xyz[MAXX]; } } private void drawFaceZ (int face, double x, double y, double z, IIcon icon) { int rangeX = (int)(Math.ceil(state.renderMaxX + state.shiftU) - Math.floor(state.renderMinX + state.shiftU)); int rangeY = (int)(Math.ceil(state.renderMaxY + state.shiftV) - Math.floor(state.renderMinY + state.shiftV)); setXYZ(x, y, z); if (state.renderFromInside) { xyz[MINX] = z + state.renderMaxX; xyz[MAXX] = z + state.renderMinX; } if (rangeX <= 1 && rangeY <= 1) { if (state.flipTexture) setUV(icon, state.renderMaxX + state.shiftU, 1 - state.renderMaxY + state.shiftV, state.renderMinX + state.shiftU, 1 - state.renderMinY + state.shiftV); else setUV(icon, state.renderMinX + state.shiftU, 1 - state.renderMaxY + state.shiftV, state.renderMaxX + state.shiftU, 1 - state.renderMinY + state.shiftV); if (state.enableAO) renderXYZUVAO(xyzuvMap[face]); else renderXYZUV(xyzuvMap[face]); return; } double uStart = (state.renderMinX + state.shiftU + rangeX) % 1.0; double uStop = (state.renderMaxX + state.shiftU + rangeX) % 1.0; double vStart = (state.renderMinY + state.shiftV + rangeY) % 1.0; double vStop = (state.renderMaxY + state.shiftV + rangeY) % 1.0; setupUVPoints(uStart, vStart, uStop, vStop, rangeX, rangeY, icon); setupAOBrightnessLerp(state.renderMinX, state.renderMaxX, state.renderMinY, state.renderMaxY, rangeX, rangeY); for (int ix = 0; ix < rangeX; ix++) { xyz[MAXX] = xyz[MINX] + maxUDiv[ix] - minUDiv[ix]; xyz[MINY] = y + state.renderMinY; for (int iy = 0; iy < rangeY; iy++) { xyz[MAXY] = xyz[MINY] + maxVDiv[iy] - minVDiv[iy]; state.brightnessTopLeft = brightnessLerp[ix][iy]; state.brightnessTopRight = brightnessLerp[ix + 1][iy]; state.brightnessBottomLeft = brightnessLerp[ix][iy + 1]; state.brightnessBottomRight = brightnessLerp[ix + 1][iy + 1]; if (state.flipTexture) setUV(icon, 1 - minUDiv[ix], 1 - maxVDiv[iy], 1 - maxUDiv[ix], 1 - minVDiv[iy]); else setUV(icon, minUDiv[ix], 1 - maxVDiv[iy], maxUDiv[ix], 1 - minVDiv[iy]); renderXYZUVAO(xyzuvMap[face]); xyz[MINY] = xyz[MAXY]; } xyz[MINX] = xyz[MAXX]; } } private void drawFaceX (int face, double x, double y, double z, IIcon icon) { int rangeZ = (int)(Math.ceil(state.renderMaxZ + state.shiftU) - Math.floor(state.renderMinZ + state.shiftU)); int rangeY = (int)(Math.ceil(state.renderMaxY + state.shiftV) - Math.floor(state.renderMinY + state.shiftV)); setXYZ(x, y, z); if (state.renderFromInside) { xyz[MINZ] = z + state.renderMaxZ; xyz[MAXZ] = z + state.renderMinZ; } if (rangeZ <= 1 && rangeY <= 1) { if (state.flipTexture) setUV(icon, state.renderMaxZ + state.shiftU, 1 - state.renderMaxY + state.shiftV, state.renderMinZ + state.shiftU, 1 - state.renderMinY + state.shiftV); else setUV(icon, state.renderMinZ + state.shiftU, 1 - state.renderMaxY + state.shiftV, state.renderMaxZ + state.shiftU, 1 - state.renderMinY + state.shiftV); if (state.enableAO) renderXYZUVAO(xyzuvMap[face]); else renderXYZUV(xyzuvMap[face]); return; } double uStart = (state.renderMinZ + state.shiftU + rangeZ) % 1.0; double uStop = (state.renderMaxZ + state.shiftU + rangeZ) % 1.0; double vStart = (state.renderMinY + state.shiftV + rangeY) % 1.0; double vStop = (state.renderMaxY + state.shiftV + rangeY) % 1.0; setupUVPoints(uStart, vStart, uStop, vStop, rangeZ, rangeY, icon); setupAOBrightnessLerp(state.renderMinZ, state.renderMaxZ, state.renderMinY, state.renderMaxY, rangeZ, rangeY); for (int iz = 0; iz < rangeZ; iz++) { xyz[MAXZ] = xyz[MINZ] + maxUDiv[iz] - minUDiv[iz]; xyz[MINY] = y + state.renderMinY; for (int iy = 0; iy < rangeY; iy++) { xyz[MAXY] = xyz[MINY] + maxVDiv[iy] - minVDiv[iy]; state.brightnessTopLeft = brightnessLerp[iz][iy]; state.brightnessTopRight = brightnessLerp[iz + 1][iy]; state.brightnessBottomLeft = brightnessLerp[iz][iy + 1]; state.brightnessBottomRight = brightnessLerp[iz + 1][iy + 1]; if (state.flipTexture) setUV(icon, 1 - minUDiv[iz], 1 - maxVDiv[iy], 1 - maxUDiv[iz], 1 - minVDiv[iy]); else setUV(icon, minUDiv[iz], 1 - maxVDiv[iy], maxUDiv[iz], 1 - minVDiv[iy]); renderXYZUVAO(xyzuvMap[face]); xyz[MINY] = xyz[MAXY]; } xyz[MINZ] = xyz[MAXZ]; } } public void drawPartialFace (int face, double x, double y, double z, IIcon icon, double uMin, double vMin, double uMax, double vMax) { setXYZ(x, y, z); setUV(icon, uMin, vMin, uMax, vMax); if (state.enableAO) renderXYZUVAO(xyzuvMap[face]); else renderXYZUV(xyzuvMap[face]); } private void setupUVPoints (double uStart, double vStart, double uStop, double vStop, int rangeU, int rangeV, IIcon icon) { if (rangeU <= 1) { minUDiv[0] = uStart; maxUDiv[0] = uStop; } else { minUDiv[0] = uStart; maxUDiv[0] = 1; for (int i = 1; i < rangeU - 1; i++) { minUDiv[i] = 0; maxUDiv[i] = 1; } minUDiv[rangeU - 1] = 0; maxUDiv[rangeU - 1] = uStop; } if (rangeV <= 1) { minVDiv[0] = vStart; maxVDiv[0] = vStop; } else { minVDiv[0] = vStart; maxVDiv[0] = 1; for (int i = 1; i < rangeV - 1; i++) { minVDiv[i] = 0; maxVDiv[i] = 1; } minVDiv[rangeV - 1] = 0; maxVDiv[rangeV - 1] = vStop; } } private void setupAOBrightnessLerp (double left, double right, double top, double bottom, int rangeLR, int rangeTB) { double diffLR = right - left; double diffTB = bottom - top; double posLR = 0; for (int lr = 0; lr <= rangeLR; lr++) { float lerpLR = (float)(posLR / diffLR); int brightTop = RenderHelperAO.mixAOBrightness(state.brightnessTopLeft, state.brightnessTopRight, 1 - lerpLR, lerpLR); int brightBottom = RenderHelperAO.mixAOBrightness(state.brightnessBottomLeft, state.brightnessBottomRight, 1 - lerpLR, lerpLR); double posTB = 0; for (int tb = 0; tb <= rangeTB; tb++) { float lerpTB = (float)(posTB / diffTB); brightnessLerp[lr][tb] = RenderHelperAO.mixAOBrightness(brightTop, brightBottom, 1 - lerpTB, lerpTB); if (tb < rangeTB) posTB += maxVDiv[tb] - minVDiv[tb]; } if (lr < rangeLR) posLR += maxUDiv[lr] - minUDiv[lr]; } } private void setUV (IIcon icon, double uMin, double vMin, double uMax, double vMax) { uv[0] = icon.getInterpolatedU(uMin * 16); uv[1] = icon.getInterpolatedU(uMax * 16); uv[2] = icon.getInterpolatedV(vMin * 16); uv[3] = icon.getInterpolatedV(vMax * 16); } private void setUV (double uMin, double vMin, double uMax, double vMax) { uv[0] = uMin; uv[1] = uMax; uv[2] = vMin; uv[3] = vMax; } private void setXYZ (double x, double y, double z) { xyz[0] = x + state.renderOffsetX + state.renderMinX; xyz[1] = x + state.renderOffsetX + state.renderMaxX; xyz[2] = y + state.renderOffsetY + state.renderMinY; xyz[3] = y + state.renderOffsetY + state.renderMaxY; xyz[4] = z + state.renderOffsetZ + state.renderMinZ; xyz[5] = z + state.renderOffsetZ + state.renderMaxZ; } private void renderXYZUV (int[][] index) { Tessellator tessellator = Tessellator.instance; int[] tl = index[TL]; int[] bl = index[BL]; int[] br = index[BR]; int[] tr = index[TR]; tessellator.addVertexWithUV(xyz[tl[0]], xyz[tl[1]], xyz[tl[2]], uv[tl[3]], uv[tl[4]]); tessellator.addVertexWithUV(xyz[bl[0]], xyz[bl[1]], xyz[bl[2]], uv[bl[3]], uv[bl[4]]); tessellator.addVertexWithUV(xyz[br[0]], xyz[br[1]], xyz[br[2]], uv[br[3]], uv[br[4]]); tessellator.addVertexWithUV(xyz[tr[0]], xyz[tr[1]], xyz[tr[2]], uv[tr[3]], uv[tr[4]]); } private void renderXYZUVAO (int[][] index) { Tessellator tessellator = Tessellator.instance; int[] tl = index[TL]; int[] bl = index[BL]; int[] br = index[BR]; int[] tr = index[TR]; tessellator.setColorOpaque_F(state.colorTopLeft[0], state.colorTopLeft[1], state.colorTopLeft[2]); tessellator.setBrightness(state.brightnessTopLeft); tessellator.addVertexWithUV(xyz[tl[0]], xyz[tl[1]], xyz[tl[2]], uv[tl[3]], uv[tl[4]]); tessellator.setColorOpaque_F(state.colorBottomLeft[0], state.colorBottomLeft[1], state.colorBottomLeft[2]); tessellator.setBrightness(state.brightnessBottomLeft); tessellator.addVertexWithUV(xyz[bl[0]], xyz[bl[1]], xyz[bl[2]], uv[bl[3]], uv[bl[4]]); tessellator.setColorOpaque_F(state.colorBottomRight[0], state.colorBottomRight[1], state.colorBottomRight[2]); tessellator.setBrightness(state.brightnessBottomRight); tessellator.addVertexWithUV(xyz[br[0]], xyz[br[1]], xyz[br[2]], uv[br[3]], uv[br[4]]); tessellator.setColorOpaque_F(state.colorTopRight[0], state.colorTopRight[1], state.colorTopRight[2]); tessellator.setBrightness(state.brightnessTopRight); tessellator.addVertexWithUV(xyz[tr[0]], xyz[tr[1]], xyz[tr[2]], uv[tr[3]], uv[tr[4]]); } }