RyanHub – file viewer
filename: common/src/main/java/rearth/oritech/client/renderers/SmallTankRenderer.java
branch: 1.21
back to repo
package rearth.oritech.client.renderers;

import dev.architectury.hooks.fluid.FluidStackHooks;
import io.wispforest.owo.ui.core.Color;
import net.minecraft.client.render.RenderLayer;
import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.block.entity.BlockEntityRenderer;
import net.minecraft.client.texture.Sprite;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.fluid.Fluids;
import net.minecraft.util.math.Direction;
import org.joml.Matrix4f;
import rearth.oritech.block.entity.storage.SmallTankEntity;

public class SmallTankRenderer implements BlockEntityRenderer<SmallTankEntity> {
    
    @Override
    public void render(SmallTankEntity entity, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay) {
        
        var storage = entity.fluidStorage;
        if (storage.getAmount() <= 0 || storage.getFluid().equals(Fluids.EMPTY)) return;
        
        var fluid = storage.getFluid();
        var fill = storage.getAmount() / (float) storage.getCapacity();
        
        var sprite = FluidStackHooks.getStillTexture(fluid);
        var spriteColor = FluidStackHooks.getColor(fluid);
        var consumer = vertexConsumers.getBuffer(RenderLayer.getTranslucent());
        
        var parsedColor = Color.ofArgb(spriteColor);
        var opaqueColor = new Color(parsedColor.red(), parsedColor.green(), parsedColor.blue(), 1f);
        spriteColor = opaqueColor.argb();
        
        matrices.push();
        matrices.translate(0.126, 0.126, 0.126);
        matrices.scale(0.745f, 0.745f * fill, 0.745f);
        
        // because fabric fluidRender() doesnt seem to do the job, we manually draw rects:
        var entry = matrices.peek();
        var modelMatrix = entry.getPositionMatrix();
        var normalMatrix = entry.getNormalMatrix();
        
        // Draw the cube using quads
        for (Direction direction : Direction.values()) {
            if (direction.equals(Direction.DOWN)) continue; // skip bottom, as it's never visible
            drawQuad(direction, consumer, modelMatrix, entry, sprite, spriteColor, light, overlay);
        }
        
        matrices.pop();
        
    }
    
    private void drawQuad(Direction direction, VertexConsumer consumer, Matrix4f modelMatrix, MatrixStack.Entry normalMatrix, Sprite sprite, int color, int light, int overlay) {
        // Define the vertices of the quad based on the direction it's facing
        
        var normal = direction.getUnitVector();
        
        var positions = getQuadVerticesByDirection(direction);
        
        for (int i = positions.length - 1; i >= 0; i--) {
            
            var pos = positions[i];
            var u = sprite.getFrameU(getFrameU()[i]);
            var v = sprite.getFrameV(getFrameV()[i]);
            
            consumer.vertex(modelMatrix, pos[0], pos[1], pos[2])
              .color(color)
              .texture(u, v)
              .light(light)
              .overlay(overlay)
              .normal(normalMatrix, normal.x, normal.y, normal.z);
        }
        
    }
    
    private static float[] getFrameU() {
        return new float[] {0, 1, 1, 0};
    }
    
    private static float[] getFrameV() {
        return new float[] {0, 0, 1, 1};
    }
    
    private static float[][] getQuadVerticesByDirection(Direction direction) {
        // Define the vertices for each face of the cube
        return switch (direction) {
            case UP -> new float[][]{
              {0, 1, 0}, // Top-left
              {1, 1, 0}, // Top-right
              {1, 1, 1}, // Bottom-right
              {0, 1, 1}  // Bottom-left
            };
            case DOWN -> new float[][]{
              {0, 0, 1}, // Top-left
              {1, 0, 1}, // Top-right
              {1, 0, 0}, // Bottom-right
              {0, 0, 0}  // Bottom-left
            };
            case NORTH -> new float[][]{
              {1, 1, 0}, // Top-left
              {0, 1, 0}, // Top-right
              {0, 0, 0}, // Bottom-right
              {1, 0, 0}  // Bottom-left
            };
            case SOUTH -> new float[][]{
              {0, 1, 1}, // Top-left
              {1, 1, 1}, // Top-right
              {1, 0, 1}, // Bottom-right
              {0, 0, 1}  // Bottom-left
            };
            case WEST -> new float[][]{
              {0, 1, 0}, // Top-left
              {0, 1, 1}, // Top-right
              {0, 0, 1}, // Bottom-right
              {0, 0, 0}  // Bottom-left
            };
            case EAST -> new float[][]{
              {1, 1, 1}, // Top-left
              {1, 1, 0}, // Top-right
              {1, 0, 0}, // Bottom-right
              {1, 0, 1}  // Bottom-left
            };
        };
    }
}