2025-11-24 22:52:51 +03:00

375 lines
14 KiB
Java

/*
* Decompiled with CFR 0.152.
*
* Could not load the following classes:
* org.joml.Matrix3f
* org.joml.Matrix4f
* org.joml.Quaternionf
* org.joml.Quaternionfc
* org.joml.Vector3f
* org.joml.Vector3fc
* org.jspecify.annotations.Nullable
*/
package net.minecraft.client.model.geom;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.Function;
import net.minecraft.client.model.geom.PartPose;
import net.minecraft.core.Direction;
import net.minecraft.util.RandomSource;
import org.joml.Matrix3f;
import org.joml.Matrix4f;
import org.joml.Quaternionf;
import org.joml.Quaternionfc;
import org.joml.Vector3f;
import org.joml.Vector3fc;
import org.jspecify.annotations.Nullable;
public final class ModelPart {
public static final float DEFAULT_SCALE = 1.0f;
public float x;
public float y;
public float z;
public float xRot;
public float yRot;
public float zRot;
public float xScale = 1.0f;
public float yScale = 1.0f;
public float zScale = 1.0f;
public boolean visible = true;
public boolean skipDraw;
private final List<Cube> cubes;
private final Map<String, ModelPart> children;
private PartPose initialPose = PartPose.ZERO;
public ModelPart(List<Cube> cubes, Map<String, ModelPart> children) {
this.cubes = cubes;
this.children = children;
}
public PartPose storePose() {
return PartPose.offsetAndRotation(this.x, this.y, this.z, this.xRot, this.yRot, this.zRot);
}
public PartPose getInitialPose() {
return this.initialPose;
}
public void setInitialPose(PartPose initialPose) {
this.initialPose = initialPose;
}
public void resetPose() {
this.loadPose(this.initialPose);
}
public void loadPose(PartPose pose) {
this.x = pose.x();
this.y = pose.y();
this.z = pose.z();
this.xRot = pose.xRot();
this.yRot = pose.yRot();
this.zRot = pose.zRot();
this.xScale = pose.xScale();
this.yScale = pose.yScale();
this.zScale = pose.zScale();
}
public boolean hasChild(String name) {
return this.children.containsKey(name);
}
public ModelPart getChild(String name) {
ModelPart result = this.children.get(name);
if (result == null) {
throw new NoSuchElementException("Can't find part " + name);
}
return result;
}
public void setPos(float x, float y, float z) {
this.x = x;
this.y = y;
this.z = z;
}
public void setRotation(float xRot, float yRot, float zRot) {
this.xRot = xRot;
this.yRot = yRot;
this.zRot = zRot;
}
public void render(PoseStack poseStack, VertexConsumer buffer, int lightCoords, int overlayCoords) {
this.render(poseStack, buffer, lightCoords, overlayCoords, -1);
}
public void render(PoseStack poseStack, VertexConsumer buffer, int lightCoords, int overlayCoords, int color) {
if (!this.visible) {
return;
}
if (this.cubes.isEmpty() && this.children.isEmpty()) {
return;
}
poseStack.pushPose();
this.translateAndRotate(poseStack);
if (!this.skipDraw) {
this.compile(poseStack.last(), buffer, lightCoords, overlayCoords, color);
}
for (ModelPart child : this.children.values()) {
child.render(poseStack, buffer, lightCoords, overlayCoords, color);
}
poseStack.popPose();
}
public void rotateBy(Quaternionf rotation) {
Matrix3f oldRotation = new Matrix3f().rotationZYX(this.zRot, this.yRot, this.xRot);
Matrix3f newRotation = oldRotation.rotate((Quaternionfc)rotation);
Vector3f newAngles = newRotation.getEulerAnglesZYX(new Vector3f());
this.setRotation(newAngles.x, newAngles.y, newAngles.z);
}
public void getExtentsForGui(PoseStack poseStack, Set<Vector3f> output) {
this.visit(poseStack, (pose, partPath, cubeIndex, cube) -> {
for (Polygon polygon : cube.polygons) {
for (Vertex vertex : polygon.vertices()) {
float x = vertex.worldX();
float y = vertex.worldY();
float z = vertex.worldZ();
Vector3f pos = pose.pose().transformPosition(x, y, z, new Vector3f());
output.add(pos);
}
}
});
}
public void visit(PoseStack poseStack, Visitor visitor) {
this.visit(poseStack, visitor, "");
}
private void visit(PoseStack poseStack, Visitor visitor, String path) {
if (this.cubes.isEmpty() && this.children.isEmpty()) {
return;
}
poseStack.pushPose();
this.translateAndRotate(poseStack);
PoseStack.Pose pose = poseStack.last();
for (int i = 0; i < this.cubes.size(); ++i) {
visitor.visit(pose, path, i, this.cubes.get(i));
}
String childPath = path + "/";
this.children.forEach((name, child) -> child.visit(poseStack, visitor, childPath + name));
poseStack.popPose();
}
public void translateAndRotate(PoseStack poseStack) {
poseStack.translate(this.x / 16.0f, this.y / 16.0f, this.z / 16.0f);
if (this.xRot != 0.0f || this.yRot != 0.0f || this.zRot != 0.0f) {
poseStack.mulPose((Quaternionfc)new Quaternionf().rotationZYX(this.zRot, this.yRot, this.xRot));
}
if (this.xScale != 1.0f || this.yScale != 1.0f || this.zScale != 1.0f) {
poseStack.scale(this.xScale, this.yScale, this.zScale);
}
}
private void compile(PoseStack.Pose pose, VertexConsumer builder, int lightCoords, int overlayCoords, int color) {
for (Cube cube : this.cubes) {
cube.compile(pose, builder, lightCoords, overlayCoords, color);
}
}
public Cube getRandomCube(RandomSource random) {
return this.cubes.get(random.nextInt(this.cubes.size()));
}
public boolean isEmpty() {
return this.cubes.isEmpty();
}
public void offsetPos(Vector3f offset) {
this.x += offset.x();
this.y += offset.y();
this.z += offset.z();
}
public void offsetRotation(Vector3f offset) {
this.xRot += offset.x();
this.yRot += offset.y();
this.zRot += offset.z();
}
public void offsetScale(Vector3f offset) {
this.xScale += offset.x();
this.yScale += offset.y();
this.zScale += offset.z();
}
public List<ModelPart> getAllParts() {
ArrayList<ModelPart> allParts = new ArrayList<ModelPart>();
allParts.add(this);
this.addAllChildren((name, part) -> allParts.add((ModelPart)part));
return List.copyOf(allParts);
}
public Function<String, @Nullable ModelPart> createPartLookup() {
HashMap<String, ModelPart> parts = new HashMap<String, ModelPart>();
parts.put("root", this);
this.addAllChildren(parts::putIfAbsent);
return parts::get;
}
private void addAllChildren(BiConsumer<String, ModelPart> output) {
for (Map.Entry<String, ModelPart> entry : this.children.entrySet()) {
output.accept(entry.getKey(), entry.getValue());
}
for (ModelPart part : this.children.values()) {
part.addAllChildren(output);
}
}
@FunctionalInterface
public static interface Visitor {
public void visit(PoseStack.Pose var1, String var2, int var3, Cube var4);
}
public static class Cube {
public final Polygon[] polygons;
public final float minX;
public final float minY;
public final float minZ;
public final float maxX;
public final float maxY;
public final float maxZ;
public Cube(int xTexOffs, int yTexOffs, float minX, float minY, float minZ, float width, float height, float depth, float growX, float growY, float growZ, boolean mirror, float xTexSize, float yTexSize, Set<Direction> visibleFaces) {
this.minX = minX;
this.minY = minY;
this.minZ = minZ;
this.maxX = minX + width;
this.maxY = minY + height;
this.maxZ = minZ + depth;
this.polygons = new Polygon[visibleFaces.size()];
float maxX = minX + width;
float maxY = minY + height;
float maxZ = minZ + depth;
minX -= growX;
minY -= growY;
minZ -= growZ;
maxX += growX;
maxY += growY;
maxZ += growZ;
if (mirror) {
float tmp = maxX;
maxX = minX;
minX = tmp;
}
Vertex t0 = new Vertex(minX, minY, minZ, 0.0f, 0.0f);
Vertex t1 = new Vertex(maxX, minY, minZ, 0.0f, 8.0f);
Vertex t2 = new Vertex(maxX, maxY, minZ, 8.0f, 8.0f);
Vertex t3 = new Vertex(minX, maxY, minZ, 8.0f, 0.0f);
Vertex l0 = new Vertex(minX, minY, maxZ, 0.0f, 0.0f);
Vertex l1 = new Vertex(maxX, minY, maxZ, 0.0f, 8.0f);
Vertex l2 = new Vertex(maxX, maxY, maxZ, 8.0f, 8.0f);
Vertex l3 = new Vertex(minX, maxY, maxZ, 8.0f, 0.0f);
float u0 = xTexOffs;
float u1 = (float)xTexOffs + depth;
float u2 = (float)xTexOffs + depth + width;
float u22 = (float)xTexOffs + depth + width + width;
float u3 = (float)xTexOffs + depth + width + depth;
float u4 = (float)xTexOffs + depth + width + depth + width;
float v0 = yTexOffs;
float v1 = (float)yTexOffs + depth;
float v2 = (float)yTexOffs + depth + height;
int pos = 0;
if (visibleFaces.contains(Direction.DOWN)) {
this.polygons[pos++] = new Polygon(new Vertex[]{l1, l0, t0, t1}, u1, v0, u2, v1, xTexSize, yTexSize, mirror, Direction.DOWN);
}
if (visibleFaces.contains(Direction.UP)) {
this.polygons[pos++] = new Polygon(new Vertex[]{t2, t3, l3, l2}, u2, v1, u22, v0, xTexSize, yTexSize, mirror, Direction.UP);
}
if (visibleFaces.contains(Direction.WEST)) {
this.polygons[pos++] = new Polygon(new Vertex[]{t0, l0, l3, t3}, u0, v1, u1, v2, xTexSize, yTexSize, mirror, Direction.WEST);
}
if (visibleFaces.contains(Direction.NORTH)) {
this.polygons[pos++] = new Polygon(new Vertex[]{t1, t0, t3, t2}, u1, v1, u2, v2, xTexSize, yTexSize, mirror, Direction.NORTH);
}
if (visibleFaces.contains(Direction.EAST)) {
this.polygons[pos++] = new Polygon(new Vertex[]{l1, t1, t2, l2}, u2, v1, u3, v2, xTexSize, yTexSize, mirror, Direction.EAST);
}
if (visibleFaces.contains(Direction.SOUTH)) {
this.polygons[pos] = new Polygon(new Vertex[]{l0, l1, l2, l3}, u3, v1, u4, v2, xTexSize, yTexSize, mirror, Direction.SOUTH);
}
}
public void compile(PoseStack.Pose pose, VertexConsumer builder, int lightCoords, int overlayCoords, int color) {
Matrix4f matrix = pose.pose();
Vector3f scratchVector = new Vector3f();
for (Polygon polygon : this.polygons) {
Vector3f normal = pose.transformNormal(polygon.normal, scratchVector);
float nx = normal.x();
float ny = normal.y();
float nz = normal.z();
for (Vertex vertex : polygon.vertices) {
float x = vertex.worldX();
float y = vertex.worldY();
float z = vertex.worldZ();
Vector3f pos = matrix.transformPosition(x, y, z, scratchVector);
builder.addVertex(pos.x(), pos.y(), pos.z(), color, vertex.u, vertex.v, overlayCoords, lightCoords, nx, ny, nz);
}
}
}
}
public record Polygon(Vertex[] vertices, Vector3fc normal) {
public Polygon(Vertex[] vertices, float u0, float v0, float u1, float v1, float xTexSize, float yTexSize, boolean mirror, Direction facing) {
this(vertices, (mirror ? Polygon.mirrorFacing(facing) : facing).getUnitVec3f());
float us = 0.0f / xTexSize;
float vs = 0.0f / yTexSize;
vertices[0] = vertices[0].remap(u1 / xTexSize - us, v0 / yTexSize + vs);
vertices[1] = vertices[1].remap(u0 / xTexSize + us, v0 / yTexSize + vs);
vertices[2] = vertices[2].remap(u0 / xTexSize + us, v1 / yTexSize - vs);
vertices[3] = vertices[3].remap(u1 / xTexSize - us, v1 / yTexSize - vs);
if (mirror) {
int length = vertices.length;
for (int i = 0; i < length / 2; ++i) {
Vertex tmp = vertices[i];
vertices[i] = vertices[length - 1 - i];
vertices[length - 1 - i] = tmp;
}
}
}
private static Direction mirrorFacing(Direction facing) {
return facing.getAxis() == Direction.Axis.X ? facing.getOpposite() : facing;
}
}
public record Vertex(float x, float y, float z, float u, float v) {
public static final float SCALE_FACTOR = 16.0f;
public Vertex remap(float u, float v) {
return new Vertex(this.x, this.y, this.z, u, v);
}
public float worldX() {
return this.x / 16.0f;
}
public float worldY() {
return this.y / 16.0f;
}
public float worldZ() {
return this.z / 16.0f;
}
}
}