Skip to content

Commit

Permalink
Rewrite renderers in Java
Browse files Browse the repository at this point in the history
  • Loading branch information
Juuxel committed Aug 2, 2024
1 parent 4cd54f7 commit 0add2f6
Show file tree
Hide file tree
Showing 8 changed files with 308 additions and 324 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package juuxel.adorn.client.renderer;

import net.minecraft.client.render.entity.EntityRenderer;
import net.minecraft.client.render.entity.EntityRendererFactory;
import net.minecraft.entity.Entity;
import net.minecraft.util.Identifier;

public final class InvisibleEntityRenderer extends EntityRenderer<Entity> {
private static final Identifier TEXTURE = new Identifier("missingno");

public InvisibleEntityRenderer(EntityRendererFactory.Context ctx) {
super(ctx);
}

@Override
public Identifier getTexture(Entity entity) {
return TEXTURE;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package juuxel.adorn.client.renderer;

import juuxel.adorn.block.AbstractKitchenCounterBlock;
import juuxel.adorn.block.entity.KitchenSinkBlockEntity;
import juuxel.adorn.client.FluidRenderingBridge;
import juuxel.adorn.util.Logging;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.RenderLayer;
import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.block.entity.BlockEntityRenderer;
import net.minecraft.client.render.block.entity.BlockEntityRendererFactory;
import net.minecraft.client.texture.MissingSprite;
import net.minecraft.client.texture.Sprite;
import net.minecraft.client.texture.SpriteAtlasTexture;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.RotationAxis;
import org.slf4j.Logger;

public abstract class KitchenSinkRenderer<T extends KitchenSinkBlockEntity> implements BlockEntityRenderer<T> {
private static final Logger LOGGER = Logging.logger();
private static final float PX = 1 / 16f;
private static final float X_START = 2 * PX;
private static final float X_END = 13 * PX;
private static final float Z_START = 2 * PX;
private static final float Z_END = 14 * PX;
private static final float Y_START = 7 * PX;
private static final float Y_END = 15 * PX;
private static final double LITRES_PER_BLOCK = 1000.0;

// Wave period in ms
private static final float WAVE_PERIOD = 12_000f;
private static final float WAVE_HEIGHT = PX;
private static final float MS_PER_TICK = 50f;

private static float getRotation(Direction facing) {
return switch (facing) {
case EAST -> 0f;
case NORTH -> 90f;
case WEST -> 180f;
case SOUTH -> 270f;
// Vertical orientations
default -> 0f;
};
}

protected KitchenSinkRenderer(BlockEntityRendererFactory.Context context) {
}

@Override
public void render(T entity, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay) {
// Skip if there's nothing to render
if (isEmpty(entity)) return;

var sprite = getFluidSprite(entity);
var buffer = vertexConsumers.getBuffer(RenderLayer.getEntityTranslucent(sprite.getAtlasId()));
float u0 = MathHelper.lerp(2 * PX, sprite.getMinU(), sprite.getMaxU());
float u1 = MathHelper.lerp(14 * PX, sprite.getMinU(), sprite.getMaxU());
float v0 = MathHelper.lerp(2 * PX, sprite.getMinV(), sprite.getMaxV());
float v1 = MathHelper.lerp(13 * PX, sprite.getMinV(), sprite.getMaxV());

matrices.push();
// Rotate because the model depends on the facing property
matrices.translate(0.5, 0.0, 0.5);
matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(getRotation(entity.getCachedState().get(AbstractKitchenCounterBlock.FACING))));
matrices.translate(-0.5, 0.0, -0.5);

// Move vertically to correct level
double fluidLevel = getFluidLevel(entity) / LITRES_PER_BLOCK;
matrices.translate(0.0, MathHelper.lerp(fluidLevel, Y_START, Y_END), 0.0);

// Draw the sprite

var positionMatrix = matrices.peek().getPositionMatrix();
var normalMatrix = matrices.peek().getNormalMatrix();
var color = getFluidColor(entity);
buffer.vertex(positionMatrix, X_START, computeY(X_START, Z_END), Z_END)
.color(color).texture(u0, v0).overlay(overlay).light(light).normal(normalMatrix, 0f, 1f, 0f).next();
buffer.vertex(positionMatrix, X_END, computeY(X_END, Z_END), Z_END)
.color(color).texture(u0, v1).overlay(overlay).light(light).normal(normalMatrix, 0f, 1f, 0f).next();
buffer.vertex(positionMatrix, X_END, computeY(X_END, Z_START), Z_START)
.color(color).texture(u1, v1).overlay(overlay).light(light).normal(normalMatrix, 0f, 1f, 0f).next();
buffer.vertex(positionMatrix, X_START, computeY(X_START, Z_START), Z_START)
.color(color).texture(u1, v0).overlay(overlay).light(light).normal(normalMatrix, 0f, 1f, 0f).next();
matrices.pop();
}

private static float computeY(float x, float z) {
var time = (MinecraftClient.getInstance().player.age * MS_PER_TICK) % WAVE_PERIOD;
var t = time * MathHelper.TAU / WAVE_PERIOD;
return MathHelper.sin(t + x + z) * WAVE_HEIGHT / 2;
}

private Sprite getFluidSprite(T entity) {
var sprite = FluidRenderingBridge.get().getStillSprite(entity.getFluidReference());

if (sprite == null) {
LOGGER.error("Could not find sprite for fluid reference {} when rendering kitchen sink at {}", entity.getFluidReference(), entity.getPos());
return MinecraftClient.getInstance()
.getSpriteAtlas(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE)
.apply(MissingSprite.getMissingSpriteId());
}

return sprite;
}

/** Gets the entity's fluid's color. */
private int getFluidColor(T entity) {
return FluidRenderingBridge.get().getColor(entity.getFluidReference(), entity.getWorld(), entity.getPos());
}

/** Gets the fluid level from the entity in litres. */
protected abstract double getFluidLevel(T entity);

/** Tests whether the [entity] has no fluid inside. */
protected abstract boolean isEmpty(T entity);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package juuxel.adorn.client.renderer;

import juuxel.adorn.block.ShelfBlock;
import juuxel.adorn.block.entity.ShelfBlockEntity;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.block.entity.BlockEntityRenderer;
import net.minecraft.client.render.block.entity.BlockEntityRendererFactory;
import net.minecraft.client.render.model.json.ModelTransformationMode;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.RotationAxis;

public final class ShelfRenderer implements BlockEntityRenderer<ShelfBlockEntity> {
private static final float ITEM_SCALE = 0.5f;
private static final float ITEM_1_Y_ROT = 10f;
private static final float ITEM_2_Y_ROT = -17f;

public ShelfRenderer(BlockEntityRendererFactory.Context context) {
}

@Override
public void render(ShelfBlockEntity be, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay) {
Direction facing = be.getCachedState().get(ShelfBlock.FACING);

// For first item
double tx1 = switch (facing) {
case SOUTH, WEST -> 12 / 16.0;
default -> 4 / 16.0;
};
double tz1 = switch (facing) {
case NORTH, WEST -> 12 / 16.0;
default -> 4 / 16.0;
};

// For second item
double tx2 = switch (facing) {
case NORTH, WEST -> 12 / 16.0;
default -> 4 / 16.0;
};
double tz2 = switch (facing) {
case NORTH, EAST -> 12 / 16.0;
default -> 4 / 16.0;
};

var itemRenderer = MinecraftClient.getInstance().getItemRenderer();

matrices.push();
matrices.translate(tx1, 9.6 / 16.0, tz1);
matrices.scale(ITEM_SCALE, ITEM_SCALE, ITEM_SCALE);
matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(ITEM_1_Y_ROT + 180 - facing.asRotation()));
itemRenderer.renderItem(
be.getStack(0),
ModelTransformationMode.FIXED,
light,
overlay,
matrices,
vertexConsumers,
be.getWorld(),
0 // seed
);
matrices.pop();

matrices.push();
matrices.translate(tx2, 9.6 / 16.0, tz2);
matrices.scale(ITEM_SCALE, ITEM_SCALE, ITEM_SCALE);
matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(ITEM_2_Y_ROT + 180 - facing.asRotation()));
itemRenderer.renderItem(
be.getStack(1),
ModelTransformationMode.FIXED,
light,
overlay,
matrices,
vertexConsumers,
be.getWorld(),
0 // seed
);
matrices.pop();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package juuxel.adorn.client.renderer;

import juuxel.adorn.block.entity.TradingStationBlockEntity;
import juuxel.adorn.config.ConfigManager;
import juuxel.adorn.util.Colors;
import juuxel.adorn.util.ColorsKt;
import juuxel.adorn.util.ExtensionsKt;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.block.entity.BlockEntityRenderDispatcher;
import net.minecraft.client.render.block.entity.BlockEntityRenderer;
import net.minecraft.client.render.block.entity.BlockEntityRendererFactory;
import net.minecraft.client.render.model.json.ModelTransformationMode;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.text.Text;
import net.minecraft.util.Formatting;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.hit.HitResult;
import net.minecraft.util.math.RotationAxis;

public final class TradingStationRenderer implements BlockEntityRenderer<TradingStationBlockEntity> {
private static final float SELLING_ROTATION_MULTIPLIER = 1.2f;
private static final String OWNER_LABEL = "block.adorn.trading_station.label.owner";
private static final String SELLING_LABEL = "block.adorn.trading_station.label.selling";
private static final String PRICE_LABEL = "block.adorn.trading_station.label.price";

private final BlockEntityRenderDispatcher dispatcher;
private final TextRenderer textRenderer;

public TradingStationRenderer(BlockEntityRendererFactory.Context context) {
dispatcher = context.getRenderDispatcher();
textRenderer = context.getTextRenderer();
}

@Override
public void render(TradingStationBlockEntity be, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay) {
var hitResult = dispatcher.crosshairTarget;
var lookingAtBlock = hitResult != null && hitResult.getType() == HitResult.Type.BLOCK && be.getPos().equals(((BlockHitResult) hitResult).getBlockPos());
var trade = be.getTrade();

if (!trade.isEmpty()) {
matrices.push();
matrices.translate(0.5, 1.2, 0.5);
int playerAge = MinecraftClient.getInstance().player.age;
matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees((playerAge + tickDelta) * SELLING_ROTATION_MULTIPLIER));
matrices.scale(0.6f, 0.6f, 0.6f);
matrices.translate(0.0, 0.3, 0.0);
var itemRenderer = MinecraftClient.getInstance().getItemRenderer();
itemRenderer.renderItem(trade.getSelling(), ModelTransformationMode.FIXED, light, overlay, matrices, vertexConsumers, be.getWorld(), 0);
matrices.pop();
}

if (lookingAtBlock && ConfigManager.config().client.showTradingStationTooltips) {
Text label1 = Text.translatable(OWNER_LABEL, be.getOwnerName().copy().formatted(Formatting.GOLD));
renderLabel(be, label1, 0.0, 0.9, 0.0, 12, matrices, vertexConsumers, light);
if (!be.getTrade().isEmpty()) {
Text label2 = Text.translatable(SELLING_LABEL, ExtensionsKt.toTextWithCount(be.getTrade().getSelling()));
Text label3 = Text.translatable(PRICE_LABEL, ExtensionsKt.toTextWithCount(be.getTrade().getPrice()));
renderLabel(be, label2, 0.0, 0.9 - 0.25, 0.0, 12, matrices, vertexConsumers, light);
renderLabel(be, label3, 0.0, 0.9 - 0.5, 0.0, 12, matrices, vertexConsumers, light);
}
}
}

private void renderLabel(
BlockEntity be, Text label, double x, double y, double z,
int maxDistance, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light
) {
var camera = dispatcher.camera;

double dist = be.getPos().getSquaredDistanceFromCenter(camera.getPos().x, camera.getPos().y, camera.getPos().z);
if (dist < maxDistance * maxDistance) {
matrices.push();
matrices.translate(x + 0.5, y + 1.5, z + 0.5);
matrices.multiply(camera.getRotation());
matrices.scale(-0.025f, -0.025f, +0.025f);

var positionMatrix = matrices.peek().getPositionMatrix();
float opacity = MinecraftClient.getInstance().options.getTextBackgroundOpacity(0.25f);
int backgroundColor = ColorsKt.color(0x000000, opacity);
var textX = -textRenderer.getWidth(label) * 0.5f;
textRenderer.draw(label, textX, 0f, Colors.WHITE, false, positionMatrix, vertexConsumers, TextRenderer.TextLayerType.NORMAL, backgroundColor, light);

matrices.pop();
}
}


}

This file was deleted.

Loading

0 comments on commit 0add2f6

Please sign in to comment.