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

260 lines
11 KiB
Java

/*
* Decompiled with CFR 0.152.
*
* Could not load the following classes:
* org.jspecify.annotations.Nullable
*/
package net.minecraft.client.renderer;
import net.minecraft.client.renderer.chunk.SectionRenderDispatcher;
import net.minecraft.client.renderer.culling.Frustum;
import net.minecraft.core.BlockPos;
import net.minecraft.core.SectionPos;
import net.minecraft.util.Mth;
import net.minecraft.world.level.levelgen.structure.BoundingBox;
import net.minecraft.world.phys.AABB;
import org.jspecify.annotations.Nullable;
public class Octree {
private final Branch root;
private final BlockPos cameraSectionCenter;
public Octree(SectionPos cameraSection, int renderDistance, int sectionsPerChunk, int minBlockY) {
int visibleAreaDiameterInSections = renderDistance * 2 + 1;
int boundingBoxSizeInSections = Mth.smallestEncompassingPowerOfTwo(visibleAreaDiameterInSections);
int distanceToBBEdgeInBlocks = renderDistance * 16;
BlockPos cameraSectionOrigin = cameraSection.origin();
this.cameraSectionCenter = cameraSection.center();
int minX = cameraSectionOrigin.getX() - distanceToBBEdgeInBlocks;
int maxX = minX + boundingBoxSizeInSections * 16 - 1;
int minY = boundingBoxSizeInSections >= sectionsPerChunk ? minBlockY : cameraSectionOrigin.getY() - distanceToBBEdgeInBlocks;
int maxY = minY + boundingBoxSizeInSections * 16 - 1;
int minZ = cameraSectionOrigin.getZ() - distanceToBBEdgeInBlocks;
int maxZ = minZ + boundingBoxSizeInSections * 16 - 1;
this.root = new Branch(new BoundingBox(minX, minY, minZ, maxX, maxY, maxZ));
}
public boolean add(SectionRenderDispatcher.RenderSection section) {
return this.root.add(section);
}
public void visitNodes(OctreeVisitor visitor, Frustum frustum, int closeDistance) {
this.root.visitNodes(visitor, false, frustum, 0, closeDistance, true);
}
private boolean isClose(double minX, double minY, double minZ, double maxX, double maxY, double maxZ, int closeDistance) {
int cameraX = this.cameraSectionCenter.getX();
int cameraY = this.cameraSectionCenter.getY();
int cameraZ = this.cameraSectionCenter.getZ();
return (double)cameraX > minX - (double)closeDistance && (double)cameraX < maxX + (double)closeDistance && (double)cameraY > minY - (double)closeDistance && (double)cameraY < maxY + (double)closeDistance && (double)cameraZ > minZ - (double)closeDistance && (double)cameraZ < maxZ + (double)closeDistance;
}
private class Branch
implements Node {
private final @Nullable Node[] nodes = new Node[8];
private final BoundingBox boundingBox;
private final int bbCenterX;
private final int bbCenterY;
private final int bbCenterZ;
private final AxisSorting sorting;
private final boolean cameraXDiffNegative;
private final boolean cameraYDiffNegative;
private final boolean cameraZDiffNegative;
public Branch(BoundingBox boundingBox) {
this.boundingBox = boundingBox;
this.bbCenterX = this.boundingBox.minX() + this.boundingBox.getXSpan() / 2;
this.bbCenterY = this.boundingBox.minY() + this.boundingBox.getYSpan() / 2;
this.bbCenterZ = this.boundingBox.minZ() + this.boundingBox.getZSpan() / 2;
int cameraXDiff = Octree.this.cameraSectionCenter.getX() - this.bbCenterX;
int cameraYDiff = Octree.this.cameraSectionCenter.getY() - this.bbCenterY;
int cameraZDiff = Octree.this.cameraSectionCenter.getZ() - this.bbCenterZ;
this.sorting = AxisSorting.getAxisSorting(Math.abs(cameraXDiff), Math.abs(cameraYDiff), Math.abs(cameraZDiff));
this.cameraXDiffNegative = cameraXDiff < 0;
this.cameraYDiffNegative = cameraYDiff < 0;
this.cameraZDiffNegative = cameraZDiff < 0;
}
public boolean add(SectionRenderDispatcher.RenderSection section) {
long sectionNode = section.getSectionNode();
boolean sectionXDiffNegative = SectionPos.sectionToBlockCoord(SectionPos.x(sectionNode)) - this.bbCenterX < 0;
boolean sectionYDiffNegative = SectionPos.sectionToBlockCoord(SectionPos.y(sectionNode)) - this.bbCenterY < 0;
boolean sectionZDiffNegative = SectionPos.sectionToBlockCoord(SectionPos.z(sectionNode)) - this.bbCenterZ < 0;
boolean xDiffsOppositeSides = sectionXDiffNegative != this.cameraXDiffNegative;
boolean yDiffsOppositeSides = sectionYDiffNegative != this.cameraYDiffNegative;
boolean zDiffsOppositeSides = sectionZDiffNegative != this.cameraZDiffNegative;
int nodeIndex = Branch.getNodeIndex(this.sorting, xDiffsOppositeSides, yDiffsOppositeSides, zDiffsOppositeSides);
if (this.areChildrenLeaves()) {
boolean alreadyExisted = this.nodes[nodeIndex] != null;
this.nodes[nodeIndex] = new Leaf(section);
return !alreadyExisted;
}
if (this.nodes[nodeIndex] != null) {
Branch branch = (Branch)this.nodes[nodeIndex];
return branch.add(section);
}
BoundingBox childBoundingBox = this.createChildBoundingBox(sectionXDiffNegative, sectionYDiffNegative, sectionZDiffNegative);
Branch branch = new Branch(childBoundingBox);
this.nodes[nodeIndex] = branch;
return branch.add(section);
}
private static int getNodeIndex(AxisSorting sorting, boolean xDiffsOppositeSides, boolean yDiffsOppositeSides, boolean zDiffsOppositeSides) {
int index = 0;
if (xDiffsOppositeSides) {
index += sorting.xShift;
}
if (yDiffsOppositeSides) {
index += sorting.yShift;
}
if (zDiffsOppositeSides) {
index += sorting.zShift;
}
return index;
}
private boolean areChildrenLeaves() {
return this.boundingBox.getXSpan() == 32;
}
private BoundingBox createChildBoundingBox(boolean sectionXDiffNegative, boolean sectionYDiffNegative, boolean sectionZDiffNegative) {
int maxZ;
int minZ;
int maxY;
int minY;
int maxX;
int minX;
if (sectionXDiffNegative) {
minX = this.boundingBox.minX();
maxX = this.bbCenterX - 1;
} else {
minX = this.bbCenterX;
maxX = this.boundingBox.maxX();
}
if (sectionYDiffNegative) {
minY = this.boundingBox.minY();
maxY = this.bbCenterY - 1;
} else {
minY = this.bbCenterY;
maxY = this.boundingBox.maxY();
}
if (sectionZDiffNegative) {
minZ = this.boundingBox.minZ();
maxZ = this.bbCenterZ - 1;
} else {
minZ = this.bbCenterZ;
maxZ = this.boundingBox.maxZ();
}
return new BoundingBox(minX, minY, minZ, maxX, maxY, maxZ);
}
@Override
public void visitNodes(OctreeVisitor visitor, boolean skipFrustumCheck, Frustum frustum, int depth, int closeDistance, boolean isClose) {
boolean isVisible = skipFrustumCheck;
if (!skipFrustumCheck) {
int checkResult = frustum.cubeInFrustum(this.boundingBox);
skipFrustumCheck = checkResult == -2;
boolean bl = isVisible = checkResult == -2 || checkResult == -1;
}
if (isVisible) {
isClose = isClose && Octree.this.isClose(this.boundingBox.minX(), this.boundingBox.minY(), this.boundingBox.minZ(), this.boundingBox.maxX(), this.boundingBox.maxY(), this.boundingBox.maxZ(), closeDistance);
visitor.visit(this, skipFrustumCheck, depth, isClose);
for (Node node : this.nodes) {
if (node == null) continue;
node.visitNodes(visitor, skipFrustumCheck, frustum, depth + 1, closeDistance, isClose);
}
}
}
@Override
public @Nullable SectionRenderDispatcher.RenderSection getSection() {
return null;
}
@Override
public AABB getAABB() {
return new AABB(this.boundingBox.minX(), this.boundingBox.minY(), this.boundingBox.minZ(), this.boundingBox.maxX() + 1, this.boundingBox.maxY() + 1, this.boundingBox.maxZ() + 1);
}
}
@FunctionalInterface
public static interface OctreeVisitor {
public void visit(Node var1, boolean var2, int var3, boolean var4);
}
private static enum AxisSorting {
XYZ(4, 2, 1),
XZY(4, 1, 2),
YXZ(2, 4, 1),
YZX(1, 4, 2),
ZXY(2, 1, 4),
ZYX(1, 2, 4);
private final int xShift;
private final int yShift;
private final int zShift;
private AxisSorting(int xShift, int yShift, int zShift) {
this.xShift = xShift;
this.yShift = yShift;
this.zShift = zShift;
}
public static AxisSorting getAxisSorting(int absXDiff, int absYDiff, int absZDiff) {
if (absXDiff > absYDiff && absXDiff > absZDiff) {
if (absYDiff > absZDiff) {
return XYZ;
}
return XZY;
}
if (absYDiff > absXDiff && absYDiff > absZDiff) {
if (absXDiff > absZDiff) {
return YXZ;
}
return YZX;
}
if (absXDiff > absYDiff) {
return ZXY;
}
return ZYX;
}
}
public static interface Node {
public void visitNodes(OctreeVisitor var1, boolean var2, Frustum var3, int var4, int var5, boolean var6);
public @Nullable SectionRenderDispatcher.RenderSection getSection();
public AABB getAABB();
}
private final class Leaf
implements Node {
private final SectionRenderDispatcher.RenderSection section;
private Leaf(SectionRenderDispatcher.RenderSection section) {
this.section = section;
}
@Override
public void visitNodes(OctreeVisitor visitor, boolean skipFrustumCheck, Frustum frustum, int depth, int closeDistance, boolean isClose) {
AABB boundingBox = this.section.getBoundingBox();
if (skipFrustumCheck || frustum.isVisible(this.getSection().getBoundingBox())) {
isClose = isClose && Octree.this.isClose(boundingBox.minX, boundingBox.minY, boundingBox.minZ, boundingBox.maxX, boundingBox.maxY, boundingBox.maxZ, closeDistance);
visitor.visit(this, skipFrustumCheck, depth, isClose);
}
}
@Override
public SectionRenderDispatcher.RenderSection getSection() {
return this.section;
}
@Override
public AABB getAABB() {
return this.section.getBoundingBox();
}
}
}