render simple letter on screen

This commit is contained in:
Bixilon 2021-02-08 23:16:10 +01:00
parent b418145f88
commit c706ee7d36
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
11 changed files with 172 additions and 38 deletions

View File

@ -2,8 +2,12 @@ package de.bixilon.minosoft.gui.rendering
import de.bixilon.minosoft.data.entities.EntityRotation import de.bixilon.minosoft.data.entities.EntityRotation
import de.bixilon.minosoft.data.entities.Location import de.bixilon.minosoft.data.entities.Location
import de.bixilon.minosoft.data.mappings.blocks.Block
import de.bixilon.minosoft.data.world.ChunkLocation import de.bixilon.minosoft.data.world.ChunkLocation
import de.bixilon.minosoft.gui.rendering.font.Font
import de.bixilon.minosoft.gui.rendering.font.Font2DMesh
import de.bixilon.minosoft.gui.rendering.shader.Shader import de.bixilon.minosoft.gui.rendering.shader.Shader
import de.bixilon.minosoft.gui.rendering.textures.Texture
import de.bixilon.minosoft.gui.rendering.textures.TextureArray import de.bixilon.minosoft.gui.rendering.textures.TextureArray
import de.bixilon.minosoft.protocol.network.Connection import de.bixilon.minosoft.protocol.network.Connection
import de.bixilon.minosoft.protocol.packets.serverbound.play.PacketPlayerPositionAndRotationSending import de.bixilon.minosoft.protocol.packets.serverbound.play.PacketPlayerPositionAndRotationSending
@ -27,7 +31,9 @@ class RenderWindow(private val connection: Connection) {
private var screenHeight = 600 private var screenHeight = 600
private var polygonEnabled = false private var polygonEnabled = false
private lateinit var chunkShader: Shader private lateinit var chunkShader: Shader
private lateinit var fontShader: Shader
private lateinit var minecraftTextures: TextureArray private lateinit var minecraftTextures: TextureArray
private lateinit var fontAtlasTexture: TextureArray
private var windowId: Long = 0 private var windowId: Long = 0
private var deltaTime = 0.0 // time between current frame and last frame private var deltaTime = 0.0 // time between current frame and last frame
@ -36,7 +42,8 @@ class RenderWindow(private val connection: Connection) {
val renderQueue = ConcurrentLinkedQueue<Runnable>() val renderQueue = ConcurrentLinkedQueue<Runnable>()
val chunkSectionsToDraw = ConcurrentHashMap<ChunkLocation, ConcurrentHashMap<Int, Mesh>>() val chunkSectionsToDraw = ConcurrentHashMap<ChunkLocation, ConcurrentHashMap<Int, WorldMesh>>()
val font2DToDraw = ConcurrentLinkedQueue<Font2DMesh>()
fun init(latch: CountUpAndDownLatch? = null) { fun init(latch: CountUpAndDownLatch? = null) {
@ -110,17 +117,35 @@ class RenderWindow(private val connection: Connection) {
glEnable(GL_BLEND) glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
minecraftTextures = TextureArray(connection.version.assetsManager, connection.version.mapping.blockMap.values) minecraftTextures = TextureArray(connection.version.assetsManager, resolveBlockTextureIds(connection.version.mapping.blockMap.values))
minecraftTextures.load() minecraftTextures.load()
fontAtlasTexture = TextureArray(connection.version.assetsManager, listOf(Texture("font/unicode_page_00", 0)), 256)
fontAtlasTexture.load()
chunkShader = Shader("chunk_vertex.glsl", "chunk_fragment.glsl") chunkShader = Shader("chunk_vertex.glsl", "chunk_fragment.glsl")
chunkShader.load() chunkShader.load()
chunkShader.use() chunkShader.use()
chunkShader.setInt("texture0", 0)
camera.calculateProjectionMatrix(screenWidth, screenHeight, chunkShader) camera.calculateProjectionMatrix(screenWidth, screenHeight, chunkShader)
camera.calculateViewMatrix(chunkShader) camera.calculateViewMatrix(chunkShader)
fontShader = Shader("font_vertex.glsl", "font_fragment.glsl")
fontShader.load()
fontShader.use()
fontShader.setFloat("atlasSize", 256f)
val font = Font()
val char = font.chars['§']!!
font2DToDraw.add(Font2DMesh(floatArrayOf(
-0.5f, -0.5f, char.column * 16f, char.row * 16f + char.width, font.atlasOffset + char.atlasPage.toFloat(),
-0.5f, 0f, char.column * 16f, char.row * 16f, font.atlasOffset + char.atlasPage.toFloat(),
0f, -0.5f, char.column * 16f + char.width, char.row * 16f + char.width, font.atlasOffset + char.atlasPage.toFloat(),
0f, -0.5f, char.column * 16f + char.width, char.row * 16f + char.width, font.atlasOffset + char.atlasPage.toFloat(),
-0.5f, 0f, char.column * 16f, char.row * 16f, font.atlasOffset + char.atlasPage.toFloat(),
0f, 0f, char.column * 16f + char.width, char.row * 16f, font.atlasOffset + char.atlasPage.toFloat(),
)))
glfwSetWindowSizeCallback(windowId, object : GLFWWindowSizeCallback() { glfwSetWindowSizeCallback(windowId, object : GLFWWindowSizeCallback() {
override fun invoke(window: Long, width: Int, height: Int) { override fun invoke(window: Long, width: Int, height: Int) {
glViewport(0, 0, width, height) glViewport(0, 0, width, height)
@ -148,6 +173,8 @@ class RenderWindow(private val connection: Connection) {
deltaTime = currentFrame - lastFrame deltaTime = currentFrame - lastFrame
lastFrame = currentFrame lastFrame = currentFrame
glEnable(GL_DEPTH_TEST)
minecraftTextures.use(GL_TEXTURE0) minecraftTextures.use(GL_TEXTURE0)
chunkShader.use() chunkShader.use()
@ -160,6 +187,15 @@ class RenderWindow(private val connection: Connection) {
} }
} }
glDisable(GL_DEPTH_TEST)
fontAtlasTexture.use(GL_TEXTURE0)
fontShader.use()
for (font in font2DToDraw) {
font.draw()
}
glfwSwapBuffers(windowId) glfwSwapBuffers(windowId)
glfwPollEvents() glfwPollEvents()
@ -179,6 +215,7 @@ class RenderWindow(private val connection: Connection) {
if (glfwGetTime() - lastPositionChangeTime > 0.05) { if (glfwGetTime() - lastPositionChangeTime > 0.05) {
// ToDo: Replace this with proper movement and only send it, when out position changed // ToDo: Replace this with proper movement and only send it, when out position changed
connection.sendPacket(PacketPlayerPositionAndRotationSending(Location(camera.cameraPosition), EntityRotation(camera.yaw, camera.pitch), false)) connection.sendPacket(PacketPlayerPositionAndRotationSending(Location(camera.cameraPosition), EntityRotation(camera.yaw, camera.pitch), false))
lastPositionChangeTime = glfwGetTime()
} }
@ -207,4 +244,16 @@ class RenderWindow(private val connection: Connection) {
}) })
polygonEnabled = !polygonEnabled polygonEnabled = !polygonEnabled
} }
private fun resolveBlockTextureIds(blocks: Set<Block>): List<Texture> {
val textures: MutableList<Texture> = mutableListOf()
textures.add(TextureArray.DEBUG_TEXTURE)
val textureMap: MutableMap<String, Texture> = mutableMapOf()
textureMap[TextureArray.DEBUG_TEXTURE.name] = TextureArray.DEBUG_TEXTURE
for (block in blocks) {
block.blockModel?.resolveTextures(textures, textureMap)
}
return textures
}
} }

View File

@ -45,7 +45,7 @@ class Renderer(private val connection: Connection) {
renderWindow.renderQueue.add { renderWindow.renderQueue.add {
sectionMap[sectionHeight]?.unload() sectionMap[sectionHeight]?.unload()
sectionMap.remove(sectionHeight) sectionMap.remove(sectionHeight)
sectionMap[sectionHeight] = Mesh(data, Vec3(chunkLocation.x, sectionHeight, chunkLocation.z)) sectionMap[sectionHeight] = WorldMesh(data, Vec3(chunkLocation.x, sectionHeight, chunkLocation.z))
} }
} }
} }

View File

@ -2,9 +2,6 @@ package de.bixilon.minosoft.gui.rendering;
import de.bixilon.minosoft.gui.rendering.shader.Shader; import de.bixilon.minosoft.gui.rendering.shader.Shader;
import glm_.vec3.Vec3; import glm_.vec3.Vec3;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL20;
import static org.lwjgl.opengl.GL11.GL_TRIANGLES; import static org.lwjgl.opengl.GL11.GL_TRIANGLES;
import static org.lwjgl.opengl.GL11.glDrawArrays; import static org.lwjgl.opengl.GL11.glDrawArrays;
@ -12,13 +9,13 @@ import static org.lwjgl.opengl.GL15.glDeleteBuffers;
import static org.lwjgl.opengl.GL15.glGenBuffers; import static org.lwjgl.opengl.GL15.glGenBuffers;
import static org.lwjgl.opengl.GL30.*; import static org.lwjgl.opengl.GL30.*;
public class Mesh { public class WorldMesh {
int vAO; int vAO;
int vBO; int vBO;
Vec3 worldPosition; Vec3 worldPosition;
int trianglesCount; int trianglesCount;
public Mesh(float[] data, Vec3 worldPosition) { public WorldMesh(float[] data, Vec3 worldPosition) {
this.worldPosition = worldPosition; this.worldPosition = worldPosition;
this.trianglesCount = data.length / 6; // <- bytes per vertex this.trianglesCount = data.length / 6; // <- bytes per vertex
this.vAO = glGenVertexArrays(); this.vAO = glGenVertexArrays();
@ -26,17 +23,17 @@ public class Mesh {
// bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s). // bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s).
glBindVertexArray(this.vAO); glBindVertexArray(this.vAO);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, this.vBO); glBindBuffer(GL_ARRAY_BUFFER, this.vBO);
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, data, GL15.GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, data, GL_STATIC_DRAW);
GL20.glVertexAttribPointer(0, 3, GL11.GL_FLOAT, false, 6 * Float.BYTES, 0L); glVertexAttribPointer(0, 3, GL_FLOAT, false, 6 * Float.BYTES, 0L);
GL20.glEnableVertexAttribArray(0); glEnableVertexAttribArray(0);
GL20.glVertexAttribPointer(1, 2, GL11.GL_FLOAT, false, 6 * Float.BYTES, 3 * Float.BYTES); glVertexAttribPointer(1, 2, GL_FLOAT, false, 6 * Float.BYTES, 3 * Float.BYTES);
GL20.glEnableVertexAttribArray(1); glEnableVertexAttribArray(1);
GL20.glVertexAttribPointer(2, 1, GL11.GL_FLOAT, false, 6 * Float.BYTES, 5 * Float.BYTES); glVertexAttribPointer(2, 1, GL_FLOAT, false, 6 * Float.BYTES, 5 * Float.BYTES);
GL20.glEnableVertexAttribArray(2); glEnableVertexAttribArray(2);
// note that this is allowed, the call to glVertexAttribPointer registered VBO as the vertex attribute's bound vertex buffer object so afterwards we can safely unbind // note that this is allowed, the call to glVertexAttribPointer registered VBO as the vertex attribute's bound vertex buffer object so afterwards we can safely unbind
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, 0);
} }
public void draw(Shader chunkShader) { public void draw(Shader chunkShader) {

View File

@ -0,0 +1,17 @@
package de.bixilon.minosoft.gui.rendering.font
class Font {
val chars: MutableMap<Char, FontChar> = mutableMapOf()
val atlasOffset = 0
init {
for (page in 0 until 256) {
for (x in 0 until 16) {
for (y in 0 until 16) {
chars[(page * 256 + (x * 16 + y)).toChar()] = FontChar(page, x, y)
}
}
}
}
}

View File

@ -0,0 +1,40 @@
package de.bixilon.minosoft.gui.rendering.font
import glm_.BYTES
import org.lwjgl.opengl.GL11.GL_FLOAT
import org.lwjgl.opengl.GL20.glEnableVertexAttribArray
import org.lwjgl.opengl.GL20.glVertexAttribPointer
import org.lwjgl.opengl.GL30.*
class Font2DMesh(data: FloatArray) {
var vAO: Int = glGenVertexArrays()
var vBO: Int = glGenBuffers()
var trianglesCount: Int = data.size / 5 // <- bytes per vertex
fun draw() {
glBindVertexArray(vAO)
glDrawArrays(GL_TRIANGLES, 0, trianglesCount)
}
fun unload() {
glDeleteVertexArrays(vAO)
glDeleteBuffers(vBO)
}
init {
// bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s).
glBindVertexArray(vAO)
glBindBuffer(GL_ARRAY_BUFFER, vBO)
glBufferData(GL_ARRAY_BUFFER, data, GL_STATIC_DRAW)
glVertexAttribPointer(0, 2, GL_FLOAT, false, 5 * Float.BYTES, 0L)
glEnableVertexAttribArray(0)
glVertexAttribPointer(1, 2, GL_FLOAT, false, 5 * Float.BYTES, (2 * Float.BYTES).toLong())
glEnableVertexAttribArray(1)
glVertexAttribPointer(2, 1, GL_FLOAT, false, 5 * Float.BYTES, (4 * Float.BYTES).toLong())
glEnableVertexAttribArray(2)
// note that this is allowed, the call to glVertexAttribPointer registered VBO as the vertex attribute's bound vertex buffer object so afterwards we can safely unbind
glBindBuffer(GL_ARRAY_BUFFER, 0)
}
}

View File

@ -0,0 +1,6 @@
package de.bixilon.minosoft.gui.rendering.font
class FontChar(val atlasPage: Int, val row: Int, val column: Int) {
val width = 16
}

View File

@ -0,0 +1,8 @@
package de.bixilon.minosoft.gui.rendering.hud
enum class HUDScale(val scale: Float) {
TINY(0.1f),
MEDIUM(0.2f),
LARGE(0.5f),
SENIOR(1.0f),
}

View File

@ -1,8 +1,6 @@
package de.bixilon.minosoft.gui.rendering.textures package de.bixilon.minosoft.gui.rendering.textures
import de.bixilon.minosoft.data.assets.AssetsManager import de.bixilon.minosoft.data.assets.AssetsManager
import de.bixilon.minosoft.data.mappings.blocks.Block
import de.bixilon.minosoft.gui.rendering.textures.TextureLoader.loadTextureArray
import org.lwjgl.opengl.GL11.* import org.lwjgl.opengl.GL11.*
import org.lwjgl.opengl.GL12.glTexImage3D import org.lwjgl.opengl.GL12.glTexImage3D
import org.lwjgl.opengl.GL12.glTexSubImage3D import org.lwjgl.opengl.GL12.glTexSubImage3D
@ -11,7 +9,7 @@ import org.lwjgl.opengl.GL30.GL_TEXTURE_2D_ARRAY
import org.lwjgl.opengl.GL30.glGenerateMipmap import org.lwjgl.opengl.GL30.glGenerateMipmap
import java.nio.ByteBuffer import java.nio.ByteBuffer
class TextureArray(private val assetsManager: AssetsManager, private val blocks: Set<Block>) { class TextureArray(private val assetsManager: AssetsManager, private val textures: List<Texture>, private val size: Int = 16) {
var textureId = 0 var textureId = 0
fun load(): Int { fun load(): Int {
@ -24,32 +22,20 @@ class TextureArray(private val assetsManager: AssetsManager, private val blocks:
// load and generate the texture // load and generate the texture
val textures = resolveTextureIds(blocks) val textureMap: Map<Texture, ByteBuffer> = TextureLoader.loadTextureArray(assetsManager, textures)
val textureMap: Map<Texture, ByteBuffer> = loadTextureArray(assetsManager, textures) glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA, size, size, textures.size, 0, GL_RGBA, GL_UNSIGNED_BYTE, null as ByteBuffer?)
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA, 16, 16, textures.size, 0, GL_RGBA, GL_UNSIGNED_BYTE, null as ByteBuffer?)
for ((key, value) in textureMap) { for ((key, value) in textureMap) {
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, key.id, 16, 16, 1, GL_RGBA, GL_UNSIGNED_BYTE, value) glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, key.id, size, size, 1, GL_RGBA, GL_UNSIGNED_BYTE, value)
} }
glGenerateMipmap(GL_TEXTURE_2D_ARRAY) glGenerateMipmap(GL_TEXTURE_2D_ARRAY)
return textureId return textureId
} }
private fun resolveTextureIds(blocks: Set<Block>): List<Texture> {
val textures: MutableList<Texture> = mutableListOf()
textures.add(DEBUG_TEXTURE)
val textureMap: MutableMap<String, Texture> = mutableMapOf()
textureMap[DEBUG_TEXTURE.name] = DEBUG_TEXTURE
for (block in blocks) {
block.blockModel?.resolveTextures(textures, textureMap)
}
return textures
}
fun use(textureMode: Int) { fun use(textureMode: Int) {
glActiveTexture(textureMode) glActiveTexture(textureMode)
glBindTexture(GL_TEXTURE_2D, textureId) glBindTexture(GL_TEXTURE_2D_ARRAY, textureId)
} }
companion object { companion object {

View File

@ -3,7 +3,6 @@ layout (location = 0) in vec3 inPosition;
layout (location = 1) in vec2 textureIndex; layout (location = 1) in vec2 textureIndex;
layout (location = 2) in float textureLayer; layout (location = 2) in float textureLayer;
out vec3 vertexColor;
out vec3 passTextureCoordinates; out vec3 passTextureCoordinates;

View File

@ -0,0 +1,19 @@
#version 330 core
out vec4 outColor;
in vec3 passTextureCoordinates;
uniform sampler2DArray texureArray;
void main() {
vec4 texColor = texture(texureArray, passTextureCoordinates);
if (texColor.a == 0) {
discard;
}
texColor.r = 0.8f;
texColor.g = 0.8f;
texColor.b = 0.0f;
outColor = texColor;
}

View File

@ -0,0 +1,13 @@
#version 330 core
layout (location = 0) in vec2 inPosition;
layout (location = 1) in vec2 textureIndex;
layout (location = 2) in float textureLayer;
out vec3 passTextureCoordinates;
uniform float atlasSize;
void main() {
gl_Position = vec4(inPosition, 0.0f, 1.0f);
passTextureCoordinates = vec3(textureIndex / atlasSize, textureLayer);
}