From 2ea122c4a9265862e84ada78fc4ef54616547788 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Wed, 25 Feb 2026 14:17:57 +0100 Subject: [PATCH] Working full cape rendering --- .../cosmetics/CloakFeatureRenderer.java | 265 ++++++++++++++---- 1 file changed, 212 insertions(+), 53 deletions(-) diff --git a/src/main/java/org/saturnclient/saturnclient/cosmetics/CloakFeatureRenderer.java b/src/main/java/org/saturnclient/saturnclient/cosmetics/CloakFeatureRenderer.java index 948ad9b..209a5f8 100644 --- a/src/main/java/org/saturnclient/saturnclient/cosmetics/CloakFeatureRenderer.java +++ b/src/main/java/org/saturnclient/saturnclient/cosmetics/CloakFeatureRenderer.java @@ -9,12 +9,19 @@ import net.minecraft.client.render.OverlayTexture; import net.minecraft.client.render.RenderLayer; import net.minecraft.client.render.VertexConsumer; import net.minecraft.client.render.VertexConsumerProvider; +import net.minecraft.client.render.entity.equipment.EquipmentModel; import net.minecraft.client.render.entity.equipment.EquipmentModelLoader; +import net.minecraft.client.render.entity.equipment.EquipmentModel.LayerType; import net.minecraft.client.render.entity.feature.FeatureRenderer; import net.minecraft.client.render.entity.feature.FeatureRendererContext; import net.minecraft.client.render.entity.model.PlayerEntityModel; import net.minecraft.client.render.entity.state.PlayerEntityRenderState; import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.component.DataComponentTypes; +import net.minecraft.component.type.EquippableComponent; +import net.minecraft.item.ItemStack; +import net.minecraft.item.equipment.EquipmentAsset; +import net.minecraft.registry.RegistryKey; import net.minecraft.util.Identifier; import net.minecraft.util.math.Vec3d; @@ -28,14 +35,63 @@ import net.minecraft.util.math.Vec3d; public class CloakFeatureRenderer extends FeatureRenderer { private final EquipmentModelLoader equipmentModelLoader; private static final int PARTS = 16; + private float currentVelocity = 0.0f; private final float[] segmentValues = new float[PARTS]; + private static final float TEX_W = 176f; + private static final float TEX_H = 138f; + + private static final class PxRect { + final int x, y, w, h; + + PxRect(int x, int y, int w, int h) { + this.x = x; + this.y = y; + this.w = w; + this.h = h; + } + + float u1() { + return x / TEX_W; + } + + float v1() { + return y / TEX_H; + } + + float u2() { + return (x + w) / TEX_W; + } + + float v2() { + return (y + h) / TEX_H; + } + } + + private static final PxRect FRONT_RECT = new PxRect(8, 8, 80, 128); + private static final PxRect BACK_RECT = new PxRect(96, 8, 80, 128); + private static final PxRect LEFT_EDGE_RECT = new PxRect(0, 8, 8, 128); + private static final PxRect RIGHT_EDGE_RECT = new PxRect(88, 8, 8, 128); + private static final PxRect TOP_RECT = new PxRect(8, 0, 80, 8); + private static final PxRect BOTTOM_RECT = new PxRect(88, 0, 80, 8); + public CloakFeatureRenderer(FeatureRendererContext context, EquipmentModelLoader equipmentModelLoader) { super(context); this.equipmentModelLoader = equipmentModelLoader; + Arrays.fill(segmentValues, 0.5f); + } - Arrays.fill(segmentValues, 0.0f); + private boolean hasCustomModelForLayer(ItemStack stack, EquipmentModel.LayerType layerType) { + EquippableComponent equippableComponent = (EquippableComponent) stack + .get(DataComponentTypes.EQUIPPABLE); + if (equippableComponent != null && !equippableComponent.assetId().isEmpty()) { + EquipmentModel equipmentModel = this.equipmentModelLoader + .get((RegistryKey) equippableComponent.assetId().get()); + return !equipmentModel.getLayers(layerType).isEmpty(); + } else { + return false; + } } private void renderCapeQuad(VertexConsumer vertexConsumer, MatrixStack matrixStack, @@ -83,35 +139,67 @@ public class CloakFeatureRenderer extends FeatureRenderer> 4) & 0xF; + int skyLight = (light >> 20) & 0xF; + blockLight = Math.max(blockLight, minBrightness); + skyLight = Math.max(skyLight, minBrightness); + light = (skyLight << 20) | (blockLight << 4); - Arrays.fill(segmentValues, 0.5f); + VertexConsumer vertexConsumer = vertexConsumerProvider + .getBuffer(RenderLayer.getEntityAlpha(customCape)); - renderCape( - matrices, - consumer, - state, - light, - OverlayTexture.DEFAULT_UV); + float base = Math.min(currentVelocity, 1.0f); + + for (int i = 0; i < PARTS; i++) { + float falloff = i / (float) (PARTS - 1); + segmentValues[i] = base * falloff; + } + + matrixStack.push(); + + matrixStack.translate(0.0f, -0.25f, 0.0f); + + if (this.hasCustomModelForLayer(playerEntityRenderState.equippedChestStack, LayerType.HUMANOID)) { + matrixStack.translate(0.0F, -0.053125F, 0.06875F); + } + + renderCape(matrixStack, vertexConsumer, playerEntityRenderState, light, OverlayTexture.DEFAULT_UV); + + matrixStack.pop(); } }