diff --git a/src/main/java/xyz/valnet/engine/graphics/ImmediateUI.java b/src/main/java/xyz/valnet/engine/graphics/ImmediateUI.java index ac6b5ec..c1590d4 100644 --- a/src/main/java/xyz/valnet/engine/graphics/ImmediateUI.java +++ b/src/main/java/xyz/valnet/engine/graphics/ImmediateUI.java @@ -18,7 +18,9 @@ import xyz.valnet.hadean.util.Layers; public abstract class ImmediateUI extends GameObject implements IMouseCaptureArea { + @SuppressWarnings("unused") private boolean active; + @SuppressWarnings("unused") private boolean mouseDown; public void render() { @@ -27,6 +29,17 @@ public abstract class ImmediateUI extends GameObject implements IMouseCaptureAre end(); } + public void renderAlpha() { + + float f = 99; + Assets.flat.pushColor(new Vector4f(1, 0, 0, 0.3f)); + for(Vector4f box : guiAreas) { + Drawing.setLayer(f += 0.001f); + Assets.fillColor.draw(box); + } + Assets.flat.popColor(); + } + @Override public void mouseEnter() { active = true; @@ -47,8 +60,6 @@ public abstract class ImmediateUI extends GameObject implements IMouseCaptureAre if(button == 0) mouseDown = false; } - public abstract Vector4f getGuiBox(); - @Override public float getLayer() { return Layers.GENERAL_UI_INTERACTABLE; @@ -59,17 +70,18 @@ public abstract class ImmediateUI extends GameObject implements IMouseCaptureAre private record StackingContext( boolean fixedSize, Vector4f box, - Vector4f occlusionBox + Vector4f occlusionBox, + boolean hasRegisteredGuiArea // layout manager? ) {} - private StackingContext context; - private Stack contextStack; + private transient StackingContext context; + private transient Stack contextStack = new Stack();; private transient Map buttons = new HashMap(); - private Set usedButtonId = new HashSet(); + private transient Set usedButtonId = new HashSet(); private transient Map clicks = new HashMap(); - private int buttonCount; + private transient int buttonCount; private String genButtonId() { buttonCount ++; @@ -113,33 +125,96 @@ public abstract class ImmediateUI extends GameObject implements IMouseCaptureAre } } + @Override + public final List getGuiBoxes() { + return guiAreas; + } + + private transient List guiAreas = new ArrayList(); + // === ELEMENTS === + // protected void begin() { buttonCount = 0; usedButtonId.clear(); - Drawing.setLayer(Layers.GENERAL_UI_INTERACTABLE); - context = new StackingContext(true, getGuiBox(), getGuiBox()); - contextStack = new Stack(); - Assets.uiFrame.draw(context.occlusionBox); - pad(); + contextStack.clear(); + guiAreas.clear(); + } + + protected void root(int x, int y, int w, int h) { + assert context == null : "root can only be a root element"; + Vector4f box = new Vector4f(x, y, w, h); + context = new StackingContext(true, box, box, false); + } + + protected void rootEnd() { + assert contextStack.size() == 0 : "cannot end fixedFrame with un-ended elements inside"; + context = null; + } + + protected void fixedFrame(int w, int h) { + contextStack.push(context); + context = new StackingContext( + true, + new Vector4f(context.box.x, context.box.y, w, h), + context.occlusionBox.copy(), + true + ); + } + + protected void dynamicFrame() { + contextStack.push(context); + context = new StackingContext( + false, + new Vector4f(context.box.x, context.box.y, context.box.z, 0), + context.occlusionBox.copy(), + true + ); + } + + // TODO this will add _all_ frames, not just root frames to guiareas. + // not a problem, but not efficient. revisit. + protected void frameEnd() { + Drawing.setLayer(getLayer() + contextStack.size() - 1); + if(!context.fixedSize) { + Assets.uiFrame.draw(context.box); + guiAreas.add(context.box); + } else { + Assets.uiFrame.draw(context.occlusionBox); + guiAreas.add(context.occlusionBox); + } + context = contextStack.pop(); } protected boolean button(String text) { - return button(genButtonId(), text); + return button(genButtonId(), text, false); + } + + protected boolean button(String text, boolean expand) { + return button(genButtonId(), text, expand); } protected boolean button(String id, String text) { + return button(id, text, false); + } + + protected boolean button(String id, String text, boolean expand) { float h = 32; + if(expand && context.fixedSize) { + h = context.box.w; + } Vector4f buttonBox = new Vector4f(context.box.x, context.box.y, context.box.z, h); Button btn = getButton(id); + if(!context.hasRegisteredGuiArea) { + guiAreas.add(buttonBox); + } + btn.setText(text); btn.setPosition((int) buttonBox.x, (int) buttonBox.y); btn.setSize((int) buttonBox.z, (int) buttonBox.w); - btn.setLayer(Layers.GENERAL_UI_INTERACTABLE + contextStack.size()); - - // System.out.println("" + buttonBox); + btn.setLayer(getLayer() + contextStack.size() + 1); adjustBox(h); @@ -160,7 +235,8 @@ public abstract class ImmediateUI extends GameObject implements IMouseCaptureAre new Vector4f( context.box.x, context.box.y, context.box.z, 0 ), - context.occlusionBox.copy() + context.occlusionBox.copy(), + context.hasRegisteredGuiArea ); pad(); } @@ -181,14 +257,16 @@ public abstract class ImmediateUI extends GameObject implements IMouseCaptureAre new Vector4f( context.box.x + 8, context.box.y + 8, context.box.z - 16, context.box.w - 16 ), - context.occlusionBox.copy() + context.occlusionBox.copy(), + context.hasRegisteredGuiArea ); } else { context = new StackingContext(false, new Vector4f( context.box.x + 8, context.box.y + 8, context.box.z - 16, 0 ), - context.occlusionBox.copy() + context.occlusionBox.copy(), + context.hasRegisteredGuiArea ); } } @@ -200,7 +278,6 @@ public abstract class ImmediateUI extends GameObject implements IMouseCaptureAre } protected void end() { - padEnd(); List buttonIdsToRemove = new ArrayList(); diff --git a/src/main/java/xyz/valnet/engine/scenegraph/IMouseCaptureArea.java b/src/main/java/xyz/valnet/engine/scenegraph/IMouseCaptureArea.java index a59c673..aada5f7 100644 --- a/src/main/java/xyz/valnet/engine/scenegraph/IMouseCaptureArea.java +++ b/src/main/java/xyz/valnet/engine/scenegraph/IMouseCaptureArea.java @@ -1,5 +1,7 @@ package xyz.valnet.engine.scenegraph; +import java.util.List; + import xyz.valnet.engine.math.Vector4f; public interface IMouseCaptureArea { @@ -8,6 +10,6 @@ public interface IMouseCaptureArea { public void mouseDown(int button); public void mouseUp(int button); - public Vector4f getGuiBox(); + public List getGuiBoxes(); public float getLayer(); } diff --git a/src/main/java/xyz/valnet/engine/scenegraph/SceneGraph.java b/src/main/java/xyz/valnet/engine/scenegraph/SceneGraph.java index b36ecc1..a6e50a6 100644 --- a/src/main/java/xyz/valnet/engine/scenegraph/SceneGraph.java +++ b/src/main/java/xyz/valnet/engine/scenegraph/SceneGraph.java @@ -13,6 +13,7 @@ import java.util.Map.Entry; import java.util.stream.Collectors; import xyz.valnet.engine.App; +import xyz.valnet.engine.math.Vector4f; public abstract class SceneGraph implements IScene { protected final List objects = new ArrayList(); @@ -72,6 +73,10 @@ public abstract class SceneGraph implements IScene { obj.update(dTime); } + mouseUpdate(); + } + + private void mouseUpdate() { // DO MOUSE UPDATES! List mouseListeners = getAll(IMouseCaptureArea.class); mouseListeners.sort(new Comparator() { @@ -82,22 +87,25 @@ public abstract class SceneGraph implements IScene { return al < bl ? 1 : bl < al ? -1 : 0; } }); + for(IMouseCaptureArea listener : mouseListeners) { - boolean currentlyEntered = listener.getGuiBox().contains(App.mouseX, App.mouseY); - if(currentlyEntered) { - if(listener != hoveredMouseListener) { - if(hoveredMouseListener != null) { - hoveredMouseListener.mouseLeave(); + for(Vector4f guiBox : listener.getGuiBoxes()) { + boolean currentlyEntered = guiBox.contains(App.mouseX, App.mouseY); + if(currentlyEntered) { + if(listener != hoveredMouseListener) { + if(hoveredMouseListener != null) { + hoveredMouseListener.mouseLeave(); + } + hoveredMouseListener = listener; + listener.mouseEnter(); } - hoveredMouseListener = listener; - listener.mouseEnter(); + return; + } else if(listener == hoveredMouseListener) { + // this is the one that is currently hovered, but it isnt! + // turn that shit OFF + hoveredMouseListener.mouseLeave(); + hoveredMouseListener = null; } - break; - } else if(listener == hoveredMouseListener) { - // this is the one that is currently hovered, but it isnt! - // turn that shit OFF - hoveredMouseListener.mouseLeave(); - hoveredMouseListener = null; } } } diff --git a/src/main/java/xyz/valnet/hadean/gameobjects/SelectionUI.java b/src/main/java/xyz/valnet/hadean/gameobjects/SelectionUI.java index 62a4a57..bc8d91a 100644 --- a/src/main/java/xyz/valnet/hadean/gameobjects/SelectionUI.java +++ b/src/main/java/xyz/valnet/hadean/gameobjects/SelectionUI.java @@ -71,12 +71,6 @@ public class SelectionUI extends ImmediateUI implements ISelectionChangeListener } } - @Override - public Vector4f getGuiBox() { - if(selected.isEmpty()) return Vector4f.zero; - return new Vector4f(10, 576 - BottomBar.bottomBarHeight - height - padding, width, height); - } - @Override public float getLayer() { return Layers.GENERAL_UI; diff --git a/src/main/java/xyz/valnet/hadean/gameobjects/inputlayer/BuildLayer.java b/src/main/java/xyz/valnet/hadean/gameobjects/inputlayer/BuildLayer.java index 61bb9aa..3d28762 100644 --- a/src/main/java/xyz/valnet/hadean/gameobjects/inputlayer/BuildLayer.java +++ b/src/main/java/xyz/valnet/hadean/gameobjects/inputlayer/BuildLayer.java @@ -1,5 +1,7 @@ package xyz.valnet.hadean.gameobjects.inputlayer; +import java.util.List; + import xyz.valnet.engine.App; import xyz.valnet.engine.math.Vector2i; import xyz.valnet.engine.math.Vector4f; @@ -129,8 +131,8 @@ public class BuildLayer extends GameObject implements IMouseCaptureArea, ITransi } @Override - public Vector4f getGuiBox() { - return active ? new Vector4f(0, 0, 1024, 576) : Vector4f.zero; + public List getGuiBoxes() { + return List.of(active ? new Vector4f(0, 0, 1024, 576) : Vector4f.zero); } @Override diff --git a/src/main/java/xyz/valnet/hadean/gameobjects/inputlayer/SelectionLayer.java b/src/main/java/xyz/valnet/hadean/gameobjects/inputlayer/SelectionLayer.java index 614ad0d..a1010cf 100644 --- a/src/main/java/xyz/valnet/hadean/gameobjects/inputlayer/SelectionLayer.java +++ b/src/main/java/xyz/valnet/hadean/gameobjects/inputlayer/SelectionLayer.java @@ -181,8 +181,8 @@ public class SelectionLayer extends GameObject implements IMouseCaptureArea, ITr } @Override - public Vector4f getGuiBox() { - return new Vector4f(0, 0, 1000, 1000); + public List getGuiBoxes() { + return List.of(new Vector4f(0, 0, 1000, 1000)); } @Override diff --git a/src/main/java/xyz/valnet/hadean/gameobjects/ui/Popup.java b/src/main/java/xyz/valnet/hadean/gameobjects/ui/Popup.java index 1c37266..c41f69b 100644 --- a/src/main/java/xyz/valnet/hadean/gameobjects/ui/Popup.java +++ b/src/main/java/xyz/valnet/hadean/gameobjects/ui/Popup.java @@ -1,34 +1,42 @@ package xyz.valnet.hadean.gameobjects.ui; import xyz.valnet.engine.graphics.ImmediateUI; -import xyz.valnet.engine.math.Vector4f; public class Popup extends ImmediateUI { - @Override - public Vector4f getGuiBox() { - return new Vector4f(256, 100, 512, 300); - } - @Override protected void gui() { - header(" Popup Test"); - - text("1\n1.5"); - text("2"); - - group(); - text("This should be in a frame!"); - text("And this!"); - groupEnd(); + root(100, 100, 200, 200); { + fixedFrame(200, 100); { + pad(); { + header(" Popup Test"); - text("But not this..."); + text("1\n1.5"); + text("2"); + + group(); { + text("This should be in a frame!"); + text("And this!"); + } groupEnd(); + + text("But not this..."); + + if(button("Click Me!")) { + System.out.println("The Event!"); + } + + text("This after button..."); + } padEnd(); + } frameEnd(); + } rootEnd(); - if(button("Click Me!")) { - System.out.println("The Event!"); - } - text("This after button..."); + + root(724, 100, 200, 200); + // text("Test Frame!"); + button("Test Button Expand!", true); + button("Test Button Expand 2!", true); + rootEnd(); } } diff --git a/src/main/java/xyz/valnet/hadean/gameobjects/ui/tabs/BuildTab.java b/src/main/java/xyz/valnet/hadean/gameobjects/ui/tabs/BuildTab.java index 2136e91..303ee1e 100644 --- a/src/main/java/xyz/valnet/hadean/gameobjects/ui/tabs/BuildTab.java +++ b/src/main/java/xyz/valnet/hadean/gameobjects/ui/tabs/BuildTab.java @@ -289,8 +289,8 @@ public class BuildTab extends Tab implements ISelectionChangeListener, IMouseCap public void mouseUp(int button) {} @Override - public Vector4f getGuiBox() { - return new Vector4f(padding, 576 - BottomBar.bottomBarHeight - padding - height, width, height); + public List getGuiBoxes() { + return List.of(new Vector4f(padding, 576 - BottomBar.bottomBarHeight - padding - height, width, height)); } @Override diff --git a/src/main/java/xyz/valnet/hadean/input/Button.java b/src/main/java/xyz/valnet/hadean/input/Button.java index d1f2dd2..445bf62 100644 --- a/src/main/java/xyz/valnet/hadean/input/Button.java +++ b/src/main/java/xyz/valnet/hadean/input/Button.java @@ -1,6 +1,8 @@ package xyz.valnet.hadean.input; -import static xyz.valnet.engine.util.Math.lerp; +import static xyz.valnet.engine.util.Math.*; + +import java.util.List; import xyz.valnet.engine.graphics.Drawing; import xyz.valnet.engine.graphics.Tile9; @@ -222,8 +224,8 @@ public class Button extends GameObject implements IMouseCaptureArea, ITransient } @Override - public Vector4f getGuiBox() { - return new Vector4f(x, y, width, height); + public List getGuiBoxes() { + return List.of(new Vector4f(x, y, width, height)); } @Override diff --git a/src/main/java/xyz/valnet/hadean/scenes/GameScene.java b/src/main/java/xyz/valnet/hadean/scenes/GameScene.java index e37d02e..87028da 100644 --- a/src/main/java/xyz/valnet/hadean/scenes/GameScene.java +++ b/src/main/java/xyz/valnet/hadean/scenes/GameScene.java @@ -45,7 +45,7 @@ public class GameScene extends SceneGraph { } objects.add(new SelectionLayer()); - objects.add(new SelectionUI()); + // objects.add(new SelectionUI()); objects.add(new BuildLayer()); @@ -59,7 +59,7 @@ public class GameScene extends SceneGraph { objects.add(new SaveTab()); objects.add(new LoadTab()); - // objects.add(new Popup()); + objects.add(new Popup()); } }