rendering: code improvements

This commit is contained in:
Bixilon 2021-02-28 17:17:52 +01:00
parent 649921a468
commit a8fcc8efe1
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
11 changed files with 206 additions and 150 deletions

View File

@ -41,15 +41,18 @@ import org.lwjgl.system.MemoryStack
import org.lwjgl.system.MemoryUtil
import java.util.concurrent.ConcurrentLinkedQueue
class RenderWindow(val connection: Connection, val rendering: Rendering) {
class RenderWindow(
val connection: Connection,
val rendering: Rendering,
) {
private val keyBindingCallbacks: MutableMap<ResourceLocation, Pair<KeyBinding, MutableSet<((keyCode: KeyCodes, keyEvent: KeyAction) -> Unit)>>> = mutableMapOf()
private val keysDown: MutableSet<KeyCodes> = mutableSetOf()
private val keyBindingDown: MutableSet<KeyBinding> = mutableSetOf()
val renderStats = RenderStats()
var screenWidth = 900
var screenHeight = 500
private var windowId: Long = 0
private var deltaTime = 0.0 // time between current frame and last frame
private var windowId = 0L
private var deltaFrameTime = 0.0 // time between current frame and last frame
private var lastFrame = 0.0
val camera: Camera = Camera(connection, Minosoft.getConfig().config.game.camera.fov, this)
@ -317,7 +320,7 @@ class RenderWindow(val connection: Connection, val rendering: Rendering) {
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT) // clear the framebuffer
val currentFrame = glfwGetTime()
deltaTime = currentFrame - lastFrame
deltaFrameTime = currentFrame - lastFrame
lastFrame = currentFrame
@ -331,7 +334,7 @@ class RenderWindow(val connection: Connection, val rendering: Rendering) {
glfwSwapBuffers(windowId)
glfwPollEvents()
camera.draw()
camera.handleInput(deltaTime)
camera.handleInput(deltaFrameTime)
// handle opengl context tasks, maximum 10 per frame

View File

@ -16,6 +16,7 @@ package de.bixilon.minosoft.gui.rendering
import de.bixilon.minosoft.protocol.network.Connection
import de.bixilon.minosoft.protocol.protocol.ConnectionStates
import de.bixilon.minosoft.util.CountUpAndDownLatch
import de.bixilon.minosoft.util.MMath
import de.bixilon.minosoft.util.Util
import de.bixilon.minosoft.util.logging.Log
import org.lwjgl.Version
@ -24,7 +25,7 @@ import java.util.concurrent.Executors
class Rendering(private val connection: Connection) {
val renderWindow: RenderWindow = RenderWindow(connection, this)
val executor: ExecutorService = Executors.newFixedThreadPool(4, Util.getThreadFactory(String.format("Rendering#%d", connection.connectionId)))
val executor: ExecutorService = Executors.newFixedThreadPool(MMath.clamp(Runtime.getRuntime().availableProcessors() / 2, 1, 4), Util.getThreadFactory(String.format("Rendering#%d", connection.connectionId)))
fun start(latch: CountUpAndDownLatch) {
latch.countUp()

View File

@ -1,6 +1,6 @@
/*
* Minosoft
* Copyright (C) 2020 Moritz Zwerger, Lukas Eisenhauer
* 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.
*
@ -15,19 +15,15 @@ package de.bixilon.minosoft.gui.rendering.chunk
import de.bixilon.minosoft.data.text.RGBColor
import de.bixilon.minosoft.gui.rendering.textures.Texture
import de.bixilon.minosoft.gui.rendering.util.Mesh
import glm_.BYTES
import glm_.vec2.Vec2
import glm_.vec3.Vec3
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 ChunkMesh {
private val data: MutableList<Float> = mutableListOf()
private var vao: Int = 0
private var vbo: Int = 0
private var trianglesCount: Int = 0
class ChunkMesh : Mesh() {
fun addVertex(position: Vec3, textureCoordinates: Vec2, texture: Texture, tintColor: RGBColor?, lightLevel: Byte = 14) {
data.add(position.x)
@ -51,16 +47,8 @@ class ChunkMesh {
data.add(lightLevel / MAX_LIGHT_LEVEL)
}
fun load() {
trianglesCount = data.size / FLOATS_PER_VERTEX
vao = glGenVertexArrays()
vbo = glGenBuffers()
// 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.toFloatArray(), GL_STATIC_DRAW)
data.clear() // clear data ((do not store in memory)
override fun load() {
super.initializeBuffers(FLOATS_PER_VERTEX)
var index = 0
glVertexAttribPointer(index, 3, GL_FLOAT, false, FLOATS_PER_VERTEX * Float.BYTES, 0L)
glEnableVertexAttribArray(index++)
@ -80,22 +68,10 @@ class ChunkMesh {
glVertexAttribPointer(index, 1, GL_FLOAT, false, FLOATS_PER_VERTEX * Float.BYTES, (10 * Float.BYTES).toLong())
glEnableVertexAttribArray(index++)
// don't remove the ++ above!
index.let { }
// 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)
super.unbind()
}
fun draw() {
glBindVertexArray(vao)
glDrawArrays(GL_TRIANGLES, 0, trianglesCount)
}
fun unload() {
glDeleteVertexArrays(vao)
glDeleteBuffers(vbo)
}
companion object {
private const val FLOATS_PER_VERTEX = 11

View File

@ -6,8 +6,8 @@ import de.bixilon.minosoft.protocol.network.Connection
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
import glm_.vec3.Vec3
class Frustum(val camera: Camera) {
val normals: Array<Vec3>
class Frustum(private val camera: Camera) {
private val normals: Array<Vec3>
init {
val realFront = Vec3(camera.cameraFront)
@ -20,32 +20,45 @@ class Frustum(val camera: Camera) {
camera.cameraFront.normalize(),
// left.normalize(),
// right.normalize(),
)
)
}
private fun containsRegion(from: Vec3, to: Vec3): Boolean {
val min = Vec3()
for (normal in normals) {
// get the point most likely to be in the frustum
min.x = if (normal.x < 0) from.x else to.x
min.y = if (normal.y < 0) from.y else to.y
min.z = if (normal.z < 0) from.z else to.z
min.x = if (normal.x < 0) {
from.x
} else {
to.x
}
min.y = if (normal.y < 0) {
from.y
} else {
to.y
}
min.z = if (normal.z < 0) {
from.z
} else {
to.z
}
if (dotProduct(normal, min - camera.cameraPosition) < 0f) {
return false // region lies outside of frustum
if (normal.dotProduct(min - camera.cameraPosition) < 0f) {
return false // region is outside of frustum
}
}
return true
}
private fun dotProduct(v1: Vec3, v2: Vec3): Float {
return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z
}
fun containsChunk(chunkPosition: ChunkPosition, connection: Connection): Boolean {
val from = Vec3(chunkPosition.x * ProtocolDefinition.SECTION_WIDTH_X, connection.player.world.dimension!!.minY, chunkPosition.z * ProtocolDefinition.SECTION_WIDTH_Z)
val to = from + Vec3(ProtocolDefinition.SECTION_WIDTH_X, connection.player.world.dimension!!.logicalHeight, ProtocolDefinition.SECTION_WIDTH_Z)
val dimension = connection.player.world.dimension!!
val from = Vec3(chunkPosition.x * ProtocolDefinition.SECTION_WIDTH_X, dimension.minY, chunkPosition.z * ProtocolDefinition.SECTION_WIDTH_Z)
val to = from + Vec3(ProtocolDefinition.SECTION_WIDTH_X, dimension.logicalHeight, ProtocolDefinition.SECTION_WIDTH_Z)
val frustum = Frustum(connection.renderer.renderWindow.camera)
return frustum.containsRegion(from, to)
}
}
private fun Vec3.dotProduct(vec3: Vec3): Float {
return this.x * vec3.x + this.y * vec3.y + this.z * vec3.z
}

View File

@ -32,8 +32,12 @@ import org.lwjgl.opengl.GL11.glEnable
import org.lwjgl.opengl.GL13.glDisable
import java.util.concurrent.ConcurrentHashMap
class WorldRenderer(private val connection: Connection, private val world: World, val renderWindow: RenderWindow) : Renderer {
private lateinit var minecraftTextures: TextureArray
class WorldRenderer(
private val connection: Connection,
private val world: World,
val renderWindow: RenderWindow,
) : Renderer {
private lateinit var blockTextureArray: TextureArray
lateinit var chunkShader: Shader
val chunkSectionsToDraw = ConcurrentHashMap<ChunkPosition, ConcurrentHashMap<Int, ChunkMesh>>()
val visibleChunks: MutableSet<ChunkPosition> = mutableSetOf()
@ -84,8 +88,8 @@ class WorldRenderer(private val connection: Connection, private val world: World
}
override fun init() {
minecraftTextures = TextureArray.createTextureArray(connection.version.assetsManager, resolveBlockTextureIds(connection.version.mapping.blockStateIdMap.values))
minecraftTextures.load()
blockTextureArray = TextureArray.createTextureArray(connection.version.assetsManager, resolveBlockTextureIds(connection.version.mapping.blockStateIdMap.values))
blockTextureArray.load()
chunkShader = Shader("chunk_vertex.glsl", "chunk_fragment.glsl")
@ -94,13 +98,13 @@ class WorldRenderer(private val connection: Connection, private val world: World
// register keybindings
renderWindow.registerKeyCallback(KeyBindingsNames.DEBUG_CLEAR_CHUNK_CACHE) { _, _ ->
clearChunkCache()
connection.sender.sendFakeChatMessage("§f[§e§lDEBUG§f] §9Cleared chunk cache!")
renderWindow.sendDebugMessage("Cleared chunk cache!")
prepareWorld(world)
}
}
override fun postInit() {
minecraftTextures.use(chunkShader, "blockTextureArray")
blockTextureArray.use(chunkShader, "blockTextureArray")
}
override fun draw() {

View File

@ -13,10 +13,10 @@
package de.bixilon.minosoft.gui.rendering.chunk.models.loading
import com.google.gson.JsonArray
import com.google.gson.JsonObject
import de.bixilon.minosoft.data.Axes
import de.bixilon.minosoft.data.Directions
import de.bixilon.minosoft.gui.rendering.util.VecUtil
import glm_.glm
import glm_.vec2.Vec2
import glm_.vec3.Vec3
@ -26,16 +26,15 @@ open class BlockModelElement(data: JsonObject) {
var positions: Array<Vec3>
init {
var from = Vec3(0, 0, 0)
var to = Vec3(BLOCK_RESOLUTION, BLOCK_RESOLUTION, BLOCK_RESOLUTION)
data["from"]?.let {
val array = it.asJsonArray
from = Vec3(array[0].asFloat, array[1].asFloat, array[2].asFloat)
}
data["to"]?.let {
val array = it.asJsonArray
to = Vec3(array[0].asFloat, array[1].asFloat, array[2].asFloat)
}
val from = data["from"]?.asJsonArray?.let {
VecUtil.jsonToVec3(it)
} ?: Vec3()
val to = data["to"]?.asJsonArray?.let {
VecUtil.jsonToVec3(it)
} ?: Vec3(BLOCK_RESOLUTION)
positions = arrayOf(
Vec3(from),
Vec3(to.x, from.y, from.z),
@ -46,15 +45,15 @@ open class BlockModelElement(data: JsonObject) {
Vec3(from.x, to.y, to.z),
Vec3(to),
)
data["rotation"]?.let {
val rotation = it.asJsonObject
val axis = Axes.valueOf(rotation["axis"].asString.toUpperCase())
val angle = glm.radians(rotation["angle"].asDouble)
val rescale = rotation["rescale"]?.asBoolean ?: false
rotatePositions(positions, axis, angle, jsonArrayToVec3(rotation["origin"].asJsonArray), rescale)
data["rotation"]?.asJsonObject?.let {
val axis = Axes.valueOf(it["axis"].asString.toUpperCase())
val angle = glm.radians(it["angle"].asDouble)
val rescale = it["rescale"]?.asBoolean ?: false
rotatePositions(positions, axis, angle, VecUtil.jsonToVec3(it["origin"].asJsonArray), rescale)
}
data["faces"]?.let {
for ((directionName, json) in it.asJsonObject.entrySet()) {
data["faces"]?.asJsonObject?.let {
for ((directionName, json) in it.entrySet()) {
val direction = Directions.valueOf(directionName.toUpperCase())
faces[direction] = BlockModelFace(json.asJsonObject, from, to, direction)
}
@ -65,9 +64,7 @@ open class BlockModelElement(data: JsonObject) {
}
companion object {
fun jsonArrayToVec3(array: JsonArray): Vec3 {
return Vec3(array[0].asFloat, array[1].asFloat, array[2].asFloat)
}
const val BLOCK_RESOLUTION = 16f
val FACE_POSITION_MAP_TEMPLATE = arrayOf(
@ -88,13 +85,13 @@ open class BlockModelElement(data: JsonObject) {
private val POSITION_7 = Vec3(-0.5f, +0.5f, +0.5f) // Vec3(0, BLOCK_RESOLUTION, BLOCK_RESOLUTION)
private val POSITION_8 = Vec3(+0.5f, +0.5f, +0.5f) // Vec3(BLOCK_RESOLUTION, BLOCK_RESOLUTION, BLOCK_RESOLUTION)
val fullTestPositions = mapOf(
Directions.EAST to setOf(POSITION_1, POSITION_3, POSITION_5, POSITION_7),
Directions.WEST to setOf(POSITION_2, POSITION_4, POSITION_6, POSITION_8),
Directions.DOWN to setOf(POSITION_1, POSITION_2, POSITION_3, POSITION_4),
Directions.UP to setOf(POSITION_5, POSITION_6, POSITION_7, POSITION_8),
Directions.SOUTH to setOf(POSITION_1, POSITION_2, POSITION_5, POSITION_6),
Directions.NORTH to setOf(POSITION_3, POSITION_4, POSITION_7, POSITION_8),
val FULL_TEST_POSITIONS = arrayOf(
setOf(POSITION_1, POSITION_2, POSITION_3, POSITION_4),
setOf(POSITION_5, POSITION_6, POSITION_7, POSITION_8),
setOf(POSITION_3, POSITION_4, POSITION_7, POSITION_8),
setOf(POSITION_1, POSITION_2, POSITION_5, POSITION_6),
setOf(POSITION_2, POSITION_4, POSITION_6, POSITION_8),
setOf(POSITION_1, POSITION_3, POSITION_5, POSITION_7)
)
fun getRotatedValues(x: Float, y: Float, sin: Double, cos: Double): Vec2 {
@ -135,7 +132,7 @@ open class BlockModelElement(data: JsonObject) {
fun transformPosition(position: Vec3): Vec3 {
fun positionToFloat(uv: Float): Float {
return (uv - 8f) / BLOCK_RESOLUTION
return (uv - (BLOCK_RESOLUTION / 2)) / BLOCK_RESOLUTION
}
return Vec3(positionToFloat(position.x), positionToFloat(position.y), positionToFloat(position.z))
}

View File

@ -39,9 +39,9 @@ class ElementRenderer(element: BlockModelElement, rotation: Vec3, uvLock: Boolea
init {
rotatePositionsAxes(positions, rotation, rescale)
// TODO : uvlock
// TODO : uvLock
for (direction in Directions.DIRECTIONS) {
if (positions.containsAllVectors(BlockModelElement.fullTestPositions[direction], 0.0001f)) { // TODO: check if texture is transparent ==> && ! texture.isTransparent
if (positions.containsAllVectors(BlockModelElement.FULL_TEST_POSITIONS[direction.ordinal], 0.0001f)) { // TODO: check if texture is transparent ==> && ! texture.isTransparent
fullFaceDirections.add(direction)
}
directionMapping[direction] = getRotatedDirection(rotation, direction)
@ -68,7 +68,7 @@ class ElementRenderer(element: BlockModelElement, rotation: Vec3, uvLock: Boolea
fun createQuad(drawPositions: Array<Vec3>, texturePositions: Array<Vec2?>) {
for (vertex in drawOrder) {
for (vertex in DRAW_ODER) {
val input = Vec4(drawPositions[vertex.first], 1.0f)
val output = modelMatrix * input
mesh.addVertex(
@ -102,25 +102,9 @@ class ElementRenderer(element: BlockModelElement, rotation: Vec3, uvLock: Boolea
}
companion object {
val EMPTY_VECTOR = Vec3()
private val EMPTY_VECTOR = Vec3()
fun createElements(state: JsonObject, parent: BlockModel): MutableList<ElementRenderer> {
val rotation = glm.radians(vec3InJsonObject(state))
val uvLock = state["uvlock"]?.asBoolean ?: false
val rescale = state["rescale"]?.asBoolean ?: false
val parentElements = parent.elements
val result: MutableList<ElementRenderer> = mutableListOf()
for (parentElement in parentElements) {
result.add(ElementRenderer(parentElement, rotation, true, rescale)) // uvlock is not yet implemented in the data generator
}
return result
}
private fun vec3InJsonObject(json: JsonObject): Vec3 {
return Vec3(json["x"]?.asFloat ?: 0, json["y"]?.asFloat ?: 0, json["z"]?.asFloat ?: 0)
}
val drawOrder = arrayOf(
val DRAW_ODER = arrayOf(
Pair(0, 1),
Pair(3, 2),
Pair(2, 3),
@ -129,15 +113,29 @@ class ElementRenderer(element: BlockModelElement, rotation: Vec3, uvLock: Boolea
Pair(0, 1),
)
private fun Array<Vec3>.containsAllVectors(set: Set<Vec3>?, margin: Float): Boolean {
for (position in set!!) {
var isIn = false
for (testposition in this) {
if ((position - testposition).length() < margin) {
isIn = true
fun createElements(state: JsonObject, parent: BlockModel): MutableList<ElementRenderer> {
val rotation = glm.radians(state.asVec3())
val uvLock = state["uvlock"]?.asBoolean ?: false
val rescale = state["rescale"]?.asBoolean ?: false
val parentElements = parent.elements
val result: MutableList<ElementRenderer> = mutableListOf()
for (parentElement in parentElements) {
result.add(ElementRenderer(parentElement, rotation, uvLock, rescale))
}
return result
}
private fun Array<Vec3>.containsAllVectors(their: Set<Vec3>, margin: Float): Boolean {
for (theirPosition in their) {
var vec3WasIn = false
for (thisPosition in this) {
if ((theirPosition - thisPosition).length() < margin) {
vec3WasIn = true
break
}
}
if (!isIn) {
if (!vec3WasIn) {
return false
}
}
@ -157,9 +155,13 @@ class ElementRenderer(element: BlockModelElement, rotation: Vec3, uvLock: Boolea
if (angles == EMPTY_VECTOR) {
return
}
BlockModelElement.rotatePositions(positions, Axes.X, angles.x.toDouble(), Vec3(), rescale)
BlockModelElement.rotatePositions(positions, Axes.Y, angles.y.toDouble(), Vec3(), rescale)
BlockModelElement.rotatePositions(positions, Axes.Z, angles.z.toDouble(), Vec3(), rescale)
BlockModelElement.rotatePositions(positions, Axes.X, angles.x.toDouble(), EMPTY_VECTOR, rescale)
BlockModelElement.rotatePositions(positions, Axes.Y, angles.y.toDouble(), EMPTY_VECTOR, rescale)
BlockModelElement.rotatePositions(positions, Axes.Z, angles.z.toDouble(), EMPTY_VECTOR, rescale)
}
}
}
private fun JsonObject.asVec3(): Vec3 {
return Vec3(this["x"]?.asFloat ?: 0, this["y"]?.asFloat ?: 0, this["z"]?.asFloat ?: 0)
}

View File

@ -1,6 +1,6 @@
/*
* Minosoft
* Copyright (C) 2020 Moritz Zwerger
* 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.
*
@ -14,31 +14,18 @@
package de.bixilon.minosoft.gui.rendering.hud.elements.text
import de.bixilon.minosoft.data.text.RGBColor
import de.bixilon.minosoft.gui.rendering.util.Mesh
import glm_.BYTES
import glm_.vec2.Vec2
import glm_.vec3.Vec3
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 HUDFontMesh {
private val data: MutableList<Float> = mutableListOf()
private var vao: Int = 0
private var vbo: Int = 0
private var trianglesCount: Int = 0
class HUDFontMesh : Mesh() {
fun load() {
trianglesCount = data.size / FLOATS_PER_VERTEX
vao = glGenVertexArrays()
vbo = glGenBuffers()
// 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.toFloatArray(), GL_STATIC_DRAW)
data.clear() // clear data ((do not store in memory)
override fun load() {
super.initializeBuffers(FLOATS_PER_VERTEX)
var index = 0
glVertexAttribPointer(index, 3, GL_FLOAT, false, FLOATS_PER_VERTEX * Float.BYTES, 0L)
glEnableVertexAttribArray(index++)
@ -48,9 +35,7 @@ class HUDFontMesh {
glEnableVertexAttribArray(index++)
glVertexAttribPointer(index, 1, GL_FLOAT, false, FLOATS_PER_VERTEX * Float.BYTES, (6 * Float.BYTES).toLong())
glEnableVertexAttribArray(index++)
// 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)
super.unbind()
}
@ -64,15 +49,6 @@ class HUDFontMesh {
data.add(Float.fromBits(color.color))
}
fun draw() {
glBindVertexArray(vao)
glDrawArrays(GL_TRIANGLES, 0, trianglesCount)
}
fun unload() {
glDeleteVertexArrays(vao)
glDeleteBuffers(vbo)
}
companion object {
private const val FLOATS_PER_VERTEX = 7

View File

@ -0,0 +1,52 @@
/*
* 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.util
import org.lwjgl.opengl.GL11.GL_TRIANGLES
import org.lwjgl.opengl.GL11.glDrawArrays
import org.lwjgl.opengl.GL30.*
abstract class Mesh {
protected val data: MutableList<Float> = mutableListOf()
private var vao: Int = 0
private var vbo: Int = 0
private var trianglesCount: Int = 0
abstract fun load()
protected fun initializeBuffers(floatsPerVertex: Int) {
trianglesCount = data.size / floatsPerVertex
vao = glGenVertexArrays()
vbo = glGenBuffers()
glBindVertexArray(vao)
glBindBuffer(GL_ARRAY_BUFFER, vbo)
glBufferData(GL_ARRAY_BUFFER, data.toFloatArray(), GL_STATIC_DRAW)
data.clear() // clear data ((do not store in memory)
}
protected fun unbind() {
glBindBuffer(GL_ARRAY_BUFFER, 0)
}
fun draw() {
glBindVertexArray(vao)
glDrawArrays(GL_TRIANGLES, 0, trianglesCount)
}
fun unload() {
glDeleteVertexArrays(vao)
glDeleteBuffers(vbo)
}
}

View File

@ -32,7 +32,6 @@ class ScreenshotTaker(
fun takeScreenshot() {
try {
val basePath = "${StaticConfiguration.HOME_DIRECTORY}/screenshots/${renderWindow.connection.address.hostname}/${DATE_FORMATTER.format(System.currentTimeMillis())}"
Util.createParentFolderIfNotExist(basePath)
var path = "$basePath.png"
var i = 1
while (File(path).exists()) {
@ -56,9 +55,12 @@ class ScreenshotTaker(
}
}
ImageIO.write(bufferedImage, "png", File(path))
val file = File(path)
Util.createParentFolderIfNotExist(file)
renderWindow.sendDebugMessage("§aScreenshot saved to §f$path")
ImageIO.write(bufferedImage, "png", file)
renderWindow.sendDebugMessage("§aScreenshot saved to §f${file.name}")
} catch (exception: Exception) {
exception.printStackTrace()
renderWindow.sendDebugMessage("§cFailed to make a screenshot!")

View File

@ -0,0 +1,30 @@
/*
* 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.util
import com.google.gson.JsonArray
import com.google.gson.JsonElement
import com.google.gson.JsonObject
import glm_.vec3.Vec3
object VecUtil {
fun jsonToVec3(json: JsonElement): Vec3 {
when (json) {
is JsonArray -> return Vec3(json[0].asFloat, json[1].asFloat, json[2].asFloat)
is JsonObject -> TODO()
else -> throw IllegalArgumentException("Not a Vec3!")
}
}
}