Implemented spatial pylon rendering.

This commit is contained in:
Sebastian Hartte
2016-09-15 01:26:53 +02:00
parent 653ba814cc
commit d48e7e1f6d
8 changed files with 831 additions and 217 deletions
@@ -20,24 +20,47 @@ package appeng.block.spatial;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.state.BlockStateContainer;
import net.minecraft.block.state.IBlockState; import net.minecraft.block.state.IBlockState;
import net.minecraft.util.BlockRenderLayer;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockAccess; import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraftforge.common.property.ExtendedBlockState;
import net.minecraftforge.common.property.IExtendedBlockState;
import net.minecraftforge.common.property.IUnlistedProperty;
import appeng.block.AEBaseTileBlock; import appeng.block.AEBaseTileBlock;
import appeng.client.render.spatial.SpatialPylonStateProperty;
import appeng.helpers.AEGlassMaterial; import appeng.helpers.AEGlassMaterial;
import appeng.tile.spatial.TileSpatialPylon; import appeng.tile.spatial.TileSpatialPylon;
public class BlockSpatialPylon extends AEBaseTileBlock public class BlockSpatialPylon extends AEBaseTileBlock
{ {
public static final SpatialPylonStateProperty STATE = new SpatialPylonStateProperty();
public BlockSpatialPylon() public BlockSpatialPylon()
{ {
super( AEGlassMaterial.INSTANCE ); super( AEGlassMaterial.INSTANCE );
this.setTileEntity( TileSpatialPylon.class ); this.setTileEntity( TileSpatialPylon.class );
} }
@Override
protected BlockStateContainer createBlockState()
{
return new ExtendedBlockState( this, getAEStates(), new IUnlistedProperty[] { STATE } );
}
@Override
public IBlockState getExtendedState( IBlockState state, IBlockAccess world, BlockPos pos )
{
IExtendedBlockState extState = (IExtendedBlockState) state;
return extState.withProperty( STATE, getDisplayState( world, pos ) );
}
@Override @Override
public void neighborChanged( final IBlockState state, final World w, final BlockPos pos, final Block neighborBlock ) public void neighborChanged( final IBlockState state, final World w, final BlockPos pos, final Block neighborBlock )
{ {
@@ -58,4 +81,23 @@ public class BlockSpatialPylon extends AEBaseTileBlock
} }
return super.getLightValue( state, w, pos ); return super.getLightValue( state, w, pos );
} }
private int getDisplayState( IBlockAccess world, BlockPos pos )
{
TileSpatialPylon te = getTileEntity( world, pos );
if( te == null )
{
return 0;
}
return te.getDisplayBits();
}
@Override
public BlockRenderLayer getBlockLayer()
{
return BlockRenderLayer.CUTOUT;
}
} }
@@ -7,6 +7,8 @@ import java.util.EnumSet;
import java.util.List; import java.util.List;
import javax.vecmath.Vector4f; import javax.vecmath.Vector4f;
import com.google.common.base.Preconditions;
import net.minecraft.client.renderer.block.model.BakedQuad; import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
@@ -19,7 +21,8 @@ import net.minecraftforge.client.model.pipeline.UnpackedBakedQuad;
/** /**
* Builds the quads for a cube. * Builds the quads for a cube.
*/ */
public class CubeBuilder { public class CubeBuilder
{
private VertexFormat format; private VertexFormat format;
@@ -31,20 +34,25 @@ public class CubeBuilder {
private final EnumMap<EnumFacing, Vector4f> customUv = new EnumMap<>( EnumFacing.class ); private final EnumMap<EnumFacing, Vector4f> customUv = new EnumMap<>( EnumFacing.class );
private byte[] uvRotations = new byte[EnumFacing.values().length];
private int color = 0xFFFFFFFF; private int color = 0xFFFFFFFF;
private boolean renderFullBright; private boolean renderFullBright;
public CubeBuilder(VertexFormat format, List<BakedQuad> output) { public CubeBuilder( VertexFormat format, List<BakedQuad> output )
{
this.output = output; this.output = output;
this.format = format; this.format = format;
} }
public CubeBuilder(VertexFormat format) { public CubeBuilder( VertexFormat format )
{
this( format, new ArrayList<>( 6 ) ); this( format, new ArrayList<>( 6 ) );
} }
public void addCube(float x1, float y1, float z1, float x2, float y2, float z2) { public void addCube( float x1, float y1, float z1, float x2, float y2, float z2 )
{
x1 /= 16.0f; x1 /= 16.0f;
y1 /= 16.0f; y1 /= 16.0f;
z1 /= 16.0f; z1 /= 16.0f;
@@ -54,28 +62,41 @@ public class CubeBuilder {
// If brightness is forced to specific values, extend the vertex format to contain the multi-texturing lightmap offset // If brightness is forced to specific values, extend the vertex format to contain the multi-texturing lightmap offset
VertexFormat savedFormat = null; VertexFormat savedFormat = null;
if (renderFullBright) { if( renderFullBright )
{
savedFormat = format; savedFormat = format;
format = new VertexFormat( savedFormat ); format = new VertexFormat( savedFormat );
if (!format.getElements().contains(DefaultVertexFormats.TEX_2S)) { if( !format.getElements().contains( DefaultVertexFormats.TEX_2S ) )
{
format.addElement( DefaultVertexFormats.TEX_2S ); format.addElement( DefaultVertexFormats.TEX_2S );
} }
} }
for (EnumFacing face : drawFaces) { for( EnumFacing face : drawFaces )
{
putFace( face, x1, y1, z1, x2, y2, z2 ); putFace( face, x1, y1, z1, x2, y2, z2 );
} }
// Restore old format // Restore old format
if (savedFormat != null) { if( savedFormat != null )
{
format = savedFormat; format = savedFormat;
} }
} }
private static final class UvVector
{
float u1;
float u2;
float v1;
float v2;
}
private void putFace( EnumFacing face, private void putFace( EnumFacing face,
float x1, float y1, float z1, float x1, float y1, float z1,
float x2, float y2, float z2 float x2, float y2, float z2
) { )
{
TextureAtlasSprite texture = textures.get( face ); TextureAtlasSprite texture = textures.get( face );
@@ -83,105 +104,59 @@ public class CubeBuilder {
builder.setTexture( texture ); builder.setTexture( texture );
builder.setQuadOrientation( face ); builder.setQuadOrientation( face );
float u1 = 0; UvVector uv = new UvVector();
float v1 = 0;
float u2 = 0;
float v2 = 0;
// The user might have set specific UV coordinates for this face // The user might have set specific UV coordinates for this face
Vector4f customUv = this.customUv.get( face ); Vector4f customUv = this.customUv.get( face );
if( customUv != null ) if( customUv != null )
{ {
u1 = texture.getInterpolatedU( customUv.x ); uv.u1 = texture.getInterpolatedU( customUv.x );
v1 = texture.getInterpolatedV( customUv.y ); uv.v1 = texture.getInterpolatedV( customUv.y );
u2 = texture.getInterpolatedU( customUv.z ); uv.u2 = texture.getInterpolatedU( customUv.z );
v2 = texture.getInterpolatedV( customUv.w ); uv.v2 = texture.getInterpolatedV( customUv.w );
} }
else
switch (face) {
case DOWN:
if (customUv == null)
{ {
u1 = texture.getInterpolatedU( x1 * 16 ); uv = getDefaultUv( face, texture, x1, y1, z1, x2, y2, z2 );
v1 = texture.getInterpolatedV( z1 * 16 );
u2 = texture.getInterpolatedU( x2 * 16 );
v2 = texture.getInterpolatedV( z2 * 16 );
} }
putVertex(builder, face, x2, y1, z1, u2, v1); switch( face )
putVertex(builder, face, x2, y1, z2, u2, v2); {
putVertex(builder, face, x1, y1, z2, u1, v2); case DOWN:
putVertex(builder, face, x1, y1, z1, u1, v1); putVertexTR( builder, face, x2, y1, z1, uv );
putVertexBR( builder, face, x2, y1, z2, uv );
putVertexBL( builder, face, x1, y1, z2, uv );
putVertexTL( builder, face, x1, y1, z1, uv );
break; break;
case UP: case UP:
if (customUv == null) putVertexTL( builder, face, x1, y2, z1, uv );
{ putVertexBL( builder, face, x1, y2, z2, uv );
u1 = texture.getInterpolatedU( x1 * 16 ); putVertexBR( builder, face, x2, y2, z2, uv );
v1 = texture.getInterpolatedV( z1 * 16 ); putVertexTR( builder, face, x2, y2, z1, uv );
u2 = texture.getInterpolatedU( x2 * 16 );
v2 = texture.getInterpolatedV( z2 * 16 );
}
putVertex(builder, face, x1, y2, z1, u1, v1);
putVertex(builder, face, x1, y2, z2, u1, v2);
putVertex(builder, face, x2, y2, z2, u2, v2);
putVertex(builder, face, x2, y2, z1, u2, v1);
break; break;
case NORTH: case NORTH:
if (customUv == null) putVertexBR( builder, face, x2, y2, z1, uv );
{ putVertexTR( builder, face, x2, y1, z1, uv );
u1 = texture.getInterpolatedU( x1 * 16 ); putVertexTL( builder, face, x1, y1, z1, uv );
v1 = texture.getInterpolatedV( 16 - y1 * 16 ); putVertexBL( builder, face, x1, y2, z1, uv );
u2 = texture.getInterpolatedU( x2 * 16 );
v2 = texture.getInterpolatedV( 16 - y2 * 16 );
}
putVertex(builder, face, x2, y2, z1, u2, v2);
putVertex(builder, face, x2, y1, z1, u2, v1);
putVertex(builder, face, x1, y1, z1, u1, v1);
putVertex(builder, face, x1, y2, z1, u1, v2);
break; break;
case SOUTH: case SOUTH:
if (customUv == null) putVertexBL( builder, face, x1, y2, z2, uv );
{ putVertexTL( builder, face, x1, y1, z2, uv );
u1 = texture.getInterpolatedU( x1 * 16 ); putVertexTR( builder, face, x2, y1, z2, uv );
v1 = texture.getInterpolatedV( 16 - y1 * 16 ); putVertexBR( builder, face, x2, y2, z2, uv );
u2 = texture.getInterpolatedU( x2 * 16 );
v2 = texture.getInterpolatedV( 16 - y2 * 16 );
}
putVertex(builder, face, x1, y2, z2, u1, v2);
putVertex(builder, face, x1, y1, z2, u1, v1);
putVertex(builder, face, x2, y1, z2, u2, v1);
putVertex(builder, face, x2, y2, z2, u2, v2);
break; break;
case WEST: case WEST:
if (customUv == null) putVertexTL( builder, face, x1, y1, z1, uv );
{ putVertexTR( builder, face, x1, y1, z2, uv );
u1 = texture.getInterpolatedU( z1 * 16 ); putVertexBR( builder, face, x1, y2, z2, uv );
v1 = texture.getInterpolatedV( 16 - y1 * 16 ); putVertexBL( builder, face, x1, y2, z1, uv );
u2 = texture.getInterpolatedU( z2 * 16 );
v2 = texture.getInterpolatedV( 16 - y2 * 16 );
}
putVertex(builder, face, x1, y1, z1, u1, v1);
putVertex(builder, face, x1, y1, z2, u2, v1);
putVertex(builder, face, x1, y2, z2, u2, v2);
putVertex(builder, face, x1, y2, z1, u1, v2);
break; break;
case EAST: case EAST:
if (customUv == null) putVertexBR( builder, face, x2, y2, z1, uv );
{ putVertexBL( builder, face, x2, y2, z2, uv );
u1 = texture.getInterpolatedU( z2 * 16 ); putVertexTL( builder, face, x2, y1, z2, uv );
v1 = texture.getInterpolatedV( 16 - y1 * 16 ); putVertexTR( builder, face, x2, y1, z1, uv );
u2 = texture.getInterpolatedU( z1 * 16 );
v2 = texture.getInterpolatedV( 16 - y2 * 16 );
}
putVertex(builder, face, x2, y2, z1, u2, v2);
putVertex(builder, face, x2, y2, z2, u1, v2);
putVertex(builder, face, x2, y1, z2, u1, v1);
putVertex(builder, face, x2, y1, z1, u2, v1);
break; break;
} }
@@ -189,12 +164,181 @@ public class CubeBuilder {
output.add( new BakedQuad( vertexData, -1, face, texture, true, format ) ); output.add( new BakedQuad( vertexData, -1, face, texture, true, format ) );
} }
private void putVertex(UnpackedBakedQuad.Builder builder, EnumFacing face, float x, float y, float z, float u, float v) { private UvVector getDefaultUv( EnumFacing face, TextureAtlasSprite texture,
float x1, float y1, float z1,
float x2, float y2, float z2 )
{
UvVector uv = new UvVector();
switch( face )
{
case DOWN:
uv.u1 = texture.getInterpolatedU( x1 * 16 );
uv.v1 = texture.getInterpolatedV( z1 * 16 );
uv.u2 = texture.getInterpolatedU( x2 * 16 );
uv.v2 = texture.getInterpolatedV( z2 * 16 );
break;
case UP:
uv.u1 = texture.getInterpolatedU( x1 * 16 );
uv.v1 = texture.getInterpolatedV( z1 * 16 );
uv.u2 = texture.getInterpolatedU( x2 * 16 );
uv.v2 = texture.getInterpolatedV( z2 * 16 );
break;
case NORTH:
uv.u1 = texture.getInterpolatedU( x1 * 16 );
uv.v1 = texture.getInterpolatedV( 16 - y1 * 16 );
uv.u2 = texture.getInterpolatedU( x2 * 16 );
uv.v2 = texture.getInterpolatedV( 16 - y2 * 16 );
break;
case SOUTH:
uv.u1 = texture.getInterpolatedU( x1 * 16 );
uv.v1 = texture.getInterpolatedV( 16 - y1 * 16 );
uv.u2 = texture.getInterpolatedU( x2 * 16 );
uv.v2 = texture.getInterpolatedV( 16 - y2 * 16 );
break;
case WEST:
uv.u1 = texture.getInterpolatedU( z1 * 16 );
uv.v1 = texture.getInterpolatedV( 16 - y1 * 16 );
uv.u2 = texture.getInterpolatedU( z2 * 16 );
uv.v2 = texture.getInterpolatedV( 16 - y2 * 16 );
break;
case EAST:
uv.u1 = texture.getInterpolatedU( z2 * 16 );
uv.v1 = texture.getInterpolatedV( 16 - y1 * 16 );
uv.u2 = texture.getInterpolatedU( z1 * 16 );
uv.v2 = texture.getInterpolatedV( 16 - y2 * 16 );
break;
}
return uv;
}
// uv.u1, uv.v1
private void putVertexTL( UnpackedBakedQuad.Builder builder, EnumFacing face, float x, float y, float z, UvVector uv )
{
float u, v;
switch (uvRotations[face.ordinal()]) {
default:
case 0:
u = uv.u1;
v = uv.v1;
break;
case 1: // 90° clockwise
u = uv.u1;
v = uv.v2;
break;
case 2: // 180° clockwise
u = uv.u2;
v = uv.v2;
break;
case 3: // 270° clockwise
u = uv.u2;
v = uv.v1;
break;
}
putVertex(builder, face, x, y, z, u, v );
}
// uv.u2, uv.v1
private void putVertexTR( UnpackedBakedQuad.Builder builder, EnumFacing face, float x, float y, float z, UvVector uv )
{
float u;
float v;
switch (uvRotations[face.ordinal()]) {
default:
case 0:
u = uv.u2;
v = uv.v1;
break;
case 1: // 90° clockwise
u = uv.u1;
v = uv.v1;
break;
case 2: // 180° clockwise
u = uv.u1;
v = uv.v2;
break;
case 3: // 270° clockwise
u = uv.u2;
v = uv.v2;
break;
}
putVertex(builder, face, x, y, z, u, v );
}
// uv.u2, uv.v2
private void putVertexBR( UnpackedBakedQuad.Builder builder, EnumFacing face, float x, float y, float z, UvVector uv )
{
float u;
float v;
switch (uvRotations[face.ordinal()]) {
default:
case 0:
u = uv.u2;
v = uv.v2;
break;
case 1: // 90° clockwise
u = uv.u2;
v = uv.v1;
break;
case 2: // 180° clockwise
u = uv.u1;
v = uv.v1;
break;
case 3: // 270° clockwise
u = uv.u1;
v = uv.v2;
break;
}
putVertex(builder, face, x, y, z, u, v );
}
// uv.u1, uv.v2
private void putVertexBL( UnpackedBakedQuad.Builder builder, EnumFacing face, float x, float y, float z, UvVector uv )
{
float u;
float v;
switch (uvRotations[face.ordinal()]) {
default:
case 0:
u = uv.u1;
v = uv.v2;
break;
case 1: // 90° clockwise
u = uv.u2;
v = uv.v2;
break;
case 2: // 180° clockwise
u = uv.u2;
v = uv.v1;
break;
case 3: // 270° clockwise
u = uv.u1;
v = uv.v1;
break;
}
putVertex(builder, face, x, y, z, u, v );
}
private void putVertex( UnpackedBakedQuad.Builder builder, EnumFacing face, float x, float y, float z, float u, float v )
{
VertexFormat format = builder.getVertexFormat(); VertexFormat format = builder.getVertexFormat();
for (int i = 0; i < format.getElementCount(); i++) { for( int i = 0; i < format.getElementCount(); i++ )
{
VertexFormatElement e = format.getElement( i ); VertexFormatElement e = format.getElement( i );
switch (e.getUsage()) { switch( e.getUsage() )
{
case POSITION: case POSITION:
builder.put( i, x, y, z ); builder.put( i, x, y, z );
break; break;
@@ -213,9 +357,12 @@ public class CubeBuilder {
builder.put( i, r, g, b, a ); builder.put( i, r, g, b, a );
break; break;
case UV: case UV:
if (e.getIndex() == 0) { if( e.getIndex() == 0 )
{
builder.put( i, u, v ); builder.put( i, u, v );
} else { }
else
{
// Force Brightness to 15, this is for full bright mode // Force Brightness to 15, this is for full bright mode
// this vertex element will only be present in that case // this vertex element will only be present in that case
final float lightMapU = (float) ( 15 * 0x20 ) / 0xFFFF; final float lightMapU = (float) ( 15 * 0x20 ) / 0xFFFF;
@@ -230,13 +377,16 @@ public class CubeBuilder {
} }
} }
public void setTexture(TextureAtlasSprite texture) { public void setTexture( TextureAtlasSprite texture )
for (EnumFacing face : EnumFacing.values()) { {
for( EnumFacing face : EnumFacing.values() )
{
textures.put( face, texture ); textures.put( face, texture );
} }
} }
public void setTextures(TextureAtlasSprite up, TextureAtlasSprite down, TextureAtlasSprite north, TextureAtlasSprite south, TextureAtlasSprite east, TextureAtlasSprite west) { public void setTextures( TextureAtlasSprite up, TextureAtlasSprite down, TextureAtlasSprite north, TextureAtlasSprite south, TextureAtlasSprite east, TextureAtlasSprite west )
{
textures.put( EnumFacing.UP, up ); textures.put( EnumFacing.UP, up );
textures.put( EnumFacing.DOWN, down ); textures.put( EnumFacing.DOWN, down );
textures.put( EnumFacing.NORTH, north ); textures.put( EnumFacing.NORTH, north );
@@ -245,22 +395,26 @@ public class CubeBuilder {
textures.put( EnumFacing.WEST, west ); textures.put( EnumFacing.WEST, west );
} }
public void setDrawFaces(EnumSet<EnumFacing> drawFaces) { public void setDrawFaces( EnumSet<EnumFacing> drawFaces )
{
this.drawFaces = drawFaces; this.drawFaces = drawFaces;
} }
public void setColor(int color) { public void setColor( int color )
{
this.color = color; this.color = color;
} }
/** /**
* Sets the vertex color for future vertices to the given RGB value, and forces the alpha component to 255. * Sets the vertex color for future vertices to the given RGB value, and forces the alpha component to 255.
*/ */
public void setColorRGB(int color) { public void setColorRGB( int color )
{
setColor( color | 0xFF000000 ); setColor( color | 0xFF000000 );
} }
public void setRenderFullBright(boolean renderFullBright) { public void setRenderFullBright( boolean renderFullBright )
{
this.renderFullBright = renderFullBright; this.renderFullBright = renderFullBright;
} }
@@ -269,7 +423,19 @@ public class CubeBuilder {
customUv.put( facing, new Vector4f( u1, v1, u2, v2 ) ); customUv.put( facing, new Vector4f( u1, v1, u2, v2 ) );
} }
public List<BakedQuad> getOutput() { public void setUvRotation( EnumFacing facing, int rotation )
{
if ( rotation == 2 ) {
rotation = 3;
} else if ( rotation == 3 ) {
rotation = 2;
}
Preconditions.checkArgument( rotation >= 0 && rotation <= 3, "rotation" );
uvRotations[facing.ordinal()] = (byte) rotation;
}
public List<BakedQuad> getOutput()
{
return output; return output;
} }
} }
@@ -0,0 +1,245 @@
package appeng.client.render.spatial;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
import com.google.common.collect.ImmutableMap;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.renderer.block.model.IBakedModel;
import net.minecraft.client.renderer.block.model.ItemCameraTransforms;
import net.minecraft.client.renderer.block.model.ItemOverrideList;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.vertex.VertexFormat;
import net.minecraft.util.EnumFacing;
import net.minecraftforge.common.property.IExtendedBlockState;
import appeng.block.spatial.BlockSpatialPylon;
import appeng.client.render.cablebus.CubeBuilder;
import appeng.tile.spatial.TileSpatialPylon;
/**
* The baked model that will be used for rendering the spatial pylon.
*/
class SpatialPylonBakedModel implements IBakedModel
{
private final Map<SpatialPylonTextureType, TextureAtlasSprite> textures;
private final VertexFormat format;
SpatialPylonBakedModel( VertexFormat format, Map<SpatialPylonTextureType, TextureAtlasSprite> textures )
{
this.textures = ImmutableMap.copyOf( textures );
this.format = format;
}
@Override
public List<BakedQuad> getQuads( @Nullable IBlockState state, @Nullable EnumFacing side, long rand )
{
int flags = getFlags( state );
CubeBuilder builder = new CubeBuilder( format );
if( flags != 0 )
{
EnumFacing ori = null;
int displayAxis = flags & TileSpatialPylon.DISPLAY_Z;
if( displayAxis == TileSpatialPylon.DISPLAY_X )
{
ori = EnumFacing.EAST;
if( ( flags & TileSpatialPylon.DISPLAY_MIDDLE ) == TileSpatialPylon.DISPLAY_END_MAX )
{
builder.setUvRotation( EnumFacing.SOUTH, 1 );
builder.setUvRotation( EnumFacing.NORTH, 1 );
builder.setUvRotation( EnumFacing.UP, 2 );
builder.setUvRotation( EnumFacing.DOWN, 1 );
}
else if( ( flags & TileSpatialPylon.DISPLAY_MIDDLE ) == TileSpatialPylon.DISPLAY_END_MIN )
{
builder.setUvRotation( EnumFacing.SOUTH, 2 );
builder.setUvRotation( EnumFacing.NORTH, 2 );
builder.setUvRotation( EnumFacing.UP, 1 );
builder.setUvRotation( EnumFacing.DOWN, 2 );
}
else
{
builder.setUvRotation( EnumFacing.SOUTH, 1 );
builder.setUvRotation( EnumFacing.NORTH, 1 );
builder.setUvRotation( EnumFacing.UP, 1 );
builder.setUvRotation( EnumFacing.DOWN, 1 );
}
}
else if( displayAxis == TileSpatialPylon.DISPLAY_Y )
{
ori = EnumFacing.UP;
if( ( flags & TileSpatialPylon.DISPLAY_MIDDLE ) == TileSpatialPylon.DISPLAY_END_MAX )
{
builder.setUvRotation( EnumFacing.NORTH, 3 );
builder.setUvRotation( EnumFacing.SOUTH, 3 );
builder.setUvRotation( EnumFacing.EAST, 3 );
builder.setUvRotation( EnumFacing.WEST, 3 );
}
}
else if( displayAxis == TileSpatialPylon.DISPLAY_Z )
{
ori = EnumFacing.NORTH;
if( ( flags & TileSpatialPylon.DISPLAY_MIDDLE ) == TileSpatialPylon.DISPLAY_END_MAX )
{
builder.setUvRotation( EnumFacing.EAST, 2 );
builder.setUvRotation( EnumFacing.WEST, 1 );
}
else if( ( flags & TileSpatialPylon.DISPLAY_MIDDLE ) == TileSpatialPylon.DISPLAY_END_MIN )
{
builder.setUvRotation( EnumFacing.EAST, 1 );
builder.setUvRotation( EnumFacing.WEST, 2 );
builder.setUvRotation( EnumFacing.UP, 3 );
builder.setUvRotation( EnumFacing.DOWN, 3 );
}
else
{
builder.setUvRotation( EnumFacing.EAST, 1 );
builder.setUvRotation( EnumFacing.WEST, 2 );
}
}
builder.setTextures(
textures.get( getTextureTypeFromSideOutside( flags, ori, EnumFacing.UP ) ),
textures.get( getTextureTypeFromSideOutside( flags, ori, EnumFacing.DOWN ) ),
textures.get( getTextureTypeFromSideOutside( flags, ori, EnumFacing.NORTH ) ),
textures.get( getTextureTypeFromSideOutside( flags, ori, EnumFacing.SOUTH ) ),
textures.get( getTextureTypeFromSideOutside( flags, ori, EnumFacing.EAST ) ),
textures.get( getTextureTypeFromSideOutside( flags, ori, EnumFacing.WEST ) )
);
builder.addCube( 0, 0, 0, 16, 16, 16 );
if( ( flags & TileSpatialPylon.DISPLAY_POWERED_ENABLED ) == TileSpatialPylon.DISPLAY_POWERED_ENABLED )
{
builder.setRenderFullBright( true );
}
builder.setTextures(
textures.get( getTextureTypeFromSideInside( flags, ori, EnumFacing.UP ) ),
textures.get( getTextureTypeFromSideInside( flags, ori, EnumFacing.DOWN ) ),
textures.get( getTextureTypeFromSideInside( flags, ori, EnumFacing.NORTH ) ),
textures.get( getTextureTypeFromSideInside( flags, ori, EnumFacing.SOUTH ) ),
textures.get( getTextureTypeFromSideInside( flags, ori, EnumFacing.EAST ) ),
textures.get( getTextureTypeFromSideInside( flags, ori, EnumFacing.WEST ) )
);
builder.addCube( 0, 0, 0, 16, 16, 16 );
}
else
{
builder.setTexture( textures.get( SpatialPylonTextureType.BASE ) );
builder.addCube( 0, 0, 0, 16, 16, 16 );
builder.setTexture( textures.get( SpatialPylonTextureType.DIM ) );
builder.addCube( 0, 0, 0, 16, 16, 16 );
}
return builder.getOutput();
}
private int getFlags( IBlockState state )
{
if( !( state instanceof IExtendedBlockState ) )
{
return 0;
}
IExtendedBlockState extState = (IExtendedBlockState) state;
return extState.getValue( BlockSpatialPylon.STATE );
}
private static SpatialPylonTextureType getTextureTypeFromSideOutside( int flags, EnumFacing ori, EnumFacing dir )
{
if( ori == dir || ori.getOpposite() == dir )
{
return SpatialPylonTextureType.BASE;
}
if( ( flags & TileSpatialPylon.DISPLAY_MIDDLE ) == TileSpatialPylon.DISPLAY_MIDDLE )
{
return SpatialPylonTextureType.BASE_SPANNED;
}
else if( ( flags & TileSpatialPylon.DISPLAY_MIDDLE ) == TileSpatialPylon.DISPLAY_END_MIN )
{
return SpatialPylonTextureType.BASE_END;
}
else if( ( flags & TileSpatialPylon.DISPLAY_MIDDLE ) == TileSpatialPylon.DISPLAY_END_MAX )
{
return SpatialPylonTextureType.BASE_END;
}
return SpatialPylonTextureType.BASE;
}
private static SpatialPylonTextureType getTextureTypeFromSideInside( int flags, EnumFacing ori, EnumFacing dir )
{
final boolean good = ( flags & TileSpatialPylon.DISPLAY_ENABLED ) == TileSpatialPylon.DISPLAY_ENABLED;
if( ori == dir || ori.getOpposite() == dir )
{
return good ? SpatialPylonTextureType.DIM : SpatialPylonTextureType.RED;
}
if( ( flags & TileSpatialPylon.DISPLAY_MIDDLE ) == TileSpatialPylon.DISPLAY_MIDDLE )
{
return good ? SpatialPylonTextureType.DIM_SPANNED : SpatialPylonTextureType.RED_SPANNED;
}
else if( ( flags & TileSpatialPylon.DISPLAY_MIDDLE ) == TileSpatialPylon.DISPLAY_END_MIN )
{
return good ? SpatialPylonTextureType.DIM_END : SpatialPylonTextureType.RED_END;
}
else if( ( flags & TileSpatialPylon.DISPLAY_MIDDLE ) == TileSpatialPylon.DISPLAY_END_MAX )
{
return good ? SpatialPylonTextureType.DIM_END : SpatialPylonTextureType.RED_END;
}
return SpatialPylonTextureType.BASE;
}
@Override
public boolean isAmbientOcclusion()
{
return true;
}
@Override
public boolean isGui3d()
{
return false;
}
@Override
public boolean isBuiltInRenderer()
{
return false;
}
@Override
public TextureAtlasSprite getParticleTexture()
{
return null;
}
@Override
public ItemCameraTransforms getItemCameraTransforms()
{
return ItemCameraTransforms.DEFAULT;
}
@Override
public ItemOverrideList getOverrides()
{
return ItemOverrideList.NONE;
}
}
@@ -0,0 +1,65 @@
package appeng.client.render.spatial;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumMap;
import java.util.Map;
import java.util.stream.Collectors;
import com.google.common.base.Function;
import net.minecraft.client.renderer.block.model.IBakedModel;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.vertex.VertexFormat;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.model.IModel;
import net.minecraftforge.common.model.IModelState;
import net.minecraftforge.common.model.TRSRTransformation;
import appeng.core.AppEng;
class SpatialPylonModel implements IModel
{
@Override
public Collection<ResourceLocation> getDependencies()
{
return Collections.emptyList();
}
@Override
public Collection<ResourceLocation> getTextures()
{
return Arrays.stream( SpatialPylonTextureType.values() )
.map( SpatialPylonModel::getTexturePath )
.collect( Collectors.toList() );
}
@Override
public IBakedModel bake( IModelState state, VertexFormat format, Function<ResourceLocation, TextureAtlasSprite> bakedTextureGetter )
{
Map<SpatialPylonTextureType, TextureAtlasSprite> textures = new EnumMap<>( SpatialPylonTextureType.class );
for( SpatialPylonTextureType type : SpatialPylonTextureType.values() )
{
ResourceLocation loc = getTexturePath( type );
textures.put( type, bakedTextureGetter.apply( loc ) );
}
return new SpatialPylonBakedModel( format, textures );
}
@Override
public IModelState getDefaultState()
{
return TRSRTransformation.identity();
}
private static ResourceLocation getTexturePath( SpatialPylonTextureType type )
{
return new ResourceLocation( AppEng.MOD_ID, "blocks/spatial_pylon/" + type.name().toLowerCase() );
}
}
@@ -0,0 +1,41 @@
package appeng.client.render.spatial;
import java.util.Map;
import com.google.common.collect.ImmutableMap;
import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import appeng.bootstrap.BlockRenderingCustomizer;
import appeng.bootstrap.IBlockRendering;
import appeng.bootstrap.IItemRendering;
import appeng.core.AppEng;
public class SpatialPylonRendering extends BlockRenderingCustomizer
{
private static final ResourceLocation MODEL_ID = new ResourceLocation( AppEng.MOD_ID, "models/blocks/spatial_pylon/builtin" );
@Override
@SideOnly( Side.CLIENT )
public void customize( IBlockRendering rendering, IItemRendering itemRendering )
{
rendering.builtInModel( MODEL_ID.getResourcePath(), new SpatialPylonModel() );
rendering.stateMapper( this::mapState );
}
private Map<IBlockState, ModelResourceLocation> mapState( Block block )
{
return ImmutableMap.of(
block.getDefaultState(), new ModelResourceLocation( MODEL_ID, "normal" )
);
}
}
@@ -0,0 +1,38 @@
package appeng.client.render.spatial;
import net.minecraftforge.common.property.IUnlistedProperty;
/**
* Models the rendering state of the spatial pylon, which is largely determined by the state of neighboring tiles.
*/
public class SpatialPylonStateProperty implements IUnlistedProperty<Integer>
{
@Override
public String getName()
{
return "spatial_state";
}
@Override
public boolean isValid( Integer value )
{
int val = value;
// The lower 6 bits are used
return ( val & ~0x3F ) == 0;
}
@Override
public Class<Integer> getType()
{
return Integer.class;
}
@Override
public String valueToString( Integer value )
{
return value.toString();
}
}
@@ -0,0 +1,15 @@
package appeng.client.render.spatial;
enum SpatialPylonTextureType
{
BASE,
BASE_END,
BASE_SPANNED,
DIM,
DIM_END,
DIM_SPANNED,
RED,
RED_END,
RED_SPANNED
}
@@ -84,6 +84,7 @@ import appeng.bootstrap.IBlockRendering;
import appeng.bootstrap.IItemRendering; import appeng.bootstrap.IItemRendering;
import appeng.client.render.crafting.CraftingCubeRendering; import appeng.client.render.crafting.CraftingCubeRendering;
import appeng.client.render.model.GlassModel; import appeng.client.render.model.GlassModel;
import appeng.client.render.spatial.SpatialPylonRendering;
import appeng.core.AppEng; import appeng.core.AppEng;
import appeng.core.features.AEFeature; import appeng.core.features.AEFeature;
import appeng.core.features.registries.PartModels; import appeng.core.features.registries.PartModels;
@@ -280,6 +281,7 @@ public final class ApiBlocks implements IBlocks
this.spatialPylon = registry.block( "spatial_pylon", BlockSpatialPylon::new ) this.spatialPylon = registry.block( "spatial_pylon", BlockSpatialPylon::new )
.features( AEFeature.SpatialIO ) .features( AEFeature.SpatialIO )
.useCustomItemModel() .useCustomItemModel()
.rendering( new SpatialPylonRendering() )
.build(); .build();
this.spatialIOPort = registry.block( "spatial_ioport", BlockSpatialIOPort::new ).features( AEFeature.SpatialIO ).build(); this.spatialIOPort = registry.block( "spatial_ioport", BlockSpatialIOPort::new ).features( AEFeature.SpatialIO ).build();
this.controller = registry.block( "controller", BlockController::new ) this.controller = registry.block( "controller", BlockController::new )