package com.bioxx.tfc2.rendering.bakedmodels; import java.util.List; import javax.vecmath.Matrix3f; 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.*; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.renderer.vertex.VertexFormat; import net.minecraft.client.renderer.vertex.VertexFormatElement; import net.minecraft.entity.EntityLivingBase; import net.minecraft.item.ItemStack; import net.minecraft.util.EnumFacing; import net.minecraft.world.World; import net.minecraftforge.client.model.pipeline.UnpackedBakedQuad; import net.minecraftforge.client.model.pipeline.VertexTransformer; import net.minecraftforge.common.model.TRSRTransformation; import com.google.common.collect.ImmutableList; // for those wondering TRSR stands for Translation Rotation Scale Rotation public class TRSRBakedModel implements IBakedModel { protected final IBakedModel original; protected final TRSRTransformation transformation; private final TRSROverride override; private final int faceOffset; public TRSRBakedModel(IBakedModel original, float x, float y, float z, float scale) { this(original, x, y, z, 0, 0, 0, scale, scale, scale); } public TRSRBakedModel(IBakedModel original, float x, float y, float z, float rotX, float rotY, float rotZ, float scale) { this(original, x, y, z, rotX, rotY, rotZ, scale, scale, scale); } public TRSRBakedModel(IBakedModel original, float x, float y, float z, float rotX, float rotY, float rotZ, float scaleX, float scaleY, float scaleZ) { this(original, new TRSRTransformation(new Vector3f(x, y, z), null, new Vector3f(scaleX, scaleY, scaleZ), TRSRTransformation.quatFromXYZ(rotX, rotY, rotZ))); } public TRSRBakedModel(IBakedModel original, TRSRTransformation transform) { this.original = original; this.transformation = TRSRTransformation.blockCenterToCorner(transform); this.override = new TRSROverride(this); this.faceOffset = 0; } /** Rotates around the Y axis and adjusts culling appropriately. South is default. */ public TRSRBakedModel(IBakedModel original, EnumFacing facing) { this.original = original; this.override = new TRSROverride(this); this.faceOffset = 4 + EnumFacing.NORTH.getHorizontalIndex() - facing.getHorizontalIndex(); double r = Math.PI * (360 - facing.getOpposite().getHorizontalIndex() * 90)/180d; TRSRTransformation t = new TRSRTransformation(null, null, null, TRSRTransformation.quatFromXYZ(0, (float)r, 0)); this.transformation = TRSRTransformation.blockCenterToCorner(t); } @Override public List<BakedQuad> getQuads(IBlockState state, EnumFacing side, long rand) { // transform quads obtained from parent ImmutableList.Builder<BakedQuad> builder = ImmutableList.builder(); if(!original.isBuiltInRenderer()) { // adjust side to facing-rotation if(side != null && side.getHorizontalIndex() > -1) { side = EnumFacing.getHorizontal((side.getHorizontalIndex() + faceOffset) % 4); } for(BakedQuad quad : original.getQuads(state, side, rand)) { if(quad.getFormat() != null) { Transformer transformer = new Transformer(transformation, quad.getFormat()); quad.pipe(transformer); builder.add(transformer.build()); } } } return builder.build(); } @Override public boolean isAmbientOcclusion() { return false; } @Override public boolean isGui3d() { return original.isGui3d(); } @Override public boolean isBuiltInRenderer() { return original.isBuiltInRenderer(); } @Override public TextureAtlasSprite getParticleTexture() { return original.getParticleTexture(); } @Override public ItemCameraTransforms getItemCameraTransforms() { return original.getItemCameraTransforms(); } @Override public ItemOverrideList getOverrides() { return override; } private static class TRSROverride extends ItemOverrideList { private final TRSRBakedModel model; public TRSROverride(TRSRBakedModel model) { super(ImmutableList.<ItemOverride>of()); this.model = model; } @Override public IBakedModel handleItemState(IBakedModel originalModel, ItemStack stack, World world, EntityLivingBase entity) { IBakedModel baked = model.original.getOverrides().handleItemState(originalModel, stack, world, entity); return new TRSRBakedModel(baked, model.transformation); } } private static class Transformer extends VertexTransformer { protected Matrix4f transformation; protected Matrix3f normalTransformation; public Transformer(TRSRTransformation transformation, VertexFormat format) { super(new UnpackedBakedQuad.Builder(format)); // position transform this.transformation = transformation.getMatrix(); // normal transform this.normalTransformation = new Matrix3f(); this.transformation.getRotationScale(this.normalTransformation); this.normalTransformation.invert(); this.normalTransformation.transpose(); } @Override public void put(int element, float... data) { VertexFormatElement.EnumUsage usage = parent.getVertexFormat().getElement(element).getUsage(); // transform normals and position if(usage == VertexFormatElement.EnumUsage.POSITION && data.length >= 3) { Vector4f vec = new Vector4f(data[0], data[1], data[2], 1f); transformation.transform(vec); data = new float[4]; vec.get(data); } else if(usage == VertexFormatElement.EnumUsage.NORMAL && data.length >= 3) { Vector3f vec = new Vector3f(data); normalTransformation.transform(vec); vec.normalize(); data = new float[4]; vec.get(data); } super.put(element, data); } public UnpackedBakedQuad build() { return ((UnpackedBakedQuad.Builder) parent).build(); } } }