Skip to content

Commit

Permalink
Use a model for rendering pocket computers
Browse files Browse the repository at this point in the history
  • Loading branch information
SquidDev committed Feb 12, 2025
1 parent f211993 commit 1f62a76
Show file tree
Hide file tree
Showing 9 changed files with 120 additions and 8 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// SPDX-FileCopyrightText: 2024 The CC: Tweaked Developers
//
// SPDX-License-Identifier: MPL-2.0

package dan200.computercraft.client.model;

import com.mojang.blaze3d.vertex.PoseStack;
import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.client.render.CustomLecternRenderer;
import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.pocket.items.PocketComputerItem;
import net.minecraft.client.model.geom.ModelPart;
import net.minecraft.client.model.geom.PartPose;
import net.minecraft.client.model.geom.builders.CubeListBuilder;
import net.minecraft.client.model.geom.builders.MeshDefinition;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.resources.model.Material;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.FastColor;
import net.minecraft.world.inventory.InventoryMenu;

/**
* A model for {@linkplain PocketComputerItem pocket computers} placed on a lectern.
*
* @see CustomLecternRenderer
*/
public class LecternPocketModel {
public static final ResourceLocation TEXTURE_NORMAL = new ResourceLocation(ComputerCraftAPI.MOD_ID, "entity/pocket_computer_normal");
public static final ResourceLocation TEXTURE_ADVANCED = new ResourceLocation(ComputerCraftAPI.MOD_ID, "entity/pocket_computer_advanced");
public static final ResourceLocation TEXTURE_COLOUR = new ResourceLocation(ComputerCraftAPI.MOD_ID, "entity/pocket_computer_colour");

private static final Material MATERIAL_NORMAL = new Material(InventoryMenu.BLOCK_ATLAS, TEXTURE_NORMAL);
private static final Material MATERIAL_ADVANCED = new Material(InventoryMenu.BLOCK_ATLAS, TEXTURE_ADVANCED);
private static final Material MATERIAL_COLOUR = new Material(InventoryMenu.BLOCK_ATLAS, TEXTURE_COLOUR);

public static final float TERM_WIDTH = 12.0f / 32.0f;
public static final float TERM_HEIGHT = 14.0f / 32.0f;

private final ModelPart basic;
private final ModelPart colourFrame;
private final ModelPart colourBody;

public LecternPocketModel() {
basic = buildPages(18, 18, 0, 0);
colourFrame = buildPages(32, 32, 0, 0);
colourBody = buildPages(32, 32, 14, 14);
}

private static ModelPart buildPages(int width, int height, int textureOffX, int textureOffY) {
var mesh = new MeshDefinition();
var parts = mesh.getRoot();
parts.addOrReplaceChild(
"root",
CubeListBuilder.create().texOffs(textureOffX, textureOffY).addBox(0f, -5.0f, -4.0f, 1f, 10.0f, 8.0f),
PartPose.ZERO
);
return mesh.getRoot().bake(width, height);
}

public void render(PoseStack poseStack, MultiBufferSource buffers, int packedLight, int packedOverlay, ComputerFamily family, int colour) {
if (colour != -1) {
var buffer = MATERIAL_COLOUR.buffer(buffers, RenderType::entityCutout);
int red = FastColor.ARGB32.red(colour), green = FastColor.ARGB32.green(colour), blue = FastColor.ARGB32.blue(colour);
colourFrame.render(poseStack, buffer, packedLight, packedOverlay, 1, 1, 1, 1);
colourBody.render(poseStack, buffer, packedLight, packedOverlay, red / 255.0f, green / 255.0f, blue / 255.0f, 1);
} else {
var buffer = (family == ComputerFamily.ADVANCED ? MATERIAL_ADVANCED : MATERIAL_NORMAL).buffer(buffers, RenderType::entityCutout);
basic.render(poseStack, buffer, packedLight, packedOverlay, 1, 1, 1, 1);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@

import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.math.Axis;
import dan200.computercraft.client.model.LecternPocketModel;
import dan200.computercraft.client.model.LecternPrintoutModel;
import dan200.computercraft.client.pocket.ClientPocketComputers;
import dan200.computercraft.client.render.text.FixedWidthFontRenderer;
import dan200.computercraft.core.terminal.Terminal;
import dan200.computercraft.shared.lectern.CustomLecternBlockEntity;
import dan200.computercraft.shared.media.items.PrintoutItem;
import dan200.computercraft.shared.pocket.items.PocketComputerItem;
Expand All @@ -17,16 +21,22 @@
import net.minecraft.client.renderer.blockentity.LecternRenderer;
import net.minecraft.world.level.block.LecternBlock;

import static dan200.computercraft.client.render.ComputerBorderRenderer.MARGIN;
import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FONT_HEIGHT;
import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FONT_WIDTH;

/**
* A block entity renderer for our {@linkplain CustomLecternBlockEntity lectern}.
* <p>
* This largely follows {@link LecternRenderer}, but with support for multiple types of item.
*/
public class CustomLecternRenderer implements BlockEntityRenderer<CustomLecternBlockEntity> {
private final LecternPrintoutModel printoutModel;
private final LecternPocketModel pocketModel;

public CustomLecternRenderer(BlockEntityRendererProvider.Context context) {
printoutModel = new LecternPrintoutModel();
pocketModel = new LecternPocketModel();
}

@Override
Expand All @@ -45,12 +55,38 @@ public void render(CustomLecternBlockEntity lectern, float partialTick, PoseStac
} else {
printoutModel.renderPages(poseStack, vertexConsumer, packedLight, packedOverlay, PrintoutItem.getPageCount(item));
}
} else if (item.getItem() instanceof PocketComputerItem) {
poseStack.mulPose(Axis.YP.rotationDegrees(-90f));
poseStack.mulPose(Axis.ZP.rotationDegrees(180f));
PocketItemRenderer.render(poseStack, buffer, item, packedLight);
} else if (item.getItem() instanceof PocketComputerItem pocket) {
pocketModel.render(poseStack, buffer, packedLight, packedOverlay, pocket.getFamily(), pocket.getColour(item));

var computer = ClientPocketComputers.get(item);
var terminal = computer == null ? null : computer.getTerminal();
if (terminal != null) renderPocketTerminal(poseStack, buffer, terminal);
}

poseStack.popPose();
}

private static void renderPocketTerminal(PoseStack poseStack, MultiBufferSource buffer, Terminal terminal) {
var width = terminal.getWidth() * FONT_WIDTH;
var height = terminal.getHeight() * FONT_HEIGHT;

// Scale the terminal down to fit in the available space.
var scaleX = LecternPocketModel.TERM_WIDTH / (width + MARGIN * 2);
var scaleY = LecternPocketModel.TERM_HEIGHT / (height + MARGIN * 2);
var scale = Math.min(scaleX, scaleY);

// Jiggle the terminal about a bit, so it's centred.
poseStack.mulPose(Axis.YP.rotationDegrees(90f));
poseStack.translate(0, 1f / 32.0f, 1 / 16.0f);
poseStack.mulPose(Axis.XP.rotationDegrees(180));
poseStack.scale(scale, scale, -1.0f);
poseStack.translate(-0.5f * width, -0.5f * height, 0);

// Convert the model dimensions to terminal space, then find out how much padding we need.
var marginX = ((LecternPocketModel.TERM_WIDTH / scale) - width) / 2;
var marginY = ((LecternPocketModel.TERM_HEIGHT / scale) - height) / 2;

var quadEmitter = FixedWidthFontRenderer.toVertexConsumer(poseStack, buffer.getBuffer(RenderTypes.TERMINAL));
FixedWidthFontRenderer.drawTerminal(quadEmitter, 0, 0, terminal, marginY, marginY, marginX, marginX);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public final class FixedWidthFontRenderer {
static final float BACKGROUND_END = (WIDTH - 4.0f) / WIDTH;

private static final int BLACK = FastColor.ARGB32.color(255, byteColour(Colour.BLACK.getR()), byteColour(Colour.BLACK.getR()), byteColour(Colour.BLACK.getR()));
private static final float Z_OFFSET = 1e-3f;
private static final float Z_OFFSET = 1e-4f;

private FixedWidthFontRenderer() {
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import com.mojang.serialization.Codec;
import dan200.computercraft.client.gui.GuiSprites;
import dan200.computercraft.client.model.LecternPocketModel;
import dan200.computercraft.client.model.LecternPrintoutModel;
import dan200.computercraft.shared.turtle.inventory.UpgradeSlot;
import net.minecraft.client.renderer.texture.atlas.SpriteSource;
Expand Down Expand Up @@ -54,7 +55,8 @@ public static void add(GeneratorSink generator) {
out.accept(new ResourceLocation("blocks"), makeSprites(Stream.of(
UpgradeSlot.LEFT_UPGRADE,
UpgradeSlot.RIGHT_UPGRADE,
LecternPrintoutModel.TEXTURE
LecternPrintoutModel.TEXTURE,
LecternPocketModel.TEXTURE_NORMAL, LecternPocketModel.TEXTURE_ADVANCED, LecternPocketModel.TEXTURE_COLOUR
)));
out.accept(GuiSprites.SPRITE_SHEET, makeSprites(
Stream.of(GuiSprites.TURTLE_NORMAL_SELECTED_SLOT, GuiSprites.TURTLE_ADVANCED_SELECTED_SLOT),
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@ protected void onTerminalChanged() {
var holder = brain.holder() instanceof PocketHolder.PlayerHolder h && h.isValid(this) ? h.entity() : null;
if (brain.holder().isTerminalAlwaysVisible() && !tracking.isEmpty()) {
// If the terminal is always visible, send it to all players *and* the holder.
System.out.println("Sending " + getInstanceUUID());
var packet = new PocketComputerDataMessage(this, true);
ServerNetworking.sendToPlayers(packet, tracking);
if (holder != null && !tracking.contains(holder)) ServerNetworking.sendToPlayer(packet, holder);
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 1f62a76

Please sign in to comment.