Cables & parts and Baking pipeline

- Added cables & parts rendering.
- Facades got a completely new way of rendering. Anvil facades are
totally a thing.
- Added baking pipeline for simplified, highly configurable quad baking.

NOTE: Yes, there are a lot of improvements to do, bugs to fix, stuff to
add. I'm just pushing it prior to code structure change, so it does not
get lost in stashes. But it actually works!
This commit is contained in:
elix-x
2016-08-19 22:45:27 +02:00
parent 8b9743f2bf
commit d7f32a985d
186 changed files with 2102 additions and 295 deletions
+75 -21
View File
@@ -24,15 +24,16 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import com.google.common.collect.ImmutableMap;
import org.lwjgl.opengl.GL11;
import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
import net.minecraft.client.renderer.color.IBlockColor;
import net.minecraft.client.renderer.color.IItemColor;
import net.minecraft.client.renderer.color.ItemColors;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.client.resources.IReloadableResourceManager;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Items;
@@ -40,20 +41,21 @@ import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumHand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import net.minecraftforge.client.event.ModelBakeEvent;
import net.minecraftforge.client.event.MouseEvent;
import net.minecraftforge.client.event.RenderLivingEvent;
import net.minecraftforge.client.event.TextureStitchEvent;
import net.minecraftforge.client.model.IModel;
import net.minecraftforge.client.model.ModelLoaderRegistry;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import appeng.api.parts.CableRenderMode;
import appeng.api.util.AECableType;
import appeng.api.util.AEColor;
import appeng.block.AEBaseBlock;
import appeng.client.render.effects.AssemblerFX;
@@ -63,11 +65,13 @@ import appeng.client.render.effects.LightningArcFX;
import appeng.client.render.effects.LightningFX;
import appeng.client.render.effects.VibrantFX;
import appeng.client.render.model.GlassModelLoader;
import appeng.client.render.model.ModelsCache;
import appeng.client.render.model.UVLModelLoader;
import appeng.client.render.textures.ParticleTextures;
import appeng.core.AEConfig;
import appeng.core.AELog;
import appeng.core.Api;
import appeng.core.AppEng;
import appeng.core.CommonHelper;
import appeng.core.features.IAEFeature;
import appeng.core.sync.network.NetworkHandler;
@@ -81,6 +85,8 @@ import appeng.helpers.IMouseWheelItem;
import appeng.hooks.TickHandler;
import appeng.hooks.TickHandler.PlayerColor;
import appeng.items.misc.ItemPaintBall;
import appeng.items.parts.PartType;
import appeng.parts.AEBasePart;
import appeng.server.ServerHelper;
import appeng.transformer.MissingCoreMod;
import appeng.util.Platform;
@@ -95,6 +101,7 @@ public class ClientHelper extends ServerHelper
MinecraftForge.EVENT_BUS.register( this );
ModelLoaderRegistry.registerLoader( UVLModelLoader.INSTANCE );
ModelLoaderRegistry.registerLoader( new GlassModelLoader() );
( (IReloadableResourceManager) Minecraft.getMinecraft().getResourceManager() ).registerReloadListener( ModelsCache.INSTANCE );
for( IAEFeature feature : Api.INSTANCE.definitions().getFeatureRegistry().getRegisteredFeatures() )
{
feature.handler().registerStateMapper();
@@ -125,10 +132,6 @@ public class ClientHelper extends ServerHelper
for( IAEFeature feature : Api.INSTANCE.definitions().getFeatureRegistry().getRegisteredFeatures() )
{
feature.handler().registerModel();
if( feature instanceof AEBaseBlock )
{
Minecraft.getMinecraft().getBlockColors().registerBlockColorHandler( new AEBaseBlockColor(), (Block) feature );
}
}
// Register color handling for paintball items
@@ -296,12 +299,6 @@ public class ClientHelper extends ServerHelper
throw new MissingCoreMod();
}
@SubscribeEvent
public void modelsBake( ModelBakeEvent event )
{
UVLModelLoader.INSTANCE.setLoader( event.getModelLoader() );
}
@SubscribeEvent
public void postPlayerRender( final RenderLivingEvent.Pre p )
{
@@ -383,9 +380,10 @@ public class ClientHelper extends ServerHelper
@SubscribeEvent
public void onModelBakeEvent( final ModelBakeEvent event )
{
UVLModelLoader.INSTANCE.setLoader( event.getModelLoader() );
for( IAEFeature feature : Api.INSTANCE.definitions().getFeatureRegistry().getRegisteredFeatures() )
{
feature.handler().registerCustomModelOverride(event.getModelRegistry());
feature.handler().registerCustomModelOverride( event.getModelRegistry() );
}
}
@@ -432,6 +430,48 @@ public class ClientHelper extends ServerHelper
public void onTextureStitch( final TextureStitchEvent.Pre event )
{
ParticleTextures.registerSprite( event );
for( AECableType type : AECableType.VALIDCABLES )
{
for( IModel model : new IModel[] { ModelsCache.INSTANCE.getOrLoadModel( type.getModel() ), ModelsCache.INSTANCE.getOrLoadModel( type.getConnectionModel() ), ModelsCache.INSTANCE.getOrLoadModel( type.getStraightModel() ) } )
{
for( ResourceLocation location : model.getTextures() )
{
for( AEColor color : AEColor.values() )
{
if( type.displayedChannels() > 0 )
{
for( int i = 0; i <= type.displayedChannels(); i++ )
{
event.getMap().registerSprite( AEBasePart.replaceProperties( location, ImmutableMap.of( "color", color.name(), "channels", String.valueOf( i ) ) ) );
}
}
else
{
event.getMap().registerSprite( AEBasePart.replaceProperties( location, ImmutableMap.of( "color", color.name() ) ) );
}
}
}
}
}
for( PartType part : PartType.values() )
{
if( !part.isCable() )
{
IModel model = ModelsCache.INSTANCE.getOrLoadModel( part.getModel() );
for( ResourceLocation location : model.getTextures() )
{
for( AEColor color : AEColor.values() )
{
event.getMap().registerSprite( AEBasePart.replaceProperties( location, ImmutableMap.of( "color", color.name() ) ) );
}
}
}
}
for( ResourceLocation location : ModelsCache.INSTANCE.getOrLoadModel( new ResourceLocation( AppEng.MOD_ID, "part/cable_facade" ) ).getTextures() )
{
event.getMap().registerSprite( location );
}
}
private static class IconReg
@@ -458,15 +498,29 @@ public class ClientHelper extends ServerHelper
}
}
public static class AEBaseBlockColor implements IBlockColor
public class ItemPaintBallColor implements IItemColor
{
@Override
public int colorMultiplier( IBlockState state, IBlockAccess worldIn, BlockPos pos, int tintIndex )
public int getColorFromItemstack( ItemStack stack, int tintIndex )
{
return tintIndex;
final AEColor col = ( (ItemPaintBall) stack.getItem() ).getColor( stack );
final int colorValue = stack.getItemDamage() >= 20 ? col.mediumVariant : col.mediumVariant;
final int r = ( colorValue >> 16 ) & 0xff;
final int g = ( colorValue >> 8 ) & 0xff;
final int b = ( colorValue ) & 0xff;
if( stack.getItemDamage() >= 20 )
{
final float fail = 0.7f;
final int full = (int) ( 255 * 0.3 );
return (int) ( full + r * fail ) << 16 | (int) ( full + g * fail ) << 8 | (int) ( full + b * fail ) | 0xff << 24;
}
else
{
return r << 16 | g << 8 | b | 0xff << 24;
}
}
}
}
@@ -0,0 +1,119 @@
package appeng.client.render.model;
import java.util.HashMap;
import java.util.Map;
import com.google.common.base.Function;
import com.google.common.base.Optional;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.block.model.IBakedModel;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.client.renderer.vertex.VertexFormat;
import net.minecraft.client.resources.IResourceManager;
import net.minecraft.client.resources.IResourceManagerReloadListener;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.model.IModel;
import net.minecraftforge.client.model.ModelLoaderRegistry;
import net.minecraftforge.common.model.IModelState;
public enum ModelsCache implements IResourceManagerReloadListener
{
INSTANCE;
public static final IModelState DEFAULTMODELSTATE = opt -> Optional.absent();
public static final VertexFormat DEFAULTVERTEXFORMAT = DefaultVertexFormats.BLOCK;
public static final Function<ResourceLocation, TextureAtlasSprite> DEFAULTTEXTUREGETTER = texture -> Minecraft.getMinecraft().getTextureMapBlocks().getAtlasSprite( texture.toString() );
private final Map<ResourceLocation, IModel> cache = new HashMap<>();
private final Map<ResourceLocation, IBakedModel> bakedCache = new HashMap<>();
public IModel getOrLoadModel( ResourceLocation location )
{
IModel model = cache.get( location );
if( model == null )
{
try
{
model = ModelLoaderRegistry.getModel( location );
}
catch( Exception e )
{
// TODO 1.10.2-R - log this in pretty way
e.printStackTrace();
model = ModelLoaderRegistry.getMissingModel();
}
cache.put( location, model );
}
return model;
}
public IBakedModel getModel( ResourceLocation key )
{
return bakedCache.get( key );
}
public IBakedModel getOrLoadModel( ResourceLocation key, ResourceLocation location, IModelState state, VertexFormat format, Function<ResourceLocation, TextureAtlasSprite> textureGetter )
{
IBakedModel model = getModel( key );
if( model == null )
{
model = getOrLoadModel( location ).bake( state, format, textureGetter );
bakedCache.put( key, model );
}
return model;
}
public IBakedModel getOrLoadModel( ResourceLocation key, ResourceLocation location, IModelState state, VertexFormat format )
{
return getOrLoadModel( key, location, state, format, DEFAULTTEXTUREGETTER );
}
public IBakedModel getOrLoadModel( ResourceLocation key, ResourceLocation location, IModelState state, Function<ResourceLocation, TextureAtlasSprite> textureGetter )
{
return getOrLoadModel( key, location, state, DEFAULTVERTEXFORMAT, textureGetter );
}
public IBakedModel getOrLoadModel( ResourceLocation key, ResourceLocation location, VertexFormat format, Function<ResourceLocation, TextureAtlasSprite> textureGetter )
{
return getOrLoadModel( key, location, DEFAULTMODELSTATE, format, textureGetter );
}
public IBakedModel getOrLoadModel( ResourceLocation key, ResourceLocation location, IModelState state )
{
return getOrLoadModel( key, location, state, DEFAULTVERTEXFORMAT, DEFAULTTEXTUREGETTER );
}
public IBakedModel getOrLoadModel( ResourceLocation key, ResourceLocation location, VertexFormat format )
{
return getOrLoadModel( key, location, DEFAULTMODELSTATE, format, DEFAULTTEXTUREGETTER );
}
public IBakedModel getOrLoadModel( ResourceLocation key, ResourceLocation location, Function<ResourceLocation, TextureAtlasSprite> textureGetter )
{
return getOrLoadModel( key, location, DEFAULTMODELSTATE, DEFAULTVERTEXFORMAT, textureGetter );
}
public IBakedModel getOrLoadModel( ResourceLocation key, ResourceLocation location )
{
return getOrLoadModel( key, location, DEFAULTMODELSTATE, DEFAULTVERTEXFORMAT, DEFAULTTEXTUREGETTER );
}
public IBakedModel getOrLoadBakedModel( ResourceLocation location )
{
return getOrLoadModel( location, location, DEFAULTMODELSTATE, DEFAULTVERTEXFORMAT, DEFAULTTEXTUREGETTER );
}
@Override
public void onResourceManagerReload( IResourceManager resourceManager )
{
cache.clear();
bakedCache.clear();
}
}
@@ -0,0 +1,72 @@
package appeng.client.render.model.pipeline;
import java.util.ArrayList;
import java.util.List;
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.util.EnumFacing;
import appeng.api.client.BakingPipeline;
import appeng.api.client.BakingPipelineElement;
public class BakingPipelineBakedModel extends BakingPipeline implements IBakedModel
{
private final IBakedModel parent;
public BakingPipelineBakedModel( IBakedModel parent, BakingPipelineElement<?, ?>... pipeline )
{
super( pipeline );
this.parent = parent;
}
@Override
public List<BakedQuad> getQuads( IBlockState state, EnumFacing side, long rand )
{
return pipe( new ArrayList(), parent, state, side, rand );
}
@Override
public boolean isAmbientOcclusion()
{
return parent.isAmbientOcclusion();
}
@Override
public boolean isGui3d()
{
return parent.isGui3d();
}
@Override
public boolean isBuiltInRenderer()
{
return parent.isBuiltInRenderer();
}
@Override
public TextureAtlasSprite getParticleTexture()
{
return parent.getParticleTexture();
}
@Override
public ItemCameraTransforms getItemCameraTransforms()
{
return parent.getItemCameraTransforms();
}
@Override
public ItemOverrideList getOverrides()
{
return parent.getOverrides();
}
}
@@ -0,0 +1,107 @@
package appeng.client.render.model.pipeline;
import java.util.ArrayList;
import java.util.List;
import javax.vecmath.Vector3f;
import javax.vecmath.Vector4f;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.renderer.block.model.IBakedModel;
import net.minecraft.client.renderer.vertex.VertexFormatElement;
import net.minecraft.util.EnumFacing;
import appeng.api.client.BakingPipelineElement;
import appeng.block.AEBaseTileBlock;
import appeng.client.render.FacingToRotation;
public class DoubleFacingQuadRotator implements BakingPipelineElement<QuadVertexData, QuadVertexData>
{
@Override
public List<QuadVertexData> pipe( List<QuadVertexData> elements, IBakedModel parent, IBlockState state, EnumFacing side, long rand )
{
if( state != null )
{
final EnumFacing forward = state.getValue( AEBaseTileBlock.AE_BLOCK_FORWARD );
final EnumFacing up = state.getValue( AEBaseTileBlock.AE_BLOCK_UP );
final FacingToRotation f2r = FacingToRotation.get( forward, up );
List<QuadVertexData> rotated = new ArrayList();
for( QuadVertexData data : elements )
{
data.setFace( f2r.rotate( data.getFace() ) );
float[][][] qd = data.getData();
for( int v = 0; v < 4; v++ )
{
for( int e = 0; e < data.getFormat().getElementCount(); e++ )
{
VertexFormatElement element = data.getFormat().getElement( e );
if( element.getUsage() == VertexFormatElement.EnumUsage.POSITION )
{
qd[v][e] = transform( f2r, qd[v][e] );
}
else if( element.getUsage() == VertexFormatElement.EnumUsage.NORMAL )
{
qd[v][e] = transformNormal( f2r, qd[v][e] );
}
}
}
rotated.add( new QuadVertexData( data.getFormat(), qd, data.getTintIndex(), data.getFace(), data.getSprite(), data.shouldApplyDiffuseLighting() ) );
}
return rotated;
}
return elements;
}
private float[] transform( FacingToRotation f2r, float[] fs )
{
switch( fs.length )
{
case 3:
Vector3f vec = new Vector3f( fs[0], fs[1], fs[2] );
vec.x -= 0.5f;
vec.y -= 0.5f;
vec.z -= 0.5f;
f2r.getMat().transform( vec );
vec.x += 0.5f;
vec.y += 0.5f;
vec.z += 0.5f;
return new float[] { vec.x, vec.y, vec.z };
case 4:
Vector4f vecc = new Vector4f( fs[0], fs[1], fs[2], fs[3] );
vecc.x -= 0.5f;
vecc.y -= 0.5f;
vecc.z -= 0.5f;
f2r.getMat().transform( vecc );
vecc.x += 0.5f;
vecc.y += 0.5f;
vecc.z += 0.5f;
return new float[] { vecc.x, vecc.y, vecc.z, vecc.w };
default:
return fs;
}
}
private float[] transformNormal( FacingToRotation f2r, float[] fs )
{
switch( fs.length )
{
case 3:
Vector3f vec = new Vector3f( fs[0], fs[1], fs[2] );
f2r.getMat().transform( vec );
return new float[] { vec.x, vec.y, vec.z };
case 4:
Vector4f vecc = new Vector4f( fs[0], fs[1], fs[2], fs[3] );
f2r.getMat().transform( vecc );
return new float[] { vecc.x, vecc.y, vecc.z, vecc.w };
default:
return fs;
}
}
}
@@ -0,0 +1,39 @@
package appeng.client.render.model.pipeline;
import java.util.List;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.renderer.block.model.IBakedModel;
import net.minecraft.util.EnumFacing;
import net.minecraftforge.common.model.TRSRTransformation;
public class FacingQuadRotator extends MatVecApplicator
{
private EnumFacing override;
public FacingQuadRotator( EnumFacing override )
{
super( TRSRTransformation.getMatrix( override ) );
this.override = override;
}
public FacingQuadRotator()
{
this.override = null;
}
@Override
public List<QuadVertexData> pipe( List<QuadVertexData> elements, IBakedModel parent, IBlockState state, EnumFacing side, long rand )
{
if( override == null )
{
setMatrix( TRSRTransformation.getMatrix( side ) );
}
return super.pipe( elements, parent, state, side, rand );
}
}
@@ -0,0 +1,141 @@
package appeng.client.render.model.pipeline;
import java.util.ArrayList;
import java.util.List;
import javax.vecmath.Matrix4f;
import javax.vecmath.Vector3f;
import javax.vecmath.Vector4f;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.renderer.block.model.IBakedModel;
import net.minecraft.client.renderer.vertex.VertexFormatElement;
import net.minecraft.util.EnumFacing;
import net.minecraftforge.common.model.TRSRTransformation;
import appeng.api.client.BakingPipelineElement;
public class MatVecApplicator implements BakingPipelineElement<QuadVertexData, QuadVertexData>
{
private Matrix4f matrix;
private boolean forceTranslate;
public MatVecApplicator( Matrix4f matrix, boolean forceTranslate )
{
this.matrix = matrix;
this.forceTranslate = forceTranslate;
}
public MatVecApplicator( Matrix4f matrix )
{
this( matrix, false );
}
public MatVecApplicator()
{
this( new Matrix4f() );
}
public Matrix4f getMatrix()
{
return matrix;
}
public void setMatrix( Matrix4f matrix )
{
this.matrix = matrix;
}
public boolean forceTranslate()
{
return forceTranslate;
}
public void setForceTranslate( boolean forceTranslate )
{
this.forceTranslate = forceTranslate;
}
@Override
public List<QuadVertexData> pipe( List<QuadVertexData> elements, IBakedModel parent, IBlockState state, EnumFacing side, long rand )
{
List<QuadVertexData> rotated = new ArrayList();
for( QuadVertexData data : elements )
{
float[][][] qd = data.getData();
data.setFace( side != null ? TRSRTransformation.rotate( matrix, side ) : side );
for( int v = 0; v < 4; v++ )
{
for( int e = 0; e < data.getFormat().getElementCount(); e++ )
{
VertexFormatElement element = data.getFormat().getElement( e );
if( element.getUsage() == VertexFormatElement.EnumUsage.POSITION )
{
qd[v][e] = transform( qd[v][e] );
}
else if( element.getUsage() == VertexFormatElement.EnumUsage.NORMAL )
{
qd[v][e] = transformNormal( qd[v][e] );
}
}
}
rotated.add( new QuadVertexData( data.getFormat(), qd, data.getTintIndex(), data.getFace(), data.getSprite(), data.shouldApplyDiffuseLighting() ) );
}
return rotated;
}
private float[] transform( float[] fs )
{
switch( fs.length )
{
case 3:
Vector4f vec = new Vector4f( fs[0], fs[1], fs[2], forceTranslate ? 1 : 0 );
vec.x -= 0.5f;
vec.y -= 0.5f;
vec.z -= 0.5f;
this.matrix.transform( vec );
vec.x += 0.5f;
vec.y += 0.5f;
vec.z += 0.5f;
return new float[] { vec.x, vec.y, vec.z };
case 4:
Vector4f vecc = new Vector4f( fs[0], fs[1], fs[2], forceTranslate ? 1 : fs[3] );
vecc.x -= 0.5f;
vecc.y -= 0.5f;
vecc.z -= 0.5f;
this.matrix.transform( vecc );
vecc.x += 0.5f;
vecc.y += 0.5f;
vecc.z += 0.5f;
return new float[] { vecc.x, vecc.y, vecc.z, vecc.w };
default:
return fs;
}
}
private float[] transformNormal( float[] fs )
{
switch( fs.length )
{
case 3:
Vector3f vec = new Vector3f( fs[0], fs[1], fs[2] );
this.matrix.transform( vec );
vec.normalize();
return new float[] { vec.x, vec.y, vec.z };
case 4:
Vector4f vecc = new Vector4f( fs[0], fs[1], fs[2], fs[3] );
this.matrix.transform( vecc );
vecc.normalize();
return new float[] { vecc.x, vecc.y, vecc.z, vecc.w };
default:
return fs;
}
}
}
@@ -0,0 +1,37 @@
package appeng.client.render.model.pipeline;
import java.util.ArrayList;
import java.util.List;
import com.google.common.collect.ImmutableList;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.renderer.block.model.IBakedModel;
import net.minecraft.util.EnumFacing;
import appeng.api.client.BakingPipelineElement;
public class Merge<F, T> implements BakingPipelineElement<F, T>
{
private final ImmutableList<BakingPipelineElement<?, ?>> pipeline;
public Merge( BakingPipelineElement<?, ?>... pipeline )
{
this.pipeline = ImmutableList.copyOf( pipeline );
}
@Override
public List pipe( List elements, IBakedModel parent, IBlockState state, EnumFacing side, long rand )
{
for( BakingPipelineElement<?, ?> element : pipeline )
{
elements.addAll( element.pipe( new ArrayList<>(), parent, state, side, rand ) );
}
return elements;
}
}
@@ -0,0 +1,21 @@
package appeng.client.render.model.pipeline;
import java.util.List;
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.util.EnumFacing;
import appeng.api.client.BakingPipelineElement;
public class ParentQuads implements BakingPipelineElement<Void, BakedQuad>
{
@Override
public List<BakedQuad> pipe( List<Void> elements, IBakedModel parent, IBlockState state, EnumFacing side, long rand )
{
return parent.getQuads( state, side, rand );
}
}
@@ -0,0 +1,121 @@
package appeng.client.render.model.pipeline;
import java.lang.reflect.Field;
import com.google.common.base.Throwables;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.vertex.VertexFormat;
import net.minecraft.util.EnumFacing;
import net.minecraftforge.client.model.pipeline.UnpackedBakedQuad;
import net.minecraftforge.fml.relauncher.ReflectionHelper;
public final class QuadVertexData
{
private static final Field unpackedData = ReflectionHelper.findField( UnpackedBakedQuad.class, "unpackedData" );
private static float[][][] unpackedData( UnpackedBakedQuad quad )
{
try
{
return (float[][][]) unpackedData.get( quad );
}
catch( Exception e )
{
throw Throwables.propagate( e );
}
}
private VertexFormat format;
private float[][][] data;
private int tintIndex;
private EnumFacing face;
private TextureAtlasSprite sprite;
protected boolean applyDiffuseLighting;
public QuadVertexData( VertexFormat format, float[][][] data, int tintIndex, EnumFacing face, TextureAtlasSprite sprite, boolean applyDiffuseLighting )
{
this.format = format;
this.data = data;
this.tintIndex = tintIndex;
this.face = face;
this.sprite = sprite;
this.applyDiffuseLighting = applyDiffuseLighting;
}
public QuadVertexData( UnpackedBakedQuad quad )
{
this( quad.getFormat(), unpackedData( quad ), quad.getTintIndex(), quad.getFace(), quad.getSprite(), quad.shouldApplyDiffuseLighting() );
}
public UnpackedBakedQuad toQuad()
{
return new UnpackedBakedQuad( data, tintIndex, face, sprite, applyDiffuseLighting, format );
}
public VertexFormat getFormat()
{
return format;
}
public void setFormat( VertexFormat format )
{
this.format = format;
}
public float[][][] getData()
{
return data;
}
public void setData( float[][][] data )
{
this.data = data;
}
public int getTintIndex()
{
return tintIndex;
}
public void setTintIndex( int tintIndex )
{
this.tintIndex = tintIndex;
}
public EnumFacing getFace()
{
return face;
}
public void setFace( EnumFacing face )
{
this.face = face;
}
public TextureAtlasSprite getSprite()
{
return sprite;
}
public void setSprite( TextureAtlasSprite sprite )
{
this.sprite = sprite;
}
public boolean shouldApplyDiffuseLighting()
{
return applyDiffuseLighting;
}
public void setApplyDiffuseLighting( boolean applyDiffuseLighting )
{
this.applyDiffuseLighting = applyDiffuseLighting;
}
}
@@ -0,0 +1,71 @@
package appeng.client.render.model.pipeline;
import java.util.List;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.block.model.IBakedModel;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockAccess;
import appeng.api.client.BakingPipelineElement;
public class StatePosRecolorator implements BakingPipelineElement<QuadVertexData, QuadVertexData>
{
private IBlockAccess blockAccess;
private BlockPos pos;
private IBlockState state;
public StatePosRecolorator( IBlockAccess blockAccess, BlockPos pos, IBlockState state )
{
this.blockAccess = blockAccess;
this.pos = pos;
this.state = state;
}
public IBlockAccess getBlockAccess()
{
return blockAccess;
}
public void setBlockAccess( IBlockAccess blockAccess )
{
this.blockAccess = blockAccess;
}
public BlockPos getPos()
{
return pos;
}
public void setPos( BlockPos pos )
{
this.pos = pos;
}
public IBlockState getState()
{
return state;
}
public void setState( IBlockState state )
{
this.state = state;
}
@Override
public List<QuadVertexData> pipe( List<QuadVertexData> elements, IBakedModel parent, IBlockState state, EnumFacing side, long rand )
{
for( QuadVertexData data : elements )
{
data.setTintIndex( Minecraft.getMinecraft().getBlockColors().colorMultiplier( this.state, blockAccess, this.pos, data.getTintIndex() ) );
}
return elements;
}
}
@@ -0,0 +1,45 @@
package appeng.client.render.model.pipeline;
import java.util.List;
import java.util.function.Function;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.renderer.block.model.IBakedModel;
import net.minecraft.util.EnumFacing;
import appeng.api.client.BakingPipelineElement;
public class TintIndexModifier implements BakingPipelineElement<QuadVertexData, QuadVertexData>
{
private Function<Integer, Integer> tintTransformer;
public TintIndexModifier( Function<Integer, Integer> tintTransformer )
{
this.tintTransformer = tintTransformer;
}
public Function<Integer, Integer> getTintTransformer()
{
return tintTransformer;
}
public void setTintTransformer( Function<Integer, Integer> tintTransformer )
{
this.tintTransformer = tintTransformer;
}
@Override
public List<QuadVertexData> pipe( List<QuadVertexData> elements, IBakedModel parent, IBlockState state, EnumFacing side, long rand )
{
for( QuadVertexData quad : elements )
{
quad.setTintIndex( tintTransformer.apply( quad.getTintIndex() ) );
}
return elements;
}
}
@@ -0,0 +1,63 @@
package appeng.client.render.model.pipeline;
import java.util.List;
import com.google.common.collect.Lists;
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.util.EnumFacing;
import net.minecraftforge.client.model.pipeline.LightUtil;
import net.minecraftforge.client.model.pipeline.UnpackedBakedQuad;
import appeng.api.client.BakingPipelineElement;
public class TypeTransformer
{
public static final BakingPipelineElement<BakedQuad, QuadVertexData> quads2vecs = new BakingPipelineElement<BakedQuad, QuadVertexData>(){
@Override
public List<QuadVertexData> pipe( List<BakedQuad> elements, IBakedModel parent, IBlockState state, EnumFacing side, long rand )
{
return Lists.transform( elements, ( quad ) -> {
if( quad instanceof UnpackedBakedQuad )
{
return new QuadVertexData( (UnpackedBakedQuad) quad );
}
else
{
int[] qdata = quad.getVertexData();
float[][][] data = new float[4][quad.getFormat().getElementCount()][4];
for( int v = 0; v < data.length; v++ )
{
float[][] vd = data[v];
for( int e = 0; e < vd.length; e++ )
{
LightUtil.unpack( qdata, vd[e], quad.getFormat(), v, e );
}
}
return new QuadVertexData( quad.getFormat(), data, quad.getTintIndex(), quad.getFace(), quad.getSprite(), quad.shouldApplyDiffuseLighting() );
}
} );
}
};
public static final BakingPipelineElement<QuadVertexData, BakedQuad> vecs2quads = new BakingPipelineElement<QuadVertexData, BakedQuad>(){
@Override
public List<BakedQuad> pipe( List<QuadVertexData> elements, IBakedModel parent, IBlockState state, EnumFacing side, long rand )
{
return Lists.transform( elements, ( data ) -> {
return data.toQuad();
} );
}
};
}
@@ -0,0 +1,53 @@
package appeng.client.render.model.pipeline.cable;
import java.util.List;
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.util.EnumFacing;
import net.minecraftforge.common.property.IExtendedBlockState;
import appeng.api.client.BakingPipeline;
import appeng.api.client.BakingPipelineElement;
import appeng.api.implementations.parts.IPartCable;
import appeng.api.parts.IPart;
import appeng.api.util.AEPartLocation;
import appeng.block.networking.BlockCableBus;
import appeng.client.render.model.pipeline.TintIndexModifier;
import appeng.parts.CableBusContainer;
public class CableAndConnections implements BakingPipelineElement<BakedQuad, BakedQuad>
{
private final BakingPipeline rotatingPipeline;
private final TintIndexModifier tintIndexModifier;
private final BakingPipeline tintIndexFixPipeline;
public CableAndConnections( BakingPipeline rotatingPipeline, TintIndexModifier tintIndexModifier, BakingPipeline tintIndexFixPipeline )
{
this.rotatingPipeline = rotatingPipeline;
this.tintIndexModifier = tintIndexModifier;
this.tintIndexFixPipeline = tintIndexFixPipeline;
}
@Override
public List<BakedQuad> pipe( List<BakedQuad> elements, IBakedModel parent, IBlockState state, EnumFacing side, long rand )
{
if( state != null )
{
CableBusContainer cableBus = ( (IExtendedBlockState) state ).getValue( BlockCableBus.cableBus );
IPart part = cableBus.getPart( AEPartLocation.INTERNAL );
if( part instanceof IPartCable )
{
tintIndexModifier.setTintTransformer( tint -> ( AEPartLocation.INTERNAL.ordinal() << 2 ) | tint );
elements.addAll( tintIndexFixPipeline.pipe( ( (IPartCable) part ).getOrBakeQuads( rotatingPipeline, state, side, rand ), parent, state, side, rand ) );
}
}
return elements;
}
}
@@ -0,0 +1,55 @@
package appeng.client.render.model.pipeline.cable;
import java.util.List;
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.util.EnumFacing;
import net.minecraftforge.common.property.IExtendedBlockState;
import appeng.api.client.BakingPipeline;
import appeng.api.client.BakingPipelineElement;
import appeng.api.parts.IFacadePart;
import appeng.api.util.AEPartLocation;
import appeng.block.networking.BlockCableBus;
import appeng.client.render.model.pipeline.TintIndexModifier;
import appeng.parts.CableBusContainer;
public class Facades implements BakingPipelineElement<BakedQuad, BakedQuad>
{
private final BakingPipeline rotatingPipeline;
private final TintIndexModifier tintIndexModifier;
private final BakingPipeline tintIndexFixPipeline;
public Facades( BakingPipeline rotatingPipeline, TintIndexModifier tintIndexModifier, BakingPipeline tintIndexFixPipeline )
{
this.rotatingPipeline = rotatingPipeline;
this.tintIndexModifier = tintIndexModifier;
this.tintIndexFixPipeline = tintIndexFixPipeline;
}
@Override
public List<BakedQuad> pipe( List<BakedQuad> elements, IBakedModel parent, IBlockState state, EnumFacing side, long rand )
{
if( state != null )
{
CableBusContainer cableBus = ( (IExtendedBlockState) state ).getValue( BlockCableBus.cableBus );
for( AEPartLocation facing : AEPartLocation.SIDE_LOCATIONS )
{
IFacadePart facade = cableBus.getFacadeContainer().getFacade( facing );
if( facade != null )
{
tintIndexModifier.setTintTransformer( tint -> ( facing.ordinal() << 2 ) | tint );
elements.addAll( tintIndexFixPipeline.pipe( facade.getOrBakeQuads( cableBus, rotatingPipeline, state, side, rand ), parent, state, side, rand ) );
}
}
}
return elements;
}
}
@@ -0,0 +1,55 @@
package appeng.client.render.model.pipeline.cable;
import java.util.List;
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.util.EnumFacing;
import net.minecraftforge.common.property.IExtendedBlockState;
import appeng.api.client.BakingPipeline;
import appeng.api.client.BakingPipelineElement;
import appeng.api.parts.IPart;
import appeng.api.util.AEPartLocation;
import appeng.block.networking.BlockCableBus;
import appeng.client.render.model.pipeline.TintIndexModifier;
import appeng.parts.CableBusContainer;
public class Parts implements BakingPipelineElement<BakedQuad, BakedQuad>
{
private final BakingPipeline rotatingPipeline;
private final TintIndexModifier tintIndexModifier;
private final BakingPipeline tintIndexFixPipeline;
public Parts( BakingPipeline rotatingPipeline, TintIndexModifier tintIndexModifier, BakingPipeline tintIndexFixPipeline )
{
this.rotatingPipeline = rotatingPipeline;
this.tintIndexModifier = tintIndexModifier;
this.tintIndexFixPipeline = tintIndexFixPipeline;
}
@Override
public List<BakedQuad> pipe( List<BakedQuad> elements, IBakedModel parent, IBlockState state, EnumFacing side, long rand )
{
if( state != null )
{
CableBusContainer cableBus = ( (IExtendedBlockState) state ).getValue( BlockCableBus.cableBus );
for( AEPartLocation facing : AEPartLocation.SIDE_LOCATIONS )
{
IPart part = cableBus.getPart( facing );
if( part != null )
{
tintIndexModifier.setTintTransformer( tint -> ( facing.ordinal() << 2 ) | tint );
elements.addAll( tintIndexFixPipeline.pipe( part.getOrBakeQuads( rotatingPipeline, state, side, rand ), parent, state, side, rand ) );
}
}
}
return elements;
}
}