282 lines
7.6 KiB
Java
282 lines
7.6 KiB
Java
/*
|
|
* This file is part of Applied Energistics 2.
|
|
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
|
|
*
|
|
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
|
*/
|
|
|
|
package appeng.client.render.model;
|
|
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
import javax.vecmath.Vector3f;
|
|
import javax.vecmath.Vector4f;
|
|
|
|
import com.google.common.base.Objects;
|
|
import com.google.common.cache.CacheBuilder;
|
|
import com.google.common.cache.CacheLoader;
|
|
import com.google.common.cache.LoadingCache;
|
|
|
|
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.client.renderer.vertex.VertexFormatElement;
|
|
import net.minecraft.util.EnumFacing;
|
|
import net.minecraft.util.math.Vec3i;
|
|
import net.minecraftforge.client.model.pipeline.IVertexConsumer;
|
|
import net.minecraftforge.client.model.pipeline.QuadGatheringTransformer;
|
|
import net.minecraftforge.client.model.pipeline.UnpackedBakedQuad;
|
|
import net.minecraftforge.common.property.IExtendedBlockState;
|
|
|
|
import appeng.block.AEBaseTileBlock;
|
|
import appeng.client.render.FacingToRotation;
|
|
|
|
|
|
public class AutoRotatingModel implements IBakedModel
|
|
{
|
|
|
|
private final IBakedModel parent;
|
|
private final LoadingCache<AutoRotatingCacheKey, List<BakedQuad>> quadCache;
|
|
|
|
public AutoRotatingModel( IBakedModel parent )
|
|
{
|
|
this.parent = parent;
|
|
// 6 (DUNSWE) * 6 (DUNSWE) * 7 (DUNSWE + null) = 252
|
|
this.quadCache = CacheBuilder.newBuilder().maximumSize( 252 ).build( new CacheLoader<AutoRotatingCacheKey, List<BakedQuad>>(){
|
|
@Override
|
|
public List<BakedQuad> load( AutoRotatingCacheKey key ) throws Exception
|
|
{
|
|
return getRotatedModel( key.getBlockState(), key.getSide(), key.getForward(), key.getUp() );
|
|
}
|
|
} );
|
|
}
|
|
|
|
private List<BakedQuad> getRotatedModel( IBlockState state, EnumFacing side, EnumFacing forward, EnumFacing up )
|
|
{
|
|
FacingToRotation f2r = FacingToRotation.get( forward, up );
|
|
List<BakedQuad> original = AutoRotatingModel.this.parent.getQuads( state, f2r.resultingRotate( side ), 0 );
|
|
List<BakedQuad> rotated = new ArrayList<>( original.size() );
|
|
for( BakedQuad quad : original )
|
|
{
|
|
VertexFormat format = quad.getFormat();
|
|
UnpackedBakedQuad.Builder builder = new UnpackedBakedQuad.Builder( format );
|
|
VertexRotator rot = new VertexRotator( f2r, quad.getFace() );
|
|
rot.setParent( builder );
|
|
quad.pipe( rot );
|
|
builder.setQuadOrientation( f2r.rotate( quad.getFace() ) );
|
|
BakedQuad q = builder.build();
|
|
rotated.add( q );
|
|
}
|
|
return rotated;
|
|
}
|
|
|
|
@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();
|
|
}
|
|
|
|
@Override
|
|
public List<BakedQuad> getQuads( IBlockState state, EnumFacing side, long rand )
|
|
{
|
|
if( !( state instanceof IExtendedBlockState ) )
|
|
{
|
|
return parent.getQuads( state, side, rand );
|
|
}
|
|
|
|
IExtendedBlockState extState = (IExtendedBlockState) state;
|
|
|
|
EnumFacing forward = extState.getValue( AEBaseTileBlock.FORWARD );
|
|
EnumFacing up = extState.getValue( AEBaseTileBlock.UP );
|
|
|
|
if( forward == null || up == null )
|
|
{
|
|
return parent.getQuads( state, side, rand );
|
|
}
|
|
|
|
// The model has other properties than just forward/up, so it would cause our cache to inadvertendly also cache
|
|
// these
|
|
// additional states, possibly leading to huge isseus if the other extended state properties do not implement
|
|
// equals/hashCode correctly
|
|
if( extState.getUnlistedProperties().size() != 2 )
|
|
{
|
|
return getRotatedModel( extState, side, forward, up );
|
|
}
|
|
|
|
AutoRotatingCacheKey key = new AutoRotatingCacheKey( extState.getClean(), forward, up, side );
|
|
|
|
return quadCache.getUnchecked( key );
|
|
}
|
|
|
|
public static class VertexRotator extends QuadGatheringTransformer
|
|
{
|
|
private final FacingToRotation f2r;
|
|
private final EnumFacing face;
|
|
|
|
public VertexRotator( FacingToRotation f2r, EnumFacing face )
|
|
{
|
|
this.f2r = f2r;
|
|
this.face = face;
|
|
}
|
|
|
|
@Override
|
|
public void setParent( IVertexConsumer parent )
|
|
{
|
|
super.setParent( parent );
|
|
if( Objects.equal( getVertexFormat(), parent.getVertexFormat() ) )
|
|
{
|
|
return;
|
|
}
|
|
setVertexFormat( parent.getVertexFormat() );
|
|
}
|
|
|
|
@Override
|
|
protected void processQuad()
|
|
{
|
|
VertexFormat format = parent.getVertexFormat();
|
|
int count = format.getElementCount();
|
|
|
|
for( int v = 0; v < 4; v++ )
|
|
{
|
|
for( int e = 0; e < count; e++ )
|
|
{
|
|
VertexFormatElement element = format.getElement( e );
|
|
if( element.getUsage() == VertexFormatElement.EnumUsage.POSITION )
|
|
{
|
|
parent.put( e, transform( quadData[e][v] ) );
|
|
}
|
|
else if( element.getUsage() == VertexFormatElement.EnumUsage.NORMAL )
|
|
{
|
|
parent.put( e, transformNormal( quadData[e][v] ) );
|
|
}
|
|
else
|
|
{
|
|
parent.put( e, quadData[e][v] );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private float[] transform( 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( float[] fs )
|
|
{
|
|
switch( fs.length )
|
|
{
|
|
case 3:
|
|
Vec3i vec = f2r.rotate( face ).getDirectionVec();
|
|
return new float[] { vec.getX(), vec.getY(), vec.getZ()
|
|
};
|
|
case 4:
|
|
Vector4f veccc = new Vector4f( fs[0], fs[1], fs[2], fs[3] );
|
|
Vec3i vecc = f2r.rotate( face ).getDirectionVec();
|
|
return new float[] { vecc.getX(), vecc.getY(), vecc.getZ(), veccc.w
|
|
};
|
|
|
|
default:
|
|
return fs;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void setQuadTint( int tint )
|
|
{
|
|
parent.setQuadTint( tint );
|
|
}
|
|
|
|
@Override
|
|
public void setQuadOrientation( EnumFacing orientation )
|
|
{
|
|
parent.setQuadOrientation( orientation );
|
|
}
|
|
|
|
@Override
|
|
public void setApplyDiffuseLighting( boolean diffuse )
|
|
{
|
|
parent.setApplyDiffuseLighting( diffuse );
|
|
}
|
|
|
|
@Override
|
|
public void setTexture( TextureAtlasSprite texture )
|
|
{
|
|
parent.setTexture( texture );
|
|
}
|
|
}
|
|
}
|