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.List;
import com.google.common.eventbus.Subscribe;
import ru.windcorp.optica.client.graphics.input.FrameResizeEvent;
public class GUI {
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;
import java.util.concurrent.atomic.AtomicBoolean;
import ru.windcorp.optica.client.graphics.backend.GraphicsInterface;
public abstract class Layer {
private final String name;
private boolean hasInitialized = false;
private final AtomicBoolean isValid = new AtomicBoolean(false);
public Layer(String name) {
this.name = name;
}
@ -33,7 +38,9 @@ public abstract class Layer {
return "Layer " + name;
}
public void render() {
void render() {
validate();
if (!hasInitialized) {
initialize();
hasInitialized = true;
@ -42,16 +49,28 @@ public abstract class Layer {
doRender();
}
void validate() {
if (isValid.compareAndSet(false, true)) {
doValidate();
}
}
public void invalidate() {
isValid.set(false);
}
protected abstract void initialize();
protected abstract void doValidate();
protected abstract void doRender();
protected int getWidth() {
return GraphicsInterface.getFramebufferWidth();
return GraphicsInterface.getFrameWidth();
}
protected int getHeight() {
return GraphicsInterface.getFramebufferHeight();
return GraphicsInterface.getFrameHeight();
}
}

View File

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

View File

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

View File

@ -26,35 +26,16 @@ public class InputHandler {
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
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) {
this.setTime(GraphicsInterface.getTime());
this.key = key;
this.scancode = scancode;
this.action = action;
@ -82,15 +63,18 @@ public class InputHandler {
private static class ModifiableCursorMoveEvent extends CursorMoveEvent {
protected ModifiableCursorMoveEvent() {
super(0, 0, Double.NaN);
}
public void initialize(double x, double y) {
Vec2d newPos = getNewPosition();
newPos.x = x;
newPos.y = y;
this.setTime(GraphicsInterface.getTime());
getNewPosition().set(x, y);
}
}
private static final Vec2d CURSOR_POSITION = new Vec2d().set(
private static final Vec2d CURSOR_POSITION = new Vec2d(
Double.NaN, Double.NaN
);
@ -113,8 +97,6 @@ public class InputHandler {
CURSOR_POSITION.set(x, y);
}
// Misc
public static double getCursorX() {
return CURSOR_POSITION.x;
}
@ -127,6 +109,65 @@ public class InputHandler {
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) {
INPUT_EVENT_BUS.post(event);
}

View File

@ -23,6 +23,8 @@ import static org.lwjgl.system.MemoryUtil.*;
import org.lwjgl.opengl.GL;
import ru.windcorp.optica.client.graphics.GUI;
class LWJGLInitializer {
private LWJGLInitializer() {}
@ -88,12 +90,14 @@ class LWJGLInitializer {
long handle = GraphicsBackend.getWindowHandle();
glfwSetFramebufferSizeCallback(handle,
GraphicsBackend::onFramebufferResized);
GraphicsBackend::onFrameResized);
glfwSetKeyCallback(handle, InputHandler::handleKeyInput);
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 boolean needsReassembly = true;
private RenderTarget.Clip[] clips = null;
public AssembledFlatLayer(String name) {
@ -39,24 +38,16 @@ public abstract class AssembledFlatLayer extends Layer {
}
public void markForReassembly() {
needsReassembly = true;
}
private void doReassemble() {
@Override
protected void doValidate() {
assemble(target);
clips = target.assemble();
needsReassembly = false;
}
protected abstract void assemble(RenderTarget target);
@Override
protected void doRender() {
if (needsReassembly) {
doReassemble();
}
for (RenderTarget.Clip clip : clips) {
clip.render(helper);
}

View File

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

View File

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

View File

@ -106,7 +106,7 @@ public class TransformedMask {
}
private void flipY() {
float height = GraphicsInterface.getFramebufferHeight();
float height = GraphicsInterface.getFrameHeight();
startXstartY.y = height - startXstartY.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 CursorEvent(double time) {
super(time);
}
public double getCursorX() {
return GraphicsInterface.getCursorX();
}

View File

@ -24,12 +24,13 @@ public class CursorMoveEvent extends CursorEvent {
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);
}
protected CursorMoveEvent(Vec2d newPos) {
newPosition.set(newPos.x, newPos.y);
protected CursorMoveEvent(Vec2d newPos, double time) {
this(newPos.x, newPos.y, time);
}
@Override
@ -83,8 +84,6 @@ public class CursorMoveEvent extends CursorEvent {
return result.set(getChangeX(), getChangeY());
}
protected CursorMoveEvent() {}
@Override
public CursorMoveEvent snapshot() {
return new StaticMouseMoveEvent(
@ -96,7 +95,6 @@ public class CursorMoveEvent extends CursorEvent {
private class StaticMouseMoveEvent extends CursorMoveEvent {
private final double time;
private final Vec2d previousPosition = new Vec2d();
public StaticMouseMoveEvent(
@ -104,9 +102,8 @@ public class CursorMoveEvent extends CursorEvent {
Vec2d newPosition,
double time
) {
super(newPosition);
super(newPosition, time);
this.previousPosition.set(previousPosition.x, previousPosition.y);
this.time = time;
}
@Override
@ -114,16 +111,6 @@ public class CursorMoveEvent extends CursorEvent {
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;
import ru.windcorp.optica.client.graphics.backend.GraphicsInterface;
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() {
return GraphicsInterface.getTime();
return time;
}
public abstract InputEvent snapshot();

View File

@ -26,15 +26,16 @@ public class KeyEvent extends InputEvent {
protected int action;
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.scancode = scancode;
this.action = action;
this.mods = mods;
}
protected KeyEvent() {}
public int getKey() {
return key;
}
@ -64,32 +65,8 @@ public class KeyEvent extends InputEvent {
}
@Override
public InputEvent snapshot() {
return new StaticKeyEvent(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;
}
public KeyEvent snapshot() {
return new KeyEvent(key, scancode, action, mods, getTime());
}
}

View File

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

View File

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

View File

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