wip: abstract glfw window

This commit is contained in:
Bixilon 2021-06-20 00:08:42 +02:00
parent 7ff391f703
commit b7fa34dc24
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
19 changed files with 504 additions and 156 deletions

View File

@ -17,6 +17,7 @@ import com.google.gson.JsonObject
import de.bixilon.minosoft.data.registries.ResourceLocation
import de.bixilon.minosoft.data.registries.blocks.BlockState
import de.bixilon.minosoft.data.registries.blocks.properties.BlockProperties
import de.bixilon.minosoft.data.registries.blocks.types.FluidFillable
import de.bixilon.minosoft.data.registries.fluid.FlowableFluid
import de.bixilon.minosoft.data.registries.fluid.Fluid
import de.bixilon.minosoft.data.registries.versions.Registries
@ -49,6 +50,10 @@ class WaterFluid(
if (other.properties[BlockProperties.WATERLOGGED] == true) {
return true
}
if (other.block is FluidFillable && resourceLocation == other.block.fluid) {
return true
}
return super.matches(other)
}

View File

@ -111,7 +111,7 @@ data class Version(
registries.load(this, pixlyzerData)
latch.dec()
if (pixlyzerData.size() > 0) {
Log.log(LogMessageType.VERSION_LOADING, level = LogLevels.INFO) { "Loaded registries for $this (${versionName} in ${System.currentTimeMillis() - startTime}ms" }
Log.log(LogMessageType.VERSION_LOADING, level = LogLevels.INFO) { "Loaded registries for $this $versionName in ${System.currentTimeMillis() - startTime}ms" }
} else {
Log.log(LogMessageType.VERSION_LOADING, level = LogLevels.WARN) { "Could not load registries for $this (${versionName}. Some features might not work." }
}

View File

@ -14,7 +14,6 @@
package de.bixilon.minosoft.gui.rendering
import de.bixilon.minosoft.Minosoft
import de.bixilon.minosoft.config.StaticConfiguration
import de.bixilon.minosoft.config.config.game.controls.KeyBindingsNames
import de.bixilon.minosoft.data.registries.ResourceLocation
import de.bixilon.minosoft.gui.rendering.chunk.ChunkBorderRenderer
@ -27,12 +26,13 @@ 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.ScreenResizeEvent
import de.bixilon.minosoft.gui.rendering.modding.events.ResizeWindowEvent
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.GLFWWindow
import de.bixilon.minosoft.gui.rendering.textures.Texture
import de.bixilon.minosoft.gui.rendering.textures.TextureArray
import de.bixilon.minosoft.gui.rendering.util.ScreenshotTaker
@ -49,28 +49,32 @@ 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.*
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.*
import org.lwjgl.system.MemoryStack
import org.lwjgl.system.MemoryUtil
class RenderWindow(
val connection: PlayConnection,
val rendering: Rendering,
) {
val renderSystem: RenderSystem = OpenGLRenderSystem()
val window = GLFWWindow(connection)
val renderSystem: RenderSystem = OpenGLRenderSystem(this)
var initialized = false
private set
private lateinit var renderThread: Thread
val renderStats = RenderStats()
var screenDimensions = Vec2i(900, 500)
private set
var screenDimensionsF = Vec2(screenDimensions)
private set
@Deprecated(message = "", replaceWith = ReplaceWith("window.size"))
val screenDimensions
get() = window.size
@Deprecated(message = "", replaceWith = ReplaceWith("window.sizef"))
val screenDimensionsF: Vec2
get() = window.sizef
val inputHandler = RenderWindowInputHandler(this)
var windowId = 0L
private var deltaFrameTime = 0.0
private var lastFrame = 0.0
@ -132,58 +136,16 @@ class RenderWindow(
renderThread = Thread.currentThread()
Log.log(LogMessageType.RENDERING_LOADING) { "Creating window..." }
val stopwatch = Stopwatch()
// Setup an error callback. The default implementation
// will print the error message in System.err.
GLFWErrorCallback.createPrint(System.err).set()
// Initialize Most GLFW functions will not work before doing this.
check(glfwInit()) { "Unable to initialize GLFW" }
window.init()
// Configure GLFW
glfwDefaultWindowHints() // optional, the current window hints are already the default
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3)
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3)
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE)
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE) // the window will stay hidden after creation
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE) // the window will be resizable
// Create the window
windowId = glfwCreateWindow(screenDimensions.x, screenDimensions.y, "Minosoft", MemoryUtil.NULL, MemoryUtil.NULL)
if (windowId == MemoryUtil.NULL) {
glfwTerminate()
throw RuntimeException("Failed to create the GLFW window")
}
inputHandler.camera.init(this)
tintColorCalculator.init(connection.assetsManager)
if (!StaticConfiguration.DEBUG_MODE) {
glfwSetInputMode(windowId, GLFW_CURSOR, GLFW_CURSOR_DISABLED)
}
glfwSetWindowSizeLimits(windowId, 100, 100, GLFW_DONT_CARE, GLFW_DONT_CARE)
MemoryStack.stackPush().let { stack ->
val pWidth = stack.mallocInt(1)
val pHeight = stack.mallocInt(1)
// Get the window size passed to glfwCreateWindow
glfwGetWindowSize(windowId, pWidth, pHeight)
// Get the resolution of the primary monitor
val videoMode = glfwGetVideoMode(glfwGetPrimaryMonitor())!!
// Center the window
glfwSetWindowPos(windowId, (videoMode.width() - pWidth[0]) / 2, (videoMode.height() - pHeight[0]) / 2)
}
Log.log(LogMessageType.RENDERING_LOADING) { "Creating context (${stopwatch.labTime()})..." }
// Make the OpenGL context current
glfwMakeContextCurrent(windowId)
// Enable v-sync
glfwSwapInterval(Minosoft.config.config.game.other.swapInterval)
renderSystem.init()
@ -213,7 +175,6 @@ class RenderWindow(
renderer.init()
}
Log.log(LogMessageType.RENDERING_LOADING) { "Preloading textures (${stopwatch.labTime()})..." }
textures.preLoad(connection.assetsManager)
font.loadAtlas()
@ -228,17 +189,8 @@ class RenderWindow(
Log.log(LogMessageType.RENDERING_LOADING) { "Registering glfw callbacks (${stopwatch.labTime()})..." }
glfwSetWindowSizeCallback(windowId, object : GLFWWindowSizeCallback() {
override fun invoke(window: Long, width: Int, height: Int) {
glViewport(0, 0, width, height)
val previousSize = screenDimensions
screenDimensions = Vec2i(width, height)
screenDimensionsF = Vec2(screenDimensions)
connection.fireEvent(ScreenResizeEvent(previousScreenDimensions = previousSize, screenDimensions = screenDimensions))
}
})
glfwSetWindowFocusCallback(windowId, object : GLFWWindowFocusCallback() {
glfwSetWindowFocusCallback(window.window, object : GLFWWindowFocusCallback() {
override fun invoke(window: Long, focused: Boolean) {
setRenderStatus(if (focused) {
RenderingStates.RUNNING
@ -248,7 +200,7 @@ class RenderWindow(
}
})
glfwSetWindowIconifyCallback(windowId, object : GLFWWindowIconifyCallback() {
glfwSetWindowIconifyCallback(window.window, object : GLFWWindowIconifyCallback() {
override fun invoke(window: Long, iconified: Boolean) {
setRenderStatus(if (iconified) {
RenderingStates.PAUSED
@ -257,18 +209,13 @@ class RenderWindow(
})
}
})
glfwSetKeyCallback(this.windowId, inputHandler::keyInput)
glfwSetMouseButtonCallback(this.windowId, inputHandler::mouseKeyInput)
glfwSetCharCallback(windowId, inputHandler::charInput)
glfwSetCursorPosCallback(windowId, inputHandler::mouseMove)
inputHandler.init()
registerGlobalKeyCombinations()
connection.fireEvent(ScreenResizeEvent(previousScreenDimensions = Vec2i(0, 0), screenDimensions = screenDimensions))
connection.fireEvent(ResizeWindowEvent(previousSize = Vec2i(0, 0), size = window.size))
Log.log(LogMessageType.RENDERING_LOADING) { "Rendering is fully prepared in ${stopwatch.totalTime()}" }
@ -276,7 +223,7 @@ class RenderWindow(
latch.dec()
latch.await()
this.latch.await()
glfwShowWindow(windowId)
window.visible = true
Log.log(LogMessageType.RENDERING_GENERAL) { "Showing window after ${stopwatch.totalTime()}" }
}
@ -290,7 +237,7 @@ class RenderWindow(
sendDebugMessage("Toggled polygon mode!")
}
inputHandler.registerKeyCallback(KeyBindingsNames.QUIT_RENDERING) { glfwSetWindowShouldClose(windowId, true) }
inputHandler.registerKeyCallback(KeyBindingsNames.QUIT_RENDERING) { glfwSetWindowShouldClose(window.window, true) }
inputHandler.registerKeyCallback(KeyBindingsNames.TAKE_SCREENSHOT) { screenshotTaker.takeScreenshot() }
inputHandler.registerKeyCallback(KeyBindingsNames.DEBUG_PAUSE_INCOMING_PACKETS) {
@ -305,7 +252,7 @@ class RenderWindow(
fun startLoop() {
Log.log(LogMessageType.RENDERING_LOADING) { "Starting loop" }
while (!glfwWindowShouldClose(windowId)) {
while (!glfwWindowShouldClose(window.window)) {
if (connection.wasConnected) {
break
}
@ -346,7 +293,7 @@ class RenderWindow(
renderStats.endDraw()
glfwSwapBuffers(windowId)
glfwSwapBuffers(window.window)
glfwPollEvents()
inputHandler.draw(deltaFrameTime)
@ -357,12 +304,12 @@ class RenderWindow(
RenderingStates.SLOW -> Thread.sleep(100L)
RenderingStates.RUNNING, RenderingStates.PAUSED -> {
}
RenderingStates.STOPPED -> glfwSetWindowShouldClose(windowId, true)
RenderingStates.STOPPED -> glfwSetWindowShouldClose(window.window, true)
}
renderStats.endFrame()
if (RenderConstants.SHOW_FPS_IN_WINDOW_TITLE) {
glfwSetWindowTitle(windowId, "Minosoft | FPS: ${renderStats.fpsLastSecond}")
glfwSetWindowTitle(window.window, "Minosoft | FPS: ${renderStats.fpsLastSecond}")
}
}
}
@ -370,8 +317,8 @@ class RenderWindow(
fun exit() {
Log.log(LogMessageType.RENDERING_LOADING) { "Destroying render window..." }
// Free the window callbacks and destroy the window
Callbacks.glfwFreeCallbacks(windowId)
glfwDestroyWindow(windowId)
Callbacks.glfwFreeCallbacks(window.window)
glfwDestroyWindow(window.window)
// Terminate GLFW and free the error callback
glfwTerminate()
@ -404,7 +351,7 @@ class RenderWindow(
}
fun getClipboardText(): String {
return glfwGetClipboardString(windowId) ?: ""
return glfwGetClipboardString(window.window) ?: ""
}
fun assertOnRenderThread() {

View File

@ -27,7 +27,7 @@ import de.bixilon.minosoft.gui.rendering.hud.nodes.HUDElement
import de.bixilon.minosoft.gui.rendering.hud.nodes.chat.ChatBoxHUDElement
import de.bixilon.minosoft.gui.rendering.hud.nodes.debug.HUDSystemDebugNode
import de.bixilon.minosoft.gui.rendering.hud.nodes.debug.HUDWorldDebugNode
import de.bixilon.minosoft.gui.rendering.modding.events.ScreenResizeEvent
import de.bixilon.minosoft.gui.rendering.modding.events.ResizeWindowEvent
import de.bixilon.minosoft.gui.rendering.shader.Shader
import de.bixilon.minosoft.modding.event.CallbackEventInvoker
import de.bixilon.minosoft.protocol.network.connection.PlayConnection
@ -76,8 +76,8 @@ class HUDRenderer(val connection: PlayConnection, val renderWindow: RenderWindow
}
connection.registerEvent(CallbackEventInvoker.of<ScreenResizeEvent> {
orthographicMatrix = glm.ortho(-it.screenDimensions.x / 2.0f, it.screenDimensions.x / 2.0f, -it.screenDimensions.y / 2.0f, it.screenDimensions.y / 2.0f)
connection.registerEvent(CallbackEventInvoker.of<ResizeWindowEvent> {
orthographicMatrix = glm.ortho(-it.size.x / 2.0f, it.size.x / 2.0f, -it.size.y / 2.0f, it.size.y / 2.0f)
for ((_, hudElement) in hudElements.values) {
hudElement.layout.clearChildrenCache()
}
@ -178,7 +178,7 @@ class HUDRenderer(val connection: PlayConnection, val renderWindow: RenderWindow
realSize.x = MMath.clamp(realSize.x, hudElement.layout.sizing.minSize.x, hudElement.layout.sizing.maxSize.x)
realSize.y = MMath.clamp(realSize.y, hudElement.layout.sizing.minSize.y, hudElement.layout.sizing.maxSize.y)
val elementStart = getRealPosition(realSize, elementProperties, renderWindow.screenDimensions)
val elementStart = getRealPosition(realSize, elementProperties, renderWindow.window.size)
hudElement.layout.checkCache(elementStart, realScaleFactor, orthographicMatrix, 0)
tempMesh.addCacheMesh(hudElement.layout.cache)

View File

@ -23,7 +23,7 @@ import de.bixilon.minosoft.gui.rendering.hud.elements.input.TextField
import de.bixilon.minosoft.gui.rendering.hud.elements.input.TextFieldProperties
import de.bixilon.minosoft.gui.rendering.hud.nodes.HUDElement
import de.bixilon.minosoft.gui.rendering.hud.nodes.layout.AbsoluteLayout
import de.bixilon.minosoft.gui.rendering.modding.events.ScreenResizeEvent
import de.bixilon.minosoft.gui.rendering.modding.events.ResizeWindowEvent
import de.bixilon.minosoft.modding.event.CallbackEventInvoker
import glm_.vec2.Vec2
import glm_.vec2.Vec2i
@ -49,9 +49,9 @@ class ChatBoxHUDElement(hudRenderer: HUDRenderer) : HUDElement(hudRenderer) {
hudRenderer.renderWindow.inputHandler.registerKeyCallback(KeyBindingsNames.OPEN_CHAT) {
openChat()
}
hudRenderer.connection.registerEvent(CallbackEventInvoker.of<ScreenResizeEvent> {
layout.sizing.minSize.x = it.screenDimensions.x
layout.sizing.maxSize.x = it.screenDimensions.x
hudRenderer.connection.registerEvent(CallbackEventInvoker.of<ResizeWindowEvent> {
layout.sizing.minSize.x = it.size.x
layout.sizing.maxSize.x = it.size.x
inputField.textElement.setProperties.hardWrap = (inputField.textElement.sizing.minSize.x / scale).toInt()
layout.apply()
})

View File

@ -19,7 +19,7 @@ import de.bixilon.minosoft.gui.rendering.hud.HUDElementProperties
import de.bixilon.minosoft.gui.rendering.hud.HUDRenderBuilder
import de.bixilon.minosoft.gui.rendering.hud.HUDRenderer
import de.bixilon.minosoft.gui.rendering.hud.nodes.properties.NodeAlignment
import de.bixilon.minosoft.gui.rendering.modding.events.ScreenResizeEvent
import de.bixilon.minosoft.gui.rendering.modding.events.ResizeWindowEvent
import de.bixilon.minosoft.modding.event.CallbackEventInvoker
import de.bixilon.minosoft.modding.loading.ModLoader
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
@ -74,7 +74,7 @@ class HUDSystemDebugNode(hudRenderer: HUDRenderer) : DebugScreenNode(hudRenderer
gpuText.sText = "GPU: " + (glGetString(GL_RENDERER) ?: "unknown")
gpuVersionText.sText = "Version: " + (glGetString(GL_VERSION) ?: "unknown")
hudRenderer.connection.registerEvent(CallbackEventInvoker.of<ScreenResizeEvent> {
hudRenderer.connection.registerEvent(CallbackEventInvoker.of<ResizeWindowEvent> {
displayText.sText = "Display: ${getScreenDimensions()}"
})
}
@ -123,7 +123,7 @@ class HUDSystemDebugNode(hudRenderer: HUDRenderer) : DebugScreenNode(hudRenderer
}
private fun getScreenDimensions(): String {
return "${hudRenderer.renderWindow.screenDimensions.x}x${hudRenderer.renderWindow.screenDimensions.y}"
return "${hudRenderer.renderWindow.window.size.x}x${hudRenderer.renderWindow.window.size.y}"
}
companion object : HUDRenderBuilder<HUDSystemDebugNode> {

View File

@ -22,7 +22,7 @@ import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.modding.events.CameraMatrixChangeEvent
import de.bixilon.minosoft.gui.rendering.modding.events.CameraPositionChangeEvent
import de.bixilon.minosoft.gui.rendering.modding.events.FrustumChangeEvent
import de.bixilon.minosoft.gui.rendering.modding.events.ScreenResizeEvent
import de.bixilon.minosoft.gui.rendering.modding.events.ResizeWindowEvent
import de.bixilon.minosoft.gui.rendering.sky.SkyRenderer
import de.bixilon.minosoft.gui.rendering.util.VecUtil
import de.bixilon.minosoft.gui.rendering.util.VecUtil.floor
@ -35,6 +35,7 @@ import glm_.func.sin
import glm_.glm
import glm_.mat4x4.Mat4d
import glm_.vec2.Vec2
import glm_.vec2.Vec2d
import glm_.vec3.Vec3d
class Camera(
@ -44,8 +45,7 @@ class Camera(
private var mouseSensitivity = Minosoft.getConfig().config.game.camera.moseSensitivity
val entity: LocalPlayerEntity
get() = connection.player
private var lastMouseX = 0.0
private var lastMouseY = 0.0
private var lastMousePosition: Vec2d = Vec2d(0.0, 0.0)
private var zoom = 0.0f
var cameraFront = Vec3d(0.0, 0.0, -1.0)
@ -65,7 +65,7 @@ class Camera(
var viewMatrix = calculateViewMatrix()
private set
var projectionMatrix = calculateProjectionMatrix(renderWindow.screenDimensionsF)
var projectionMatrix = calculateProjectionMatrix(renderWindow.window.sizef)
private set
var viewProjectionMatrix = projectionMatrix * viewMatrix
private set
@ -74,24 +74,21 @@ class Camera(
val frustum: Frustum = Frustum(this)
fun mouseCallback(xPos: Double, yPos: Double) {
var xOffset = xPos - this.lastMouseX
var yOffset = yPos - this.lastMouseY
lastMouseX = xPos
lastMouseY = yPos
fun mouseCallback(position: Vec2d) {
val delta = position - lastMousePosition
lastMousePosition = position
if (renderWindow.inputHandler.currentKeyConsumer != null) {
return
}
xOffset *= mouseSensitivity
yOffset *= mouseSensitivity
var yaw = xOffset + entity.rotation.headYaw
delta *= mouseSensitivity
var yaw = delta.x + entity.rotation.headYaw
if (yaw > 180) {
yaw -= 360
} else if (yaw < -180) {
yaw += 360
}
yaw %= 180
val pitch = glm.clamp(yOffset + entity.rotation.pitch, -89.9, 89.9)
val pitch = glm.clamp(delta.y + entity.rotation.pitch, -89.9, 89.9)
entity.rotation = EntityRotation(yaw, pitch)
setRotation(yaw, pitch)
}
@ -111,14 +108,14 @@ class Camera(
KeyBindingsNames.MOVE_TOGGLE_FLY,
)
connection.registerEvent(CallbackEventInvoker.of<ScreenResizeEvent> { recalculateViewProjectionMatrix() })
connection.registerEvent(CallbackEventInvoker.of<ResizeWindowEvent> { recalculateViewProjectionMatrix() })
frustum.recalculate()
connection.fireEvent(FrustumChangeEvent(renderWindow, frustum))
}
private fun recalculateViewProjectionMatrix() {
viewMatrix = calculateViewMatrix()
projectionMatrix = calculateProjectionMatrix(renderWindow.screenDimensionsF)
projectionMatrix = calculateProjectionMatrix(renderWindow.window.sizef)
viewProjectionMatrix = projectionMatrix * viewMatrix
connection.fireEvent(CameraMatrixChangeEvent(
renderWindow = renderWindow,

View File

@ -24,10 +24,12 @@ import de.bixilon.minosoft.gui.rendering.hud.elements.input.KeyConsumer
import de.bixilon.minosoft.gui.rendering.input.LeftClickHandler
import de.bixilon.minosoft.gui.rendering.input.RightClickHandler
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.KeyChangeTypes
import de.bixilon.minosoft.modding.event.CallbackEventInvoker
import de.bixilon.minosoft.protocol.network.connection.PlayConnection
import de.bixilon.minosoft.util.logging.Log
import de.bixilon.minosoft.util.logging.LogLevels
import de.bixilon.minosoft.util.logging.LogMessageType
import org.lwjgl.glfw.GLFW.*
class RenderWindowInputHandler(
@ -53,7 +55,7 @@ class RenderWindowInputHandler(
} else {
GLFW_CURSOR_NORMAL
}
glfwSetInputMode(renderWindow.windowId, GLFW_CURSOR, newCursorMode)
glfwSetInputMode(renderWindow.window.window, GLFW_CURSOR, newCursorMode)
renderWindow.sendDebugMessage("Toggled mouse catch!")
}
}
@ -61,35 +63,28 @@ class RenderWindowInputHandler(
fun init() {
rightClickHandler.init()
leftClickHandler.init()
connection.registerEvent(CallbackEventInvoker.of<RawCharInputEvent> { charInput(it.char) })
connection.registerEvent(CallbackEventInvoker.of<RawKeyInputEvent> { keyInput(it.keyCode, it.keyChangeType) })
connection.registerEvent(CallbackEventInvoker.of<MouseMoveEvent> { camera.mouseCallback(it.position) })
}
var currentKeyConsumer: KeyConsumer? = null
fun mouseKeyInput(windowId: Long, button: Int, action: Int, modifierKey: Int) {
keyInput(windowId, button, 0, action, modifierKey)
}
fun keyInput(windowId: Long, key: Int, char: Int, action: Int, modifierKey: Int) {
if (windowId != renderWindow.windowId) {
return
}
val keyCode = KeyCodes.KEY_CODE_GLFW_ID_MAP[key] ?: KeyCodes.KEY_UNKNOWN
val keyDown = when (action) {
GLFW_PRESS -> {
private fun keyInput(keyCode: KeyCodes, keyChangeType: KeyChangeTypes) {
val keyDown = when (keyChangeType) {
KeyChangeTypes.PRESS -> {
currentKeyConsumer?.keyInput(keyCode)
true
}
GLFW_RELEASE -> false
GLFW_REPEAT -> {
KeyChangeTypes.RELEASE -> false
KeyChangeTypes.REPEAT -> {
currentKeyConsumer?.keyInput(keyCode)
return
}
else -> {
Log.log(LogMessageType.RENDERING_GENERAL, LogLevels.WARN) { "Unknown glfw action $action" }
return
}
}
val currentTime = System.currentTimeMillis()
@ -219,10 +214,7 @@ class RenderWindowInputHandler(
}
}
fun charInput(windowId: Long, char: Int) {
if (windowId != renderWindow.windowId) {
return
}
private fun charInput(char: Int) {
if (skipNextCharPress) {
skipNextCharPress = false
return
@ -230,13 +222,6 @@ class RenderWindowInputHandler(
currentKeyConsumer?.charInput(char.toChar())
}
fun mouseMove(windowId: Long, xPos: Double, yPos: Double) {
if (windowId != renderWindow.windowId) {
return
}
camera.mouseCallback(xPos, yPos)
}
fun registerKeyCallback(resourceLocation: ResourceLocation, callback: ((keyDown: Boolean) -> Unit)) {
val keyBinding = Minosoft.getConfig().config.game.controls.keyBindings.entries[resourceLocation] ?: return
val callbackPair = keyBindingCallbacks.getOrPut(resourceLocation) { KeyBindingCallbackPair(keyBinding) }

View File

@ -0,0 +1,26 @@
/*
* 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 glm_.vec2.Vec2d
class MouseMoveEvent(
renderWindow: RenderWindow = Rendering.currentContext!!,
position: Vec2d,
) : RenderEvent(renderWindow) {
val position: Vec2d = position
get() = Vec2d(field)
}

View File

@ -0,0 +1,22 @@
/*
* 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
class RawCharInputEvent(
renderWindow: RenderWindow = Rendering.currentContext!!,
val char: Int,
) : RenderEvent(renderWindow)

View File

@ -0,0 +1,25 @@
/*
* 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.config.key.KeyCodes
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.Rendering
import de.bixilon.minosoft.gui.rendering.system.window.KeyChangeTypes
class RawKeyInputEvent(
renderWindow: RenderWindow = Rendering.currentContext!!,
val keyCode: KeyCodes,
val keyChangeType: KeyChangeTypes,
) : RenderEvent(renderWindow)

View File

@ -17,8 +17,8 @@ import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.Rendering
import glm_.vec2.Vec2i
class ScreenResizeEvent(
class ResizeWindowEvent(
renderWindow: RenderWindow = Rendering.currentContext!!,
val previousScreenDimensions: Vec2i,
val screenDimensions: Vec2i,
val previousSize: Vec2i,
val size: Vec2i,
) : RenderEvent(renderWindow)

View File

@ -13,17 +13,22 @@
package de.bixilon.minosoft.gui.rendering.system.opengl
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.modding.events.ResizeWindowEvent
import de.bixilon.minosoft.gui.rendering.shader.Shader
import de.bixilon.minosoft.gui.rendering.system.base.BlendingFunctions
import de.bixilon.minosoft.gui.rendering.system.base.DepthFunctions
import de.bixilon.minosoft.gui.rendering.system.base.RenderSystem
import de.bixilon.minosoft.gui.rendering.system.base.RenderingCapabilities
import de.bixilon.minosoft.modding.event.CallbackEventInvoker
import de.bixilon.minosoft.util.KUtil.synchronizedMapOf
import de.bixilon.minosoft.util.KUtil.synchronizedSetOf
import org.lwjgl.opengl.GL
import org.lwjgl.opengl.GL20.*
class OpenGLRenderSystem : RenderSystem {
class OpenGLRenderSystem(
private val renderWindow: RenderWindow,
) : RenderSystem {
val shaders: MutableMap<Shader, Int> = synchronizedMapOf() // ToDo
private val capabilities: MutableSet<RenderingCapabilities> = synchronizedSetOf()
var blendingSource = BlendingFunctions.ONE
@ -44,6 +49,12 @@ class OpenGLRenderSystem : RenderSystem {
override fun init() {
GL.createCapabilities()
renderWindow.connection.registerEvent(CallbackEventInvoker.of<ResizeWindowEvent> {
renderWindow.queue += {
glViewport(0, 0, it.size.x, it.size.y)
}
})
}
override fun enable(capability: RenderingCapabilities) {

View File

@ -0,0 +1,58 @@
/*
* 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.system.window
import de.bixilon.minosoft.Minosoft
import de.bixilon.minosoft.config.StaticConfiguration
import glm_.vec2.Vec2
import glm_.vec2.Vec2i
interface BaseWindow {
var size: Vec2i
val sizef: Vec2
get() = Vec2(size)
var minSize: Vec2i
var maxSize: Vec2i
var visible: Boolean
var resizable: Boolean
var swapInterval: Int
var cursorMode: CursorModes
fun init() {
resizable = true
swapInterval = Minosoft.config.config.game.other.swapInterval
if (!StaticConfiguration.DEBUG_MODE) {
cursorMode = CursorModes.DISABLED
}
size = DEFAULT_WINDOW_SIZE
minSize = DEFAULT_MINIMUM_WINDOW_SIZE
maxSize = DEFAULT_MAXIMUM_WINDOW_SIZE
}
fun close()
companion object {
val DEFAULT_WINDOW_SIZE: Vec2i
get() = Vec2i(900, 500)
val DEFAULT_MINIMUM_WINDOW_SIZE: Vec2i
get() = Vec2i(100, 100)
val DEFAULT_MAXIMUM_WINDOW_SIZE: Vec2i
get() = Vec2i(-1, -1)
}
}

View File

@ -0,0 +1,21 @@
/*
* 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.system.window
enum class CursorModes {
NORMAL,
HIDDEN,
DISABLED,
;
}

View File

@ -0,0 +1,204 @@
/*
* 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.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.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
import de.bixilon.minosoft.modding.event.EventMaster
import de.bixilon.minosoft.util.logging.Log
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.GLFW.*
import org.lwjgl.glfw.GLFWErrorCallback
import org.lwjgl.system.MemoryUtil
class GLFWWindow(
private val eventMaster: EventMaster,
) : BaseWindow {
@Deprecated("Will be private soon")
var window = -1L
override var cursorMode: CursorModes = CursorModes.NORMAL
set(value) {
if (field == value) {
return
}
glfwSetInputMode(window, GLFW_CURSOR, value.glfw)
field = value
}
private var _size = DEFAULT_WINDOW_SIZE
override var size: Vec2i
get() = _size
set(value) {
glfwSetWindowSize(window, value.x, value.y)
_size = size
}
override var minSize: Vec2i = DEFAULT_MINIMUM_WINDOW_SIZE
set(value) {
glfwSetWindowSizeLimits(window, value.x, value.y, maxSize.x, maxSize.y)
field = value
}
override var maxSize: Vec2i = DEFAULT_MAXIMUM_WINDOW_SIZE
set(value) {
glfwSetWindowSizeLimits(window, minSize.x, minSize.y, value.x, value.y)
field = value
}
override var visible: Boolean = false
set(value) {
if (field == value) {
return
}
when (value) {
true -> glfwShowWindow(window)
false -> glfwHideWindow(window)
}
field = value
}
override var resizable: Boolean = true
set(value) {
if (field == value) {
return
}
glfwWindowHint(GLFW_RESIZABLE, value.glfw)
field = value
}
override var swapInterval: Int = -1
set(value) {
if (field == value) {
return
}
glfwSwapInterval(value)
field = value
}
override fun init() {
GLFWErrorCallback.createPrint(System.err).set()
check(glfwInit()) { "Unable to initialize GLFW" }
glfwDefaultWindowHints()
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3)
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3)
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE)
glfwWindowHint(GLFW_VISIBLE, false.glfw)
window = glfwCreateWindow(size.x, size.y, "Minosoft", MemoryUtil.NULL, MemoryUtil.NULL)
if (window == MemoryUtil.NULL) {
close()
throw RuntimeException("Failed to create the GLFW window")
}
val videoMode = glfwGetVideoMode(glfwGetPrimaryMonitor())!!
glfwSetWindowPos(window, (videoMode.width() - size.x) / 2, (videoMode.height() - size.y) / 2)
glfwMakeContextCurrent(window)
glfwSetKeyCallback(window, this::keyInput)
glfwSetMouseButtonCallback(window, this::mouseKeyInput)
glfwSetCharCallback(window, this::charInput)
glfwSetCursorPosCallback(window, this::mouseMove)
glfwSetWindowSizeCallback(window, this::onResize)
super.init()
}
override fun close() {
glfwTerminate()
}
private fun onResize(window: Long, width: Int, height: Int) {
if (window != this.window) {
return
}
val previousSize = Vec2i(_size)
_size = Vec2i(width, height)
eventMaster.fireEvent(ResizeWindowEvent(previousSize = previousSize, size = _size))
}
private fun mouseKeyInput(windowId: Long, button: Int, action: Int, modifierKey: Int) {
keyInput(windowId, button, 0, action, modifierKey)
}
private fun keyInput(window: Long, key: Int, char: Int, action: Int, modifierKey: Int) {
if (window != this.window) {
return
}
val keyCode = KeyCodes.KEY_CODE_GLFW_ID_MAP[key] ?: KeyCodes.KEY_UNKNOWN
val keyAction = when (action) {
GLFW_PRESS -> KeyChangeTypes.PRESS
GLFW_RELEASE -> KeyChangeTypes.RELEASE
GLFW_REPEAT -> KeyChangeTypes.REPEAT
else -> {
Log.log(LogMessageType.RENDERING_GENERAL, LogLevels.WARN) { "Unknown glfw action $action" }
return
}
}
eventMaster.fireEvent(RawKeyInputEvent(keyCode = keyCode, keyChangeType = keyAction))
}
private fun charInput(windowId: Long, char: Int) {
if (windowId != window) {
return
}
eventMaster.fireEvent(RawCharInputEvent(char = char))
}
private fun mouseMove(windowId: Long, x: Double, y: Double) {
if (windowId != window) {
return
}
eventMaster.fireEvent(MouseMoveEvent(position = Vec2d(x, y)))
}
companion object {
val CursorModes.glfw: Int
get() {
return when (this) {
CursorModes.NORMAL -> GLFW_CURSOR_NORMAL
CursorModes.HIDDEN -> GLFW_CURSOR_HIDDEN
CursorModes.DISABLED -> GLFW_CURSOR_DISABLED
}
}
val Boolean.glfw: Int
get() {
return when (this) {
true -> GLFW_TRUE
false -> GLFW_FALSE
}
}
}
}

View File

@ -0,0 +1,21 @@
/*
* 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.system.window
enum class KeyChangeTypes {
PRESS,
RELEASE,
REPEAT,
;
}

View File

@ -0,0 +1,25 @@
/*
* 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.modding.event
import de.bixilon.minosoft.modding.event.events.Event
interface EventMaster {
fun fireEvent(event: Event): Boolean
fun registerEvent(method: EventInvoker)
fun registerEvents(vararg method: EventInvoker)
}

View File

@ -15,8 +15,9 @@ package de.bixilon.minosoft.protocol.network.connection
import de.bixilon.minosoft.Minosoft
import de.bixilon.minosoft.modding.event.EventInvoker
import de.bixilon.minosoft.modding.event.EventMaster
import de.bixilon.minosoft.modding.event.events.CancelableEvent
import de.bixilon.minosoft.modding.event.events.ConnectionEvent
import de.bixilon.minosoft.modding.event.events.Event
import de.bixilon.minosoft.modding.event.events.PacketSendEvent
import de.bixilon.minosoft.protocol.network.Network
import de.bixilon.minosoft.protocol.packets.c2s.C2SPacket
@ -27,7 +28,7 @@ import de.bixilon.minosoft.protocol.protocol.PacketTypes.S2C
import de.bixilon.minosoft.util.KUtil.synchronizedListOf
import de.bixilon.minosoft.util.KUtil.toSynchronizedList
abstract class Connection {
abstract class Connection : EventMaster {
val network = Network.getNetworkInstance(this)
protected val eventListeners: MutableList<EventInvoker> = synchronizedListOf()
val connectionId = lastConnectionId++
@ -47,24 +48,24 @@ abstract class Connection {
}
/**
* @param connectionEvent The event to fire
* @param event The event to fire
* @return if the event has been cancelled or not
*/
fun fireEvent(connectionEvent: ConnectionEvent): Boolean {
override fun fireEvent(event: Event): Boolean {
for (eventManager in Minosoft.EVENT_MANAGERS) {
for (eventListener in eventManager.globalEventListeners) {
eventListener(connectionEvent)
eventListener(event)
}
}
for (eventInvoker in eventListeners.toSynchronizedList()) {
if (!eventInvoker.eventType.isAssignableFrom(connectionEvent::class.java)) {
if (!eventInvoker.eventType.isAssignableFrom(event::class.java)) {
continue
}
eventInvoker(connectionEvent)
eventInvoker(event)
}
if (connectionEvent is CancelableEvent) {
return connectionEvent.isCancelled
if (event is CancelableEvent) {
return event.isCancelled
}
return false
}
@ -84,11 +85,11 @@ abstract class Connection {
eventListeners.remove(method)
}
open fun registerEvent(method: EventInvoker) {
override fun registerEvent(method: EventInvoker) {
eventListeners.add(method)
}
open fun registerEvents(vararg method: EventInvoker) {
override fun registerEvents(vararg method: EventInvoker) {
eventListeners.addAll(method)
}