Files
TiedUp-/src/main/java/com/tiedup/remake/client/gltf/GltfRenderLayer.java
NotEvil a71093ba9c Remove internal phase comments and format code
Strip all Phase references, TODO/FUTURE roadmap notes, and internal
planning comments from the codebase. Run Prettier for consistent
formatting across all Java files.
2026-04-12 01:25:55 +02:00

107 lines
3.6 KiB
Java

package com.tiedup.remake.client.gltf;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.Minecraft;
import net.minecraft.client.model.PlayerModel;
import net.minecraft.client.player.AbstractClientPlayer;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.entity.RenderLayerParent;
import net.minecraft.client.renderer.entity.layers.RenderLayer;
import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.joml.Matrix4f;
/**
* RenderLayer that renders the glTF mesh (handcuffs) on the player.
* Only active when enabled and only renders on the local player.
* <p>
* Uses the live skinning path: reads live skeleton from HumanoidModel
* via {@link GltfLiveBoneReader}, following PlayerAnimator + bendy-lib rotations.
* Falls back to GLB-internal skinning via {@link GltfSkinningEngine} if live reading fails.
*/
@OnlyIn(Dist.CLIENT)
public class GltfRenderLayer
extends RenderLayer<AbstractClientPlayer, PlayerModel<AbstractClientPlayer>>
{
private static final Logger LOGGER = LogManager.getLogger("GltfPipeline");
private static final ResourceLocation CUFFS_MODEL =
ResourceLocation.fromNamespaceAndPath(
"tiedup",
"models/gltf/v2/handcuffs/cuffs_prototype.glb"
);
public GltfRenderLayer(
RenderLayerParent<
AbstractClientPlayer,
PlayerModel<AbstractClientPlayer>
> renderer
) {
super(renderer);
}
/**
* The Y translate offset to place the glTF mesh in the MC PoseStack.
* <p>
* After LivingEntityRenderer's scale(-1,-1,1) + translate(0,-1.501,0),
* the PoseStack origin is at the model top (1.501 blocks above feet), Y-down.
* The glTF mesh (MC-converted) has feet at Y=0 and head at Y≈-1.5.
* Translating by 1.501 maps glTF feet to PoseStack feet and head to top.
*/
private static final float ALIGNMENT_Y = 1.501f;
@Override
public void render(
PoseStack poseStack,
MultiBufferSource buffer,
int packedLight,
AbstractClientPlayer entity,
float limbSwing,
float limbSwingAmount,
float partialTick,
float ageInTicks,
float netHeadYaw,
float headPitch
) {
if (!GltfAnimationApplier.isEnabled()) return;
if (entity != Minecraft.getInstance().player) return;
GltfData data = GltfCache.get(CUFFS_MODEL);
if (data == null) return;
// Live path: read skeleton from HumanoidModel (after PlayerAnimator)
PlayerModel<AbstractClientPlayer> parentModel = this.getParentModel();
Matrix4f[] joints = GltfLiveBoneReader.computeJointMatricesFromModel(
parentModel,
data,
entity
);
if (joints == null) {
// Fallback to GLB-internal path if live reading fails
joints = GltfSkinningEngine.computeJointMatrices(data);
}
poseStack.pushPose();
// Align glTF mesh with MC model (feet-to-feet alignment)
poseStack.translate(0, ALIGNMENT_Y, 0);
GltfMeshRenderer.renderSkinned(
data,
joints,
poseStack,
buffer,
packedLight,
net.minecraft.client.renderer.entity.LivingEntityRenderer.getOverlayCoords(
entity,
0.0f
)
);
poseStack.popPose();
}
}