From ffc12e498b8d7a5f420cff3b42dfd95314d2da52 Mon Sep 17 00:00:00 2001 From: austin Date: Thu, 28 Apr 2022 16:19:25 -0400 Subject: [PATCH] Add slider ui element --- assets/Shaders/ui/plainBox/plainBox.fs | 8 + assets/Shaders/ui/plainBox/plainBox.vs | 16 + .../controls/ControlHandler.java | 4 + src/main/java/electrosphere/main/Globals.java | 10 +- .../electrosphere/menu/MenuGenerators.java | 7 + .../electrosphere/renderer/RenderUtils.java | 4 +- .../electrosphere/renderer/ui/Window.java | 2 +- .../ui/elements/ScrollableContainer.java | 2 +- .../renderer/ui/elements/Slider.java | 308 ++++++++++++++++++ .../ui/layout/LayoutSchemeListScrollable.java | 2 +- 10 files changed, 355 insertions(+), 8 deletions(-) create mode 100644 assets/Shaders/ui/plainBox/plainBox.fs create mode 100644 assets/Shaders/ui/plainBox/plainBox.vs create mode 100644 src/main/java/electrosphere/renderer/ui/elements/Slider.java diff --git a/assets/Shaders/ui/plainBox/plainBox.fs b/assets/Shaders/ui/plainBox/plainBox.fs new file mode 100644 index 00000000..a48b9927 --- /dev/null +++ b/assets/Shaders/ui/plainBox/plainBox.fs @@ -0,0 +1,8 @@ +#version 330 core +out vec4 FragColor; + +uniform vec3 color; + +void main(){ + FragColor = vec4(color,1.0); +} \ No newline at end of file diff --git a/assets/Shaders/ui/plainBox/plainBox.vs b/assets/Shaders/ui/plainBox/plainBox.vs new file mode 100644 index 00000000..580a6056 --- /dev/null +++ b/assets/Shaders/ui/plainBox/plainBox.vs @@ -0,0 +1,16 @@ +#version 330 core +layout (location = 0) in vec3 aPos; + +uniform vec3 mPosition; +uniform vec3 mDimension; +uniform vec3 tPosition; +uniform vec3 tDimension; + +void main(){ + vec2 finalPos = vec2( + ((aPos.x + 1)/2 * mDimension.x + mPosition.x) * 2 - 1, + -((((aPos.y + 1)/2) * mDimension.y + mPosition.y) * 2 - 1) + // aPos.y * mDimension.y + (mPosition.y) + (1 - mDimension.y) + ); + gl_Position = vec4(finalPos.x, finalPos.y, 0.0, 1.0); +} diff --git a/src/main/java/electrosphere/controls/ControlHandler.java b/src/main/java/electrosphere/controls/ControlHandler.java index 43f4e5e2..cef1bbcb 100644 --- a/src/main/java/electrosphere/controls/ControlHandler.java +++ b/src/main/java/electrosphere/controls/ControlHandler.java @@ -996,6 +996,7 @@ public class ControlHandler { if(!control.isState()){ //on press control.onPress(); + control.setPressFrame(Main.getCurrentFrame()); } else { //on repeat control.onRepeat(); @@ -1005,6 +1006,9 @@ public class ControlHandler { if(control.isState()){ //on release control.onRelease(); + if(Main.getCurrentFrame() - control.getPressFrame() < control.getRepeatTimeout()){ + control.onClick(); + } } else { } control.setState(false); diff --git a/src/main/java/electrosphere/main/Globals.java b/src/main/java/electrosphere/main/Globals.java index a077859e..abc2e534 100644 --- a/src/main/java/electrosphere/main/Globals.java +++ b/src/main/java/electrosphere/main/Globals.java @@ -223,7 +223,8 @@ public class Globals { public static String whiteTexture; public static String offWhiteTexture; - public static String planeModelID; + public static String imagePlaneModelID; + public static String solidPlaneModelID; public static ArrayList lightPointListDefault; public static SpotLight lightSpotDefault; @@ -411,10 +412,11 @@ public class Globals { assetManager.addModelPathToQueue("Models/unitcylinder.fbx"); assetManager.addModelPathToQueue("Models/unitplane.fbx"); assetManager.addModelPathToQueue("Models/unitcube.fbx"); - planeModelID = assetManager.registerModel(RenderUtils.createPlaneModel()); + imagePlaneModelID = assetManager.registerModel(RenderUtils.createPlaneModel("Shaders/plane/plane.vs", "Shaders/plane/plane.fs")); + solidPlaneModelID = assetManager.registerModel(RenderUtils.createPlaneModel("Shaders/ui/plainBox/plainBox.vs", "Shaders/ui/plainBox/plainBox.fs")); //image panel - ImagePanel.imagePanelModelPath = assetManager.registerModel(RenderUtils.createPlaneModel()); + ImagePanel.imagePanelModelPath = imagePlaneModelID; Globals.assetManager.queueOverrideMeshShader(ImagePanel.imagePanelModelPath, "plane", "Shaders/font/bitmapchar/bitmapchar.vs", "Shaders/font/bitmapchar/bitmapchar.fs"); //init ui images @@ -422,6 +424,8 @@ public class Globals { testingTexture = "Textures/Testing1.png"; Globals.assetManager.addTexturePathtoQueue(testingTexture); + + Globals.assetManager.addShaderToQueue("Shaders/ui/plainBox/plainBox.vs", "Shaders/ui/plainBox/plainBox.fs"); // //in game ui stuff // elementManager.registerWindow(WindowStrings.WINDOW_MENU_MAIN,WidgetUtils.createInGameMainMenuButton()); diff --git a/src/main/java/electrosphere/menu/MenuGenerators.java b/src/main/java/electrosphere/menu/MenuGenerators.java index 510680b0..01c932ec 100644 --- a/src/main/java/electrosphere/menu/MenuGenerators.java +++ b/src/main/java/electrosphere/menu/MenuGenerators.java @@ -32,6 +32,7 @@ import electrosphere.renderer.ui.elements.Div; import electrosphere.renderer.ui.elements.ImagePanel; import electrosphere.renderer.ui.elements.Label; import electrosphere.renderer.ui.elements.ScrollableContainer; +import electrosphere.renderer.ui.elements.Slider; import electrosphere.renderer.ui.elements.TextInput; import electrosphere.renderer.ui.events.ClickEvent; import electrosphere.renderer.ui.events.DragEvent; @@ -43,6 +44,8 @@ import java.util.List; import javax.management.relation.Relation; +import org.joml.Vector3f; + /** * * @author amaterasu @@ -398,6 +401,10 @@ public class MenuGenerators { return false; }}); + //slider test + Slider slider = new Slider(500, 500, 500, 100, new Vector3f(0.1f,0.1f,0.1f), new Vector3f(1,0,0)); + rVal.addChild(slider); + return rVal; } diff --git a/src/main/java/electrosphere/renderer/RenderUtils.java b/src/main/java/electrosphere/renderer/RenderUtils.java index 337c5558..0fd7cef0 100644 --- a/src/main/java/electrosphere/renderer/RenderUtils.java +++ b/src/main/java/electrosphere/renderer/RenderUtils.java @@ -497,7 +497,7 @@ public class RenderUtils { } - public static Model createPlaneModel(){ + public static Model createPlaneModel(String vertexShader, String fragmentShader){ Model rVal = new Model(); rVal.meshes = new ArrayList(); @@ -590,7 +590,7 @@ public class RenderUtils { - planeMesh.shader = ShaderProgram.loadSpecificShader("Shaders/plane/plane.vs", "Shaders/plane/plane.fs"); + planeMesh.shader = ShaderProgram.loadSpecificShader(vertexShader,fragmentShader); planeMesh.hasBones = false; diff --git a/src/main/java/electrosphere/renderer/ui/Window.java b/src/main/java/electrosphere/renderer/ui/Window.java index 30d2301d..0967c247 100644 --- a/src/main/java/electrosphere/renderer/ui/Window.java +++ b/src/main/java/electrosphere/renderer/ui/Window.java @@ -67,7 +67,7 @@ public class Window implements DrawableElement, ContainerElement, NavigableEleme glBindFramebuffer(GL_FRAMEBUFFER, parentFramebufferPointer); Globals.renderingEngine.setViewportSize(parentWidth, parentHeight); - Model planeModel = Globals.assetManager.fetchModel(Globals.planeModelID); + Model planeModel = Globals.assetManager.fetchModel(Globals.imagePlaneModelID); if(planeModel != null){ planeModel.pushUniformToMesh("plane", "mPosition", boxPosition); planeModel.pushUniformToMesh("plane", "mDimension", boxDimensions); diff --git a/src/main/java/electrosphere/renderer/ui/elements/ScrollableContainer.java b/src/main/java/electrosphere/renderer/ui/elements/ScrollableContainer.java index 0bf39f1a..059fe69a 100644 --- a/src/main/java/electrosphere/renderer/ui/elements/ScrollableContainer.java +++ b/src/main/java/electrosphere/renderer/ui/elements/ScrollableContainer.java @@ -251,7 +251,7 @@ public class ScrollableContainer implements DrawableElement, ContainerElement { glBindFramebuffer(GL_FRAMEBUFFER, parentFramebufferPointer); Globals.renderingEngine.setViewportSize(parentWidth, parentHeight); - Model planeModel = Globals.assetManager.fetchModel(Globals.planeModelID); + Model planeModel = Globals.assetManager.fetchModel(Globals.imagePlaneModelID); if(planeModel != null){ planeModel.pushUniformToMesh("plane", "mPosition", boxPosition); planeModel.pushUniformToMesh("plane", "mDimension", boxDimensions); diff --git a/src/main/java/electrosphere/renderer/ui/elements/Slider.java b/src/main/java/electrosphere/renderer/ui/elements/Slider.java new file mode 100644 index 00000000..c6b2953f --- /dev/null +++ b/src/main/java/electrosphere/renderer/ui/elements/Slider.java @@ -0,0 +1,308 @@ +package electrosphere.renderer.ui.elements; + +import org.joml.Vector3f; + +import electrosphere.logger.LoggerInterface; +import electrosphere.main.Globals; +import electrosphere.renderer.Model; +import electrosphere.renderer.ui.ClickableElement; +import electrosphere.renderer.ui.DraggableElement; +import electrosphere.renderer.ui.DrawableElement; +import electrosphere.renderer.ui.FocusableElement; +import electrosphere.renderer.ui.KeyEventElement; +import electrosphere.renderer.ui.events.ClickEvent; +import electrosphere.renderer.ui.events.DragEvent; +import electrosphere.renderer.ui.events.Event; +import electrosphere.renderer.ui.events.FocusEvent; +import electrosphere.renderer.ui.events.KeyboardEvent; +import electrosphere.renderer.ui.events.MouseEvent; +import electrosphere.renderer.ui.events.DragEvent.DragEventType; + +public class Slider implements ClickableElement, DraggableElement, FocusableElement, DrawableElement, KeyEventElement { + + public int width = 1; + public int height = 1; + + public int positionX = 0; + public int positionY = 0; + + public int parentWidth = 1; + public int parentHeight = 1; + + public boolean visible = false; + + boolean focused = false; + FocusEventCallback onFocusCallback; + FocusEventCallback onLoseFocusCallback; + KeyboardEventCallback onKeyPressCallback; + DragEventCallback onDragStart; + DragEventCallback onDrag; + DragEventCallback onDragRelease; + ClickEventCallback onClick; + + float min = 0.0f; + float max = 1.0f; + float value = 0.5f; + + Vector3f colorBackground = new Vector3f(0,0,0); + Vector3f colorForeground = new Vector3f(1,1,1); + + + + static final int idealMargin = 5; //5 pixels margin ideally + + + + public Slider(int positionX, int positionY, int width, int height, Vector3f colorBackground, Vector3f colorForeground){ + this.positionX = positionX; + this.positionY = positionY; + this.width = width; + this.height = height; + this.colorBackground.set(colorBackground); + this.colorForeground.set(colorForeground); + } + + + + @Override + public void draw(int parentFramebufferPointer, int parentWidth, int parentHeight) { + + Globals.renderingEngine.bindFramebuffer(parentFramebufferPointer); + Globals.renderingEngine.setViewportSize(parentWidth, parentHeight); + + int marginX = Math.max(width - idealMargin * 2, 0); + if(marginX < idealMargin){ + marginX = 0; + } else { + marginX = idealMargin; + } + int marginY = Math.max(height - idealMargin * 2, 0); + if(marginY < idealMargin){ + marginY = 0; + } else { + marginY = idealMargin; + } + + + float ndcX = (float)positionX/parentWidth; + float ndcY = (float)positionY/parentHeight; + float ndcWidth = (float)width/parentWidth; + float ndcHeight = (float)height/parentHeight; + + Vector3f boxPosition = new Vector3f(ndcX,ndcY,0); + Vector3f boxDimensions = new Vector3f(ndcWidth,ndcHeight,0); + + + Model planeModel = Globals.assetManager.fetchModel(Globals.solidPlaneModelID); + if(planeModel != null){ + //bounding box/margin + planeModel.pushUniformToMesh("plane", "mPosition", boxPosition); + planeModel.pushUniformToMesh("plane", "mDimension", boxDimensions); + planeModel.pushUniformToMesh("plane", "tPosition", new Vector3f(0,0,0)); + planeModel.pushUniformToMesh("plane", "tDimension", new Vector3f(1,1,0)); + planeModel.pushUniformToMesh(planeModel.meshes.get(0).nodeID, "color", colorBackground); + planeModel.drawUI(); + + //actual slider + ndcX = (float)(positionX + marginX)/parentWidth; + ndcY = (float)(positionY + marginY)/parentHeight; + ndcWidth = (float)(width * value - marginX * 2)/parentWidth; + ndcHeight = (float)(height - marginY * 2)/parentHeight; + boxPosition = new Vector3f(ndcX,ndcY,0); + boxDimensions = new Vector3f(ndcWidth,ndcHeight,0); + planeModel.pushUniformToMesh("plane", "mPosition", boxPosition); + planeModel.pushUniformToMesh("plane", "mDimension", boxDimensions); + planeModel.pushUniformToMesh("plane", "tPosition", new Vector3f(0,0,0)); + planeModel.pushUniformToMesh("plane", "tDimension", new Vector3f(1,1,0)); + planeModel.pushUniformToMesh(planeModel.meshes.get(0).nodeID, "color", colorForeground); + planeModel.drawUI(); + } else { + LoggerInterface.loggerRenderer.ERROR("Window unable to find plane model!!", new Exception()); + } + } + + + + public float getMinimum(){ + return min; + } + + public void setMinimum(float min){ + this.min = min; + } + + public float getMaximum(){ + return max; + } + + public void setMaximum(float max){ + this.max = max; + } + + public float getValue(){ + return value; + } + + public void setValue(float value){ + this.value = value; + } + + public int getWidth() { + return width; + } + + public int getHeight() { + return height; + } + + public int getPositionX() { + return positionX; + } + + public int getPositionY() { + return positionY; + } + + public boolean getVisible() { + return visible; + } + + public void setWidth(int width) { + this.width = width; + } + + public void setHeight(int height) { + this.height = height; + } + + public void setPositionX(int posX) { + this.positionX = posX; + } + + public void setPositionY(int posY) { + this.positionY = posY; + } + + public void setVisible(boolean draw) { + this.visible = draw; + } + + public void setParentWidth(int width){ + parentWidth = width; + } + + public void setParentHeight(int height){ + this.parentHeight = height; + } + + @Override + public boolean isFocused() { + return focused; + } + + @Override + public void setOnFocus(FocusEventCallback callback) { + onFocusCallback = callback; + } + + @Override + public void setOnLoseFocus(FocusEventCallback callback) { + onLoseFocusCallback = callback; + } + + @Override + public void setOnPress(KeyboardEventCallback callback) { + onKeyPressCallback = callback; + } + + @Override + public void setOnDragStart(DragEventCallback callback) { + this.onDragStart = callback; + } + + @Override + public void setOnDrag(DragEventCallback callback) { + this.onDrag = callback; + } + + @Override + public void setOnDragRelease(DragEventCallback callback) { + this.onDragRelease = callback; + } + + @Override + public void setOnClick(ClickEventCallback callback) { + this.onClick = callback; + } + + + @Override + public boolean handleEvent(Event event) { + boolean propagate = true; + if(event instanceof FocusEvent){ + FocusEvent focusEvent = (FocusEvent)event; + if(focusEvent.isFocused()){ + if(this.onFocusCallback != null){ + propagate = this.onFocusCallback.execute(focusEvent); + } else { + //default behavior/ + propagate = true; + } + } else { + if(this.onLoseFocusCallback != null){ + propagate = this.onLoseFocusCallback.execute(focusEvent); + } else { + //default behavior + propagate = true; + } + } + } else if(event instanceof KeyboardEvent){ + KeyboardEvent keyEvent = (KeyboardEvent)event; + if(onKeyPressCallback != null){ + propagate = onKeyPressCallback.execute(keyEvent); + } else { + //default behavior + propagate = true; + } + } else if(event instanceof DragEvent){ + DragEvent dragEvent = (DragEvent) event; + if(dragEvent.getType() == DragEventType.START){ + if(onDragStart != null){ + propagate = onDragStart.execute(dragEvent); + } else { + //default behavior + propagate = true; + } + } else if(dragEvent.getType() == DragEventType.DRAG){ + if(onDrag != null){ + propagate = onDrag.execute(dragEvent); + } else { + //default behavior + propagate = false; + } + } else if(dragEvent.getType() == DragEventType.RELEASE){ + if(onDragRelease != null){ + propagate = onDragRelease.execute(dragEvent); + } else { + //default behavior + propagate = true; + } + } + } else if(event instanceof ClickEvent){ + ClickEvent clickEvent = (ClickEvent) event; + if(clickEvent.getButton1()){ + if(this.onClick != null){ + propagate = this.onClick.execute((ClickEvent)event); + } else { + //default behavior + int percentage = clickEvent.getCurrentX() - positionX; + int max = width; + value = Math.max(Math.min((float)percentage/max,1.0f),0.0f); + propagate = false; + } + } + } + return propagate; + } + +} diff --git a/src/main/java/electrosphere/renderer/ui/layout/LayoutSchemeListScrollable.java b/src/main/java/electrosphere/renderer/ui/layout/LayoutSchemeListScrollable.java index 38afd3d5..9cee8dc4 100644 --- a/src/main/java/electrosphere/renderer/ui/layout/LayoutSchemeListScrollable.java +++ b/src/main/java/electrosphere/renderer/ui/layout/LayoutSchemeListScrollable.java @@ -74,7 +74,7 @@ public class LayoutSchemeListScrollable implements DrawableElement,LayoutScheme aaaa = -1; } texPosition.y = aaaa; - Model planeModel = Globals.assetManager.fetchModel(Globals.planeModelID); + Model planeModel = Globals.assetManager.fetchModel(Globals.imagePlaneModelID); planeModel.pushUniformToMesh("plane", "mPosition", boxPosition); planeModel.pushUniformToMesh("plane", "mDimension", boxDimensions); planeModel.pushUniformToMesh("plane", "tPosition", texPosition);