aboutsummaryrefslogtreecommitdiff
path: root/runtime/src/main/java
diff options
context:
space:
mode:
authorshedaniel <daniel@shedaniel.me>2022-02-09 20:17:34 +0800
committershedaniel <daniel@shedaniel.me>2022-02-09 20:17:34 +0800
commitcaa850ff55576c8aef92c28ab5dcf87a319f6e3a (patch)
tree4fbb17d0d7ee6c3d523ff5839288315e483accea /runtime/src/main/java
parent48ef9ff7f4b1be74006837b51a683d5e8b9bdc52 (diff)
downloadRoughlyEnoughItems-caa850ff55576c8aef92c28ab5dcf87a319f6e3a.tar.gz
RoughlyEnoughItems-caa850ff55576c8aef92c28ab5dcf87a319f6e3a.tar.bz2
RoughlyEnoughItems-caa850ff55576c8aef92c28ab5dcf87a319f6e3a.zip
Migrate to Cloth Config's ValueAnimator, and add option to cache entry renders
Diffstat (limited to 'runtime/src/main/java')
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/REIRuntimeImpl.java2
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/config/ConfigObjectImpl.java11
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringScreen.java28
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/ScreenOverlayImpl.java5
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/dragging/CurrentDraggingStack.java4
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/Menu.java6
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/entries/EntryStackSubsetsMenuEntry.java2
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/CompositeDisplayViewingScreen.java5
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/DefaultDisplayViewingScreen.java2
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/UncertainDisplayViewingScreen.java4
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/BatchedEntryRendererManager.java2
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/CachedEntryListRender.java176
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/EntryListWidget.java65
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/EntryStacksRegionWidget.java26
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/EntryWidget.java4
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/FavoritesListWidget.java18
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/TabWidget.java4
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/ArrowWidget.java4
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/BurningFireWidget.java4
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/ButtonWidget.java2
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/LabelWidget.java4
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/PanelWidget.java4
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/region/RealRegionEntry.java4
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/search/OverlaySearchField.java4
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/common/entry/AbstractEntryStack.java11
25 files changed, 311 insertions, 90 deletions
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/REIRuntimeImpl.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/REIRuntimeImpl.java
index 9351303cb..d5a6ddf94 100644
--- a/runtime/src/main/java/me/shedaniel/rei/impl/client/REIRuntimeImpl.java
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/REIRuntimeImpl.java
@@ -43,6 +43,7 @@ import me.shedaniel.rei.api.client.registry.screen.ScreenRegistry;
import me.shedaniel.rei.api.common.registry.ReloadStage;
import me.shedaniel.rei.impl.client.gui.ScreenOverlayImpl;
import me.shedaniel.rei.impl.client.gui.hints.HintProvider;
+import me.shedaniel.rei.impl.client.gui.widget.CachedEntryListRender;
import me.shedaniel.rei.impl.client.gui.widget.search.OverlaySearchField;
import me.shedaniel.rei.impl.client.search.argument.Argument;
import net.fabricmc.api.EnvType;
@@ -240,6 +241,7 @@ public class REIRuntimeImpl implements REIRuntime {
Argument.SEARCH_CACHE.clear();
getOverlay().ifPresent(ScreenOverlay::queueReloadOverlay);
lastDisplayScreen.clear();
+ CachedEntryListRender.refresh();
}
@Override
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/ConfigObjectImpl.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/config/ConfigObjectImpl.java
index 4fe37ff72..e79aecaa8 100644
--- a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/ConfigObjectImpl.java
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/config/ConfigObjectImpl.java
@@ -255,6 +255,15 @@ public class ConfigObjectImpl implements ConfigObject, ConfigData {
}
@Override
+ public boolean doesCacheEntryRendering() {
+ return advanced.miscellaneous.cachingFastEntryRendering;
+ }
+
+ public void setDoesCacheEntryRendering(boolean doesCacheEntryRendering) {
+ advanced.miscellaneous.cachingFastEntryRendering = doesCacheEntryRendering;
+ }
+
+ @Override
public boolean doDebugRenderTimeRequired() {
return advanced.layout.debugRenderTimeRequired;
}
@@ -622,6 +631,8 @@ public class ConfigObjectImpl implements ConfigObject, ConfigData {
@Comment("Declares whether arrows in containers should be clickable.") private boolean clickableRecipeArrows = true;
private boolean registerRecipesInAnotherThread = true;
private boolean newFastEntryRendering = true;
+ @ConfigEntry.Gui.PrefixText
+ private boolean cachingFastEntryRendering = false;
}
public static class Filtering {
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringScreen.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringScreen.java
index 2ea8b127a..5fcd5790e 100644
--- a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringScreen.java
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringScreen.java
@@ -30,8 +30,7 @@ import com.mojang.blaze3d.vertex.*;
import com.mojang.math.Matrix4f;
import me.shedaniel.clothconfig2.ClothConfigInitializer;
import me.shedaniel.clothconfig2.api.ScissorsHandler;
-import me.shedaniel.clothconfig2.api.ScrollingContainer;
-import me.shedaniel.clothconfig2.gui.widget.DynamicNewSmoothScrollingEntryListWidget;
+import me.shedaniel.clothconfig2.api.scroll.ScrollingContainer;
import me.shedaniel.math.Point;
import me.shedaniel.math.Rectangle;
import me.shedaniel.math.impl.PointHelper;
@@ -80,7 +79,7 @@ public class FilteringScreen extends Screen {
}
@Override
- public int getScrollBarX() {
+ public int getScrollBarX(int maxX) {
return width - 7;
}
};
@@ -130,7 +129,7 @@ public class FilteringScreen extends Screen {
for (int i = 0; i < entryStacks.size(); i++) {
EntryStack<?> stack = entryStacks.get(i);
EntryListEntry entry = entries.get(i);
- entry.getBounds().y = (int) (entry.backupY - scrolling.scrollAmount);
+ entry.getBounds().y = entry.backupY - scrolling.scrollAmountInt();
if (entry.isSelected() && !entry.isFiltered()) {
filteringEntry.configFiltered.add(stack);
filteringEntry.edited = true;
@@ -145,7 +144,7 @@ public class FilteringScreen extends Screen {
for (int i = 0; i < entryStacks.size(); i++) {
EntryStack<?> stack = entryStacks.get(i);
EntryListEntry entry = entries.get(i);
- entry.getBounds().y = (int) (entry.backupY - scrolling.scrollAmount);
+ entry.getBounds().y = entry.backupY - scrolling.scrollAmountInt();
if (entry.isSelected() && filteringEntry.configFiltered.remove(stack)) {
filteringEntry.edited = true;
entry.dirty = true;
@@ -219,14 +218,14 @@ public class FilteringScreen extends Screen {
ScissorsHandler.INSTANCE.scissor(bounds);
for (EntryListEntry entry : entries)
entry.clearStacks();
- int skip = Math.max(0, Mth.floor(scrolling.scrollAmount / (float) entrySize()));
+ int skip = Math.max(0, Mth.floor(scrolling.scrollAmount() / (float) entrySize()));
int nextIndex = skip * innerBounds.width / entrySize();
int i = nextIndex;
BatchedEntryRendererManager manager = new BatchedEntryRendererManager();
for (; i < entryStacks.size(); i++) {
EntryStack<?> stack = entryStacks.get(i);
EntryListEntry entry = entries.get(nextIndex);
- entry.getBounds().y = (int) (entry.backupY - scrolling.scrollAmount);
+ entry.getBounds().y = entry.backupY - scrolling.scrollAmountInt();
if (entry.getBounds().y > bounds.getMaxY())
break;
entry.entry(stack);
@@ -281,13 +280,13 @@ public class FilteringScreen extends Screen {
Point p = secondPoint;
if (p == null) {
p = PointHelper.ofMouse();
- p.translate(0, (int) scrolling.scrollAmount);
+ p.translate(0, scrolling.scrollAmountInt());
}
int left = Math.min(p.x, selectionPoint.x);
int top = Math.min(p.y, selectionPoint.y);
int right = Math.max(p.x, selectionPoint.x);
int bottom = Math.max(p.y, selectionPoint.y);
- selectionCache = new Rectangle(left, (int) (top - scrolling.scrollAmount), right - left, bottom - top);
+ selectionCache = new Rectangle(left, top - scrolling.scrollAmountInt(), right - left, bottom - top);
return;
}
selectionCache = new Rectangle(0, 0, 0, 0);
@@ -301,13 +300,6 @@ public class FilteringScreen extends Screen {
}
private void updatePosition(float delta) {
- if (ConfigObject.getInstance().doesSnapToRows() && scrolling.scrollTarget >= 0 && scrolling.scrollTarget <= scrolling.getMaxScroll()) {
- double nearestRow = Math.round(scrolling.scrollTarget / (double) entrySize()) * (double) entrySize();
- if (!DynamicNewSmoothScrollingEntryListWidget.Precision.almostEquals(scrolling.scrollTarget, nearestRow, DynamicNewSmoothScrollingEntryListWidget.Precision.FLOAT_EPSILON))
- scrolling.scrollTarget += (nearestRow - scrolling.scrollTarget) * Math.min(delta / 2.0, 1.0);
- else
- scrolling.scrollTarget = nearestRow;
- }
scrolling.updatePosition(delta);
}
@@ -377,7 +369,7 @@ public class FilteringScreen extends Screen {
return true;
}
if (int_1 == 0) {
- this.selectionPoint = new Point(double_1, double_2 + scrolling.scrollAmount);
+ this.selectionPoint = new Point(double_1, double_2 + scrolling.scrollAmount());
this.secondPoint = null;
return true;
}
@@ -388,7 +380,7 @@ public class FilteringScreen extends Screen {
@Override
public boolean mouseReleased(double mouseX, double mouseY, int button) {
if (selectionPoint != null && button == 0 && secondPoint == null) {
- this.secondPoint = new Point(mouseX, mouseY + scrolling.scrollAmount);
+ this.secondPoint = new Point(mouseX, mouseY + scrolling.scrollAmount());
if (secondPoint.equals(selectionPoint)) {
secondPoint.translate(1, 1);
}
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/ScreenOverlayImpl.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/ScreenOverlayImpl.java
index ff1fa2a2d..067e8d32e 100644
--- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/ScreenOverlayImpl.java
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/ScreenOverlayImpl.java
@@ -442,6 +442,11 @@ public class ScreenOverlayImpl extends ScreenOverlay {
config::setEntryListWidgetScrolled
),
new SeparatorMenuEntry(),
+ ToggleMenuEntry.of(new TranslatableComponent("text.rei.config.menu.display.caching_entry_rendering"),
+ config::doesCacheEntryRendering,
+ config::setDoesCacheEntryRendering
+ ),
+ new SeparatorMenuEntry(),
ToggleMenuEntry.of(new TranslatableComponent("text.rei.config.menu.display.side_search_field"),
() -> config.getSearchFieldLocation() != SearchFieldLocation.CENTER,
bool -> config.setSearchFieldLocation(bool ? SearchFieldLocation.BOTTOM_SIDE : SearchFieldLocation.CENTER)
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/dragging/CurrentDraggingStack.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/dragging/CurrentDraggingStack.java
index 1e204dbb2..df2d8d452 100644
--- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/dragging/CurrentDraggingStack.java
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/dragging/CurrentDraggingStack.java
@@ -24,13 +24,13 @@
package me.shedaniel.rei.impl.client.gui.dragging;
import com.mojang.blaze3d.vertex.PoseStack;
+import me.shedaniel.clothconfig2.api.animator.NumberAnimator;
+import me.shedaniel.clothconfig2.api.animator.ValueAnimator;
import me.shedaniel.math.FloatingRectangle;
import me.shedaniel.math.Point;
import me.shedaniel.math.Rectangle;
import me.shedaniel.math.impl.PointHelper;
import me.shedaniel.rei.RoughlyEnoughItemsCoreClient;
-import me.shedaniel.rei.api.client.gui.animator.NumberAnimator;
-import me.shedaniel.rei.api.client.gui.animator.ValueAnimator;
import me.shedaniel.rei.api.client.gui.drag.*;
import me.shedaniel.rei.api.client.gui.widgets.Widget;
import me.shedaniel.rei.impl.client.gui.widget.LateRenderable;
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/Menu.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/Menu.java
index 15afb1a4b..490a22d2a 100644
--- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/Menu.java
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/Menu.java
@@ -29,7 +29,7 @@ import com.google.common.collect.Sets;
import com.mojang.blaze3d.vertex.PoseStack;
import me.shedaniel.clothconfig2.ClothConfigInitializer;
import me.shedaniel.clothconfig2.api.ScissorsHandler;
-import me.shedaniel.clothconfig2.api.ScrollingContainer;
+import me.shedaniel.clothconfig2.api.scroll.ScrollingContainer;
import me.shedaniel.math.Point;
import me.shedaniel.math.Rectangle;
import me.shedaniel.rei.RoughlyEnoughItemsCore;
@@ -244,7 +244,7 @@ public class Menu extends WidgetWithBounds implements LateRenderable {
fill(matrices, innerBounds.x, innerBounds.y, innerBounds.getMaxX(), innerBounds.getMaxY(), -16777216);
boolean contains = innerBounds.contains(mouseX, mouseY);
MenuEntry focused = getFocused() instanceof MenuEntry menuEntry ? menuEntry : null;
- int currentY = (int) (innerBounds.y - scrolling.scrollAmount);
+ int currentY = innerBounds.y - scrolling.scrollAmountInt();
for (MenuEntry child : children()) {
boolean containsMouse = contains && mouseY >= currentY && mouseY < currentY + child.getEntryHeight();
if (containsMouse) {
@@ -252,7 +252,7 @@ public class Menu extends WidgetWithBounds implements LateRenderable {
}
currentY += child.getEntryHeight();
}
- currentY = (int) (innerBounds.y - scrolling.scrollAmount);
+ currentY = innerBounds.y - scrolling.scrollAmountInt();
ScissorsHandler.INSTANCE.scissor(scrolling.getScissorBounds());
for (MenuEntry child : children()) {
boolean rendering = currentY + child.getEntryHeight() >= innerBounds.y && currentY <= innerBounds.getMaxY();
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/entries/EntryStackSubsetsMenuEntry.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/entries/EntryStackSubsetsMenuEntry.java
index 27919c5d1..d6029865f 100644
--- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/entries/EntryStackSubsetsMenuEntry.java
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/entries/EntryStackSubsetsMenuEntry.java
@@ -79,7 +79,7 @@ public class EntryStackSubsetsMenuEntry extends AbstractMenuEntry {
REIRuntime.getInstance().queueTooltip(stack.getTooltip(new Point(mouseX, mouseY)));
if (RoughlyEnoughItemsCoreClient.isLeftMousePressed && !clickedLast) {
clickedLast = true;
- if (!getParent().scrolling.draggingScrollBar) {
+ if (getParent().scrolling.getScissorBounds().contains(mouseX, mouseY)) {
minecraft.getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1.0F));
List<EntryStackProvider<?>> filteredStacks = ConfigObject.getInstance().getFilteredStackProviders();
if (isFiltered()) {
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/CompositeDisplayViewingScreen.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/CompositeDisplayViewingScreen.java
index f986f5e61..1102abca8 100644
--- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/CompositeDisplayViewingScreen.java
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/CompositeDisplayViewingScreen.java
@@ -27,7 +27,7 @@ import com.google.common.collect.Lists;
import com.mojang.blaze3d.vertex.PoseStack;
import me.shedaniel.clothconfig2.ClothConfigInitializer;
import me.shedaniel.clothconfig2.api.ScissorsHandler;
-import me.shedaniel.clothconfig2.api.ScrollingContainer;
+import me.shedaniel.clothconfig2.api.scroll.ScrollingContainer;
import me.shedaniel.math.Point;
import me.shedaniel.math.Rectangle;
import me.shedaniel.math.impl.PointHelper;
@@ -109,7 +109,6 @@ public class CompositeDisplayViewingScreen extends AbstractDisplayViewingScreen
super.init();
boolean isCompactTabs = ConfigObject.getInstance().isUsingCompactTabs();
int tabSize = isCompactTabs ? 24 : 28;
- scrolling.draggingScrollBar = false;
this.children().clear();
this.widgets.clear();
this.buttonList.clear();
@@ -357,7 +356,7 @@ public class CompositeDisplayViewingScreen extends AbstractDisplayViewingScreen
matrices.pushPose();
ScissorsHandler.INSTANCE.scissor(scrolling.getBounds());
for (Button button : buttonList) {
- button.getBounds().y = scrollListBounds.y + 1 + yOffset - (int) scrolling.scrollAmount;
+ button.getBounds().y = scrollListBounds.y + 1 + yOffset - scrolling.scrollAmountInt();
if (button.getBounds().getMaxY() > scrollListBounds.getMinY() && button.getBounds().getMinY() < scrollListBounds.getMaxY()) {
button.render(matrices, mouseX, mouseY, delta);
}
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/DefaultDisplayViewingScreen.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/DefaultDisplayViewingScreen.java
index e90637e2e..b5457e2ed 100644
--- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/DefaultDisplayViewingScreen.java
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/DefaultDisplayViewingScreen.java
@@ -30,13 +30,13 @@ import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.Tesselator;
import com.mojang.math.Matrix4f;
import me.shedaniel.clothconfig2.api.ModifierKeyCode;
+import me.shedaniel.clothconfig2.api.animator.ValueAnimator;
import me.shedaniel.math.Color;
import me.shedaniel.math.Point;
import me.shedaniel.math.Rectangle;
import me.shedaniel.math.impl.PointHelper;
import me.shedaniel.rei.api.client.REIRuntime;
import me.shedaniel.rei.api.client.config.ConfigObject;
-import me.shedaniel.rei.api.client.gui.animator.ValueAnimator;
import me.shedaniel.rei.api.client.gui.widgets.Button;
import me.shedaniel.rei.api.client.gui.widgets.Panel;
import me.shedaniel.rei.api.client.gui.widgets.Widget;
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/UncertainDisplayViewingScreen.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/UncertainDisplayViewingScreen.java
index 7a363f315..e9c71f7cd 100644
--- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/UncertainDisplayViewingScreen.java
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/UncertainDisplayViewingScreen.java
@@ -30,6 +30,8 @@ import com.mojang.math.Matrix4f;
import dev.architectury.platform.Platform;
import it.unimi.dsi.fastutil.booleans.BooleanConsumer;
import me.shedaniel.clothconfig2.api.ScissorsHandler;
+import me.shedaniel.clothconfig2.api.animator.NumberAnimator;
+import me.shedaniel.clothconfig2.api.animator.ValueAnimator;
import me.shedaniel.clothconfig2.gui.widget.DynamicNewSmoothScrollingEntryListWidget;
import me.shedaniel.clothconfig2.impl.EasingMethod;
import me.shedaniel.math.Point;
@@ -40,8 +42,6 @@ import me.shedaniel.rei.api.client.ClientHelper;
import me.shedaniel.rei.api.client.REIRuntime;
import me.shedaniel.rei.api.client.config.ConfigManager;
import me.shedaniel.rei.api.client.config.ConfigObject;
-import me.shedaniel.rei.api.client.gui.animator.NumberAnimator;
-import me.shedaniel.rei.api.client.gui.animator.ValueAnimator;
import me.shedaniel.rei.api.client.gui.config.DisplayScreenType;
import me.shedaniel.rei.api.client.gui.widgets.Button;
import me.shedaniel.rei.api.client.gui.widgets.Widget;
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/BatchedEntryRendererManager.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/BatchedEntryRendererManager.java
index 4693b12c9..ff472a9be 100644
--- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/BatchedEntryRendererManager.java
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/BatchedEntryRendererManager.java
@@ -212,7 +212,7 @@ public class BatchedEntryRendererManager {
firstRenderer.endBatch(first, extraData[0], matrices, delta);
}
- private static <T extends EntryWidget> void renderSlow(boolean debugTime, MutableInt size, MutableLong time, PoseStack matrices, int mouseX, int mouseY, float delta, Iterable<T> entries) {
+ public static <T extends EntryWidget> void renderSlow(boolean debugTime, MutableInt size, MutableLong time, PoseStack matrices, int mouseX, int mouseY, float delta, Iterable<T> entries) {
for (T entry : entries) {
if (entry.getCurrentEntry().isEmpty())
continue;
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/CachedEntryListRender.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/CachedEntryListRender.java
new file mode 100644
index 000000000..65447b81b
--- /dev/null
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/CachedEntryListRender.java
@@ -0,0 +1,176 @@
+/*
+ * This file is licensed under the MIT License, part of Roughly Enough Items.
+ * Copyright (c) 2018, 2019, 2020, 2021, 2022 shedaniel
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package me.shedaniel.rei.impl.client.gui.widget;
+
+import com.mojang.blaze3d.pipeline.TextureTarget;
+import com.mojang.blaze3d.platform.Lighting;
+import com.mojang.blaze3d.platform.NativeImage;
+import com.mojang.blaze3d.platform.Window;
+import com.mojang.blaze3d.systems.RenderSystem;
+import com.mojang.blaze3d.vertex.PoseStack;
+import com.mojang.math.Matrix4f;
+import dev.architectury.registry.ReloadListenerRegistry;
+import it.unimi.dsi.fastutil.longs.Long2LongMap;
+import it.unimi.dsi.fastutil.longs.Long2LongOpenHashMap;
+import me.shedaniel.math.Rectangle;
+import me.shedaniel.rei.RoughlyEnoughItemsCore;
+import me.shedaniel.rei.api.client.entry.renderer.EntryRenderer;
+import me.shedaniel.rei.api.client.registry.entry.EntryRegistry;
+import me.shedaniel.rei.api.common.entry.EntryStack;
+import me.shedaniel.rei.api.common.entry.type.VanillaEntryTypes;
+import me.shedaniel.rei.api.common.util.EntryStacks;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.renderer.texture.DynamicTexture;
+import net.minecraft.resources.ResourceLocation;
+import net.minecraft.server.packs.PackType;
+import net.minecraft.util.Unit;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+
+public class CachedEntryListRender {
+ public static final int RESOLUTION = 64;
+ public static DynamicTexture cachedTexture;
+ public static ResourceLocation cachedTextureLocation;
+ public static Long2LongMap hash = new Long2LongOpenHashMap();
+
+ public static class Sprite {
+ public final float u0;
+ public final float u1;
+ public final float v0;
+ public final float v1;
+
+ public Sprite(float u0, float u1, float v0, float v1) {
+ this.u0 = u0;
+ this.u1 = u1;
+ this.v0 = v0;
+ this.v1 = v1;
+ }
+ }
+
+ static {
+ ReloadListenerRegistry.register(PackType.CLIENT_RESOURCES, (barrier, resourceManager, preparationProfiler, reloadProfiler, preparationExecutor, reloadExecutor) -> {
+ return barrier.wait(Unit.INSTANCE).thenRunAsync(CachedEntryListRender::refresh, reloadExecutor);
+ });
+ }
+
+ public static void refresh() {
+ RoughlyEnoughItemsCore.LOGGER.info("Refreshing cached entry list texture...");
+ if (cachedTextureLocation != null) {
+ Minecraft.getInstance().getTextureManager().release(cachedTextureLocation);
+ cachedTextureLocation = null;
+ }
+ if (cachedTexture != null) {
+ cachedTexture.close();
+ cachedTexture = null;
+ }
+ hash = new Long2LongOpenHashMap();
+ }
+
+ @Nullable
+ public static Sprite get(EntryStack<?> stack) {
+ if (stack.getType() == VanillaEntryTypes.ITEM) {
+ if (stack.getNullable(EntryStack.Settings.RENDERER) != null) {
+ return null;
+ }
+
+ if (cachedTexture == null) {
+ prepare();
+ }
+
+ long hashExact = EntryStacks.hashExact(stack);
+
+ long hashOrDefault = hash.getOrDefault(hashExact, -1L);
+ if (hashOrDefault != -1L) {
+ // unpack
+ int x = (int) (hashOrDefault >> 32);
+ int y = (int) (hashOrDefault & 0xFFFFFFFFL);
+ float width = cachedTexture.getPixels().getWidth();
+ float height = cachedTexture.getPixels().getWidth();
+ return new Sprite(x * RESOLUTION / width, (x + 1) * RESOLUTION / width, y * RESOLUTION / height, (y + 1) * RESOLUTION / height);
+ }
+ }
+
+ return null;
+ }
+
+ private static void prepare() {
+ int side = 4;
+ List<EntryStack<?>> list = EntryRegistry.getInstance().getPreFilteredList();
+ while (side * side < list.size()) {
+ side++;
+ }
+
+ int width = side * RESOLUTION;
+ int height = side * RESOLUTION;
+
+ RoughlyEnoughItemsCore.LOGGER.info("Preparing cached texture with size %sx%s for %sx%s entries", width, height, side, side);
+
+ hash = new Long2LongOpenHashMap(list.size() + 10);
+ Minecraft minecraft = Minecraft.getInstance();
+ Window window = minecraft.getWindow();
+ TextureTarget target = new TextureTarget(width, height, true, false);
+ target.bindWrite(true);
+ Matrix4f projectionMatrix = Matrix4f.orthographic(0.0F, width, 0.0F, height, 1000.0F, 3000.0F);
+ RenderSystem.setProjectionMatrix(projectionMatrix);
+ PoseStack modelViewStack = RenderSystem.getModelViewStack();
+ modelViewStack.pushPose();
+ modelViewStack.setIdentity();
+ modelViewStack.translate(0.0D, 0.0D, -2000.0D);
+ RenderSystem.applyModelViewMatrix();
+
+ Lighting.setupFor3DItems();
+ PoseStack matrices = new PoseStack();
+ Rectangle bounds = new Rectangle();
+
+ int index = 0;
+ for (EntryStack<?> stack : list) {
+ int x = index % side;
+ int y = index / side;
+ bounds.setBounds(x * RESOLUTION, y * RESOLUTION, RESOLUTION, RESOLUTION);
+ ((EntryRenderer<Object>) stack.getDefinition().getRenderer()).render((EntryStack<Object>) stack, matrices, bounds, -1, -1, 0);
+ hash.put(EntryStacks.hashExact(stack), pack(x, y));
+ index++;
+ }
+
+ NativeImage nativeImage = new Nat