wip: abstract opengl render system

This commit is contained in:
Bixilon 2021-06-19 21:30:24 +02:00
parent 9e3d3a409f
commit 5a991b45b8
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
14 changed files with 307 additions and 47 deletions

View File

@ -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) }

View File

@ -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)
}

View File

@ -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<BlockState>, textures: MutableMap<ResourceLocation, Texture>) {
@ -263,14 +262,14 @@ class WorldRenderer(
}
private fun checkNeighbours(chunkPosition: Vec2i) {
val neighborsVec2is: Array<Vec2i> = arrayOf(
val neighborsPositions: Array<Vec2i> = arrayOf(
chunkPosition + Directions.NORTH,
chunkPosition + Directions.SOUTH,
chunkPosition + Directions.WEST,
chunkPosition + Directions.EAST,
)
checkQueuedChunks(neighborsVec2is)
checkQueuedChunks(neighborsPositions)
}
private fun checkQueuedChunks(chunkPositions: Array<Vec2i>) {

View File

@ -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() {

View File

@ -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)
}
}

View File

@ -158,6 +158,7 @@ class HUDRenderer(val connection: PlayConnection, val renderWindow: RenderWindow
if (!hudEnabled) {
return
}
renderWindow.renderSystem.reset()
var needsUpdate = false
val tempMesh = HUDMesh()

View File

@ -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<ParticleRenderer> {

View File

@ -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<OpenGLRenderSystem>().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<String, Any>, uniforms: MutableList<String>): Int? {
val shaderId = glCreateShaderObjectARB(shaderType)

View File

@ -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<SkyRenderer> {

View File

@ -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 <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.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,
;
}

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.system.base
enum class DepthFunctions {
NEVER,
LESS,
EQUAL,
LESS_OR_EQUAL,
GREATER,
NOT_EQUAL,
GREATER_OR_EQUAL,
ALWAYS,
;
}

View File

@ -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 <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.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
}

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.base
enum class RenderingCapabilities {
DEPTH_TEST,
BLENDING,
FACE_CULLING,
;
}

View File

@ -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 <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.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<Shader, Int> = synchronizedMapOf() // ToDo
private val capabilities: MutableSet<RenderingCapabilities> = 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")
}
}
}
}