Added FrameResizeEvent, refactored input events a little

This commit is contained in:
OLEGSHA 2020-08-03 22:41:07 +03:00
parent 7dee1eb95f
commit 4bd5411abb
18 changed files with 295 additions and 156 deletions

View File

@ -20,6 +20,10 @@ package ru.windcorp.optica.client.graphics;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import com.google.common.eventbus.Subscribe;
import ru.windcorp.optica.client.graphics.input.FrameResizeEvent;
public class GUI { public class GUI {
private static final List<Layer> LAYERS = new ArrayList<>(); private static final List<Layer> LAYERS = new ArrayList<>();
@ -44,4 +48,19 @@ public class GUI {
} }
} }
public static void invalidateEverything() {
LAYERS.forEach(Layer::invalidate);
}
public static Object getEventSubscriber() {
return new Object() {
@Subscribe
public void onFrameResized(FrameResizeEvent event) {
GUI.invalidateEverything();
}
};
}
} }

View File

@ -17,13 +17,18 @@
*******************************************************************************/ *******************************************************************************/
package ru.windcorp.optica.client.graphics; package ru.windcorp.optica.client.graphics;
import java.util.concurrent.atomic.AtomicBoolean;
import ru.windcorp.optica.client.graphics.backend.GraphicsInterface; import ru.windcorp.optica.client.graphics.backend.GraphicsInterface;
public abstract class Layer { public abstract class Layer {
private final String name; private final String name;
private boolean hasInitialized = false; private boolean hasInitialized = false;
private final AtomicBoolean isValid = new AtomicBoolean(false);
public Layer(String name) { public Layer(String name) {
this.name = name; this.name = name;
} }
@ -33,7 +38,9 @@ public abstract class Layer {
return "Layer " + name; return "Layer " + name;
} }
public void render() { void render() {
validate();
if (!hasInitialized) { if (!hasInitialized) {
initialize(); initialize();
hasInitialized = true; hasInitialized = true;
@ -42,16 +49,28 @@ public abstract class Layer {
doRender(); doRender();
} }
void validate() {
if (isValid.compareAndSet(false, true)) {
doValidate();
}
}
public void invalidate() {
isValid.set(false);
}
protected abstract void initialize(); protected abstract void initialize();
protected abstract void doValidate();
protected abstract void doRender(); protected abstract void doRender();
protected int getWidth() { protected int getWidth() {
return GraphicsInterface.getFramebufferWidth(); return GraphicsInterface.getFrameWidth();
} }
protected int getHeight() { protected int getHeight() {
return GraphicsInterface.getFramebufferHeight(); return GraphicsInterface.getFrameHeight();
} }
} }

View File

@ -18,6 +18,9 @@
package ru.windcorp.optica.client.graphics.backend; package ru.windcorp.optica.client.graphics.backend;
import static org.lwjgl.opengl.GL11.*; import static org.lwjgl.opengl.GL11.*;
import glm.vec._2.i.Vec2i;
import static org.lwjgl.glfw.GLFW.*; import static org.lwjgl.glfw.GLFW.*;
public class GraphicsBackend { public class GraphicsBackend {
@ -26,8 +29,7 @@ public class GraphicsBackend {
private static long windowHandle; private static long windowHandle;
private static int framebufferWidth; private static final Vec2i FRAME_SIZE = new Vec2i();
private static int framebufferHeight;
private static double frameLength = 1.0 / 60; // TODO do something about it private static double frameLength = 1.0 / 60; // TODO do something about it
private static int framesRendered = 0; private static int framesRendered = 0;
@ -56,21 +58,25 @@ public class GraphicsBackend {
return windowHandle; return windowHandle;
} }
public static int getFramebufferWidth() { public static int getFrameWidth() {
return framebufferWidth; return FRAME_SIZE.x;
} }
public static int getFramebufferHeight() { public static int getFrameHeight() {
return framebufferHeight; return FRAME_SIZE.y;
} }
static void onFramebufferResized(long window, int newWidth, int newHeight) { public static Vec2i getFrameSize() {
return FRAME_SIZE;
}
static void onFrameResized(long window, int newWidth, int newHeight) {
if (window != windowHandle) return; if (window != windowHandle) return;
framebufferWidth = newWidth; InputHandler.handleFrameResize(newWidth, newHeight);
framebufferHeight = newHeight; FRAME_SIZE.set(newWidth, newHeight);
glViewport(0, 0, framebufferWidth, framebufferHeight); glViewport(0, 0, newWidth, newHeight);
} }
static void startFrame() { static void startFrame() {

View File

@ -18,6 +18,7 @@
package ru.windcorp.optica.client.graphics.backend; package ru.windcorp.optica.client.graphics.backend;
import glm.vec._2.d.Vec2d; import glm.vec._2.d.Vec2d;
import glm.vec._2.i.Vec2i;
public class GraphicsInterface { public class GraphicsInterface {
@ -31,16 +32,20 @@ public class GraphicsInterface {
return Thread.currentThread() == getRenderThread(); return Thread.currentThread() == getRenderThread();
} }
public static int getFramebufferWidth() { public static int getFrameWidth() {
return GraphicsBackend.getFramebufferWidth(); return GraphicsBackend.getFrameWidth();
} }
public static int getFramebufferHeight() { public static int getFrameHeight() {
return GraphicsBackend.getFramebufferHeight(); return GraphicsBackend.getFrameHeight();
}
public static Vec2i getFrameSize() {
return GraphicsBackend.getFrameSize();
} }
public static float getAspectRatio() { public static float getAspectRatio() {
return ((float) getFramebufferWidth()) / getFramebufferHeight(); return ((float) getFrameWidth()) / getFrameHeight();
} }
public static double getTime() { public static double getTime() {

View File

@ -26,35 +26,16 @@ public class InputHandler {
private static final EventBus INPUT_EVENT_BUS = new EventBus("Input"); private static final EventBus INPUT_EVENT_BUS = new EventBus("Input");
// ScrollEvent
private static class ModifiableWheelScrollEvent extends WheelScrollEvent {
public void initialize(double xoffset, double yoffset) {
this.xOffset = xoffset;
this.yOffset = yoffset;
}
}
private static final ModifiableWheelScrollEvent THE_SCROLL_EVENT =
new ModifiableWheelScrollEvent();
static void handleMouseWheel(
long window,
double xoffset,
double yoffset
) {
if (GraphicsBackend.getWindowHandle() != window) return;
THE_SCROLL_EVENT.initialize(xoffset, yoffset);
dispatch(THE_SCROLL_EVENT);
}
// KeyEvent // KeyEvent
private static class ModifiableKeyEvent extends KeyEvent { private static class ModifiableKeyEvent extends KeyEvent {
protected ModifiableKeyEvent() {
super(0, 0, 0, 0, Double.NaN);
}
public void initialize(int key, int scancode, int action, int mods) { public void initialize(int key, int scancode, int action, int mods) {
this.setTime(GraphicsInterface.getTime());
this.key = key; this.key = key;
this.scancode = scancode; this.scancode = scancode;
this.action = action; this.action = action;
@ -82,15 +63,18 @@ public class InputHandler {
private static class ModifiableCursorMoveEvent extends CursorMoveEvent { private static class ModifiableCursorMoveEvent extends CursorMoveEvent {
protected ModifiableCursorMoveEvent() {
super(0, 0, Double.NaN);
}
public void initialize(double x, double y) { public void initialize(double x, double y) {
Vec2d newPos = getNewPosition(); this.setTime(GraphicsInterface.getTime());
newPos.x = x; getNewPosition().set(x, y);
newPos.y = y;
} }
} }
private static final Vec2d CURSOR_POSITION = new Vec2d().set( private static final Vec2d CURSOR_POSITION = new Vec2d(
Double.NaN, Double.NaN Double.NaN, Double.NaN
); );
@ -113,8 +97,6 @@ public class InputHandler {
CURSOR_POSITION.set(x, y); CURSOR_POSITION.set(x, y);
} }
// Misc
public static double getCursorX() { public static double getCursorX() {
return CURSOR_POSITION.x; return CURSOR_POSITION.x;
} }
@ -127,6 +109,65 @@ public class InputHandler {
return CURSOR_POSITION; return CURSOR_POSITION;
} }
// ScrollEvent
private static class ModifiableWheelScrollEvent extends WheelScrollEvent {
public ModifiableWheelScrollEvent() {
super(0, 0, Double.NaN);
}
public void initialize(double xOffset, double yOffset) {
this.setTime(GraphicsInterface.getTime());
this.getOffset().set(xOffset, yOffset);
}
}
private static final ModifiableWheelScrollEvent THE_WHEEL_SCROLL_EVENT =
new ModifiableWheelScrollEvent();
static void handleWheelScroll(
long window,
double xoffset,
double yoffset
) {
if (GraphicsBackend.getWindowHandle() != window) return;
THE_WHEEL_SCROLL_EVENT.initialize(xoffset, yoffset);
dispatch(THE_WHEEL_SCROLL_EVENT);
}
// FrameResizeEvent
private static class ModifiableFrameResizeEvent extends FrameResizeEvent {
public ModifiableFrameResizeEvent() {
super(0, 0, Double.NaN);
}
public void initialize(int width, int height) {
this.setTime(GraphicsInterface.getTime());
this.getNewSize().set(width, height);
}
}
private static final ModifiableFrameResizeEvent THE_FRAME_RESIZE_EVENT =
new ModifiableFrameResizeEvent();
/*
* NB: this is NOT a GLFW callback, the raw callback is in GraphicsBackend
*/
static void handleFrameResize(
int width,
int height
) {
THE_FRAME_RESIZE_EVENT.initialize(width, height);
dispatch(THE_FRAME_RESIZE_EVENT);
}
// Misc
private static void dispatch(InputEvent event) { private static void dispatch(InputEvent event) {
INPUT_EVENT_BUS.post(event); INPUT_EVENT_BUS.post(event);
} }

View File

@ -23,6 +23,8 @@ import static org.lwjgl.system.MemoryUtil.*;
import org.lwjgl.opengl.GL; import org.lwjgl.opengl.GL;
import ru.windcorp.optica.client.graphics.GUI;
class LWJGLInitializer { class LWJGLInitializer {
private LWJGLInitializer() {} private LWJGLInitializer() {}
@ -88,12 +90,14 @@ class LWJGLInitializer {
long handle = GraphicsBackend.getWindowHandle(); long handle = GraphicsBackend.getWindowHandle();
glfwSetFramebufferSizeCallback(handle, glfwSetFramebufferSizeCallback(handle,
GraphicsBackend::onFramebufferResized); GraphicsBackend::onFrameResized);
glfwSetKeyCallback(handle, InputHandler::handleKeyInput); glfwSetKeyCallback(handle, InputHandler::handleKeyInput);
glfwSetCursorPosCallback(handle, InputHandler::handleMouseMoveInput); glfwSetCursorPosCallback(handle, InputHandler::handleMouseMoveInput);
glfwSetScrollCallback(handle, InputHandler::handleMouseWheel); glfwSetScrollCallback(handle, InputHandler::handleWheelScroll);
GraphicsInterface.subscribeToInputEvents(GUI.getEventSubscriber());
} }
} }

View File

@ -26,7 +26,6 @@ public abstract class AssembledFlatLayer extends Layer {
private final RenderTarget target = new RenderTarget(); private final RenderTarget target = new RenderTarget();
private boolean needsReassembly = true;
private RenderTarget.Clip[] clips = null; private RenderTarget.Clip[] clips = null;
public AssembledFlatLayer(String name) { public AssembledFlatLayer(String name) {
@ -39,24 +38,16 @@ public abstract class AssembledFlatLayer extends Layer {
} }
public void markForReassembly() { @Override
needsReassembly = true; protected void doValidate() {
}
private void doReassemble() {
assemble(target); assemble(target);
clips = target.assemble(); clips = target.assemble();
needsReassembly = false;
} }
protected abstract void assemble(RenderTarget target); protected abstract void assemble(RenderTarget target);
@Override @Override
protected void doRender() { protected void doRender() {
if (needsReassembly) {
doReassemble();
}
for (RenderTarget.Clip clip : clips) { for (RenderTarget.Clip clip : clips) {
clip.render(helper); clip.render(helper);
} }

View File

@ -33,8 +33,8 @@ public abstract class FlatRenderHelper extends ShapeRenderHelper {
@Override @Override
public Mat4 getFinalTransform() { public Mat4 getFinalTransform() {
float width = GraphicsInterface.getFramebufferWidth(); float width = GraphicsInterface.getFrameWidth();
float height = GraphicsInterface.getFramebufferHeight(); float height = GraphicsInterface.getFrameHeight();
return finalTransform.identity().translate(-1, +1, 0) return finalTransform.identity().translate(-1, +1, 0)
.scale(2 / width, -2 / height, 1 / MAX_DEPTH) .scale(2 / width, -2 / height, 1 / MAX_DEPTH)

View File

@ -133,7 +133,7 @@ public class LayerTestUI extends AssembledFlatLayer {
} }
flag = event.isPress(); flag = event.isPress();
markForReassembly(); invalidate();
} }
/* /*

View File

@ -106,7 +106,7 @@ public class TransformedMask {
} }
private void flipY() { private void flipY() {
float height = GraphicsInterface.getFramebufferHeight(); float height = GraphicsInterface.getFrameHeight();
startXstartY.y = height - startXstartY.y; startXstartY.y = height - startXstartY.y;
startXendY.y = height - startXendY.y; startXendY.y = height - startXendY.y;

View File

@ -22,6 +22,10 @@ import ru.windcorp.optica.client.graphics.backend.GraphicsInterface;
public abstract class CursorEvent extends InputEvent { public abstract class CursorEvent extends InputEvent {
public CursorEvent(double time) {
super(time);
}
public double getCursorX() { public double getCursorX() {
return GraphicsInterface.getCursorX(); return GraphicsInterface.getCursorX();
} }

View File

@ -24,12 +24,13 @@ public class CursorMoveEvent extends CursorEvent {
private final Vec2d newPosition = new Vec2d(); private final Vec2d newPosition = new Vec2d();
protected CursorMoveEvent(double newX, double newY) { protected CursorMoveEvent(double newX, double newY, double time) {
super(time);
newPosition.set(newX, newY); newPosition.set(newX, newY);
} }
protected CursorMoveEvent(Vec2d newPos) { protected CursorMoveEvent(Vec2d newPos, double time) {
newPosition.set(newPos.x, newPos.y); this(newPos.x, newPos.y, time);
} }
@Override @Override
@ -83,8 +84,6 @@ public class CursorMoveEvent extends CursorEvent {
return result.set(getChangeX(), getChangeY()); return result.set(getChangeX(), getChangeY());
} }
protected CursorMoveEvent() {}
@Override @Override
public CursorMoveEvent snapshot() { public CursorMoveEvent snapshot() {
return new StaticMouseMoveEvent( return new StaticMouseMoveEvent(
@ -96,7 +95,6 @@ public class CursorMoveEvent extends CursorEvent {
private class StaticMouseMoveEvent extends CursorMoveEvent { private class StaticMouseMoveEvent extends CursorMoveEvent {
private final double time;
private final Vec2d previousPosition = new Vec2d(); private final Vec2d previousPosition = new Vec2d();
public StaticMouseMoveEvent( public StaticMouseMoveEvent(
@ -104,9 +102,8 @@ public class CursorMoveEvent extends CursorEvent {
Vec2d newPosition, Vec2d newPosition,
double time double time
) { ) {
super(newPosition); super(newPosition, time);
this.previousPosition.set(previousPosition.x, previousPosition.y); this.previousPosition.set(previousPosition.x, previousPosition.y);
this.time = time;
} }
@Override @Override
@ -114,16 +111,6 @@ public class CursorMoveEvent extends CursorEvent {
return previousPosition; return previousPosition;
} }
@Override
public double getTime() {
return time;
}
@Override
public CursorMoveEvent snapshot() {
return this;
}
} }
} }

View File

@ -0,0 +1,85 @@
/*******************************************************************************
* Optica
* Copyright (C) 2020 Wind Corporation
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.optica.client.graphics.input;
import glm.vec._2.i.Vec2i;
import ru.windcorp.optica.client.graphics.backend.GraphicsInterface;
public class FrameResizeEvent extends InputEvent {
private final Vec2i newSize = new Vec2i();
protected FrameResizeEvent(int newWidth, int newHeight, double time) {
super(time);
this.newSize.set(newWidth, newHeight);
}
protected FrameResizeEvent(Vec2i newSize, double time) {
this(newSize.x, newSize.y, time);
}
public int getNewWidth() {
return getNewSize().x;
}
public int getNewHeight() {
return getNewSize().y;
}
public Vec2i getNewSize() {
return newSize;
}
public int getPreviousWidth() {
return getPreviousSize().x;
}
public int getPreviousHeight() {
return getPreviousSize().y;
}
public Vec2i getPreviousSize() {
return GraphicsInterface.getFrameSize();
}
@Override
public FrameResizeEvent snapshot() {
return new StaticFrameResizeEvent(getNewSize(), getPreviousSize(), getTime());
}
private static class StaticFrameResizeEvent extends FrameResizeEvent {
private final Vec2i previousSize;
public StaticFrameResizeEvent(
Vec2i newSize,
Vec2i previousSize,
double time
) {
super(newSize, time);
this.previousSize = previousSize;
}
@Override
public Vec2i getPreviousSize() {
return previousSize;
}
}
}

View File

@ -17,12 +17,20 @@
*******************************************************************************/ *******************************************************************************/
package ru.windcorp.optica.client.graphics.input; package ru.windcorp.optica.client.graphics.input;
import ru.windcorp.optica.client.graphics.backend.GraphicsInterface;
public abstract class InputEvent { public abstract class InputEvent {
private double time;
public InputEvent(double time) {
this.time = time;
}
protected void setTime(double time) {
this.time = time;
}
public double getTime() { public double getTime() {
return GraphicsInterface.getTime(); return time;
} }
public abstract InputEvent snapshot(); public abstract InputEvent snapshot();

View File

@ -26,15 +26,16 @@ public class KeyEvent extends InputEvent {
protected int action; protected int action;
protected int mods; protected int mods;
protected KeyEvent(int key, int scancode, int action, int mods) { protected KeyEvent(
int key, int scancode, int action, int mods, double time
) {
super(time);
this.key = key; this.key = key;
this.scancode = scancode; this.scancode = scancode;
this.action = action; this.action = action;
this.mods = mods; this.mods = mods;
} }
protected KeyEvent() {}
public int getKey() { public int getKey() {
return key; return key;
} }
@ -64,32 +65,8 @@ public class KeyEvent extends InputEvent {
} }
@Override @Override
public InputEvent snapshot() { public KeyEvent snapshot() {
return new StaticKeyEvent(key, scancode, action, mods, getTime()); return new KeyEvent(key, scancode, action, mods, getTime());
}
private class StaticKeyEvent extends KeyEvent {
private final double time;
public StaticKeyEvent(
int key, int scancode, int action, int mods,
double time
) {
super(key, scancode, action, mods);
this.time = time;
}
@Override
public double getTime() {
return time;
}
@Override
public InputEvent snapshot() {
return this;
}
} }
} }

View File

@ -19,7 +19,11 @@ package ru.windcorp.optica.client.graphics.input;
public abstract class WheelEvent extends InputEvent { public abstract class WheelEvent extends InputEvent {
@Override public WheelEvent(double time) {
super(time);
}
@Override
public abstract WheelEvent snapshot(); public abstract WheelEvent snapshot();
} }

View File

@ -17,75 +17,59 @@
*******************************************************************************/ *******************************************************************************/
package ru.windcorp.optica.client.graphics.input; package ru.windcorp.optica.client.graphics.input;
import glm.vec._2.d.Vec2d;
public class WheelScrollEvent extends WheelEvent { public class WheelScrollEvent extends WheelEvent {
protected double xOffset; private final Vec2d offset = new Vec2d();
protected double yOffset;
protected WheelScrollEvent(double xOffset, double yOffset) { protected WheelScrollEvent(double xOffset, double yOffset, double time) {
this.xOffset = xOffset; super(time);
this.yOffset = yOffset; this.offset.set(xOffset, yOffset);
} }
protected WheelScrollEvent() {} protected WheelScrollEvent(Vec2d offset, double time) {
this(offset.x, offset.y, time);
}
public boolean isUp() { public boolean isUp() {
return yOffset > 0; return getY() > 0;
} }
public boolean isDown() { public boolean isDown() {
return yOffset < 0; return getY() < 0;
} }
public boolean isRight() { public boolean isRight() {
return xOffset > 0; return getX() > 0;
} }
public boolean isLeft() { public boolean isLeft() {
return xOffset < 0; return getX() < 0;
} }
public boolean hasVerticalMovement() { public boolean hasVerticalMovement() {
return yOffset != 0; return getY() != 0;
} }
public boolean hasHorizontalMovement() { public boolean hasHorizontalMovement() {
return xOffset != 0; return getX() != 0;
} }
public double getX() { public double getX() {
return xOffset; return getOffset().x;
} }
public double getY() { public double getY() {
return yOffset; return getOffset().y;
} }
public Vec2d getOffset() {
return offset;
}
@Override @Override
public WheelEvent snapshot() { public WheelEvent snapshot() {
return new StaticWheelScrollEvent(xOffset, yOffset, getTime()); return new WheelScrollEvent(getOffset(), getTime());
}
private class StaticWheelScrollEvent extends WheelScrollEvent {
private final double time;
public StaticWheelScrollEvent(
double xOffset, double yOffset, double time
) {
super(xOffset, yOffset);
this.time = time;
}
@Override
public double getTime() {
return time;
}
@Override
public WheelEvent snapshot() {
return this;
}
} }
} }

View File

@ -70,6 +70,11 @@ public class LayerWorld extends Layer {
GraphicsInterface.subscribeToInputEvents(this); GraphicsInterface.subscribeToInputEvents(this);
} }
@Override
protected void doValidate() {
// Do nothing
}
@Override @Override
protected void doRender() { protected void doRender() {
camera.apply(helper); camera.apply(helper);