Skip to content

Commit

Permalink
Rewrite screens in Java
Browse files Browse the repository at this point in the history
  • Loading branch information
Juuxel committed Jul 31, 2024
1 parent 5e1936b commit e326d0b
Show file tree
Hide file tree
Showing 45 changed files with 1,401 additions and 1,170 deletions.
78 changes: 78 additions & 0 deletions common/src/main/java/juuxel/adorn/client/gui/Scissors.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package juuxel.adorn.client.gui;

import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.client.MinecraftClient;

import java.util.ArrayDeque;
import java.util.Deque;

/**
* A global GL scissor stack that is applied when pushed and popped.
*/
public final class Scissors {
private static final Deque<Frame> STACK = new ArrayDeque<>();

/**
* Pushes a new scissor frame at {@code (x, y)} with dimensions {@code (width, height)}
* and refreshes the scissor state.
*/
public static void push(int x, int y, int width, int height) {
push(new Frame(x, y, x + width, y + height));
}

/**
* Pushes a scissor frame and refreshes the scissor state.
*/
public static void push(Frame frame) {
STACK.addLast(frame);
apply();
}

/**
* Pops the topmost scissor frame and refreshes the scissor state.
* If there are no remaining frames, disables scissoring.
*/
public static Frame pop() {
var frame = STACK.removeLast();
apply();
return frame;
}

/**
* Temporarily disables the topmost scissor frame for executing the runnable.
*/
public static void suspendScissors(Runnable fn) {
var frame = pop();
fn.run();
push(frame);
}

private static void apply() {
if (STACK.isEmpty()) {
RenderSystem.disableScissor();
return;
}

var window = MinecraftClient.getInstance().getWindow();
var x1 = 0;
var y1 = 0;
var x2 = window.getScaledWidth();
var y2 = window.getScaledHeight();

for (var frame : STACK) {
x1 = Math.max(x1, frame.x1);
y1 = Math.max(y1, frame.y1);
x2 = Math.min(x2, frame.x2);
y2 = Math.min(y2, frame.y2);
}

var scale = window.getScaleFactor();
RenderSystem.enableScissor(
(int) (x1 * scale), (int) (window.getFramebufferHeight() - scale * y2),
(int) ((x2 - x1) * scale), (int) ((y2 - y1) * scale)
);
}

public record Frame(int x1, int y1, int x2, int y2) {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package juuxel.adorn.client.gui;

import juuxel.adorn.AdornCommon;
import juuxel.adorn.trading.Trade;
import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.tooltip.TooltipComponent;
import net.minecraft.util.Identifier;

public record TradeTooltipComponent(Trade trade) implements TooltipComponent {
private static final Identifier ARROW_TEXTURE = AdornCommon.id("textures/gui/tooltip_arrow.png");

@Override
public int getWidth(TextRenderer textRenderer) {
return 3 * 16;
}

@Override
public int getHeight() {
return 18;
}

@Override
public void drawItems(TextRenderer textRenderer, int x, int y, DrawContext context) {
context.drawItem(trade.getPrice(), x, y);
context.drawItemInSlot(textRenderer, trade.getPrice(), x, y);
context.drawItem(trade.getSelling(), x + 2 * 16, y);
context.drawItemInSlot(textRenderer, trade.getSelling(), x + 2 * 16, y);
context.drawTexture(ARROW_TEXTURE, x + 16, y, 0f, 0f, 16, 16, 16, 16);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package juuxel.adorn.client.gui.screen;

import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.screen.ingame.MenuScreen;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.menu.Menu;
import net.minecraft.text.Text;

public abstract class AdornMenuScreen<M extends Menu> extends MenuScreen<M> {
public AdornMenuScreen(M menu, PlayerInventory playerInventory, Text title) {
super(menu, playerInventory, title);
}

public int getPanelX() {
return x;
}

public int getPanelY() {
return y;
}

@Override
public void render(DrawContext context, int mouseX, int mouseY, float delta) {
renderBackground(context, mouseX, mouseY, delta);
super.render(context, mouseX, mouseY, delta);
drawMouseoverTooltip(context, mouseX, mouseY);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package juuxel.adorn.client.gui.screen;

import juuxel.adorn.menu.AdornMenus;
import net.minecraft.client.gui.screen.ingame.MenuScreens;

public final class AdornMenuScreens {
public static void register() {
MenuScreens.register(AdornMenus.INSTANCE.getDRAWER(), DrawerScreen::new);
MenuScreens.register(AdornMenus.INSTANCE.getKITCHEN_CUPBOARD(), KitchenCupboardScreen::new);
MenuScreens.register(AdornMenus.INSTANCE.getTRADING_STATION(), TradingStationScreen::new);
MenuScreens.register(AdornMenus.INSTANCE.getBREWER(), BrewerScreen::new);
}
}
131 changes: 131 additions & 0 deletions common/src/main/java/juuxel/adorn/client/gui/screen/BrewerScreen.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
package juuxel.adorn.client.gui.screen;

import com.mojang.blaze3d.systems.RenderSystem;
import juuxel.adorn.AdornCommon;
import juuxel.adorn.block.entity.BrewerBlockEntity;
import juuxel.adorn.client.FluidRenderingBridge;
import juuxel.adorn.fluid.FluidReference;
import juuxel.adorn.fluid.FluidVolume;
import juuxel.adorn.menu.BrewerMenu;
import juuxel.adorn.util.ColorsKt;
import juuxel.adorn.util.Logging;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.screen.ingame.MenuProvider;
import net.minecraft.client.item.TooltipContext;
import net.minecraft.client.render.BufferRenderer;
import net.minecraft.client.render.GameRenderer;
import net.minecraft.client.render.Tessellator;
import net.minecraft.client.render.VertexFormat;
import net.minecraft.client.render.VertexFormats;
import net.minecraft.client.texture.Sprite;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.MathHelper;
import org.slf4j.Logger;

import java.util.List;

public final class BrewerScreen extends AdornMenuScreen<BrewerMenu> {
private static final Logger LOGGER = Logging.logger();
public static final Identifier TEXTURE = AdornCommon.id("textures/gui/brewer.png");
public static final int FLUID_AREA_HEIGHT = 59;

public BrewerScreen(BrewerMenu menu, PlayerInventory playerInventory, Text title) {
super(menu, playerInventory, title);
}

@Override
protected void drawBackground(DrawContext context, float delta, int mouseX, int mouseY) {
context.drawTexture(TEXTURE, x, y, 0, 0, backgroundWidth, backgroundHeight);
drawFluid(context, x + 145, y + 17, menu.getFluid());
context.drawTexture(TEXTURE, x + 145, y + 21, 176, 25, 16, 51);

var progress = menu.getProgress();
if (progress > 0) {
float progressFract = (float) progress / (float) BrewerBlockEntity.MAX_PROGRESS;
context.drawTexture(TEXTURE, x + 84, y + 24, 176, 0, 8, MathHelper.ceil(progressFract * 25));
}
}

@Override
protected void drawMouseoverTooltip(DrawContext context, int x, int y) {
super.drawMouseoverTooltip(context, x, y);
int x2 = x - this.x;
int y2 = y - this.y;
if (145 <= x2 && x2 < 145 + 16 && 17 <= y2 && y2 < 17 + FLUID_AREA_HEIGHT) {
context.drawTooltip(textRenderer, getFluidTooltip(menu.getFluid()), x, y);
}
}


private List<Text> getFluidTooltip(FluidReference fluid) {
return FluidRenderingBridge.get().getTooltip(
fluid,
client.options.advancedItemTooltips ? TooltipContext.ADVANCED : TooltipContext.BASIC,
BrewerBlockEntity.FLUID_CAPACITY_IN_BUCKETS * 1000
);
}

public static void setFluidFromPacket(MinecraftClient client, int syncId, FluidVolume fluid) {
if (client.currentScreen instanceof MenuProvider<?> menuProvider) {
var menu = menuProvider.getMenu();
if (menu.syncId == syncId && menu instanceof BrewerMenu brewerMenu) {
brewerMenu.setFluid(fluid);
}
}
}

private static void drawSprite(DrawContext context, int x, float y, float width, float height, float u0, float v0, float u1, float v1, Sprite sprite, int color) {
RenderSystem.enableBlend();
RenderSystem.setShader(GameRenderer::getPositionColorTexProgram);
RenderSystem.setShaderColor(1f, 1f, 1f, 1f);
RenderSystem.setShaderTexture(0, sprite.getAtlasId());
var buffer = Tessellator.getInstance().getBuffer();
var positionMatrix = context.getMatrices().peek().getPositionMatrix();
var au0 = MathHelper.lerp(u0, sprite.getMinU(), sprite.getMaxU());
var au1 = MathHelper.lerp(u1, sprite.getMinU(), sprite.getMaxU());
var av0 = MathHelper.lerp(v0, sprite.getMinV(), sprite.getMaxV());
var av1 = MathHelper.lerp(v1, sprite.getMinV(), sprite.getMaxV());
buffer.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR_TEXTURE);
buffer.vertex(positionMatrix, x, y + height, 0f).color(color).texture(au0, av1).next();
buffer.vertex(positionMatrix, x + width, y + height, 0f).color(color).texture(au1, av1).next();
buffer.vertex(positionMatrix, x + width, y, 0f).color(color).texture(au1, av0).next();
buffer.vertex(positionMatrix, x, y, 0f).color(color).texture(au0, av0).next();
BufferRenderer.drawWithGlobalProgram(buffer.end());
RenderSystem.disableBlend();
}

public static void drawFluid(DrawContext context, int x, int y, FluidReference fluid) {
if (fluid.isEmpty()) return;

var bridge = FluidRenderingBridge.get();
var sprite = bridge.getStillSprite(fluid);
if (sprite == null) {
LOGGER.warn("Could not find sprite for {} in brewer screen", fluid);
return;
}

var color = ColorsKt.color(bridge.getColor(fluid));
var height = FLUID_AREA_HEIGHT * (float) (fluid.getAmount() / (BrewerBlockEntity.FLUID_CAPACITY_IN_BUCKETS * fluid.getUnit().getBucketVolume()));
var fluidY = 0;

int tiles = MathHelper.floor(height / 16);
for (int i = 0; i < tiles; i++) {
drawSprite(context, x, y + transformY(bridge, fluid, fluidY, 16f), 16f, 16f, 0f, 0f, 1f, 1f, sprite, color);
fluidY += 16;
}

var leftover = height % 16;
drawSprite(context, x, y + transformY(bridge, fluid, fluidY, leftover), 16f, leftover, 0f, 0f, 1f, leftover / 16f, sprite, color);
}

private static float transformY(FluidRenderingBridge bridge, FluidReference fluid, int fluidY, float areaHeight) {
if (bridge.fillsFromTop(fluid)) {
return fluidY;
} else {
return FLUID_AREA_HEIGHT - fluidY - areaHeight;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package juuxel.adorn.client.gui.screen;

import juuxel.adorn.AdornCommon;
import juuxel.adorn.menu.DrawerMenu;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.text.Text;
import net.minecraft.util.Identifier;

public final class DrawerScreen extends PalettedMenuScreen<DrawerMenu> {
private static final Identifier BACKGROUND_TEXTURE = AdornCommon.id("textures/gui/drawer.png");
private static final Identifier PALETTE_ID = AdornCommon.id("drawer");

public DrawerScreen(DrawerMenu menu, PlayerInventory playerInventory, Text title) {
super(menu, playerInventory, title);
}

@Override
protected Identifier getBackgroundTexture() {
return BACKGROUND_TEXTURE;
}

@Override
protected Identifier getPaletteId() {
return PALETTE_ID;
}
}
Loading

0 comments on commit e326d0b

Please sign in to comment.