Working full cape rendering
This commit is contained in:
@@ -9,12 +9,19 @@ import net.minecraft.client.render.OverlayTexture;
|
|||||||
import net.minecraft.client.render.RenderLayer;
|
import net.minecraft.client.render.RenderLayer;
|
||||||
import net.minecraft.client.render.VertexConsumer;
|
import net.minecraft.client.render.VertexConsumer;
|
||||||
import net.minecraft.client.render.VertexConsumerProvider;
|
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.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.FeatureRenderer;
|
||||||
import net.minecraft.client.render.entity.feature.FeatureRendererContext;
|
import net.minecraft.client.render.entity.feature.FeatureRendererContext;
|
||||||
import net.minecraft.client.render.entity.model.PlayerEntityModel;
|
import net.minecraft.client.render.entity.model.PlayerEntityModel;
|
||||||
import net.minecraft.client.render.entity.state.PlayerEntityRenderState;
|
import net.minecraft.client.render.entity.state.PlayerEntityRenderState;
|
||||||
import net.minecraft.client.util.math.MatrixStack;
|
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.Identifier;
|
||||||
import net.minecraft.util.math.Vec3d;
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
|
||||||
@@ -28,14 +35,63 @@ import net.minecraft.util.math.Vec3d;
|
|||||||
public class CloakFeatureRenderer extends FeatureRenderer<PlayerEntityRenderState, PlayerEntityModel> {
|
public class CloakFeatureRenderer extends FeatureRenderer<PlayerEntityRenderState, PlayerEntityModel> {
|
||||||
private final EquipmentModelLoader equipmentModelLoader;
|
private final EquipmentModelLoader equipmentModelLoader;
|
||||||
private static final int PARTS = 16;
|
private static final int PARTS = 16;
|
||||||
|
private float currentVelocity = 0.0f;
|
||||||
private final float[] segmentValues = new float[PARTS];
|
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<PlayerEntityRenderState, PlayerEntityModel> context,
|
public CloakFeatureRenderer(FeatureRendererContext<PlayerEntityRenderState, PlayerEntityModel> context,
|
||||||
EquipmentModelLoader equipmentModelLoader) {
|
EquipmentModelLoader equipmentModelLoader) {
|
||||||
super(context);
|
super(context);
|
||||||
this.equipmentModelLoader = equipmentModelLoader;
|
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<EquipmentAsset>) equippableComponent.assetId().get());
|
||||||
|
return !equipmentModel.getLayers(layerType).isEmpty();
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderCapeQuad(VertexConsumer vertexConsumer, MatrixStack matrixStack,
|
private void renderCapeQuad(VertexConsumer vertexConsumer, MatrixStack matrixStack,
|
||||||
@@ -83,35 +139,67 @@ public class CloakFeatureRenderer extends FeatureRenderer<PlayerEntityRenderStat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderCape(
|
private void renderCape(MatrixStack matrixStack, VertexConsumer vertexConsumer,
|
||||||
MatrixStack matrices,
|
PlayerEntityRenderState playerState, int light, int overlay) {
|
||||||
VertexConsumer consumer,
|
|
||||||
PlayerEntityRenderState state,
|
|
||||||
int light,
|
|
||||||
int overlay) {
|
|
||||||
|
|
||||||
float capeWidth = 10.0f / 16.0f;
|
float capeWidth = 10.0f / 16.0f;
|
||||||
float capeLength = 16.0f / 16.0f;
|
float capeHeight = 16.0f / 16.0f;
|
||||||
float thickness = 1.0f / 16.0f;
|
float capeDepth = 1.0f / 16.0f;
|
||||||
|
float capePartHeight = capeHeight / PARTS;
|
||||||
|
|
||||||
float segmentLength = capeLength / PARTS;
|
matrixStack.push();
|
||||||
|
matrixStack.translate(0.0f, 1.25, 0.125f);
|
||||||
|
|
||||||
matrices.push();
|
float x1 = -capeWidth / 2.0f;
|
||||||
|
float x2 = capeWidth / 2.0f;
|
||||||
|
// float y2 = -capeHeight;
|
||||||
|
float z1 = 0.0f;
|
||||||
|
float z2 = capeDepth;
|
||||||
|
|
||||||
// Proper shoulder anchor
|
final float frontU1 = FRONT_RECT.u1();
|
||||||
matrices.translate(0.0f, 1.5f, 0.2f);
|
final float frontU2 = FRONT_RECT.u2();
|
||||||
|
final float frontV1 = FRONT_RECT.v1();
|
||||||
|
final float frontV2 = FRONT_RECT.v2();
|
||||||
|
final float frontPartV = (frontV2 - frontV1) / PARTS;
|
||||||
|
|
||||||
|
final float backU1 = BACK_RECT.u1();
|
||||||
|
final float backU2 = BACK_RECT.u2();
|
||||||
|
final float backV1 = BACK_RECT.v1();
|
||||||
|
final float backV2 = BACK_RECT.v2();
|
||||||
|
final float backPartV = (backV2 - backV1) / PARTS;
|
||||||
|
|
||||||
|
final float leftU1 = LEFT_EDGE_RECT.u1();
|
||||||
|
final float leftU2 = LEFT_EDGE_RECT.u2();
|
||||||
|
final float leftV1 = LEFT_EDGE_RECT.v1();
|
||||||
|
final float leftV2 = LEFT_EDGE_RECT.v2();
|
||||||
|
final float leftPartV = (leftV2 - leftV1) / PARTS;
|
||||||
|
|
||||||
|
final float rightU1 = RIGHT_EDGE_RECT.u1();
|
||||||
|
final float rightU2 = RIGHT_EDGE_RECT.u2();
|
||||||
|
final float rightV1 = RIGHT_EDGE_RECT.v1();
|
||||||
|
final float rightV2 = RIGHT_EDGE_RECT.v2();
|
||||||
|
final float rightPartV = (rightV2 - rightV1) / PARTS;
|
||||||
|
|
||||||
|
final float topU1 = TOP_RECT.u1();
|
||||||
|
final float topU2 = TOP_RECT.u2();
|
||||||
|
final float topV1 = TOP_RECT.v1();
|
||||||
|
final float topV2 = TOP_RECT.v2();
|
||||||
|
|
||||||
|
final float bottomU1 = BOTTOM_RECT.u1();
|
||||||
|
final float bottomU2 = BOTTOM_RECT.u2();
|
||||||
|
final float bottomV1 = BOTTOM_RECT.v1();
|
||||||
|
final float bottomV2 = BOTTOM_RECT.v2();
|
||||||
|
|
||||||
float accumulatedY = 0.0f;
|
float accumulatedY = 0.0f;
|
||||||
float accumulatedZ = 0.0f;
|
float accumulatedZ = 0.0f;
|
||||||
|
|
||||||
for (int i = 0; i < PARTS; i++) {
|
for (int i = 0; i < PARTS; i++) {
|
||||||
|
|
||||||
float value = segmentValues[i]; // 0 → 1
|
float value = segmentValues[i]; // 0 → 1 per segment
|
||||||
|
|
||||||
float angle = value * ((float) Math.PI / 2f);
|
float angle = value * ((float) Math.PI / 2f);
|
||||||
|
|
||||||
float offsetY = -(float) Math.cos(angle) * segmentLength;
|
float offsetY = -(float) Math.cos(angle) * capePartHeight;
|
||||||
float offsetZ = (float) Math.sin(angle) * segmentLength;
|
float offsetZ = (float) Math.sin(angle) * capePartHeight;
|
||||||
|
|
||||||
float topY = accumulatedY;
|
float topY = accumulatedY;
|
||||||
float topZ = accumulatedZ;
|
float topZ = accumulatedZ;
|
||||||
@@ -122,55 +210,126 @@ public class CloakFeatureRenderer extends FeatureRenderer<PlayerEntityRenderStat
|
|||||||
float bottomY = accumulatedY;
|
float bottomY = accumulatedY;
|
||||||
float bottomZ = accumulatedZ;
|
float bottomZ = accumulatedZ;
|
||||||
|
|
||||||
float x1 = -capeWidth / 2f;
|
// FRONT
|
||||||
float x2 = capeWidth / 2f;
|
this.renderCapeQuad(
|
||||||
|
vertexConsumer, matrixStack,
|
||||||
|
new Vec3d(x2, bottomY, z2 + bottomZ),
|
||||||
|
new Vec3d(x1, bottomY, z2 + bottomZ),
|
||||||
|
new Vec3d(x1, topY, z2 + topZ),
|
||||||
|
new Vec3d(x2, topY, z2 + topZ),
|
||||||
|
frontU1, frontV2 - (frontPartV * i),
|
||||||
|
frontU2, frontV2 - (frontPartV * (i + 1)),
|
||||||
|
light, overlay,
|
||||||
|
0.0f, 0.0f, 1.0f, false);
|
||||||
|
|
||||||
renderCapeQuad(
|
// BACK
|
||||||
consumer,
|
this.renderCapeQuad(
|
||||||
matrices,
|
vertexConsumer, matrixStack,
|
||||||
new Vec3d(x1, bottomY, bottomZ + thickness),
|
new Vec3d(x1, bottomY, z1 + bottomZ),
|
||||||
new Vec3d(x2, bottomY, bottomZ + thickness),
|
new Vec3d(x2, bottomY, z1 + bottomZ),
|
||||||
new Vec3d(x2, topY, topZ + thickness),
|
new Vec3d(x2, topY, z1 + topZ),
|
||||||
new Vec3d(x1, topY, topZ + thickness),
|
new Vec3d(x1, topY, z1 + topZ),
|
||||||
0f, 0f, 1f, 1f,
|
backU1, backV2 - (backPartV * i),
|
||||||
light,
|
backU2, backV2 - (backPartV * (i + 1)),
|
||||||
overlay,
|
light, overlay,
|
||||||
0f, 0f, 1f,
|
0.0f, 0.0f, 1.0f, false);
|
||||||
false);
|
|
||||||
|
// LEFT
|
||||||
|
this.renderCapeQuad(
|
||||||
|
vertexConsumer, matrixStack,
|
||||||
|
new Vec3d(x2, bottomY, z1 + bottomZ),
|
||||||
|
new Vec3d(x2, bottomY, z2 + bottomZ),
|
||||||
|
new Vec3d(x2, topY, z2 + topZ),
|
||||||
|
new Vec3d(x2, topY, z1 + topZ),
|
||||||
|
leftU1, leftV2 - (leftPartV * i),
|
||||||
|
leftU2, leftV2 - (leftPartV * (i + 1)),
|
||||||
|
light, overlay,
|
||||||
|
1.0f, 0.0f, 0.0f, false);
|
||||||
|
|
||||||
|
// RIGHT
|
||||||
|
this.renderCapeQuad(
|
||||||
|
vertexConsumer, matrixStack,
|
||||||
|
new Vec3d(x1, bottomY, z2 + bottomZ),
|
||||||
|
new Vec3d(x1, bottomY, z1 + bottomZ),
|
||||||
|
new Vec3d(x1, topY, z1 + topZ),
|
||||||
|
new Vec3d(x1, topY, z2 + topZ),
|
||||||
|
rightU1, rightV2 - (rightPartV * i),
|
||||||
|
rightU2, rightV2 - (rightPartV * (i + 1)),
|
||||||
|
light, overlay,
|
||||||
|
-1.0f, 0.0f, 0.0f, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
matrices.pop();
|
// TOP FACE
|
||||||
|
this.renderCapeQuad(
|
||||||
|
vertexConsumer, matrixStack,
|
||||||
|
new Vec3d(x2, accumulatedY, z2 + accumulatedZ),
|
||||||
|
new Vec3d(x1, accumulatedY, z2 + accumulatedZ),
|
||||||
|
new Vec3d(x1, accumulatedY, z1 + accumulatedZ),
|
||||||
|
new Vec3d(x2, accumulatedY, z1 + accumulatedZ),
|
||||||
|
topU1, topV1, topU2, topV2,
|
||||||
|
light, overlay,
|
||||||
|
0.0f, 1.0f, 0.0f, true);
|
||||||
|
|
||||||
|
// BOTTOM FACE (last segment bottom)
|
||||||
|
this.renderCapeQuad(
|
||||||
|
vertexConsumer, matrixStack,
|
||||||
|
new Vec3d(x2, 0.0f, z2),
|
||||||
|
new Vec3d(x1, 0.0f, z2),
|
||||||
|
new Vec3d(x1, 0.0f, z1),
|
||||||
|
new Vec3d(x2, 0.0f, z1),
|
||||||
|
bottomU1, bottomV1, bottomU2, bottomV2,
|
||||||
|
light, overlay,
|
||||||
|
0.0f, 0.0f, 1.0f, false);
|
||||||
|
|
||||||
|
matrixStack.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public void render(MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int light,
|
||||||
public void render(
|
PlayerEntityRenderState playerEntityRenderState, float f, float g) {
|
||||||
MatrixStack matrices,
|
if (playerEntityRenderState.invisible || !playerEntityRenderState.capeVisible
|
||||||
VertexConsumerProvider providers,
|
|| playerEntityRenderState.skinTextures.capeTexture() != null) {
|
||||||
int light,
|
|
||||||
PlayerEntityRenderState state,
|
|
||||||
float f,
|
|
||||||
float g) {
|
|
||||||
if (state.invisible || !state.capeVisible || state.skinTextures.capeTexture() != null) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SaturnPlayer player = SaturnPlayer.get(state.name);
|
SaturnPlayer player = SaturnPlayer.get(playerEntityRenderState.name);
|
||||||
if (player == null)
|
|
||||||
|
if (player == null) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Identifier cape = Cloaks.getCurrentCloakTexture(player.uuid);
|
Identifier customCape = Cloaks.getCurrentCloakTexture(player.uuid);
|
||||||
if (cape == null)
|
if (customCape == null || this.hasCustomModelForLayer(playerEntityRenderState.equippedChestStack,
|
||||||
|
LayerType.WINGS)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
VertexConsumer consumer = providers.getBuffer(RenderLayer.getEntityTranslucent(cape));
|
int minBrightness = 7;
|
||||||
|
int blockLight = (light >> 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(
|
float base = Math.min(currentVelocity, 1.0f);
|
||||||
matrices,
|
|
||||||
consumer,
|
for (int i = 0; i < PARTS; i++) {
|
||||||
state,
|
float falloff = i / (float) (PARTS - 1);
|
||||||
light,
|
segmentValues[i] = base * falloff;
|
||||||
OverlayTexture.DEFAULT_UV);
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user