Files
NotEnoughItems/src/main/java/codechicken/nei/ItemsGrid.java
T

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

424 lines
12 KiB
Java
Raw Normal View History

2022-01-02 23:30:54 +02:00
package codechicken.nei;
2023-09-25 00:35:24 +02:00
import static codechicken.lib.gui.GuiDraw.drawRect;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.annotation.Nullable;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.ScaledResolution;
2022-01-02 23:30:54 +02:00
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.shader.Framebuffer;
2022-01-02 23:30:54 +02:00
import net.minecraft.item.ItemStack;
2023-09-25 00:35:24 +02:00
import org.lwjgl.opengl.GL11;
2023-09-25 00:34:42 +02:00
2023-09-25 00:35:24 +02:00
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.ItemPanel.ItemPanelSlot;
import codechicken.nei.api.GuiInfo;
import codechicken.nei.guihook.GuiContainerManager;
import codechicken.nei.recipe.StackInfo;
public class ItemsGrid {
2022-02-06 17:42:11 +02:00
public static final int SLOT_SIZE = 18;
2022-01-02 23:30:54 +02:00
protected int width;
protected int height;
protected int marginLeft;
protected int marginTop;
2022-05-06 22:41:45 +03:00
protected int paddingLeft;
2022-10-13 11:06:08 +03:00
protected ArrayList<ItemStack> realItems = new ArrayList<>();
2022-01-02 23:30:54 +02:00
protected int page;
protected int perPage;
protected int rows;
protected int columns;
protected List<Integer> gridMask = null;
2022-01-02 23:30:54 +02:00
protected boolean[] invalidSlotMap;
2022-08-31 17:43:22 +09:00
protected Label messageLabel = new Label(getMessageOnEmpty(), true);
@Nullable
private Framebuffer framebuffer = null;
protected boolean refreshBuffer = true;
public ArrayList<ItemStack> getItems() {
2022-10-13 11:06:08 +03:00
return realItems;
2022-01-02 23:30:54 +02:00
}
public ItemStack getItem(int idx) {
2022-10-13 11:06:08 +03:00
return realItems.get(idx);
2022-01-02 23:30:54 +02:00
}
public int size() {
2022-01-02 23:30:54 +02:00
return realItems.size();
}
public int indexOf(ItemStack stackA, boolean useNBT) {
2022-01-02 23:30:54 +02:00
for (int idx = 0; idx < realItems.size(); idx++) {
if (StackInfo.equalItemAndNBT(stackA, realItems.get(idx), useNBT)) {
2022-01-02 23:30:54 +02:00
return idx;
}
}
return -1;
}
public void setPage(int page) {
this.page = Math.max(0, Math.min(page, getNumPages() - 1));
onGridChanged();
}
public int getPage() {
2022-01-02 23:30:54 +02:00
return page + 1;
}
public int getPerPage() {
2022-01-02 23:30:54 +02:00
return perPage;
}
public int getNumPages() {
2022-06-23 01:03:29 +03:00
if (perPage > 0) {
return (int) Math.ceil((float) realItems.size() / (float) perPage);
}
return 0;
2022-01-02 23:30:54 +02:00
}
public int getRows() {
2022-01-02 23:30:54 +02:00
return rows;
}
public int getColumns() {
2022-01-02 23:30:54 +02:00
return columns;
}
public int getLastRowIndex() {
return this.columns > 0 ? (int) Math.ceil((float) this.getMask().size() / this.columns) - 1 : 0;
}
public void setGridSize(int mleft, int mtop, int w, int h) {
2022-02-17 09:28:48 +02:00
marginLeft = mleft;
marginTop = mtop;
2022-01-02 23:30:54 +02:00
2022-02-17 09:28:48 +02:00
width = Math.max(0, w);
height = Math.max(0, h);
2022-01-02 23:30:54 +02:00
2022-02-17 09:28:48 +02:00
columns = width / SLOT_SIZE;
rows = height / SLOT_SIZE;
2022-01-02 23:30:54 +02:00
2022-05-06 22:41:45 +03:00
paddingLeft = (width % SLOT_SIZE) / 2;
2022-08-31 17:43:22 +09:00
messageLabel.x = marginLeft + width / 2;
messageLabel.y = marginTop + height / 2;
2022-01-02 23:30:54 +02:00
}
public void shiftPage(int shift) {
2022-01-02 23:30:54 +02:00
if (perPage == 0) {
page = 0;
return;
}
2022-06-23 01:03:29 +03:00
final int numPages = getNumPages();
final int oldPage = page;
2022-01-02 23:30:54 +02:00
page += shift;
if (page >= numPages) {
page = page - numPages;
}
if (page < 0) {
page = numPages + page;
}
page = Math.max(0, Math.min(page, numPages - 1));
2022-06-23 01:03:29 +03:00
if (page != oldPage) {
onGridChanged();
}
}
protected void onGridChanged() {
2022-06-23 01:03:29 +03:00
refreshBuffer = true;
this.gridMask = null;
2022-01-02 23:30:54 +02:00
}
protected void onItemsChanged() {
onGridChanged();
}
public void refresh(GuiContainer gui) {
2022-01-02 23:30:54 +02:00
updateGuiOverlapSlots(gui);
shiftPage(0);
}
protected void updateGuiOverlapSlots(GuiContainer gui) {
2022-06-23 01:03:29 +03:00
final boolean[] oldSlotMap = invalidSlotMap;
final int oldRows = rows;
final int oldColumns = columns;
2022-01-02 23:30:54 +02:00
invalidSlotMap = new boolean[rows * columns];
perPage = columns * rows;
if (NEIClientConfig.optimizeGuiOverlapComputation()) {
checkGuiOverlap(gui, 0, columns - 2, 1);
checkGuiOverlap(gui, columns - 1, 1, -1);
} else {
checkGuiOverlap(gui, 0, columns, 1);
}
2022-06-23 01:03:29 +03:00
if (oldRows != rows || oldColumns != columns || !Arrays.equals(oldSlotMap, invalidSlotMap)) {
onGridChanged();
}
2022-01-02 23:30:54 +02:00
}
private void checkGuiOverlap(GuiContainer gui, int start, int end, int dir) {
2022-01-02 23:30:54 +02:00
boolean validColumn = false;
for (int c = start; c != end && (!NEIClientConfig.optimizeGuiOverlapComputation() || !validColumn); c += dir) {
2022-01-02 23:30:54 +02:00
validColumn = true;
for (int r = 0; r < rows; r++) {
2022-01-04 21:46:46 -08:00
final int idx = columns * r + c;
if (idx >= 0 && idx < invalidSlotMap.length
&& !invalidSlotMap[idx]
&& GuiInfo.hideItemPanelSlot(gui, getSlotRect(r, c))) {
2022-01-04 21:46:46 -08:00
invalidSlotMap[idx] = true;
2022-01-02 23:30:54 +02:00
validColumn = false;
perPage--;
}
}
}
}
public Rectangle4i getItemRect(int idx) {
final List<Integer> mask = getMask();
for (int i = 0; i < mask.size(); i++) {
if (mask.get(i) != null && idx == mask.get(i)) {
return getSlotRect(i);
}
}
return null;
}
public Rectangle4i getSlotRect(int i) {
2022-01-02 23:30:54 +02:00
return getSlotRect(i / columns, i % columns);
}
public Rectangle4i getSlotRect(int row, int column) {
return new Rectangle4i(
marginLeft + paddingLeft + column * SLOT_SIZE,
marginTop + row * SLOT_SIZE,
SLOT_SIZE,
SLOT_SIZE);
2022-01-02 23:30:54 +02:00
}
public boolean isInvalidSlot(int index) {
2022-06-23 01:03:29 +03:00
return invalidSlotMap[index];
2022-01-02 23:30:54 +02:00
}
protected List<Integer> getMask() {
2022-06-23 01:03:29 +03:00
if (this.gridMask == null) {
this.gridMask = new ArrayList<>();
int idx = page * perPage;
2022-06-23 01:03:29 +03:00
for (int i = 0; i < rows * columns && idx < size(); i++) {
this.gridMask.add(isInvalidSlot(i) ? null : idx++);
}
}
return this.gridMask;
}
private void beforeDrawItems(int mousex, int mousey, @Nullable ItemPanelSlot focused) {
final List<Integer> mask = getMask();
for (int i = 0; i < mask.size(); i++) {
if (mask.get(i) != null) {
beforeDrawSlot(focused, mask.get(i), getSlotRect(i));
}
}
}
private void afterDrawItems(int mousex, int mousey, @Nullable ItemPanelSlot focused) {
final List<Integer> mask = getMask();
for (int i = 0; i < mask.size(); i++) {
if (mask.get(i) != null) {
afterDrawSlot(focused, mask.get(i), getSlotRect(i));
}
}
}
public void update() {}
protected void beforeDrawSlot(@Nullable ItemPanelSlot focused, int slotIdx, Rectangle4i rect) {
2022-06-23 01:03:29 +03:00
if (focused != null && focused.slotIndex == slotIdx) {
drawRect(rect.x, rect.y, rect.w, rect.h, 0xee555555); // highlight
2022-06-23 01:03:29 +03:00
}
}
protected void afterDrawSlot(@Nullable ItemPanelSlot focused, int slotIdx, Rectangle4i rect) {}
private void blitExistingBuffer() {
Minecraft minecraft = Minecraft.getMinecraft();
GL11.glEnable(GL11.GL_BLEND);
OpenGlHelper.glBlendFunc(GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
getFrameBuffer().bindFramebufferTexture();
GL11.glEnable(GL11.GL_TEXTURE_2D);
ScaledResolution res = new ScaledResolution(minecraft, minecraft.displayWidth, minecraft.displayHeight);
Tessellator tessellator = Tessellator.instance;
tessellator.startDrawingQuads();
tessellator.addVertexWithUV(0, res.getScaledHeight_double(), 0.0, 0, 0);
tessellator.addVertexWithUV(res.getScaledWidth_double(), res.getScaledHeight_double(), 0.0, 1, 0);
tessellator.addVertexWithUV(res.getScaledWidth_double(), 0, 0.0, 1, 1);
tessellator.addVertexWithUV(0, 0, 0, 0, 1);
tessellator.draw();
OpenGlHelper.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO);
}
private Framebuffer getFrameBuffer() {
if (framebuffer == null) {
framebuffer = new Framebuffer(1, 1, true);
framebuffer.setFramebufferColor(0.0F, 0.0F, 0.0F, 0.0F);
}
return framebuffer;
}
private void drawItems() {
GuiContainerManager.enableMatrixStackLogging();
final List<Integer> mask = getMask();
for (int i = 0; i < mask.size(); i++) {
if (mask.get(i) != null) {
drawItem(getSlotRect(i), mask.get(i));
}
}
GuiContainerManager.disableMatrixStackLogging();
}
protected boolean shouldCacheItemRendering() {
return NEIClientConfig.shouldCacheItemRendering();
}
public void draw(int mousex, int mousey) {
2022-01-02 23:30:54 +02:00
if (getPerPage() == 0) {
return;
}
final ItemPanelSlot focused = getSlotMouseOver(mousex, mousey);
if (shouldCacheItemRendering()) {
if (refreshBuffer) {
Minecraft minecraft = Minecraft.getMinecraft();
Framebuffer framebuffer = getFrameBuffer();
framebuffer.createBindFramebuffer(minecraft.displayWidth, minecraft.displayHeight);
framebuffer.framebufferClear();
framebuffer.bindFramebuffer(false);
/* Set up some rendering state needed for items to work correctly */
GL11.glDisable(GL11.GL_BLEND);
GL11.glDepthMask(true);
OpenGlHelper.glBlendFunc(
GL11.GL_SRC_ALPHA,
GL11.GL_ONE_MINUS_SRC_ALPHA,
GL11.GL_SRC_ALPHA,
GL11.GL_ONE_MINUS_SRC_ALPHA);
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
2022-01-02 23:30:54 +02:00
drawItems();
2022-01-02 23:30:54 +02:00
Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(false);
refreshBuffer = false;
2022-01-02 23:30:54 +02:00
}
beforeDrawItems(mousex, mousey, focused);
blitExistingBuffer();
} else {
beforeDrawItems(mousex, mousey, focused);
drawItems();
2022-01-02 23:30:54 +02:00
}
afterDrawItems(mousex, mousey, focused);
}
public void postDrawTooltips(int mousex, int mousey, List<String> tooltip) {}
2022-08-31 17:43:22 +09:00
public void setVisible() {
if (getItems().isEmpty() && getMessageOnEmpty() != null) {
LayoutManager.addWidget(messageLabel);
}
}
protected void drawItem(Rectangle4i rect, int idx) {
2022-10-13 11:06:08 +03:00
GuiContainerManager.drawItem(rect.x + 1, rect.y + 1, getItem(idx));
2022-01-02 23:30:54 +02:00
}
public ItemPanelSlot getSlotMouseOver(int mousex, int mousey) {
2022-01-02 23:30:54 +02:00
if (!contains(mousex, mousey)) {
return null;
}
final int overRow = (int) ((mousey - marginTop) / SLOT_SIZE);
2022-05-06 22:41:45 +03:00
final int overColumn = (int) ((mousex - marginLeft - paddingLeft) / SLOT_SIZE);
2022-01-02 23:30:54 +02:00
final int slt = columns * overRow + overColumn;
if (overRow >= rows || overColumn >= columns) {
return null;
}
2022-06-23 01:03:29 +03:00
final List<Integer> mask = getMask();
if (mask.size() > slt && mask.get(slt) != null) {
final int idx = mask.get(slt);
return new ItemPanelSlot(idx, getItem(idx));
2022-01-02 23:30:54 +02:00
}
2022-06-23 01:03:29 +03:00
return null;
2022-01-02 23:30:54 +02:00
}
public boolean contains(int px, int py) {
final Rectangle4i rect = new Rectangle4i(
marginLeft + paddingLeft,
marginTop,
columns * SLOT_SIZE,
rows * SLOT_SIZE);
2022-01-02 23:30:54 +02:00
if (!rect.contains(px, py)) {
2022-01-02 23:30:54 +02:00
return false;
}
final int r = (int) ((py - marginTop) / SLOT_SIZE);
2022-05-06 22:41:45 +03:00
final int c = (int) ((px - marginLeft - paddingLeft) / SLOT_SIZE);
2022-01-02 23:30:54 +02:00
return !isInvalidSlot(columns * r + c);
2022-01-02 23:30:54 +02:00
}
2022-08-31 17:43:22 +09:00
public String getMessageOnEmpty() {
return null;
}
}