package net.minecraft.client.renderer.block.model; import com.google.common.annotations.VisibleForTesting; import com.mojang.math.MatrixUtil; import com.mojang.math.Quadrant; import com.mojang.math.Transformation; import java.util.function.Consumer; import javax.annotation.Nullable; import net.minecraft.client.renderer.FaceInfo; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.resources.model.ModelState; import net.minecraft.core.Direction; import net.minecraft.util.Mth; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import org.joml.Matrix4f; import org.joml.Matrix4fc; import org.joml.Quaternionf; import org.joml.Vector3f; import org.joml.Vector3fc; import org.joml.Vector4f; @OnlyIn(Dist.CLIENT) public class FaceBakery { public static final int VERTEX_INT_SIZE = 8; private static final float RESCALE_22_5 = 1.0F / (float)Math.cos((float) (Math.PI / 8)) - 1.0F; private static final float RESCALE_45 = 1.0F / (float)Math.cos((float) (Math.PI / 4)) - 1.0F; public static final int VERTEX_COUNT = 4; private static final int COLOR_INDEX = 3; public static final int UV_INDEX = 4; @VisibleForTesting static BlockElementFace.UVs defaultFaceUV(Vector3fc p_393926_, Vector3fc p_395023_, Direction p_393336_) { return switch (p_393336_) { case DOWN -> new BlockElementFace.UVs(p_393926_.x(), 16.0F - p_395023_.z(), p_395023_.x(), 16.0F - p_393926_.z()); case UP -> new BlockElementFace.UVs(p_393926_.x(), p_393926_.z(), p_395023_.x(), p_395023_.z()); case NORTH -> new BlockElementFace.UVs(16.0F - p_395023_.x(), 16.0F - p_395023_.y(), 16.0F - p_393926_.x(), 16.0F - p_393926_.y()); case SOUTH -> new BlockElementFace.UVs(p_393926_.x(), 16.0F - p_395023_.y(), p_395023_.x(), 16.0F - p_393926_.y()); case WEST -> new BlockElementFace.UVs(p_393926_.z(), 16.0F - p_395023_.y(), p_395023_.z(), 16.0F - p_393926_.y()); case EAST -> new BlockElementFace.UVs(16.0F - p_395023_.z(), 16.0F - p_395023_.y(), 16.0F - p_393926_.z(), 16.0F - p_393926_.y()); }; } public static BakedQuad bakeQuad( Vector3fc p_393181_, Vector3fc p_395026_, BlockElementFace p_111603_, TextureAtlasSprite p_111604_, Direction p_111605_, ModelState p_111606_, @Nullable BlockElementRotation p_111607_, boolean p_111608_, int p_364904_ ) { BlockElementFace.UVs blockelementface$uvs = p_111603_.uvs(); if (blockelementface$uvs == null) { blockelementface$uvs = defaultFaceUV(p_393181_, p_395026_, p_111605_); } blockelementface$uvs = shrinkUVs(p_111604_, blockelementface$uvs); Matrix4fc matrix4fc = p_111606_.inverseFaceTransformation(p_111605_); int[] aint = makeVertices( blockelementface$uvs, p_111603_.rotation(), matrix4fc, p_111604_, p_111605_, setupShape(p_393181_, p_395026_), p_111606_.transformation(), p_111607_ ); Direction direction = calculateFacing(aint); if (p_111607_ == null) { recalculateWinding(aint, direction); } return new BakedQuad(aint, p_111603_.tintIndex(), direction, p_111604_, p_111608_, p_364904_); } private static BlockElementFace.UVs shrinkUVs(TextureAtlasSprite p_397002_, BlockElementFace.UVs p_394057_) { float f = p_394057_.minU(); float f1 = p_394057_.minV(); float f2 = p_394057_.maxU(); float f3 = p_394057_.maxV(); float f4 = p_397002_.uvShrinkRatio(); float f5 = (f + f + f2 + f2) / 4.0F; float f6 = (f1 + f1 + f3 + f3) / 4.0F; return new BlockElementFace.UVs(Mth.lerp(f4, f, f5), Mth.lerp(f4, f1, f6), Mth.lerp(f4, f2, f5), Mth.lerp(f4, f3, f6)); } private static int[] makeVertices( BlockElementFace.UVs p_391814_, Quadrant p_393719_, Matrix4fc p_397140_, TextureAtlasSprite p_111575_, Direction p_111576_, float[] p_111577_, Transformation p_111578_, @Nullable BlockElementRotation p_111579_ ) { FaceInfo faceinfo = FaceInfo.fromFacing(p_111576_); int[] aint = new int[32]; for (int i = 0; i < 4; i++) { bakeVertex(aint, i, faceinfo, p_391814_, p_393719_, p_397140_, p_111577_, p_111575_, p_111578_, p_111579_); } return aint; } private static float[] setupShape(Vector3fc p_393902_, Vector3fc p_394068_) { float[] afloat = new float[Direction.values().length]; afloat[FaceInfo.Constants.MIN_X] = p_393902_.x() / 16.0F; afloat[FaceInfo.Constants.MIN_Y] = p_393902_.y() / 16.0F; afloat[FaceInfo.Constants.MIN_Z] = p_393902_.z() / 16.0F; afloat[FaceInfo.Constants.MAX_X] = p_394068_.x() / 16.0F; afloat[FaceInfo.Constants.MAX_Y] = p_394068_.y() / 16.0F; afloat[FaceInfo.Constants.MAX_Z] = p_394068_.z() / 16.0F; return afloat; } private static void bakeVertex( int[] p_111621_, int p_111622_, FaceInfo p_394082_, BlockElementFace.UVs p_395065_, Quadrant p_392208_, Matrix4fc p_396750_, float[] p_111625_, TextureAtlasSprite p_111626_, Transformation p_111627_, @Nullable BlockElementRotation p_111628_ ) { FaceInfo.VertexInfo faceinfo$vertexinfo = p_394082_.getVertexInfo(p_111622_); Vector3f vector3f = new Vector3f( p_111625_[faceinfo$vertexinfo.xFace], p_111625_[faceinfo$vertexinfo.yFace], p_111625_[faceinfo$vertexinfo.zFace] ); applyElementRotation(vector3f, p_111628_); applyModelRotation(vector3f, p_111627_); float f = BlockElementFace.getU(p_395065_, p_392208_, p_111622_); float f1 = BlockElementFace.getV(p_395065_, p_392208_, p_111622_); float f2; float f3; if (MatrixUtil.isIdentity(p_396750_)) { f3 = f; f2 = f1; } else { Vector3f vector3f1 = p_396750_.transformPosition(new Vector3f(cornerToCenter(f), cornerToCenter(f1), 0.0F)); f3 = centerToCorner(vector3f1.x); f2 = centerToCorner(vector3f1.y); } fillVertex(p_111621_, p_111622_, vector3f, p_111626_, f3, f2); } private static float cornerToCenter(float p_393791_) { return p_393791_ - 0.5F; } private static float centerToCorner(float p_392923_) { return p_392923_ + 0.5F; } private static void fillVertex(int[] p_111615_, int p_111616_, Vector3f p_254291_, TextureAtlasSprite p_111618_, float p_393253_, float p_396335_) { int i = p_111616_ * 8; p_111615_[i] = Float.floatToRawIntBits(p_254291_.x()); p_111615_[i + 1] = Float.floatToRawIntBits(p_254291_.y()); p_111615_[i + 2] = Float.floatToRawIntBits(p_254291_.z()); p_111615_[i + 3] = -1; p_111615_[i + 4] = Float.floatToRawIntBits(p_111618_.getU(p_393253_)); p_111615_[i + 4 + 1] = Float.floatToRawIntBits(p_111618_.getV(p_396335_)); } private static void applyElementRotation(Vector3f p_254412_, @Nullable BlockElementRotation p_254150_) { if (p_254150_ != null) { Vector3f vector3f; Vector3f vector3f1; switch (p_254150_.axis()) { case X: vector3f = new Vector3f(1.0F, 0.0F, 0.0F); vector3f1 = new Vector3f(0.0F, 1.0F, 1.0F); break; case Y: vector3f = new Vector3f(0.0F, 1.0F, 0.0F); vector3f1 = new Vector3f(1.0F, 0.0F, 1.0F); break; case Z: vector3f = new Vector3f(0.0F, 0.0F, 1.0F); vector3f1 = new Vector3f(1.0F, 1.0F, 0.0F); break; default: throw new IllegalArgumentException("There are only 3 axes"); } Quaternionf quaternionf = new Quaternionf().rotationAxis(p_254150_.angle() * (float) (Math.PI / 180.0), vector3f); if (p_254150_.rescale()) { if (Math.abs(p_254150_.angle()) == 22.5F) { vector3f1.mul(RESCALE_22_5); } else { vector3f1.mul(RESCALE_45); } vector3f1.add(1.0F, 1.0F, 1.0F); } else { vector3f1.set(1.0F, 1.0F, 1.0F); } rotateVertexBy(p_254412_, new Vector3f(p_254150_.origin()), new Matrix4f().rotation(quaternionf), vector3f1); } } private static void applyModelRotation(Vector3f p_254561_, Transformation p_253793_) { if (p_253793_ != Transformation.identity()) { rotateVertexBy(p_254561_, new Vector3f(0.5F, 0.5F, 0.5F), p_253793_.getMatrix(), new Vector3f(1.0F, 1.0F, 1.0F)); } } private static void rotateVertexBy(Vector3f p_393378_, Vector3fc p_396712_, Matrix4fc p_394901_, Vector3fc p_395897_) { Vector4f vector4f = p_394901_.transform(new Vector4f(p_393378_.x() - p_396712_.x(), p_393378_.y() - p_396712_.y(), p_393378_.z() - p_396712_.z(), 1.0F)); vector4f.mul(new Vector4f(p_395897_, 1.0F)); p_393378_.set(vector4f.x() + p_396712_.x(), vector4f.y() + p_396712_.y(), vector4f.z() + p_396712_.z()); } private static Direction calculateFacing(int[] p_111613_) { Vector3f vector3f = vectorFromData(p_111613_, 0); Vector3f vector3f1 = vectorFromData(p_111613_, 8); Vector3f vector3f2 = vectorFromData(p_111613_, 16); Vector3f vector3f3 = new Vector3f(vector3f).sub(vector3f1); Vector3f vector3f4 = new Vector3f(vector3f2).sub(vector3f1); Vector3f vector3f5 = new Vector3f(vector3f4).cross(vector3f3).normalize(); if (!vector3f5.isFinite()) { return Direction.UP; } else { Direction direction = null; float f = 0.0F; for (Direction direction1 : Direction.values()) { float f1 = vector3f5.dot(direction1.getUnitVec3f()); if (f1 >= 0.0F && f1 > f) { f = f1; direction = direction1; } } return direction == null ? Direction.UP : direction; } } private static float xFromData(int[] p_393171_, int p_394995_) { return Float.intBitsToFloat(p_393171_[p_394995_]); } private static float yFromData(int[] p_396587_, int p_391994_) { return Float.intBitsToFloat(p_396587_[p_391994_ + 1]); } private static float zFromData(int[] p_392671_, int p_392811_) { return Float.intBitsToFloat(p_392671_[p_392811_ + 2]); } private static Vector3f vectorFromData(int[] p_391584_, int p_394245_) { return new Vector3f(xFromData(p_391584_, p_394245_), yFromData(p_391584_, p_394245_), zFromData(p_391584_, p_394245_)); } private static void recalculateWinding(int[] p_111631_, Direction p_111632_) { int[] aint = new int[p_111631_.length]; System.arraycopy(p_111631_, 0, aint, 0, p_111631_.length); float[] afloat = new float[Direction.values().length]; afloat[FaceInfo.Constants.MIN_X] = 999.0F; afloat[FaceInfo.Constants.MIN_Y] = 999.0F; afloat[FaceInfo.Constants.MIN_Z] = 999.0F; afloat[FaceInfo.Constants.MAX_X] = -999.0F; afloat[FaceInfo.Constants.MAX_Y] = -999.0F; afloat[FaceInfo.Constants.MAX_Z] = -999.0F; for (int i = 0; i < 4; i++) { int j = 8 * i; float f = xFromData(aint, j); float f1 = yFromData(aint, j); float f2 = zFromData(aint, j); if (f < afloat[FaceInfo.Constants.MIN_X]) { afloat[FaceInfo.Constants.MIN_X] = f; } if (f1 < afloat[FaceInfo.Constants.MIN_Y]) { afloat[FaceInfo.Constants.MIN_Y] = f1; } if (f2 < afloat[FaceInfo.Constants.MIN_Z]) { afloat[FaceInfo.Constants.MIN_Z] = f2; } if (f > afloat[FaceInfo.Constants.MAX_X]) { afloat[FaceInfo.Constants.MAX_X] = f; } if (f1 > afloat[FaceInfo.Constants.MAX_Y]) { afloat[FaceInfo.Constants.MAX_Y] = f1; } if (f2 > afloat[FaceInfo.Constants.MAX_Z]) { afloat[FaceInfo.Constants.MAX_Z] = f2; } } FaceInfo faceinfo = FaceInfo.fromFacing(p_111632_); for (int i1 = 0; i1 < 4; i1++) { int j1 = 8 * i1; FaceInfo.VertexInfo faceinfo$vertexinfo = faceinfo.getVertexInfo(i1); float f8 = afloat[faceinfo$vertexinfo.xFace]; float f3 = afloat[faceinfo$vertexinfo.yFace]; float f4 = afloat[faceinfo$vertexinfo.zFace]; p_111631_[j1] = Float.floatToRawIntBits(f8); p_111631_[j1 + 1] = Float.floatToRawIntBits(f3); p_111631_[j1 + 2] = Float.floatToRawIntBits(f4); for (int k = 0; k < 4; k++) { int l = 8 * k; float f5 = xFromData(aint, l); float f6 = yFromData(aint, l); float f7 = zFromData(aint, l); if (Mth.equal(f8, f5) && Mth.equal(f3, f6) && Mth.equal(f4, f7)) { p_111631_[j1 + 4] = aint[l + 4]; p_111631_[j1 + 4 + 1] = aint[l + 4 + 1]; } } } } public static void extractPositions(int[] p_394217_, Consumer p_393107_) { for (int i = 0; i < 4; i++) { p_393107_.accept(vectorFromData(p_394217_, 8 * i)); } } }