From 5a991b45b898d4b857f626eafd18a9a21d7497cd Mon Sep 17 00:00:00 2001 From: Bixilon Date: Sat, 19 Jun 2021 21:30:24 +0200 Subject: [PATCH] wip: abstract opengl render system --- .../minosoft/gui/rendering/RenderWindow.kt | 15 +- .../rendering/chunk/ChunkBorderRenderer.kt | 4 +- .../gui/rendering/chunk/WorldRenderer.kt | 9 +- .../block/outline/BlockOutlineRenderer.kt | 10 +- .../entities/EntityHitBoxRenderer.kt | 12 +- .../minosoft/gui/rendering/hud/HUDRenderer.kt | 1 + .../rendering/particle/ParticleRenderer.kt | 5 +- .../minosoft/gui/rendering/shader/Shader.kt | 9 +- .../minosoft/gui/rendering/sky/SkyRenderer.kt | 7 +- .../system/base/BlendingFunctions.kt | 32 ++++ .../rendering/system/base/DepthFunctions.kt | 26 +++ .../gui/rendering/system/base/RenderSystem.kt | 50 ++++++ .../system/base/RenderingCapabilities.kt | 21 +++ .../system/opengl/OpenGLRenderSystem.kt | 153 ++++++++++++++++++ 14 files changed, 307 insertions(+), 47 deletions(-) create mode 100644 src/main/java/de/bixilon/minosoft/gui/rendering/system/base/BlendingFunctions.kt create mode 100644 src/main/java/de/bixilon/minosoft/gui/rendering/system/base/DepthFunctions.kt create mode 100644 src/main/java/de/bixilon/minosoft/gui/rendering/system/base/RenderSystem.kt create mode 100644 src/main/java/de/bixilon/minosoft/gui/rendering/system/base/RenderingCapabilities.kt create mode 100644 src/main/java/de/bixilon/minosoft/gui/rendering/system/opengl/OpenGLRenderSystem.kt diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/RenderWindow.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/RenderWindow.kt index 2f5c0e791..6ff921ed8 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/RenderWindow.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/RenderWindow.kt @@ -31,6 +31,8 @@ import de.bixilon.minosoft.gui.rendering.modding.events.ScreenResizeEvent 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.textures.Texture import de.bixilon.minosoft.gui.rendering.textures.TextureArray import de.bixilon.minosoft.gui.rendering.util.ScreenshotTaker @@ -49,7 +51,6 @@ import glm_.vec2.Vec2 import glm_.vec2.Vec2i import org.lwjgl.glfw.* import org.lwjgl.glfw.GLFW.* -import org.lwjgl.opengl.GL import org.lwjgl.opengl.GL11.* import org.lwjgl.system.MemoryStack import org.lwjgl.system.MemoryUtil @@ -58,6 +59,7 @@ class RenderWindow( val connection: PlayConnection, val rendering: Rendering, ) { + val renderSystem: RenderSystem = OpenGLRenderSystem() var initialized = false private set private lateinit var renderThread: Thread @@ -183,20 +185,13 @@ class RenderWindow( // Enable v-sync glfwSwapInterval(Minosoft.config.config.game.other.swapInterval) - - // Make the window visible - GL.createCapabilities() + renderSystem.init() glClearColor(1.0f, 1.0f, 0.0f, 1.0f) Log.log(LogMessageType.RENDERING_LOADING) { "Enabling all open gl features (${stopwatch.labTime()})..." } - glEnable(GL_DEPTH_TEST) - - glEnable(GL_BLEND) - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) - - glEnable(GL_CULL_FACE) + renderSystem.reset() Log.log(LogMessageType.RENDERING_LOADING) { "Generating font and gathering textures (${stopwatch.labTime()})..." } textures.allTextures.getOrPut(RenderConstants.DEBUG_TEXTURE_RESOURCE_LOCATION) { Texture(RenderConstants.DEBUG_TEXTURE_RESOURCE_LOCATION) } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/ChunkBorderRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/ChunkBorderRenderer.kt index 37445217e..58bf55c5d 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/ChunkBorderRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/ChunkBorderRenderer.kt @@ -24,7 +24,6 @@ import de.bixilon.minosoft.protocol.network.connection.PlayConnection import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition import glm_.vec2.Vec2i import glm_.vec3.Vec3 -import org.lwjgl.opengl.GL11.* class ChunkBorderRenderer( val connection: PlayConnection, @@ -113,10 +112,9 @@ class ChunkBorderRenderer( override fun draw() { prepare() val mesh = lastMesh ?: return + renderWindow.renderSystem.reset(faceCulling = false) renderWindow.shaderManager.genericColorShader.use() - glDisable(GL_CULL_FACE) mesh.draw() - glEnable(GL_CULL_FACE) } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/WorldRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/WorldRenderer.kt index 116a8301e..48450289b 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/WorldRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/WorldRenderer.kt @@ -52,7 +52,6 @@ import de.bixilon.minosoft.util.collections.SynchronizedMap import de.bixilon.minosoft.util.task.ThreadPoolRunnable import glm_.vec2.Vec2i import glm_.vec3.Vec3i -import org.lwjgl.opengl.GL11.glDepthMask class WorldRenderer( private val connection: PlayConnection, @@ -196,6 +195,7 @@ class WorldRenderer( } override fun draw() { + renderWindow.renderSystem.reset() chunkShader.use() val visibleChunks = visibleChunks.toSynchronizedMap() @@ -204,14 +204,13 @@ class WorldRenderer( mesh.opaqueSectionArrayMesh.draw() } } - glDepthMask(false) + renderWindow.renderSystem.depthMask = false for (map in visibleChunks.values) { for (mesh in map.values) { mesh.transparentSectionArrayMesh?.draw() } } - glDepthMask(true) } private fun resolveBlockTextureIds(blocks: Collection, textures: MutableMap) { @@ -263,14 +262,14 @@ class WorldRenderer( } private fun checkNeighbours(chunkPosition: Vec2i) { - val neighborsVec2is: Array = arrayOf( + val neighborsPositions: Array = arrayOf( chunkPosition + Directions.NORTH, chunkPosition + Directions.SOUTH, chunkPosition + Directions.WEST, chunkPosition + Directions.EAST, ) - checkQueuedChunks(neighborsVec2is) + checkQueuedChunks(neighborsPositions) } private fun checkQueuedChunks(chunkPositions: Array) { diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/block/outline/BlockOutlineRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/block/outline/BlockOutlineRenderer.kt index b1560105f..048f4e068 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/block/outline/BlockOutlineRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/block/outline/BlockOutlineRenderer.kt @@ -21,12 +21,12 @@ import de.bixilon.minosoft.gui.rendering.RenderConstants import de.bixilon.minosoft.gui.rendering.RenderWindow import de.bixilon.minosoft.gui.rendering.Renderer import de.bixilon.minosoft.gui.rendering.RendererBuilder +import de.bixilon.minosoft.gui.rendering.system.base.DepthFunctions import de.bixilon.minosoft.gui.rendering.util.VecUtil.getWorldOffset import de.bixilon.minosoft.gui.rendering.util.VecUtil.toVec3d import de.bixilon.minosoft.gui.rendering.util.mesh.LineMesh import de.bixilon.minosoft.protocol.network.connection.PlayConnection import glm_.vec3.Vec3i -import org.lwjgl.opengl.GL11.* class BlockOutlineRenderer( val connection: PlayConnection, @@ -39,16 +39,12 @@ class BlockOutlineRenderer( private fun drawMesh() { val currentMesh = currentMesh ?: return - glDisable(GL_CULL_FACE) + renderWindow.renderSystem.reset(faceCulling = false) if (Minosoft.config.config.game.other.blockOutline.disableZBuffer) { - glDepthFunc(GL_ALWAYS) + renderWindow.renderSystem.depth = DepthFunctions.ALWAYS } renderWindow.shaderManager.genericColorShader.use() currentMesh.draw() - glEnable(GL_CULL_FACE) - if (Minosoft.config.config.game.other.blockOutline.disableZBuffer) { - glDepthFunc(GL_LESS) - } } private fun unload() { diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/entities/EntityHitBoxRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/entities/EntityHitBoxRenderer.kt index f458e719d..3e267ce9d 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/entities/EntityHitBoxRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/entities/EntityHitBoxRenderer.kt @@ -21,6 +21,7 @@ import de.bixilon.minosoft.gui.rendering.Renderer import de.bixilon.minosoft.gui.rendering.RendererBuilder import de.bixilon.minosoft.gui.rendering.chunk.models.AABB import de.bixilon.minosoft.gui.rendering.modding.events.FrustumChangeEvent +import de.bixilon.minosoft.gui.rendering.system.base.DepthFunctions import de.bixilon.minosoft.gui.rendering.util.mesh.Mesh import de.bixilon.minosoft.modding.event.CallbackEventInvoker import de.bixilon.minosoft.modding.event.events.EntityDestroyEvent @@ -29,7 +30,6 @@ import de.bixilon.minosoft.protocol.network.connection.PlayConnection import de.bixilon.minosoft.util.KUtil.synchronizedMapOf import de.bixilon.minosoft.util.KUtil.toSynchronizedMap import de.bixilon.minosoft.util.collections.SynchronizedMap -import org.lwjgl.opengl.GL11.* class EntityHitBoxRenderer( val connection: PlayConnection, @@ -98,9 +98,9 @@ class EntityHitBoxRenderer( } override fun draw() { - glDisable(GL_CULL_FACE) + renderWindow.renderSystem.reset(faceCulling = false) if (Minosoft.config.config.game.entities.hitBox.disableZBuffer) { - glDepthFunc(GL_ALWAYS) + renderWindow.renderSystem.depth = DepthFunctions.ALWAYS } renderWindow.shaderManager.genericColorShader.use() @@ -120,12 +120,6 @@ class EntityHitBoxRenderer( for ((entity, mesh) in meshes.toSynchronizedMap()) { draw(updateMesh(entity, mesh)) } - - - glEnable(GL_CULL_FACE) - if (Minosoft.config.config.game.entities.hitBox.disableZBuffer) { - glDepthFunc(GL_LESS) - } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/hud/HUDRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/hud/HUDRenderer.kt index 8809b5e52..fe1f883e2 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/hud/HUDRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/hud/HUDRenderer.kt @@ -158,6 +158,7 @@ class HUDRenderer(val connection: PlayConnection, val renderWindow: RenderWindow if (!hudEnabled) { return } + renderWindow.renderSystem.reset() var needsUpdate = false val tempMesh = HUDMesh() diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/particle/ParticleRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/particle/ParticleRenderer.kt index 487cb5722..35ef64423 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/particle/ParticleRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/particle/ParticleRenderer.kt @@ -28,7 +28,6 @@ import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition import de.bixilon.minosoft.util.KUtil.synchronizedSetOf import de.bixilon.minosoft.util.KUtil.toSynchronizedSet import glm_.vec3.Vec3 -import org.lwjgl.opengl.GL11.glDepthMask class ParticleRenderer( @@ -82,6 +81,7 @@ class ParticleRenderer( } override fun draw() { + renderWindow.renderSystem.reset() particleShader.use() particleMesh.unload() @@ -104,9 +104,8 @@ class ParticleRenderer( particleMesh.draw() - glDepthMask(false) + renderWindow.renderSystem.depthMask = false transparentParticleMesh.draw() - glDepthMask(true) } companion object : RendererBuilder { diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/shader/Shader.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/shader/Shader.kt index 2efb0afc3..ebbd5c7ae 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/shader/Shader.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/shader/Shader.kt @@ -21,8 +21,10 @@ import de.bixilon.minosoft.data.text.RGBColor import de.bixilon.minosoft.gui.rendering.RenderWindow import de.bixilon.minosoft.gui.rendering.Rendering import de.bixilon.minosoft.gui.rendering.exceptions.ShaderLoadingException +import de.bixilon.minosoft.gui.rendering.system.opengl.OpenGLRenderSystem import de.bixilon.minosoft.gui.rendering.textures.TextureArray import de.bixilon.minosoft.gui.rendering.util.OpenGLUtil +import de.bixilon.minosoft.util.KUtil.unsafeCast import de.bixilon.minosoft.util.MMath import glm_.mat4x4.Mat4 import glm_.mat4x4.Mat4d @@ -85,14 +87,12 @@ class Shader( val context = Rendering.currentContext!! context.shaders.add(this) + context.renderSystem.unsafeCast().shaders[this] = programId return programId } fun use(): Shader { - if (currentShaderInUse !== this) { - glUseProgram(programId) - currentShaderInUse = this - } + renderWindow.renderSystem.shader = this return this } @@ -180,7 +180,6 @@ class Shader( MMath.clamp(it.textures.animator.animatedTextures.size, 1, TextureArray.MAX_ANIMATED_TEXTURES) } ) - private var currentShaderInUse: Shader? = null // ToDo: This is not safe todo private fun createShader(assetsManager: AssetsManager = Minosoft.MINOSOFT_ASSETS_MANAGER, renderWindow: RenderWindow, resourceLocation: ResourceLocation, shaderType: Int, defines: Map, uniforms: MutableList): Int? { val shaderId = glCreateShaderObjectARB(shaderType) diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/sky/SkyRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/sky/SkyRenderer.kt index 22d32813b..0a64ac184 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/sky/SkyRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/sky/SkyRenderer.kt @@ -21,6 +21,7 @@ import de.bixilon.minosoft.gui.rendering.Renderer import de.bixilon.minosoft.gui.rendering.RendererBuilder import de.bixilon.minosoft.gui.rendering.modding.events.CameraMatrixChangeEvent import de.bixilon.minosoft.gui.rendering.shader.Shader +import de.bixilon.minosoft.gui.rendering.system.base.DepthFunctions import de.bixilon.minosoft.gui.rendering.textures.Texture import de.bixilon.minosoft.gui.rendering.util.mesh.SimpleTextureMesh import de.bixilon.minosoft.modding.event.CallbackEventInvoker @@ -33,7 +34,6 @@ import glm_.mat4x4.Mat4d import glm_.vec2.Vec2 import glm_.vec3.Vec3 import glm_.vec3.Vec3d -import org.lwjgl.opengl.GL11.* import kotlin.math.cos class SkyRenderer( @@ -144,12 +144,9 @@ class SkyRenderer( } override fun draw() { - glDepthFunc(GL_LEQUAL) - + renderWindow.renderSystem.reset(depth = DepthFunctions.LESS_OR_EQUAL) drawSkybox() drawSun() - - glDepthFunc(GL_LESS) } companion object : RendererBuilder { diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/BlendingFunctions.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/BlendingFunctions.kt new file mode 100644 index 000000000..e970359fc --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/BlendingFunctions.kt @@ -0,0 +1,32 @@ +/* + * 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 . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.gui.rendering.system.base + +enum class BlendingFunctions { + ZERO, + ONE, + SOURCE_COLOR, + ONE_MINUS_SOURCE_COLOR, + DESTINATION_COLOR, + ONE_MINUS_DESTINATION_COLOR, + SOURCE_ALPHA, + ONE_MINUS_SOURCE_ALPHA, + DESTINATION_ALPHA, + ONE_MINUS_DESTINATION_ALPHA, + CONSTANT_COLOR, + ONE_MINUS_CONSTANT_COLOR, + CONSTANT_ALPHA, + ONE_MINUS_CONSTANT_ALPHA, + ; +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/DepthFunctions.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/DepthFunctions.kt new file mode 100644 index 000000000..df6466e2b --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/DepthFunctions.kt @@ -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 . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.gui.rendering.system.base + +enum class DepthFunctions { + NEVER, + LESS, + EQUAL, + LESS_OR_EQUAL, + GREATER, + NOT_EQUAL, + GREATER_OR_EQUAL, + ALWAYS, + ; +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/RenderSystem.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/RenderSystem.kt new file mode 100644 index 000000000..ee6be3bdd --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/RenderSystem.kt @@ -0,0 +1,50 @@ +/* + * 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 . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.gui.rendering.system.base + +import de.bixilon.minosoft.gui.rendering.shader.Shader + +interface RenderSystem { + var shader: Shader? + + fun init() + + fun reset( + depthTest: Boolean = true, + blending: Boolean = true, + faceCulling: Boolean = true, + sourceAlpha: BlendingFunctions = BlendingFunctions.SOURCE_ALPHA, + destinationAlpha: BlendingFunctions = BlendingFunctions.ONE_MINUS_SOURCE_ALPHA, + depth: DepthFunctions = DepthFunctions.LESS, + depthMask: Boolean = true, + ) { + this[RenderingCapabilities.DEPTH_TEST] = depthTest + this[RenderingCapabilities.BLENDING] = blending + this[RenderingCapabilities.FACE_CULLING] = faceCulling + this[sourceAlpha] = destinationAlpha + this.depth = depth + this.depthMask = depthMask + } + + fun enable(capability: RenderingCapabilities) + fun disable(capability: RenderingCapabilities) + operator fun set(capability: RenderingCapabilities, status: Boolean) + operator fun get(capability: RenderingCapabilities): Boolean + + operator fun set(source: BlendingFunctions, destination: BlendingFunctions) + + var depth: DepthFunctions + var depthMask: Boolean + +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/RenderingCapabilities.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/RenderingCapabilities.kt new file mode 100644 index 000000000..03fc358b7 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/RenderingCapabilities.kt @@ -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 . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.gui.rendering.system.base + +enum class RenderingCapabilities { + DEPTH_TEST, + BLENDING, + FACE_CULLING, + ; +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/system/opengl/OpenGLRenderSystem.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/system/opengl/OpenGLRenderSystem.kt new file mode 100644 index 000000000..9516c1c64 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/system/opengl/OpenGLRenderSystem.kt @@ -0,0 +1,153 @@ +/* + * 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 . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.gui.rendering.system.opengl + +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.util.KUtil.synchronizedMapOf +import de.bixilon.minosoft.util.KUtil.synchronizedSetOf +import org.lwjgl.opengl.GL +import org.lwjgl.opengl.GL20.* + +class OpenGLRenderSystem : RenderSystem { + val shaders: MutableMap = synchronizedMapOf() // ToDo + private val capabilities: MutableSet = synchronizedSetOf() + var blendingSource = BlendingFunctions.ONE + private set + var blendingDestination = BlendingFunctions.ZERO + private set + + override var shader: Shader? = null + set(value) { + if (value === field) { + return + } + val programId = shaders[value] ?: error("Shader not loaded: $value") + glUseProgram(programId) + field = value + } + + + override fun init() { + GL.createCapabilities() + } + + override fun enable(capability: RenderingCapabilities) { + this[capability] = true + } + + override fun disable(capability: RenderingCapabilities) { + this[capability] = false + } + + override fun set(capability: RenderingCapabilities, status: Boolean) { + val enabled = capabilities.contains(capability) + if ((enabled && status) || (!status && !enabled)) { + return + } + + val glCapability = capability.gl + + if (status) { + glEnable(glCapability) + capabilities += capability + } else { + glDisable(glCapability) + capabilities -= capability + } + } + + override fun get(capability: RenderingCapabilities): Boolean { + return capabilities.contains(capability) + } + + override fun set(source: BlendingFunctions, destination: BlendingFunctions) { + if (blendingDestination == destination && blendingSource == source) { + return + } + blendingSource = source + blendingDestination = destination + glBlendFunc(source.gl, destination.gl) + } + + override var depth: DepthFunctions = DepthFunctions.LESS + set(value) { + if (field == value) { + return + } + glDepthFunc(value.gl) + field = value + } + + override var depthMask: Boolean = true + set(value) { + if (field == value) { + return + } + glDepthMask(value) + field = value + } + + + companion object { + private val RenderingCapabilities.gl: Int + get() { + return when (this) { + RenderingCapabilities.BLENDING -> GL_BLEND + RenderingCapabilities.DEPTH_TEST -> GL_DEPTH_TEST + RenderingCapabilities.FACE_CULLING -> GL_CULL_FACE + else -> throw IllegalArgumentException("OpenGL does not support capability: $this") + } + } + + private val BlendingFunctions.gl: Int + get() { + return when (this) { + BlendingFunctions.ZERO -> GL_ZERO + BlendingFunctions.ONE -> GL_ONE + BlendingFunctions.SOURCE_COLOR -> GL_SRC_COLOR + BlendingFunctions.ONE_MINUS_SOURCE_COLOR -> GL_ONE_MINUS_SRC_COLOR + BlendingFunctions.DESTINATION_COLOR -> GL_DST_COLOR + BlendingFunctions.ONE_MINUS_DESTINATION_COLOR -> GL_ONE_MINUS_DST_COLOR + BlendingFunctions.SOURCE_ALPHA -> GL_SRC_ALPHA + BlendingFunctions.ONE_MINUS_SOURCE_ALPHA -> GL_ONE_MINUS_SRC_ALPHA + BlendingFunctions.DESTINATION_ALPHA -> GL_DST_ALPHA + BlendingFunctions.ONE_MINUS_DESTINATION_ALPHA -> GL_ONE_MINUS_DST_ALPHA + BlendingFunctions.CONSTANT_COLOR -> GL_CONSTANT_COLOR + BlendingFunctions.ONE_MINUS_CONSTANT_COLOR -> GL_ONE_MINUS_CONSTANT_COLOR + BlendingFunctions.CONSTANT_ALPHA -> GL_CONSTANT_ALPHA + BlendingFunctions.ONE_MINUS_CONSTANT_ALPHA -> GL_ONE_MINUS_CONSTANT_ALPHA + else -> throw IllegalArgumentException("OpenGL does not support blending function: $this") + } + } + + private val DepthFunctions.gl: Int + get() { + return when (this) { + DepthFunctions.NEVER -> GL_NEVER + DepthFunctions.LESS -> GL_LESS + DepthFunctions.EQUAL -> GL_EQUAL + DepthFunctions.LESS_OR_EQUAL -> GL_LEQUAL + DepthFunctions.GREATER -> GL_GREATER + DepthFunctions.NOT_EQUAL -> GL_NOTEQUAL + DepthFunctions.GREATER_OR_EQUAL -> GL_GEQUAL + DepthFunctions.ALWAYS -> GL_ALWAYS + else -> throw IllegalArgumentException("OpenGL does not support depth function: $this") + } + } + } +}