Files
Chisel/src/main/java/com/cricketcraft/chisel/client/render/RenderBlocksCTM.java
T

430 lines
15 KiB
Java
Raw Normal View History

2014-12-15 00:11:48 +00:00
package com.cricketcraft.chisel.client.render;
import net.minecraft.block.Block;
import net.minecraft.client.renderer.RenderBlocks;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.util.IIcon;
import static com.cricketcraft.chisel.client.render.RenderBlocksCTM.Vert.*;
import static com.cricketcraft.chisel.client.render.RenderBlocksCTM.SubSide.*;
2015-02-20 00:32:05 -05:00
import static com.cricketcraft.chisel.client.render.RenderBlocksCTM.Vert.Y_HALF_X;
public class RenderBlocksCTM extends RenderBlocks {
/**
* An enum for all possible 26 sub-side vertices.
2015-03-01 12:52:10 -05:00
*
* The naming scheme is as follows:
2015-03-01 12:52:10 -05:00
*
* ZERO and ONE are special cases, they are the absolute min and absolute
* max of the block. X, Y, Z, or any combination means that the axes listed
* in the name are at 1. X, Y, Z, or any combination followed by HALF means
* that those axes are at 0.5. X, Y, Z, or any combination after a HALF
* means those axes are at 1.
*/
enum Vert {
// @formatter:off
ZERO(0, 0, 0),
2015-02-20 00:32:05 -05:00
XYZ(1, 1, 1),
X(1, 0, 0),
Y(0, 1, 0),
Z(0, 0, 1),
XY(1, 1, 0),
YZ(0, 1, 1),
XZ(1, 0, 1),
X_HALF(0.5, 0, 0),
Y_HALF(0, 0.5, 0),
Z_HALF(0, 0, 0.5),
XY_HALF(0.5, 0.5, 0),
YZ_HALF(0, 0.5, 0.5),
XZ_HALF(0.5, 0, 0.5),
X_HALF_Y(0.5, 1, 0),
X_HALF_Z(0.5, 0, 1),
Y_HALF_X(1, 0.5, 0),
Y_HALF_Z(0, 0.5, 1),
Z_HALF_X(1, 0, 0.5),
Z_HALF_Y(0, 1, 0.5),
X_HALF_YZ(0.5, 1, 1),
Y_HALF_XZ(1, 0.5, 1),
Z_HALF_XY(1, 1, 0.5),
XY_HALF_Z(0.5, 0.5, 1),
YZ_HALF_X(1, 0.5, 0.5),
XZ_HALF_Y(0.5, 1, 0.5);
// @formatter:on
private double x, y, z;
private Vert(double x, double y, double z) {
this.x = x;
this.y = y;
this.z = z;
}
void render(RenderBlocksCTM inst, int cacheID) {
if (inst.enableAO) {
inst.tessellator.setColorOpaque_F(inst.redCache[cacheID], inst.grnCache[cacheID], inst.bluCache[cacheID]);
inst.tessellator.setBrightness(inst.lightingCache[cacheID]);
}
inst.tessellator.addVertexWithUV(x, y, z, inst.uCache[cacheID], inst.vCache[cacheID]);
}
}
/**
* Each side is divided into 4 sub-sides. LB(left bottom), RB(right bottom),
* LT(right top), and RT(right top).
*
* Each sub-side contains 4 {@link Vert} objects representing its position
* on the block.
*/
enum SubSide {
// @formatter:off
XNEG_LB(ZERO, Z_HALF, YZ_HALF, Y_HALF), XNEG_RB(Z_HALF, Z, Y_HALF_Z, YZ_HALF), XNEG_RT(YZ_HALF, Y_HALF_Z, YZ, Z_HALF_Y), XNEG_LT(Y_HALF, YZ_HALF, Z_HALF_Y, Y),
XPOS_LB(XZ, Z_HALF_X, YZ_HALF_X, Y_HALF_XZ), XPOS_RB(Z_HALF_X, X, Y_HALF_X, YZ_HALF_X), XPOS_RT(YZ_HALF_X, Y_HALF_X, XY, Z_HALF_XY), XPOS_LT(Y_HALF_XZ, YZ_HALF_X, Z_HALF_XY, XYZ),
2015-02-20 00:32:05 -05:00
ZNEG_LB(X, X_HALF, XY_HALF, Y_HALF_X), ZNEG_RB(X_HALF, ZERO, Y_HALF, XY_HALF), ZNEG_RT(XY_HALF, Y_HALF, Y, X_HALF_Y), ZNEG_LT(Y_HALF_X, XY_HALF, X_HALF_Y, XY),
ZPOS_LB(Z, X_HALF_Z, XY_HALF_Z, Y_HALF_Z), ZPOS_RB(X_HALF_Z, XZ, Y_HALF_XZ, XY_HALF_Z), ZPOS_RT(XY_HALF_Z, Y_HALF_XZ, XYZ, X_HALF_YZ), ZPOS_LT(Y_HALF_Z, XY_HALF_Z, X_HALF_YZ, YZ),
2015-02-20 00:32:05 -05:00
YNEG_LB(ZERO, X_HALF, XZ_HALF, Z_HALF), YNEG_RB(X_HALF, X, Z_HALF_X, XZ_HALF), YNEG_RT(XZ_HALF, Z_HALF_X, XZ, X_HALF_Z), YNEG_LT(Z_HALF, XZ_HALF, X_HALF_Z, Z),
YPOS_LB(YZ, X_HALF_YZ, XZ_HALF_Y, Z_HALF_Y), YPOS_RB(X_HALF_YZ, XYZ, Z_HALF_XY, XZ_HALF_Y), YPOS_RT(XZ_HALF_Y, Z_HALF_XY, XY, X_HALF_Y), YPOS_LT(Z_HALF_Y, XZ_HALF_Y, X_HALF_Y, Y);
// @formatter:on
private Vert xmin, xmax, ymin, ymax;
SubSide(Vert xmin, Vert ymin, Vert ymax, Vert xmax) {
this.xmin = xmin;
this.ymin = ymin;
this.ymax = ymax;
this.xmax = xmax;
}
void render(RenderBlocksCTM inst) {
xmin.render(inst, 0);
ymin.render(inst, 1);
ymax.render(inst, 2);
xmax.render(inst, 3);
}
}
private static CTM ctm = CTM.getInstance();
// globals added to save the JVM some trouble. No need to constantly create
// and destroy ints if we don't have to
int blockLightBitChannel = 0;
int redBitChannel = 0;
int greenBitChannel = 0;
int blueBitChannel = 0;
int sunlightBitChannel = 0;
RenderBlocksCTM() {
super();
}
Tessellator tessellator;
double[] uCache = new double[4];
double[] vCache = new double[4];
int[] lightingCache = new int[4];
float[] redCache = new float[4];
float[] grnCache = new float[4];
float[] bluCache = new float[4];
TextureSubmap submap;
TextureSubmap submapSmall;
RenderBlocks rendererOld;
int[][] lightmap = new int[3][3];
float[][] redmap = new float[3][3];
float[][] grnmap = new float[3][3];
float[][] blumap = new float[3][3];
2015-02-20 00:32:05 -05:00
int bx, by, bz;
@Override
public boolean renderStandardBlock(Block block, int x, int y, int z) {
bx = x;
by = y;
bz = z;
tessellator = Tessellator.instance;
tessellator.setColorOpaque_F(1.0F, 1.0F, 1.0F);
tessellator.addTranslation(x, y, z);
boolean res = super.renderStandardBlock(block, x, y, z);
tessellator.addTranslation(-x, -y, -z);
return res;
}
/* @formatter:off
* This method fills a 3x3 grid of light values based on the four corners, by averaging them together.
*
* 2 TL x TR
*
* 1 x x x
*
* 0 BL x BR
* 0 1 2
*
* Note: Variable names mean nothing... don't touch
*
* ._.
*
* shakes fist in anger
*/
// @formatter:on
void fillLightmap(int bottomLeft, int bottomRight, int topRight, int topLeft) {
lightmap[0][0] = bottomLeft;
lightmap[2][0] = bottomRight;
lightmap[2][2] = topRight;
lightmap[0][2] = topLeft;
lightmap[1][0] = avg(bottomLeft, bottomRight);
lightmap[2][1] = avg(bottomRight, topRight);
lightmap[1][2] = avg(topRight, topLeft);
lightmap[0][1] = avg(topLeft, bottomLeft);
lightmap[1][1] = avg(bottomLeft, bottomRight, topRight, topLeft);
}
void fillColormap(float bottomLeft, float bottomRight, float topRight, float topLeft, float[][] map) {
map[0][0] = bottomLeft;
map[2][0] = bottomRight;
map[2][2] = topRight;
map[0][2] = topLeft;
2015-02-20 00:32:05 -05:00
map[1][0] = (bottomLeft + bottomRight) / 2.0F;
map[2][1] = (bottomRight + topRight) / 2.0F;
map[1][2] = (topRight + topLeft) / 2.0F;
map[0][1] = (topLeft + bottomLeft) / 2.0F;
map[1][1] = (bottomLeft + bottomRight + topRight + topLeft) / 4.0F;
}
void getLight(int x, int y) {
lightingCache[0] = lightmap[0 + x][0 + y];
lightingCache[1] = lightmap[1 + x][0 + y];
lightingCache[2] = lightmap[1 + x][1 + y];
lightingCache[3] = lightmap[0 + x][1 + y];
redCache[0] = redmap[0 + x][0 + y];
redCache[1] = redmap[1 + x][0 + y];
redCache[2] = redmap[1 + x][1 + y];
redCache[3] = redmap[0 + x][1 + y];
grnCache[0] = grnmap[0 + x][0 + y];
grnCache[1] = grnmap[1 + x][0 + y];
grnCache[2] = grnmap[1 + x][1 + y];
grnCache[3] = grnmap[0 + x][1 + y];
bluCache[0] = blumap[0 + x][0 + y];
bluCache[1] = blumap[1 + x][0 + y];
bluCache[2] = blumap[1 + x][1 + y];
bluCache[3] = blumap[0 + x][1 + y];
}
2015-02-20 00:32:05 -05:00
/**
2015-02-20 00:32:05 -05:00
* This works around a bug in CLC atm
*/
2015-02-20 00:32:05 -05:00
int avg(int... lightVals) {
blockLightBitChannel = 0;
redBitChannel = 0;
greenBitChannel = 0;
blueBitChannel = 0;
sunlightBitChannel = 0;
for (int light : lightVals) {
blockLightBitChannel += (light & 0xFF);
redBitChannel += (light & 0xF00);
greenBitChannel += (light & 0xF000);
blueBitChannel += (light & 0xF0000);
sunlightBitChannel += (light & 0xF00000);
}
return ((blockLightBitChannel / lightVals.length) & 0xFF) | ((redBitChannel / lightVals.length) & 0xF00) | ((greenBitChannel / lightVals.length) & 0xF000)
| ((blueBitChannel / lightVals.length) & 0xF0000) | ((sunlightBitChannel / lightVals.length) & 0xF00000);
}
2015-03-01 12:52:10 -05:00
void side(SubSide side, int iconIndex) {
IIcon icon = iconIndex >= 16 ? submapSmall.icons[iconIndex - 16] : submap.icons[iconIndex];
double umax = icon.getMaxU();
double umin = icon.getMinU();
double vmax = icon.getMaxV();
double vmin = icon.getMinV();
2015-03-01 12:52:10 -05:00
uCache[0] = umin;
uCache[1] = umax;
2015-03-01 12:52:10 -05:00
uCache[2] = umax;
uCache[3] = umin;
2015-03-01 12:52:10 -05:00
vCache[0] = vmax;
vCache[1] = vmax;
2015-03-01 12:52:10 -05:00
vCache[2] = vmin;
vCache[3] = vmin;
side.render(this);
}
@Override
public void renderFaceXNeg(Block block, double x, double y, double z, IIcon icon) {
if (rendererOld != null && rendererOld.hasOverrideBlockTexture()) {
IIcon i = rendererOld.overrideBlockTexture;
tessellator.addVertexWithUV(0.0, 1.0, 0.0, i.getMinU(), i.getMinV());
tessellator.addVertexWithUV(0.0, 0.0, 0.0, i.getMinU(), i.getMaxV());
tessellator.addVertexWithUV(0.0, 0.0, 1.0, i.getMaxU(), i.getMaxV());
tessellator.addVertexWithUV(0.0, 1.0, 1.0, i.getMaxU(), i.getMinV());
} else {
int tex[] = ctm.getSubmapIndices(blockAccess, bx, by, bz, 4);
fillLightmap(brightnessBottomRight, brightnessTopRight, brightnessTopLeft, brightnessBottomLeft);
fillColormap(colorRedBottomRight, colorRedTopRight, colorRedTopLeft, colorRedBottomLeft, redmap);
fillColormap(colorGreenBottomRight, colorGreenTopRight, colorGreenTopLeft, colorGreenBottomLeft, grnmap);
fillColormap(colorBlueBottomRight, colorBlueTopRight, colorBlueTopLeft, colorBlueBottomLeft, blumap);
getLight(0, 0);
2015-03-01 12:52:10 -05:00
side(XNEG_LB, tex[0]);
getLight(1, 0);
2015-03-01 12:52:10 -05:00
side(XNEG_RB, tex[1]);
getLight(1, 1);
2015-03-01 12:52:10 -05:00
side(XNEG_RT, tex[2]);
getLight(0, 1);
2015-03-01 12:52:10 -05:00
side(XNEG_LT, tex[3]);
}
}
@Override
public void renderFaceXPos(Block block, double x, double y, double z, IIcon icon) {
if (rendererOld != null && rendererOld.hasOverrideBlockTexture()) {
IIcon i = rendererOld.overrideBlockTexture;
tessellator.addVertexWithUV(1.0, 1.0, 1.0, i.getMaxU(), i.getMinV());
tessellator.addVertexWithUV(1.0, 0.0, 1.0, i.getMaxU(), i.getMaxV());
tessellator.addVertexWithUV(1.0, 0.0, 0.0, i.getMinU(), i.getMaxV());
tessellator.addVertexWithUV(1.0, 1.0, 0.0, i.getMinU(), i.getMinV());
} else {
int tex[] = ctm.getSubmapIndices(blockAccess, bx, by, bz, 5);
fillLightmap(brightnessTopLeft, brightnessBottomLeft, brightnessBottomRight, brightnessTopRight);
fillColormap(colorRedTopLeft, colorRedBottomLeft, colorRedBottomRight, colorRedTopRight, redmap);
fillColormap(colorGreenTopLeft, colorGreenBottomLeft, colorGreenBottomRight, colorGreenTopRight, grnmap);
fillColormap(colorBlueTopLeft, colorBlueBottomLeft, colorBlueBottomRight, colorBlueTopRight, blumap);
getLight(0, 0);
side(XPOS_LB, tex[0]);
getLight(1, 0);
side(XPOS_RB, tex[1]);
getLight(1, 1);
side(XPOS_RT, tex[2]);
getLight(0, 1);
side(XPOS_LT, tex[3]);
}
}
@Override
public void renderFaceZNeg(Block block, double x, double y, double z, IIcon icon) {
if (rendererOld != null && rendererOld.hasOverrideBlockTexture()) {
IIcon i = rendererOld.overrideBlockTexture;
tessellator.addVertexWithUV(1.0, 1.0, 0.0, i.getMaxU(), i.getMinV());
tessellator.addVertexWithUV(1.0, 0.0, 0.0, i.getMaxU(), i.getMaxV());
tessellator.addVertexWithUV(0.0, 0.0, 0.0, i.getMinU(), i.getMaxV());
tessellator.addVertexWithUV(0.0, 1.0, 0.0, i.getMinU(), i.getMinV());
} else {
int tex[] = ctm.getSubmapIndices(blockAccess, bx, by, bz, 2);
fillLightmap(brightnessBottomRight, brightnessTopRight, brightnessTopLeft, brightnessBottomLeft);
fillColormap(colorRedBottomRight, colorRedTopRight, colorRedTopLeft, colorRedBottomLeft, redmap);
fillColormap(colorGreenBottomRight, colorGreenTopRight, colorGreenTopLeft, colorGreenBottomLeft, grnmap);
fillColormap(colorBlueBottomRight, colorBlueTopRight, colorBlueTopLeft, colorBlueBottomLeft, blumap);
getLight(0, 0);
side(ZNEG_LB, tex[0]);
getLight(1, 0);
side(ZNEG_RB, tex[1]);
getLight(1, 1);
side(ZNEG_RT, tex[2]);
getLight(0, 1);
side(ZNEG_LT, tex[3]);
}
}
@Override
public void renderFaceZPos(Block block, double x, double y, double z, IIcon icon) {
if (rendererOld != null && rendererOld.hasOverrideBlockTexture()) {
IIcon i = rendererOld.overrideBlockTexture;
tessellator.addVertexWithUV(0.0, 1.0, 1.0, i.getMinU(), i.getMinV());
tessellator.addVertexWithUV(0.0, 0.0, 1.0, i.getMinU(), i.getMaxV());
tessellator.addVertexWithUV(1.0, 0.0, 1.0, i.getMaxU(), i.getMaxV());
tessellator.addVertexWithUV(1.0, 1.0, 1.0, i.getMaxU(), i.getMinV());
} else {
int tex[] = ctm.getSubmapIndices(blockAccess, bx, by, bz, 3);
fillLightmap(brightnessBottomLeft, brightnessBottomRight, brightnessTopRight, brightnessTopLeft);
fillColormap(colorRedBottomLeft, colorRedBottomRight, colorRedTopRight, colorRedTopLeft, redmap);
fillColormap(colorGreenBottomLeft, colorGreenBottomRight, colorGreenTopRight, colorGreenTopLeft, grnmap);
fillColormap(colorBlueBottomLeft, colorBlueBottomRight, colorBlueTopRight, colorBlueTopLeft, blumap);
getLight(0, 0);
side(ZPOS_LB, tex[0]);
getLight(1, 0);
side(ZPOS_RB, tex[1]);
getLight(1, 1);
side(ZPOS_RT, tex[2]);
getLight(0, 1);
side(ZPOS_LT, tex[3]);
}
}
@Override
public void renderFaceYNeg(Block block, double x, double y, double z, IIcon icon) {
if (rendererOld != null && rendererOld.hasOverrideBlockTexture()) {
IIcon i = rendererOld.overrideBlockTexture;
tessellator.addVertexWithUV(0.0, 0.0, 1.0, i.getMinU(), i.getMaxV());
tessellator.addVertexWithUV(0.0, 0.0, 0.0, i.getMinU(), i.getMinV());
tessellator.addVertexWithUV(1.0, 0.0, 0.0, i.getMaxU(), i.getMinV());
tessellator.addVertexWithUV(1.0, 0.0, 1.0, i.getMaxU(), i.getMaxV());
} else {
int tex[] = ctm.getSubmapIndices(blockAccess, bx, by, bz, 0);
fillLightmap(brightnessBottomLeft, brightnessBottomRight, brightnessTopRight, brightnessTopLeft);
fillColormap(colorRedBottomLeft, colorRedBottomRight, colorRedTopRight, colorRedTopLeft, redmap);
fillColormap(colorGreenBottomLeft, colorGreenBottomRight, colorGreenTopRight, colorGreenTopLeft, grnmap);
fillColormap(colorBlueBottomLeft, colorBlueBottomRight, colorBlueTopRight, colorBlueTopLeft, blumap);
getLight(0, 0);
side(YNEG_LB, tex[0]);
getLight(1, 0);
side(YNEG_RB, tex[1]);
getLight(1, 1);
side(YNEG_RT, tex[2]);
getLight(0, 1);
side(YNEG_LT, tex[3]);
}
}
@Override
public void renderFaceYPos(Block block, double x, double y, double z, IIcon icon) {
if (rendererOld != null && rendererOld.hasOverrideBlockTexture()) {
IIcon i = rendererOld.overrideBlockTexture;
tessellator.addVertexWithUV(0.0, 1.0, 0.0, i.getMinU(), i.getMinV());
tessellator.addVertexWithUV(0.0, 1.0, 1.0, i.getMinU(), i.getMaxV());
tessellator.addVertexWithUV(1.0, 1.0, 1.0, i.getMaxU(), i.getMaxV());
tessellator.addVertexWithUV(1.0, 1.0, 0.0, i.getMaxU(), i.getMinV());
} else {
int tex[] = ctm.getSubmapIndices(blockAccess, bx, by, bz, 1);
fillLightmap(brightnessTopRight, brightnessTopLeft, brightnessBottomLeft, brightnessBottomRight);
fillColormap(colorRedTopRight, colorRedTopLeft, colorRedBottomLeft, colorRedBottomRight, redmap);
fillColormap(colorGreenTopRight, colorGreenTopLeft, colorGreenBottomLeft, colorGreenBottomRight, grnmap);
fillColormap(colorBlueTopRight, colorBlueTopLeft, colorBlueBottomLeft, colorBlueBottomRight, blumap);
getLight(0, 0);
side(YPOS_LB, tex[0]);
getLight(1, 0);
side(YPOS_RB, tex[1]);
getLight(1, 1);
side(YPOS_RT, tex[2]);
getLight(0, 1);
side(YPOS_LT, tex[3]);
}
}
}