fully abstract glfw window

This commit is contained in:
Bixilon 2021-06-20 13:23:21 +02:00
parent b7fa34dc24
commit 8907adb032
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
9 changed files with 194 additions and 66 deletions

View File

@ -16,6 +16,7 @@ package de.bixilon.minosoft.config.key
import org.lwjgl.glfw.GLFW.*
import java.util.*
// ToDo: Replace glfwKeyIds
enum class KeyCodes(val glfwKeyId: Int) {
KEY_UNKNOWN(GLFW_KEY_UNKNOWN),
KEY_SPACE(GLFW_KEY_SPACE),

View File

@ -25,13 +25,13 @@ import de.bixilon.minosoft.gui.rendering.hud.HUDRenderer
import de.bixilon.minosoft.gui.rendering.hud.atlas.TextureLike
import de.bixilon.minosoft.gui.rendering.hud.atlas.TextureLikeTexture
import de.bixilon.minosoft.gui.rendering.input.key.RenderWindowInputHandler
import de.bixilon.minosoft.gui.rendering.modding.events.RenderingStateChangeEvent
import de.bixilon.minosoft.gui.rendering.modding.events.ResizeWindowEvent
import de.bixilon.minosoft.gui.rendering.modding.events.*
import de.bixilon.minosoft.gui.rendering.particle.ParticleRenderer
import de.bixilon.minosoft.gui.rendering.shader.Shader
import de.bixilon.minosoft.gui.rendering.sky.SkyRenderer
import de.bixilon.minosoft.gui.rendering.system.base.RenderSystem
import de.bixilon.minosoft.gui.rendering.system.opengl.OpenGLRenderSystem
import de.bixilon.minosoft.gui.rendering.system.window.BaseWindow
import de.bixilon.minosoft.gui.rendering.system.window.GLFWWindow
import de.bixilon.minosoft.gui.rendering.textures.Texture
import de.bixilon.minosoft.gui.rendering.textures.TextureArray
@ -42,6 +42,7 @@ import de.bixilon.minosoft.protocol.network.connection.PlayConnection
import de.bixilon.minosoft.protocol.packets.s2c.play.PositionAndRotationS2CP
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
import de.bixilon.minosoft.util.CountUpAndDownLatch
import de.bixilon.minosoft.util.KUtil.decide
import de.bixilon.minosoft.util.KUtil.synchronizedMapOf
import de.bixilon.minosoft.util.Queue
import de.bixilon.minosoft.util.Stopwatch
@ -49,17 +50,13 @@ import de.bixilon.minosoft.util.logging.Log
import de.bixilon.minosoft.util.logging.LogMessageType
import glm_.vec2.Vec2
import glm_.vec2.Vec2i
import org.lwjgl.glfw.Callbacks
import org.lwjgl.glfw.GLFW.*
import org.lwjgl.glfw.GLFWWindowFocusCallback
import org.lwjgl.glfw.GLFWWindowIconifyCallback
import org.lwjgl.opengl.GL11.*
class RenderWindow(
val connection: PlayConnection,
val rendering: Rendering,
) {
val window = GLFWWindow(connection)
val window: BaseWindow = GLFWWindow(connection)
val renderSystem: RenderSystem = OpenGLRenderSystem(this)
var initialized = false
private set
@ -70,9 +67,6 @@ class RenderWindow(
val screenDimensions
get() = window.size
@Deprecated(message = "", replaceWith = ReplaceWith("window.sizef"))
val screenDimensionsF: Vec2
get() = window.sizef
val inputHandler = RenderWindowInputHandler(this)
private var deltaFrameTime = 0.0
@ -144,7 +138,6 @@ class RenderWindow(
tintColorCalculator.init(connection.assetsManager)
Log.log(LogMessageType.RENDERING_LOADING) { "Creating context (${stopwatch.labTime()})..." }
renderSystem.init()
@ -188,26 +181,14 @@ class RenderWindow(
}
Log.log(LogMessageType.RENDERING_LOADING) { "Registering glfw callbacks (${stopwatch.labTime()})..." }
Log.log(LogMessageType.RENDERING_LOADING) { "Registering window callbacks (${stopwatch.labTime()})..." }
glfwSetWindowFocusCallback(window.window, object : GLFWWindowFocusCallback() {
override fun invoke(window: Long, focused: Boolean) {
setRenderStatus(if (focused) {
RenderingStates.RUNNING
} else {
RenderingStates.SLOW
})
}
connection.registerEvent(CallbackEventInvoker.of<WindowFocusChangeEvent> {
setRenderStatus(it.focused.decide(RenderingStates.RUNNING, RenderingStates.SLOW))
})
glfwSetWindowIconifyCallback(window.window, object : GLFWWindowIconifyCallback() {
override fun invoke(window: Long, iconified: Boolean) {
setRenderStatus(if (iconified) {
RenderingStates.PAUSED
} else {
RenderingStates.RUNNING
})
}
connection.registerEvent(CallbackEventInvoker.of<WindowIconifyChangeEvent> {
setRenderStatus(it.iconified.decide(RenderingStates.PAUSED, RenderingStates.RUNNING))
})
@ -237,7 +218,7 @@ class RenderWindow(
sendDebugMessage("Toggled polygon mode!")
}
inputHandler.registerKeyCallback(KeyBindingsNames.QUIT_RENDERING) { glfwSetWindowShouldClose(window.window, true) }
inputHandler.registerKeyCallback(KeyBindingsNames.QUIT_RENDERING) { window.close() }
inputHandler.registerKeyCallback(KeyBindingsNames.TAKE_SCREENSHOT) { screenshotTaker.takeScreenshot() }
inputHandler.registerKeyCallback(KeyBindingsNames.DEBUG_PAUSE_INCOMING_PACKETS) {
@ -252,17 +233,22 @@ class RenderWindow(
fun startLoop() {
Log.log(LogMessageType.RENDERING_LOADING) { "Starting loop" }
while (!glfwWindowShouldClose(window.window)) {
if (connection.wasConnected) {
var closed = false
connection.registerEvent(CallbackEventInvoker.of<WindowCloseEvent> {
closed = true
})
while (true) {
if (connection.wasConnected || closed) {
break
}
if (renderingState == RenderingStates.PAUSED) {
Thread.sleep(100L)
glfwPollEvents()
window.pollEvents()
continue
}
renderStats.startFrame()
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT) // clear the framebuffer
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT)
val currentTickTime = System.currentTimeMillis()
@ -272,7 +258,7 @@ class RenderWindow(
this.lastTickTimer = currentTickTime
}
val currentFrame = glfwGetTime()
val currentFrame = window.time
deltaFrameTime = currentFrame - lastFrame
lastFrame = currentFrame
@ -293,8 +279,9 @@ class RenderWindow(
renderStats.endDraw()
glfwSwapBuffers(window.window)
glfwPollEvents()
window.swapBuffers()
window.pollEvents()
inputHandler.draw(deltaFrameTime)
// handle opengl context tasks, but limit it per frame
@ -304,26 +291,17 @@ class RenderWindow(
RenderingStates.SLOW -> Thread.sleep(100L)
RenderingStates.RUNNING, RenderingStates.PAUSED -> {
}
RenderingStates.STOPPED -> glfwSetWindowShouldClose(window.window, true)
RenderingStates.STOPPED -> window.close()
}
renderStats.endFrame()
if (RenderConstants.SHOW_FPS_IN_WINDOW_TITLE) {
glfwSetWindowTitle(window.window, "Minosoft | FPS: ${renderStats.fpsLastSecond}")
window.title = "Minosoft | FPS: ${renderStats.fpsLastSecond}"
}
}
}
fun exit() {
Log.log(LogMessageType.RENDERING_LOADING) { "Destroying render window..." }
// Free the window callbacks and destroy the window
Callbacks.glfwFreeCallbacks(window.window)
glfwDestroyWindow(window.window)
// Terminate GLFW and free the error callback
glfwTerminate()
glfwSetErrorCallback(null)!!.free()
window.destroy()
Log.log(LogMessageType.RENDERING_LOADING) { "Render window destroyed!" }
// disconnect
connection.disconnect()
@ -350,8 +328,9 @@ class RenderWindow(
connection.sender.sendFakeChatMessage(RenderConstants.DEBUG_MESSAGES_PREFIX + message)
}
@Deprecated(message = "", replaceWith = ReplaceWith("window.clipboardText"))
fun getClipboardText(): String {
return glfwGetClipboardString(window.window) ?: ""
return window.clipboardText
}
fun assertOnRenderThread() {

View File

@ -14,6 +14,7 @@
package de.bixilon.minosoft.gui.rendering
import de.bixilon.minosoft.Minosoft
import de.bixilon.minosoft.gui.rendering.modding.events.WindowCloseEvent
import de.bixilon.minosoft.gui.rendering.sound.AudioPlayer
import de.bixilon.minosoft.protocol.network.connection.PlayConnection
import de.bixilon.minosoft.util.CountUpAndDownLatch
@ -60,12 +61,11 @@ class Rendering(private val connection: PlayConnection) {
CONTEXT_MAP[Thread.currentThread()] = renderWindow
renderWindow.init(latch)
renderWindow.startLoop()
renderWindow.exit()
} catch (exception: Throwable) {
CONTEXT_MAP.remove(Thread.currentThread())
exception.printStackTrace()
try {
renderWindow.exit()
connection.fireEvent(WindowCloseEvent(window = renderWindow.window))
} catch (ignored: Throwable) {
}
if (connection.connectionState.connected) {

View File

@ -27,10 +27,11 @@ import de.bixilon.minosoft.gui.rendering.input.camera.Camera
import de.bixilon.minosoft.gui.rendering.modding.events.MouseMoveEvent
import de.bixilon.minosoft.gui.rendering.modding.events.RawCharInputEvent
import de.bixilon.minosoft.gui.rendering.modding.events.RawKeyInputEvent
import de.bixilon.minosoft.gui.rendering.system.window.CursorModes
import de.bixilon.minosoft.gui.rendering.system.window.KeyChangeTypes
import de.bixilon.minosoft.modding.event.CallbackEventInvoker
import de.bixilon.minosoft.protocol.network.connection.PlayConnection
import org.lwjgl.glfw.GLFW.*
import de.bixilon.minosoft.util.KUtil.decide
class RenderWindowInputHandler(
val renderWindow: RenderWindow,
@ -50,12 +51,7 @@ class RenderWindowInputHandler(
init {
registerKeyCallback(KeyBindingsNames.DEBUG_MOUSE_CATCH) {
val newCursorMode = if (it) {
GLFW_CURSOR_DISABLED
} else {
GLFW_CURSOR_NORMAL
}
glfwSetInputMode(renderWindow.window.window, GLFW_CURSOR, newCursorMode)
renderWindow.window.cursorMode = it.decide(CursorModes.DISABLED, CursorModes.NORMAL)
renderWindow.sendDebugMessage("Toggled mouse catch!")
}
}

View File

@ -0,0 +1,23 @@
/*
* Minosoft
* Copyright (C) 2021 Moritz Zwerger
*
* 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/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.gui.rendering.modding.events
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.Rendering
import de.bixilon.minosoft.gui.rendering.system.window.BaseWindow
class WindowCloseEvent(
renderWindow: RenderWindow = Rendering.currentContext!!,
val window: BaseWindow,
) : RenderEvent(renderWindow)

View File

@ -0,0 +1,24 @@
/*
* Minosoft
* Copyright (C) 2021 Moritz Zwerger
*
* 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/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.gui.rendering.modding.events
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.Rendering
import de.bixilon.minosoft.gui.rendering.system.window.BaseWindow
class WindowFocusChangeEvent(
renderWindow: RenderWindow = Rendering.currentContext!!,
val window: BaseWindow,
val focused: Boolean,
) : RenderEvent(renderWindow)

View File

@ -0,0 +1,24 @@
/*
* Minosoft
* Copyright (C) 2021 Moritz Zwerger
*
* 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/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.gui.rendering.modding.events
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.Rendering
import de.bixilon.minosoft.gui.rendering.system.window.BaseWindow
class WindowIconifyChangeEvent(
renderWindow: RenderWindow = Rendering.currentContext!!,
val window: BaseWindow,
val iconified: Boolean,
) : RenderEvent(renderWindow)

View File

@ -32,6 +32,13 @@ interface BaseWindow {
var cursorMode: CursorModes
var clipboardText: String
var title: String
val version: String
val time: Double
fun init() {
resizable = true
swapInterval = Minosoft.config.config.game.other.swapInterval
@ -44,8 +51,13 @@ interface BaseWindow {
maxSize = DEFAULT_MAXIMUM_WINDOW_SIZE
}
fun destroy()
fun close()
fun swapBuffers()
fun pollEvents()
companion object {
val DEFAULT_WINDOW_SIZE: Vec2i

View File

@ -14,10 +14,7 @@
package de.bixilon.minosoft.gui.rendering.system.window
import de.bixilon.minosoft.config.key.KeyCodes
import de.bixilon.minosoft.gui.rendering.modding.events.MouseMoveEvent
import de.bixilon.minosoft.gui.rendering.modding.events.RawCharInputEvent
import de.bixilon.minosoft.gui.rendering.modding.events.RawKeyInputEvent
import de.bixilon.minosoft.gui.rendering.modding.events.ResizeWindowEvent
import de.bixilon.minosoft.gui.rendering.modding.events.*
import de.bixilon.minosoft.gui.rendering.system.window.BaseWindow.Companion.DEFAULT_MAXIMUM_WINDOW_SIZE
import de.bixilon.minosoft.gui.rendering.system.window.BaseWindow.Companion.DEFAULT_MINIMUM_WINDOW_SIZE
import de.bixilon.minosoft.gui.rendering.system.window.BaseWindow.Companion.DEFAULT_WINDOW_SIZE
@ -27,6 +24,7 @@ import de.bixilon.minosoft.util.logging.LogLevels
import de.bixilon.minosoft.util.logging.LogMessageType
import glm_.vec2.Vec2d
import glm_.vec2.Vec2i
import org.lwjgl.glfw.Callbacks.glfwFreeCallbacks
import org.lwjgl.glfw.GLFW.*
import org.lwjgl.glfw.GLFWErrorCallback
import org.lwjgl.system.MemoryUtil
@ -34,8 +32,7 @@ import org.lwjgl.system.MemoryUtil
class GLFWWindow(
private val eventMaster: EventMaster,
) : BaseWindow {
@Deprecated("Will be private soon")
var window = -1L
private var window = -1L
override var cursorMode: CursorModes = CursorModes.NORMAL
set(value) {
@ -97,6 +94,27 @@ class GLFWWindow(
field = value
}
override var clipboardText: String
get() = glfwGetClipboardString(window) ?: ""
set(value) {
glfwSetClipboardString(window, value)
}
override val version: String
get() = glfwGetVersionString()
override val time: Double
get() = glfwGetTime()
override var title: String = "Window"
set(value) {
if (field == value) {
return
}
glfwSetWindowTitle(window, value)
field = value
}
override fun init() {
GLFWErrorCallback.createPrint(System.err).set()
check(glfwInit()) { "Unable to initialize GLFW" }
@ -110,7 +128,7 @@ class GLFWWindow(
window = glfwCreateWindow(size.x, size.y, "Minosoft", MemoryUtil.NULL, MemoryUtil.NULL)
if (window == MemoryUtil.NULL) {
close()
destroy()
throw RuntimeException("Failed to create the GLFW window")
}
@ -130,11 +148,62 @@ class GLFWWindow(
glfwSetWindowSizeCallback(window, this::onResize)
glfwSetWindowCloseCallback(window, this::onClose)
glfwSetWindowFocusCallback(window, this::onFocusChange)
glfwSetWindowIconifyCallback(window, this::onIconify)
super.init()
}
override fun close() {
override fun destroy() {
glfwFreeCallbacks(window)
glfwDestroyWindow(window)
glfwTerminate()
glfwSetErrorCallback(null)!!.free()
}
override fun close() {
if (eventMaster.fireEvent(WindowCloseEvent(window = this))) {
return
}
glfwSetWindowShouldClose(window, true)
}
override fun swapBuffers() {
glfwSwapBuffers(window)
}
override fun pollEvents() {
glfwPollEvents()
}
private fun onFocusChange(window: Long, focused: Boolean) {
if (window != this.window) {
return
}
eventMaster.fireEvent(WindowFocusChangeEvent(window = this, focused = focused))
}
private fun onIconify(window: Long, iconified: Boolean) {
if (window != this.window) {
return
}
eventMaster.fireEvent(WindowIconifyChangeEvent(window = this, iconified = iconified))
}
private fun onClose(window: Long) {
if (window != this.window) {
return
}
val cancelled = eventMaster.fireEvent(WindowCloseEvent(window = this))
if (cancelled) {
glfwSetWindowShouldClose(window, false)
}
}
private fun onResize(window: Long, width: Int, height: Int) {