Files
Applied-Energistics-2/src/main/java/appeng/client/render/tesr/ChestTileEntityRenderer.java
T
2020-07-27 20:07:27 +02:00

160 lines
6.4 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.tesr;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import net.fabricmc.fabric.api.renderer.v1.mesh.Mesh;
import net.fabricmc.fabric.api.renderer.v1.model.ForwardingBakedModel;
import net.minecraft.block.BlockState;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.RenderLayer;
import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.block.BlockModelRenderer;
import net.minecraft.client.render.block.entity.BlockEntityRenderDispatcher;
import net.minecraft.client.render.block.entity.BlockEntityRenderer;
import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.render.model.BakedModelManager;
import net.minecraft.client.render.model.BakedQuad;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.item.Item;
import net.minecraft.item.Items;
import net.minecraft.util.math.Direction;
import net.minecraft.world.World;
import appeng.api.client.ICellModelRegistry;
import appeng.block.storage.DriveSlotsState;
import appeng.client.render.BakedModelUnwrapper;
import appeng.client.render.FacingToRotation;
import appeng.client.render.model.AutoRotatingBakedModel;
import appeng.client.render.model.DriveBakedModel;
import appeng.core.Api;
import appeng.tile.storage.ChestBlockEntity;
/**
* The tile entity renderer for ME chests takes care of rendering the right
* model for the inserted cell, as well as the LED.
*/
public class ChestTileEntityRenderer extends BlockEntityRenderer<ChestBlockEntity> {
private final ICellModelRegistry cellModelRegistry = Api.instance().client().cells();
private final BakedModelManager modelManager;
private final BlockModelRenderer blockRenderer;
public ChestTileEntityRenderer(BlockEntityRenderDispatcher renderDispatcher) {
super(renderDispatcher);
MinecraftClient client = MinecraftClient.getInstance();
modelManager = client.getBakedModelManager();
blockRenderer = client.getBlockRenderManager().getModelRenderer();
}
@Override
public void render(ChestBlockEntity chest, float partialTicks, MatrixStack matrices, VertexConsumerProvider buffers,
int combinedLight, int combinedOverlay) {
World world = chest.getWorld();
if (world == null) {
return;
}
DriveSlotsState driveSlotState = DriveSlotsState.fromChestOrDrive(chest);
Item cellItem = driveSlotState.getCell(0);
if (cellItem == null || cellItem == Items.AIR) {
return; // No cell inserted into chest
}
// Try to get the right cell chassis model from the drive model since it already
// loads them all
DriveBakedModel driveModel = getDriveModel();
if (driveModel == null) {
return;
}
BakedModel cellModel = driveModel.getCellChassisModel(cellItem);
matrices.push();
matrices.translate(0.5, 0.5, 0.5);
FacingToRotation rotation = FacingToRotation.get(chest.getForward(), chest.getUp());
rotation.push(matrices);
matrices.translate(-0.5, -0.5, -0.5);
// The models are created for the top-left slot of the drive model,
// we need to move them into place for the slot on the ME chest
matrices.translate(5 / 16.0, 4 / 16.0, 0);
// Render the cell model as-if it was a block model
VertexConsumer buffer = buffers.getBuffer(RenderLayer.getCutout());
// We "fake" the position here to make it use the light-value in front of the
// drive
BakedModel rotatedModel = new FaceRotatingModel(cellModel, rotation);
blockRenderer.render(world, rotatedModel, chest.getCachedState(), chest.getPos(), matrices, buffer, false,
new Random(), 0L, combinedOverlay);
VertexConsumer ledBuffer = buffers.getBuffer(CellLedRenderer.RENDER_LAYER);
CellLedRenderer.renderLed(chest, 0, ledBuffer, matrices, partialTicks);
matrices.pop();
}
private DriveBakedModel getDriveModel() {
BakedModel driveModel = modelManager.getBlockModels()
.getModel(Api.instance().definitions().blocks().drive().block().getDefaultState());
return BakedModelUnwrapper.unwrap(driveModel, DriveBakedModel.class);
}
/**
* The actual vertex data will be transformed using the matrix stack, but the
* faces will not be correctly rotated so the incorrect lighting data would be
* used to apply diffuse lighting and the lightmap texture.
*/
private static class FaceRotatingModel extends ForwardingBakedModel {
private final FacingToRotation r;
protected FaceRotatingModel(BakedModel base, FacingToRotation r) {
this.wrapped = base;
this.r = r;
}
@Nonnull
@Override
public List<BakedQuad> getQuads(@Nullable BlockState state, @Nullable Direction side, @Nonnull Random rand) {
if (side != null) {
side = r.resultingRotate(side); // This fixes the incorrect lightmap position
}
List<BakedQuad> quads = new ArrayList<>(super.getQuads(state, side, rand));
for (int i = 0; i < quads.size(); i++) {
BakedQuad quad = quads.get(i);
quads.set(i, new BakedQuad(quad.getVertexData(), quad.getColorIndex(), r.rotate(quad.getFace()),
/* FIXME FABRIC: sprite is protected but unused?? */ null, quad.hasShade()));
}
return quads;
}
}
}