2014-12-15 00:11:48 +00:00
package com.cricketcraft.chisel.client.render ;
2014-04-21 19:13:15 +01:00
import net.minecraft.block.Block ;
import net.minecraft.client.renderer.RenderBlocks ;
import net.minecraft.client.renderer.Tessellator ;
import net.minecraft.util.IIcon ;
2015-02-18 15:27:57 -05:00
import org.apache.commons.lang3.tuple.Triple ;
import static com.cricketcraft.chisel.client.render.RenderBlocksCTM.Vert.* ;
import static com.cricketcraft.chisel.client.render.RenderBlocksCTM.SubSide.* ;
2015-01-07 19:50:18 -05:00
public class RenderBlocksCTM extends RenderBlocks {
2015-02-18 15:27:57 -05:00
/**
* An enum for all possible 26 sub-side vertices.
* <p>
* The naming scheme is as follows:
* <ul>
* <li>ZERO and ONE are special cases, they are the absolute min and absolute max of the block.</li>
* <li>X, Y, Z, or any combination means that the axes listed in the name are at 1.</li>
* <li>X, Y, Z, or any combination followed by HALF means that those axes are at 0.5.</li>
* <li>X, Y, Z, or any combination after a HALF means those axes are at 1.</li>
* </ul>
*/
enum Vert {
ZERO ( 0 , 0 , 0 ),
ONE ( 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 );
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.greenCache[cacheID], inst.blueCache[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).
* <p>
* Each sub-side contains 4 {@link Vert} objects representing its position on the block.
*/
enum SubSide {
XNEG_LB ( ZERO , Z_HALF , YZ_HALF , Y_HALF ), XNEG_RB ( Z_HALF , Z , Y_HALF_Z , YZ_HALF ), XNEG_LT ( Y_HALF , YZ_HALF , Z_HALF_Y , Y ), XNEG_RT ( YZ_HALF , Y_HALF_Z , YZ , Z_HALF_Y );
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 );
}
}
2015-01-07 19:50:18 -05:00
// 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 ;
2015-02-18 15:27:57 -05:00
double [] uCache = new double [ 4 ] ;
double [] vCache = new double [ 4 ] ;
int [] lightingCache = new int [ 4 ] ;
float [] redCache = new float [ 4 ] ;
float [] greenCache = new float [ 4 ] ;
float [] blueCache = new float [ 4 ] ;
2015-01-07 19:50:18 -05:00
TextureSubmap submap ;
TextureSubmap submapSmall ;
RenderBlocks rendererOld ;
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 ;
}
2015-02-18 15:27:57 -05:00
void updateLighting () {
lightingCache [ 0 ] = brightnessBottomLeft ;
lightingCache [ 1 ] = brightnessBottomRight ;
lightingCache [ 2 ] = brightnessTopRight ;
lightingCache [ 3 ] = brightnessTopLeft ;
// // Updated to safely average light and color channels
// L[e] = averageBrightnessChannels(brightnessBottomLeft, brightnessTopLeft, brightnessTopRight, brightnessBottomRight);
// L[xa] = averageBrightnessChannels(L[a], L[b]);
// L[xb] = averageBrightnessChannels(L[b], L[c]);
// L[xc] = averageBrightnessChannels(L[c], L[d]);
// L[xd] = averageBrightnessChannels(L[d], L[a]);
//
// Rcache[a] = colorRedBottomLeft;
// Rcache[b] = colorRedBottomRight;
// Rcache[c] = colorRedTopRight;
// Rcache[d] = colorRedTopLeft;
// Rcache[e] = (colorRedBottomLeft + colorRedTopLeft + colorRedTopRight + colorRedBottomRight) / 4;
// Rcache[xa] = (Rcache[a] + Rcache[b]) / 2;
// Rcache[xb] = (Rcache[b] + Rcache[c]) / 2;
// Rcache[xc] = (Rcache[c] + Rcache[d]) / 2;
// Rcache[xd] = (Rcache[d] + Rcache[a]) / 2;
//
// Gcache[a] = colorGreenBottomLeft;
// Gcache[b] = colorGreenBottomRight;
// Gcache[c] = colorGreenTopRight;
// Gcache[d] = colorGreenTopLeft;
// Gcache[e] = (colorGreenBottomLeft + colorGreenTopLeft + colorGreenTopRight + colorGreenBottomRight) / 4;
// Gcache[xa] = (Gcache[a] + Gcache[b]) / 2;
// Gcache[xb] = (Gcache[b] + Gcache[c]) / 2;
// Gcache[xc] = (Gcache[c] + Gcache[d]) / 2;
// Gcache[xd] = (Gcache[d] + Gcache[a]) / 2;
//
// Bcache[a] = colorBlueBottomLeft;
// Bcache[b] = colorBlueBottomRight;
// Bcache[c] = colorBlueTopRight;
// Bcache[d] = colorBlueTopLeft;
// Bcache[e] = (colorBlueBottomLeft + colorBlueTopLeft + colorBlueTopRight + colorBlueBottomRight) / 4;
// Bcache[xa] = (Bcache[a] + Bcache[b]) / 2;
// Bcache[xb] = (Bcache[b] + Bcache[c]) / 2;
// Bcache[xc] = (Bcache[c] + Bcache[d]) / 2;
// Bcache[xd] = (Bcache[d] + Bcache[a]) / 2;
2015-01-07 19:50:18 -05:00
}
2015-02-18 15:27:57 -05:00
/**
* Takes in a variable number of packed light-integers, and computes the average value of each 4 bit channel
2015-01-07 19:50:18 -05:00
*
2015-02-18 15:27:57 -05:00
* For vanilla, these look like: (S = skylight and L = block light) 0000 0000 SSSS 0000 0000 0000 LLLL 0000 With the Colored Light Core installed, these look like: (B = Blue, G = Green, R = Red)
* 0000 0000 SSSS BBBB GGGG RRRR LLLL 0000
2015-01-07 19:50:18 -05:00
*
2015-02-18 15:27:57 -05:00
* This method will average all of the values appropriately for the more complex case, by separating each color channel into a running total, then it will combine the final results together using
* integer division and a lot of bit-cramming.
2015-01-07 19:50:18 -05:00
*
2015-02-18 15:27:57 -05:00
* While slightly more complex, the runtime should not be drastically effected, and the averaging routine remains compatible with vanilla.
2015-01-07 19:50:18 -05:00
*
* Authored: CptSpaceToaster - 12/19/2014
*/
int averageBrightnessChannels ( 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-02-18 15:27:57 -05:00
void side ( SubSide side , int iconIndex , boolean flip ) {
2015-01-07 19:50:18 -05:00
IIcon icon = iconIndex >= 16 ? submapSmall . icons [ iconIndex - 16 ] : submap . icons [ iconIndex ] ;
2015-02-18 15:27:57 -05:00
double umax = icon . getMaxU ();
double umin = icon . getMinU ();
double vmax = icon . getMaxV ();
double vmin = icon . getMinV ();
2015-01-07 19:50:18 -05:00
2015-02-18 15:27:57 -05:00
uCache [ 0 ] = flip ? umax : umin ;
uCache [ 1 ] = umax ;
uCache [ 2 ] = flip ? umin : umax ;
uCache [ 3 ] = umin ;
vCache [ 0 ] = flip ? vmin : vmax ;
vCache [ 1 ] = vmax ;
vCache [ 2 ] = flip ? vmax : vmin ;
vCache [ 3 ] = vmin ;
2015-01-07 19:50:18 -05:00
2015-02-18 15:27:57 -05:00
side . render ( this );
2015-01-07 19:50:18 -05:00
}
@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 );
2015-02-18 15:27:57 -05:00
updateLighting ();
side ( XNEG_LB , tex [ 2 ] , false );
side ( XNEG_RB , tex [ 3 ] , false );
side ( XNEG_RT , tex [ 1 ] , false );
side ( XNEG_LT , tex [ 0 ] , false );
2015-01-07 19:50:18 -05:00
}
}
@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 );
2015-02-18 15:27:57 -05:00
updateLighting ();
// side(11, 21, 3, 15, tex[3], false);
// side(16, 7, 21, 11, tex[2], false);
// side(25, 11, 15, 2, tex[1], false);
// side(6, 16, 11, 25, tex[0], false);
2015-01-07 19:50:18 -05:00
}
}
@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 );
2015-02-18 15:27:57 -05:00
updateLighting ();
// side(2, 15, 8, 22, tex[0], false);
// side(15, 3, 18, 8, tex[2], false);
// side(8, 18, 0, 14, tex[3], false);
// side(22, 8, 14, 1, tex[1], false);
2015-01-07 19:50:18 -05:00
}
}
@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 );
2015-02-18 15:27:57 -05:00
updateLighting ();
// side(17, 4, 20, 10, tex[2], false);
// side(5, 17, 10, 24, tex[0], false);
// side(24, 10, 16, 6, tex[1], false);
// side(10, 20, 7, 16, tex[3], false);
2015-01-07 19:50:18 -05:00
}
}
@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 );
2015-02-18 15:27:57 -05:00
updateLighting ();
// side(13, 21, 7, 20, tex[3], true);
// side(19, 13, 20, 4, tex[2], true);
// side(0, 18, 13, 19, tex[0], true);
// side(18, 3, 21, 13, tex[1], true);
2015-01-07 19:50:18 -05:00
}
}
@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 );
2015-02-18 15:27:57 -05:00
updateLighting ();
// side(12, 24, 6, 25, tex[3], false);
// side(22, 12, 25, 2, tex[1], false);
// side(1, 23, 12, 22, tex[0], false);
// side(23, 5, 24, 12, tex[2], false);
2015-01-07 19:50:18 -05:00
}
}
2014-04-21 19:13:15 +01:00
}