abstract shaders

This commit is contained in:
Bixilon 2021-07-01 16:05:16 +02:00
parent 5e2437498b
commit 237b63ae91
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
15 changed files with 190 additions and 103 deletions

View File

@ -36,7 +36,7 @@ import java.io.StringReader
import java.util.*
import java.util.regex.Pattern
class CommandStringReader {
open class CommandStringReader {
val string: String
var cursor = 0

View File

@ -30,7 +30,6 @@ import de.bixilon.minosoft.gui.rendering.particle.ParticleRenderer
import de.bixilon.minosoft.gui.rendering.sky.SkyRenderer
import de.bixilon.minosoft.gui.rendering.system.base.PolygonModes
import de.bixilon.minosoft.gui.rendering.system.base.RenderSystem
import de.bixilon.minosoft.gui.rendering.system.base.shader.Shader
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
@ -83,8 +82,6 @@ class RenderWindow(
val queue = Queue()
val shaders: MutableList<Shader> = mutableListOf()
val shaderManager = ShaderManager(this)
lateinit var WHITE_TEXTURE: TextureLike

View File

@ -19,13 +19,10 @@ import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
class ShaderManager(
val renderWindow: RenderWindow,
) {
val genericColorShader = Shader(
renderWindow = renderWindow,
resourceLocation = ResourceLocation(ProtocolDefinition.MINOSOFT_NAMESPACE, "generic/color"),
)
val genericColorShader = renderWindow.renderSystem.createShader(ResourceLocation(ProtocolDefinition.MINOSOFT_NAMESPACE, "generic/color"))
fun init() {
genericColorShader.load(renderWindow.connection.assetsManager)
genericColorShader.load()
}
}

View File

@ -62,7 +62,7 @@ class WorldRenderer(
private val world: World = connection.world
private val waterBlock = connection.registries.blockRegistry[ResourceLocation("minecraft:water")]?.nullCast<FluidBlock>()
lateinit var chunkShader: Shader
private val chunkShader: Shader = renderWindow.renderSystem.createShader(ResourceLocation(ProtocolDefinition.MINOSOFT_NAMESPACE, "world"))
private val lightMap = LightMap(connection)
val allChunkSections: SynchronizedMap<Vec2i, SynchronizedMap<Int, ChunkSectionMeshCollection>> = synchronizedMapOf()
@ -181,10 +181,6 @@ class WorldRenderer(
override fun postInit() {
check(renderWindow.textures.animator.animatedTextures.size < TextureArray.MAX_ANIMATED_TEXTURES) { "Can not have more than ${TextureArray.MAX_ANIMATED_TEXTURES} animated textures!" }
chunkShader = Shader(
renderWindow = renderWindow,
resourceLocation = ResourceLocation(ProtocolDefinition.MINOSOFT_NAMESPACE, "world"),
)
chunkShader.load()
lightMap.init()

View File

@ -40,10 +40,7 @@ import glm_.vec2.Vec2i
class HUDRenderer(val connection: PlayConnection, val renderWindow: RenderWindow) : Renderer {
private val hudElements: MutableMap<ResourceLocation, Pair<HUDElementProperties, HUDElement>> = mutableMapOf()
private val enabledHUDElement: MutableMap<ResourceLocation, Pair<HUDElementProperties, HUDElement>> = mutableMapOf()
private val hudShader = Shader(
renderWindow = renderWindow,
resourceLocation = ResourceLocation(ProtocolDefinition.MINOSOFT_NAMESPACE, "hud"),
)
private val hudShader = renderWindow.renderSystem.createShader(ResourceLocation(ProtocolDefinition.MINOSOFT_NAMESPACE, "hud"))
lateinit var hudAtlasElements: Map<ResourceLocation, HUDAtlasElement>
var orthographicMatrix: Mat4 = Mat4()
private set
@ -55,7 +52,7 @@ class HUDRenderer(val connection: PlayConnection, val renderWindow: RenderWindow
override fun init() {
hudShader.load(Minosoft.MINOSOFT_ASSETS_MANAGER)
hudShader.load()
this.hudAtlasElements = HUDAtlasElement.deserialize(Minosoft.MINOSOFT_ASSETS_MANAGER.readJsonAsset(ResourceLocation(ProtocolDefinition.MINOSOFT_NAMESPACE, "mapping/atlas.json")).toResourceLocationMap(), renderWindow.textures.allTextures)

View File

@ -40,6 +40,7 @@ import glm_.func.cos
import glm_.func.rad
import glm_.func.sin
import glm_.glm
import glm_.mat4x4.Mat4
import glm_.mat4x4.Mat4d
import glm_.vec2.Vec2
import glm_.vec2.Vec2d
@ -152,9 +153,9 @@ class Camera(
projectionMatrix = projectionMatrix,
viewProjectionMatrix = viewProjectionMatrix,
))
for (shader in renderWindow.shaders) {
for (shader in renderWindow.renderSystem.shaders) {
if (shader.uniforms.contains("uViewProjectionMatrix")) {
shader.use().setMat4("uViewProjectionMatrix", viewProjectionMatrix)
shader.use().setMat4("uViewProjectionMatrix", Mat4(viewProjectionMatrix))
}
}
}

View File

@ -27,6 +27,7 @@ import de.bixilon.minosoft.protocol.network.connection.PlayConnection
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
import de.bixilon.minosoft.util.KUtil.synchronizedSetOf
import de.bixilon.minosoft.util.KUtil.toSynchronizedSet
import glm_.mat4x4.Mat4
import glm_.vec3.Vec3
@ -34,7 +35,7 @@ class ParticleRenderer(
private val connection: PlayConnection,
val renderWindow: RenderWindow,
) : Renderer {
private lateinit var particleShader: Shader
private val particleShader: Shader = renderWindow.renderSystem.createShader(ResourceLocation(ProtocolDefinition.MINOSOFT_NAMESPACE, "particle"))
private var particleMesh = ParticleMesh()
private var transparentParticleMesh = ParticleMesh()
@ -43,7 +44,7 @@ class ParticleRenderer(
override fun init() {
connection.registerEvent(CallbackEventInvoker.of<CameraMatrixChangeEvent> {
renderWindow.queue += {
particleShader.use().setMat4("uViewProjectionMatrix", it.viewProjectionMatrix)
particleShader.use().setMat4("uViewProjectionMatrix", Mat4(it.viewProjectionMatrix))
particleShader.use().setVec3("uCameraRight", Vec3(it.viewMatrix[0][0], it.viewMatrix[1][0], it.viewMatrix[2][0]))
particleShader.use().setVec3("uCameraUp", Vec3(it.viewMatrix[0][1], it.viewMatrix[1][1], it.viewMatrix[2][1]))
}
@ -60,10 +61,6 @@ class ParticleRenderer(
}
override fun postInit() {
particleShader = Shader(
renderWindow = renderWindow,
resourceLocation = ResourceLocation(ProtocolDefinition.MINOSOFT_NAMESPACE, "particle"),
)
particleShader.load()
renderWindow.textures.use(particleShader)
renderWindow.textures.animator.use(particleShader)

View File

@ -29,6 +29,7 @@ import de.bixilon.minosoft.protocol.network.connection.PlayConnection
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
import de.bixilon.minosoft.util.MMath
import glm_.func.rad
import glm_.mat4x4.Mat4
import glm_.mat4x4.Mat4d
import glm_.vec2.Vec2
import glm_.vec3.Vec3
@ -39,14 +40,8 @@ class SkyRenderer(
private val connection: PlayConnection,
val renderWindow: RenderWindow,
) : Renderer {
private val skyboxShader = Shader(
renderWindow = renderWindow,
resourceLocation = ResourceLocation(ProtocolDefinition.MINOSOFT_NAMESPACE, "sky/skybox"),
)
private val skySunShader = Shader(
renderWindow = renderWindow,
resourceLocation = ResourceLocation(ProtocolDefinition.MINOSOFT_NAMESPACE, "sky/sun"),
)
private val skyboxShader = renderWindow.renderSystem.createShader(ResourceLocation(ProtocolDefinition.MINOSOFT_NAMESPACE, "sky/skybox"))
private val skySunShader = renderWindow.renderSystem.createShader(ResourceLocation(ProtocolDefinition.MINOSOFT_NAMESPACE, "sky/sun"))
private val skyboxMesh = SkyboxMesh()
private var skySunMesh = SimpleTextureMesh()
private lateinit var sunTexture: Texture
@ -65,7 +60,7 @@ class SkyRenderer(
connection.registerEvent(CallbackEventInvoker.of<CameraMatrixChangeEvent> {
val viewProjectionMatrix = it.projectionMatrix * it.viewMatrix.toMat3().toMat4()
renderWindow.queue += {
skyboxShader.use().setMat4("uSkyViewProjectionMatrix", viewProjectionMatrix)
skyboxShader.use().setMat4("uSkyViewProjectionMatrix", Mat4(viewProjectionMatrix))
setSunMatrix(viewProjectionMatrix)
}
})
@ -84,7 +79,7 @@ class SkyRenderer(
} else {
projectionViewMatrix.rotate(timeAngle, Vec3d(0.0f, 0.0f, 1.0f))
}
skySunShader.use().setMat4("uSkyViewProjectionMatrix", rotatedMatrix) // ToDo: 180° is top, not correct yet
skySunShader.use().setMat4("uSkyViewProjectionMatrix", Mat4(rotatedMatrix))
}
override fun postInit() {

View File

@ -13,11 +13,13 @@
package de.bixilon.minosoft.gui.rendering.system.base
import de.bixilon.minosoft.data.registries.ResourceLocation
import de.bixilon.minosoft.gui.rendering.system.base.shader.Shader
import glm_.vec2.Vec2i
import java.nio.ByteBuffer
interface RenderSystem {
val shaders: MutableSet<Shader>
val vendor: GPUVendor
var shader: Shader?
@ -58,4 +60,7 @@ interface RenderSystem {
val maximumVRAM: Long
fun readPixels(start: Vec2i, end: Vec2i, type: PixelTypes): ByteBuffer
fun createShader(resourceLocation: ResourceLocation): Shader
}

View File

@ -8,13 +8,7 @@ import de.bixilon.minosoft.gui.rendering.RenderWindow
object GLSLUtil {
fun readGLSL(
assetsManager: AssetsManager = Minosoft.MINOSOFT_ASSETS_MANAGER,
renderWindow: RenderWindow,
resourceLocation: ResourceLocation,
defines: Map<String, Any>,
uniforms: MutableList<String>
): String {
fun readGLSL(assetsManager: AssetsManager = Minosoft.MINOSOFT_ASSETS_MANAGER, renderWindow: RenderWindow, resourceLocation: ResourceLocation, defines: Map<String, Any>, uniforms: MutableList<String>): String {
val total = StringBuilder()
val lines = assetsManager.readStringAsset(resourceLocation).lines()
@ -81,4 +75,4 @@ object GLSLUtil {
}
return total.toString()
}
}
}

View File

@ -13,8 +13,6 @@
package de.bixilon.minosoft.gui.rendering.system.base.shader
import de.bixilon.minosoft.Minosoft
import de.bixilon.minosoft.data.assets.AssetsManager
import de.bixilon.minosoft.data.registries.ResourceLocation
import de.bixilon.minosoft.data.text.RGBColor
import de.bixilon.minosoft.gui.rendering.RenderWindow
@ -27,14 +25,14 @@ import glm_.vec3.Vec3
import glm_.vec4.Vec4
interface Shader {
val loaded: Boolean
val renderWindow: RenderWindow
val resourceLocation: ResourceLocation
val uniforms: List<String>
val log: String
fun load(assetsManager: AssetsManager = Minosoft.MINOSOFT_ASSETS_MANAGER)
fun load()
fun use(): Shader {
renderWindow.renderSystem.shader = this

View File

@ -0,0 +1,87 @@
/*
* 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.shader.code.glsl
import de.bixilon.minosoft.data.registries.ResourceLocation
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.system.base.shader.Shader
class GLSLShaderCode(
private val renderWindow: RenderWindow,
private val rawCode: String,
) {
val defines: MutableMap<String, Any> = mutableMapOf()
val uniforms: MutableSet<String> = mutableSetOf()
init {
// ToDo: This is complete trash and should be replaced
for (line in rawCode.lines()) {
if (!line.startsWith("uniform ")) {
continue
}
val reader = GLSLStringReader(line.removePrefix("uniform "))
uniforms += reader.readUnquotedString()
}
for ((name, value) in Shader.DEFAULT_DEFINES) {
value(renderWindow)?.let { defines[name] = it }
}
defines[renderWindow.renderSystem.vendor.shaderDefine] = ""
}
val code: String
get() {
// ToDo: This is complete trash and should be replaced
val code = StringBuilder()
for (line in rawCode.lines()) {
fun pushLine() {
code.append(line)
code.append('\n')
}
when {
line.startsWith("#include ") -> {
val reader = GLSLStringReader(line.removePrefix("#include "))
reader.skipWhitespaces()
val include = ResourceLocation(reader.readString())
val includeCode = GLSLShaderCode(renderWindow, renderWindow.connection.assetsManager.readStringAsset(ResourceLocation(include.namespace, "rendering/shader/includes/${include.path}.glsl")))
this.uniforms += includeCode.uniforms
code.append('\n')
code.append(includeCode.code)
code.append('\n')
}
line.startsWith("#version") -> {
pushLine()
for ((name, value) in defines) {
code.append("#define ")
code.append(name)
code.append(' ')
code.append(value)
code.append('\n')
}
}
else -> pushLine()
}
}
return code.toString()
}
}

View File

@ -0,0 +1,18 @@
/*
* 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.shader.code.glsl
import de.bixilon.minosoft.data.commands.CommandStringReader
class GLSLStringReader(text: String) : CommandStringReader(text)

View File

@ -13,13 +13,13 @@
package de.bixilon.minosoft.gui.rendering.system.opengl
import de.bixilon.minosoft.data.registries.ResourceLocation
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.modding.events.ResizeWindowEvent
import de.bixilon.minosoft.gui.rendering.system.base.*
import de.bixilon.minosoft.gui.rendering.system.base.shader.Shader
import de.bixilon.minosoft.gui.rendering.system.opengl.vendor.*
import de.bixilon.minosoft.modding.event.CallbackEventInvoker
import de.bixilon.minosoft.util.KUtil.synchronizedMapOf
import de.bixilon.minosoft.util.KUtil.synchronizedSetOf
import glm_.vec2.Vec2i
import org.lwjgl.BufferUtils
@ -30,7 +30,7 @@ import java.nio.ByteBuffer
class OpenGLRenderSystem(
private val renderWindow: RenderWindow,
) : RenderSystem {
val shaders: MutableMap<Shader, Int> = synchronizedMapOf() // ToDo
override val shaders: MutableSet<Shader> = mutableSetOf()
private val capabilities: MutableSet<RenderingCapabilities> = synchronizedSetOf()
override lateinit var vendor: OpenGLVendor
private set
@ -45,8 +45,14 @@ class OpenGLRenderSystem(
if (value === field) {
return
}
val programId = shaders[value] ?: error("Shader not loaded: $value")
glUseProgram(programId)
value ?: error("Shader is null!")
check(value is OpenGLShader) { "Can not use non OpenGL shader in OpenGL render system!" }
check(value.loaded) { "Shader not loaded!" }
check(value in shaders) { "Shader not part of this context!" }
value.unsafeUse()
field = value
}
@ -151,6 +157,10 @@ class OpenGLRenderSystem(
return buffer
}
override fun createShader(resourceLocation: ResourceLocation): OpenGLShader {
return OpenGLShader(renderWindow, resourceLocation)
}
companion object {
private val RenderingCapabilities.gl: Int
get() {

View File

@ -13,17 +13,13 @@
package de.bixilon.minosoft.gui.rendering.system.opengl
import de.bixilon.minosoft.Minosoft
import de.bixilon.minosoft.data.assets.AssetsManager
import de.bixilon.minosoft.data.registries.ResourceLocation
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.base.shader.GLSLUtil
import de.bixilon.minosoft.gui.rendering.system.base.shader.Shader
import de.bixilon.minosoft.gui.rendering.system.base.shader.code.glsl.GLSLShaderCode
import de.bixilon.minosoft.gui.rendering.util.OpenGLUtil
import de.bixilon.minosoft.util.KUtil.unsafeCast
import glm_.mat4x4.Mat4
import glm_.vec2.Vec2
import glm_.vec3.Vec3
@ -36,31 +32,29 @@ import org.lwjgl.opengl.ARBVertexShader.GL_VERTEX_SHADER_ARB
import org.lwjgl.opengl.GL11.GL_FALSE
import org.lwjgl.opengl.GL43.*
import org.lwjgl.system.MemoryUtil
import java.io.FileNotFoundException
class OpenGLShader(
override val renderWindow: RenderWindow,
override val resourceLocation: ResourceLocation,
private val defines: Map<String, Any> = mapOf(),
) : Shader {
private var program = -1
override lateinit var uniforms: List<String>
override var loaded: Boolean = false
private set
val defines: MutableMap<String, Any> = mutableMapOf()
private var shader = -1
override var uniforms: List<String> = listOf()
private set
private fun load(resourceLocation: ResourceLocation, shaderType: Int): Int {
val code = GLSLShaderCode(renderWindow, renderWindow.connection.assetsManager.readStringAsset(resourceLocation))
private fun load(
assetsManager: AssetsManager = Minosoft.MINOSOFT_ASSETS_MANAGER,
resourceLocation: ResourceLocation,
shaderType: Int,
defines: Map<String, Any>,
uniforms: MutableList<String>
): Int? {
val program = glCreateShaderObjectARB(shaderType)
if (program.toLong() == MemoryUtil.NULL) {
throw ShaderLoadingException()
}
val code = GLSLUtil.readGLSL(assetsManager, renderWindow, resourceLocation, defines, uniforms)
glShaderSourceARB(program, code)
glShaderSourceARB(program, code.code)
glCompileShaderARB(program)
if (glGetObjectParameteriARB(program, GL_OBJECT_COMPILE_STATUS_ARB) == GL_FALSE) {
@ -70,57 +64,54 @@ class OpenGLShader(
return program
}
override fun load(assetsManager: AssetsManager) {
val uniforms: MutableList<String> = mutableListOf()
override fun load() {
val pathPrefix = "${resourceLocation.namespace}:rendering/shader/${resourceLocation.path}/${
resourceLocation.path.replace(
"/",
"_"
)
}"
val vertexShader =
load(assetsManager, ResourceLocation("$pathPrefix.vsh"), GL_VERTEX_SHADER_ARB, defines, uniforms)!!
val geometryShader =
load(assetsManager, ResourceLocation("$pathPrefix.gsh"), GL_GEOMETRY_SHADER_ARB, defines, uniforms)
val fragmentShader =
load(assetsManager, ResourceLocation("$pathPrefix.fsh"), GL_FRAGMENT_SHADER_ARB, defines, uniforms)!!
this.uniforms = uniforms.toList()
shader = glCreateProgramObjectARB()
program = glCreateProgramObjectARB()
if (program.toLong() == MemoryUtil.NULL) {
if (shader.toLong() == MemoryUtil.NULL) {
throw ShaderLoadingException()
}
glAttachObjectARB(program, vertexShader)
geometryShader?.let {
glAttachObjectARB(program, it)
}
glAttachObjectARB(program, fragmentShader)
glLinkProgramARB(program)
val programs: MutableList<Int> = mutableListOf()
if (glGetObjectParameteriARB(program, GL_OBJECT_LINK_STATUS_ARB) == GL_FALSE) {
throw ShaderLoadingException(OpenGLUtil.getLogInfo(program))
programs += load(ResourceLocation("$pathPrefix.vsh"), GL_VERTEX_SHADER_ARB)
try {
programs += load(ResourceLocation("$pathPrefix.gsh"), GL_GEOMETRY_SHADER_ARB)
} catch (exception: FileNotFoundException) {
}
programs += load(ResourceLocation("$pathPrefix.fsh"), GL_FRAGMENT_SHADER_ARB)
for (program in programs) {
glAttachObjectARB(shader, program)
}
glValidateProgramARB(program)
glLinkProgramARB(shader)
if (glGetObjectParameteriARB(program, GL_OBJECT_VALIDATE_STATUS_ARB) == GL_FALSE) {
throw ShaderLoadingException(OpenGLUtil.getLogInfo(program))
if (glGetObjectParameteriARB(shader, GL_OBJECT_LINK_STATUS_ARB) == GL_FALSE) {
throw ShaderLoadingException(OpenGLUtil.getLogInfo(shader))
}
glDeleteShader(vertexShader)
geometryShader?.let {
glDeleteShader(it)
}
glDeleteShader(fragmentShader)
val context = Rendering.currentContext!!
context.shaders.add(this)
context.renderSystem.unsafeCast<OpenGLRenderSystem>().shaders[this] = program
glValidateProgramARB(shader)
if (glGetObjectParameteriARB(shader, GL_OBJECT_VALIDATE_STATUS_ARB) == GL_FALSE) {
throw ShaderLoadingException(OpenGLUtil.getLogInfo(shader))
}
for (program in programs) {
glDeleteShader(program)
}
loaded = true
renderWindow.renderSystem.shaders += this
}
private fun getUniformLocation(uniformName: String): Int {
return glGetUniformLocation(program, uniformName)
return glGetUniformLocation(shader, uniformName)
}
override fun setFloat(uniformName: String, value: Float) {
@ -163,7 +154,11 @@ class OpenGLShader(
}
override fun setUniformBuffer(uniformName: String, uniformBuffer: UniformBuffer) {
glUniformBlockBinding(program, glGetUniformBlockIndex(program, uniformName), uniformBuffer.bindingIndex)
glUniformBlockBinding(shader, glGetUniformBlockIndex(shader, uniformName), uniformBuffer.bindingIndex)
}
fun unsafeUse() {
glUseProgram(shader)
}
override val log: String