minecraft-src/net/minecraft/client/gui/render/state/GuiRenderState.java
2025-09-18 12:27:44 +00:00

338 lines
9.3 KiB
Java

package net.minecraft.client.gui.render.state;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.gui.navigation.ScreenRectangle;
import net.minecraft.client.gui.render.state.pip.PictureInPictureRenderState;
import org.apache.commons.lang3.mutable.MutableInt;
import org.jetbrains.annotations.Nullable;
@Environment(EnvType.CLIENT)
public class GuiRenderState {
private static final int DEBUG_RECTANGLE_COLOR = 2000962815;
private final List<GuiRenderState.Node> strata = new ArrayList();
private int firstStratumAfterBlur = Integer.MAX_VALUE;
private GuiRenderState.Node current;
private final Set<Object> itemModelIdentities = new HashSet();
@Nullable
private ScreenRectangle lastElementBounds;
public GuiRenderState() {
this.nextStratum();
}
public void nextStratum() {
this.current = new GuiRenderState.Node(null);
this.strata.add(this.current);
}
public void blurBeforeThisStratum() {
if (this.firstStratumAfterBlur != Integer.MAX_VALUE) {
throw new IllegalStateException("Can only blur once per frame");
} else {
this.firstStratumAfterBlur = this.strata.size() - 1;
}
}
public void up() {
if (this.current.up == null) {
this.current.up = new GuiRenderState.Node(this.current);
}
this.current = this.current.up;
}
public void down() {
if (this.current.down == null) {
this.current.down = new GuiRenderState.Node(this.current);
}
this.current = this.current.down;
}
public void submitItem(GuiItemRenderState renderState) {
if (this.findAppropriateNode(renderState)) {
this.itemModelIdentities.add(renderState.itemStackRenderState().getModelIdentity());
this.current.submitItem(renderState);
this.sumbitDebugRectangleIfEnabled(renderState.bounds());
}
}
public void submitText(GuiTextRenderState renderState) {
if (this.findAppropriateNode(renderState)) {
this.current.submitText(renderState);
this.sumbitDebugRectangleIfEnabled(renderState.bounds());
}
}
public void submitPicturesInPictureState(PictureInPictureRenderState renderState) {
if (this.findAppropriateNode(renderState)) {
this.current.submitPicturesInPictureState(renderState);
this.sumbitDebugRectangleIfEnabled(renderState.bounds());
}
}
public void submitGuiElement(GuiElementRenderState renderState) {
if (this.findAppropriateNode(renderState)) {
this.current.submitGuiElement(renderState);
this.sumbitDebugRectangleIfEnabled(renderState.bounds());
}
}
private void sumbitDebugRectangleIfEnabled(@Nullable ScreenRectangle debugRectangle) {
}
private boolean findAppropriateNode(ScreenArea screenArea) {
ScreenRectangle screenRectangle = screenArea.bounds();
if (screenRectangle == null) {
return false;
} else {
if (this.lastElementBounds != null && this.lastElementBounds.encompasses(screenRectangle)) {
this.up();
} else {
this.navigateToAboveHighestElementWithIntersectingBounds(screenRectangle);
}
this.lastElementBounds = screenRectangle;
return true;
}
}
private void navigateToAboveHighestElementWithIntersectingBounds(ScreenRectangle rectangle) {
GuiRenderState.Node node = (GuiRenderState.Node)this.strata.getLast();
while (node.up != null) {
node = node.up;
}
boolean bl = false;
while (!bl) {
bl = this.hasIntersection(rectangle, node.elementStates)
|| this.hasIntersection(rectangle, node.itemStates)
|| this.hasIntersection(rectangle, node.textStates)
|| this.hasIntersection(rectangle, node.picturesInPictureStates);
if (node.parent == null) {
break;
}
if (!bl) {
node = node.parent;
}
}
this.current = node;
if (bl) {
this.up();
}
}
private boolean hasIntersection(ScreenRectangle rectangle, @Nullable List<? extends ScreenArea> screenAreas) {
if (screenAreas != null) {
for (ScreenArea screenArea : screenAreas) {
ScreenRectangle screenRectangle = screenArea.bounds();
if (screenRectangle != null && screenRectangle.intersects(rectangle)) {
return true;
}
}
}
return false;
}
public void submitBlitToCurrentLayer(BlitRenderState renderState) {
this.current.submitGuiElement(renderState);
}
public void submitGlyphToCurrentLayer(GuiElementRenderState renderState) {
this.current.submitGlyph(renderState);
}
public Set<Object> getItemModelIdentities() {
return this.itemModelIdentities;
}
public void forEachElement(GuiRenderState.LayeredElementConsumer action, GuiRenderState.TraverseRange traverseRange) {
MutableInt mutableInt = new MutableInt(0);
this.traverse(node -> {
if (node.elementStates != null || node.glyphStates != null) {
int i = mutableInt.incrementAndGet();
if (node.elementStates != null) {
for (GuiElementRenderState guiElementRenderState : node.elementStates) {
action.accept(guiElementRenderState, i);
}
}
if (node.glyphStates != null) {
for (GuiElementRenderState guiElementRenderState : node.glyphStates) {
action.accept(guiElementRenderState, i);
}
}
}
}, traverseRange);
}
public void forEachItem(Consumer<GuiItemRenderState> action) {
GuiRenderState.Node node = this.current;
this.traverse(nodex -> {
if (nodex.itemStates != null) {
this.current = nodex;
for (GuiItemRenderState guiItemRenderState : nodex.itemStates) {
action.accept(guiItemRenderState);
}
}
}, GuiRenderState.TraverseRange.ALL);
this.current = node;
}
public void forEachText(Consumer<GuiTextRenderState> action) {
GuiRenderState.Node node = this.current;
this.traverse(nodex -> {
if (nodex.textStates != null) {
for (GuiTextRenderState guiTextRenderState : nodex.textStates) {
this.current = nodex;
action.accept(guiTextRenderState);
}
}
}, GuiRenderState.TraverseRange.ALL);
this.current = node;
}
public void forEachPictureInPicture(Consumer<PictureInPictureRenderState> action) {
GuiRenderState.Node node = this.current;
this.traverse(nodex -> {
if (nodex.picturesInPictureStates != null) {
this.current = nodex;
for (PictureInPictureRenderState pictureInPictureRenderState : nodex.picturesInPictureStates) {
action.accept(pictureInPictureRenderState);
}
}
}, GuiRenderState.TraverseRange.ALL);
this.current = node;
}
public void sortElements(Comparator<GuiElementRenderState> comparator) {
this.traverse(node -> {
if (node.elementStates != null) {
node.elementStates.sort(comparator);
}
}, GuiRenderState.TraverseRange.ALL);
}
private void traverse(Consumer<GuiRenderState.Node> action, GuiRenderState.TraverseRange traverseRange) {
int i = 0;
int j = this.strata.size();
if (traverseRange == GuiRenderState.TraverseRange.BEFORE_BLUR) {
j = Math.min(this.firstStratumAfterBlur, this.strata.size());
} else if (traverseRange == GuiRenderState.TraverseRange.AFTER_BLUR) {
i = this.firstStratumAfterBlur;
}
for (int k = i; k < j; k++) {
GuiRenderState.Node node = (GuiRenderState.Node)this.strata.get(k);
this.traverse(node, action);
}
}
private void traverse(GuiRenderState.Node node, Consumer<GuiRenderState.Node> action) {
if (node.down != null) {
this.traverse(node.down, action);
}
action.accept(node);
if (node.up != null) {
this.traverse(node.up, action);
}
}
public void reset() {
this.itemModelIdentities.clear();
this.strata.clear();
this.firstStratumAfterBlur = Integer.MAX_VALUE;
this.nextStratum();
}
@Environment(EnvType.CLIENT)
public interface LayeredElementConsumer {
void accept(GuiElementRenderState guiElementRenderState, int i);
}
@Environment(EnvType.CLIENT)
static class Node {
@Nullable
public final GuiRenderState.Node parent;
@Nullable
public GuiRenderState.Node up;
@Nullable
public GuiRenderState.Node down;
@Nullable
public List<GuiElementRenderState> elementStates;
@Nullable
public List<GuiElementRenderState> glyphStates;
@Nullable
public List<GuiItemRenderState> itemStates;
@Nullable
public List<GuiTextRenderState> textStates;
@Nullable
public List<PictureInPictureRenderState> picturesInPictureStates;
Node(@Nullable GuiRenderState.Node parent) {
this.parent = parent;
}
public void submitItem(GuiItemRenderState renderState) {
if (this.itemStates == null) {
this.itemStates = new ArrayList();
}
this.itemStates.add(renderState);
}
public void submitText(GuiTextRenderState renderState) {
if (this.textStates == null) {
this.textStates = new ArrayList();
}
this.textStates.add(renderState);
}
public void submitPicturesInPictureState(PictureInPictureRenderState renderState) {
if (this.picturesInPictureStates == null) {
this.picturesInPictureStates = new ArrayList();
}
this.picturesInPictureStates.add(renderState);
}
public void submitGuiElement(GuiElementRenderState renderState) {
if (this.elementStates == null) {
this.elementStates = new ArrayList();
}
this.elementStates.add(renderState);
}
public void submitGlyph(GuiElementRenderState renderState) {
if (this.glyphStates == null) {
this.glyphStates = new ArrayList();
}
this.glyphStates.add(renderState);
}
}
@Environment(EnvType.CLIENT)
public static enum TraverseRange {
ALL,
BEFORE_BLUR,
AFTER_BLUR;
}
}