mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-16 19:05:02 -04:00
rendering: Improve HUD structure, internal changes
* Before joining a server rendering will be started now. * Rendering now uses (partly) the modding api
This commit is contained in:
parent
14a7ad6e61
commit
edcc288898
@ -43,6 +43,9 @@ public abstract class ChatComponent {
|
||||
if (raw == null) {
|
||||
return new BaseComponent();
|
||||
}
|
||||
if (raw instanceof ChatComponent component) {
|
||||
return component;
|
||||
}
|
||||
if (raw instanceof JsonPrimitive primitive) {
|
||||
raw = primitive.getAsString();
|
||||
}
|
||||
|
@ -4,9 +4,11 @@ import de.bixilon.minosoft.data.entities.EntityRotation
|
||||
import de.bixilon.minosoft.data.entities.Location
|
||||
import de.bixilon.minosoft.gui.rendering.chunk.ChunkRenderer
|
||||
import de.bixilon.minosoft.gui.rendering.hud.HUDRenderer
|
||||
import de.bixilon.minosoft.gui.rendering.hud.elements.RenderStats
|
||||
import de.bixilon.minosoft.protocol.network.Connection
|
||||
import de.bixilon.minosoft.protocol.packets.serverbound.play.PacketPlayerPositionAndRotationSending
|
||||
import de.bixilon.minosoft.util.CountUpAndDownLatch
|
||||
import de.bixilon.minosoft.util.logging.Log
|
||||
import org.lwjgl.*
|
||||
import org.lwjgl.glfw.Callbacks
|
||||
import org.lwjgl.glfw.GLFW.*
|
||||
@ -17,26 +19,27 @@ import org.lwjgl.opengl.GL11.*
|
||||
import org.lwjgl.system.MemoryStack
|
||||
import org.lwjgl.system.MemoryUtil
|
||||
import java.util.concurrent.ConcurrentLinkedQueue
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
class RenderWindow(private val connection: Connection, val rendering: Rendering) {
|
||||
private var screenWidth = 800
|
||||
private var screenHeight = 600
|
||||
val renderStats = RenderStats()
|
||||
var screenWidth = 800
|
||||
var screenHeight = 600
|
||||
private var polygonEnabled = false
|
||||
private var windowId: Long = 0
|
||||
private var deltaTime = 0.0 // time between current frame and last frame
|
||||
|
||||
private var lastFrame = 0.0
|
||||
lateinit var camera: Camera
|
||||
var latch = CountUpAndDownLatch(1)
|
||||
|
||||
// all renderers
|
||||
val chunkRenderer: ChunkRenderer = ChunkRenderer(connection.player.world, this)
|
||||
val chunkRenderer: ChunkRenderer = ChunkRenderer(connection, connection.player.world, this)
|
||||
val hudRenderer: HUDRenderer = HUDRenderer(connection, this)
|
||||
|
||||
val renderQueue = ConcurrentLinkedQueue<Runnable>()
|
||||
|
||||
|
||||
fun init(latch: CountUpAndDownLatch? = null) {
|
||||
fun init(latch: CountUpAndDownLatch) {
|
||||
// Setup an error callback. The default implementation
|
||||
// will print the error message in System.err.
|
||||
GLFWErrorCallback.createPrint(System.err).set()
|
||||
@ -107,9 +110,9 @@ class RenderWindow(private val connection: Connection, val rendering: Rendering)
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
|
||||
|
||||
|
||||
chunkRenderer.init(connection)
|
||||
chunkRenderer.init()
|
||||
|
||||
hudRenderer.init(connection)
|
||||
hudRenderer.init()
|
||||
|
||||
|
||||
glfwSetWindowSizeCallback(windowId, object : GLFWWindowSizeCallback() {
|
||||
@ -128,23 +131,22 @@ class RenderWindow(private val connection: Connection, val rendering: Rendering)
|
||||
camera.calculateProjectionMatrix(screenWidth, screenHeight, chunkRenderer.chunkShader)
|
||||
camera.calculateViewMatrix(chunkRenderer.chunkShader)
|
||||
|
||||
glfwShowWindow(windowId)
|
||||
|
||||
latch?.countDown()
|
||||
Log.debug("Rendering is prepared and ready to go!")
|
||||
latch.countDown()
|
||||
latch.waitUntilZero()
|
||||
this.latch.waitUntilZero()
|
||||
glfwShowWindow(windowId)
|
||||
}
|
||||
|
||||
fun startRenderLoop() {
|
||||
var framesLastSecond = 0
|
||||
var lastCalcTime = glfwGetTime()
|
||||
var frameTimeLastCalc = 0.0
|
||||
|
||||
var lastPositionChangeTime = 0.0
|
||||
|
||||
while (!glfwWindowShouldClose(windowId)) {
|
||||
renderStats.startFrame()
|
||||
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT) // clear the framebuffer
|
||||
|
||||
val currentFrame = glfwGetTime()
|
||||
|
||||
deltaTime = currentFrame - lastFrame
|
||||
lastFrame = currentFrame
|
||||
|
||||
@ -153,26 +155,15 @@ class RenderWindow(private val connection: Connection, val rendering: Rendering)
|
||||
|
||||
|
||||
chunkRenderer.draw()
|
||||
|
||||
hudRenderer.draw()
|
||||
|
||||
renderStats.endDraw()
|
||||
|
||||
|
||||
glfwSwapBuffers(windowId)
|
||||
|
||||
glfwPollEvents()
|
||||
|
||||
camera.handleInput(deltaTime)
|
||||
|
||||
frameTimeLastCalc += glfwGetTime() - currentFrame
|
||||
|
||||
if (glfwGetTime() - lastCalcTime >= 0.25) {
|
||||
glfwSetWindowTitle(windowId, "Minosoft | FPS: ${framesLastSecond * 4} (${(0.25 * framesLastSecond / (frameTimeLastCalc)).roundToInt()})")
|
||||
hudRenderer.fps = framesLastSecond * 4
|
||||
lastCalcTime = glfwGetTime()
|
||||
framesLastSecond = 0
|
||||
frameTimeLastCalc = 0.0
|
||||
}
|
||||
framesLastSecond++
|
||||
|
||||
if (glfwGetTime() - lastPositionChangeTime > 0.05) {
|
||||
// ToDo: Replace this with proper movement and only send it, when our position changed
|
||||
@ -181,10 +172,13 @@ class RenderWindow(private val connection: Connection, val rendering: Rendering)
|
||||
}
|
||||
|
||||
|
||||
// handle opengl context tasks
|
||||
for (renderQueueElement in renderQueue) {
|
||||
renderQueueElement.run()
|
||||
renderQueue.remove(renderQueueElement)
|
||||
}
|
||||
|
||||
renderStats.endFrame()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,10 +1,7 @@
|
||||
package de.bixilon.minosoft.gui.rendering
|
||||
|
||||
import de.bixilon.minosoft.protocol.network.Connection
|
||||
|
||||
interface Renderer {
|
||||
|
||||
fun init(connection: Connection)
|
||||
|
||||
fun init()
|
||||
fun draw()
|
||||
fun screenChangeResizeCallback(width: Int, height: Int) {}
|
||||
}
|
||||
|
@ -13,10 +13,10 @@ import java.util.concurrent.Executors
|
||||
|
||||
class Rendering(private val connection: Connection) {
|
||||
val renderWindow: RenderWindow = RenderWindow(connection, this)
|
||||
val latch = CountUpAndDownLatch(1)
|
||||
val executor: ExecutorService = Executors.newFixedThreadPool(4, Util.getThreadFactory(String.format("Rendering#%d", connection.connectionId)))
|
||||
|
||||
fun start() {
|
||||
fun start(latch: CountUpAndDownLatch) {
|
||||
latch.countUp()
|
||||
Thread({
|
||||
Log.info("Hello LWJGL " + Version.getVersion() + "!")
|
||||
renderWindow.init(latch)
|
||||
@ -27,6 +27,10 @@ class Rendering(private val connection: Connection) {
|
||||
|
||||
|
||||
fun teleport(position: Location) {
|
||||
// tell the window we are ready (received position)
|
||||
if (renderWindow.latch.count > 0) {
|
||||
renderWindow.latch.countDown()
|
||||
}
|
||||
renderWindow.renderQueue.add {
|
||||
renderWindow.camera.cameraPosition = Vec3(position.x, position.y, position.z)
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ import org.lwjgl.opengl.GL11.glEnable
|
||||
import org.lwjgl.opengl.GL13.GL_TEXTURE0
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
class ChunkRenderer(private val world: World, val renderWindow: RenderWindow) : Renderer {
|
||||
class ChunkRenderer(private val connection: Connection, private val world: World, val renderWindow: RenderWindow) : Renderer {
|
||||
private lateinit var minecraftTextures: TextureArray
|
||||
lateinit var chunkShader: Shader
|
||||
private val chunkSectionsToDraw = ConcurrentHashMap<ChunkLocation, ConcurrentHashMap<Int, WorldMesh>>()
|
||||
@ -81,7 +81,7 @@ class ChunkRenderer(private val world: World, val renderWindow: RenderWindow) :
|
||||
return data.toFloatArray()
|
||||
}
|
||||
|
||||
override fun init(connection: Connection) {
|
||||
override fun init() {
|
||||
minecraftTextures = TextureArray.createTextureArray(connection.version.assetsManager, resolveBlockTextureIds(connection.version.mapping.blockMap.values), 16, 16) // ToDo :Remove fixed size
|
||||
minecraftTextures.load()
|
||||
|
||||
@ -124,7 +124,6 @@ class ChunkRenderer(private val world: World, val renderWindow: RenderWindow) :
|
||||
|
||||
fun prepareChunkSection(chunkLocation: ChunkLocation, sectionHeight: Int, section: ChunkSection) {
|
||||
renderWindow.rendering.executor.execute {
|
||||
renderWindow.rendering.latch.waitUntilZero() // Wait until rendering is started
|
||||
try {
|
||||
val data = prepareChunk(chunkLocation, sectionHeight, section)
|
||||
val sectionMap = chunkSectionsToDraw[chunkLocation]!!
|
||||
|
@ -1,135 +1,54 @@
|
||||
package de.bixilon.minosoft.gui.rendering.hud
|
||||
|
||||
import de.bixilon.minosoft.data.text.ChatComponent
|
||||
import de.bixilon.minosoft.data.mappings.ModIdentifier
|
||||
import de.bixilon.minosoft.gui.rendering.RenderWindow
|
||||
import de.bixilon.minosoft.gui.rendering.Renderer
|
||||
import de.bixilon.minosoft.gui.rendering.font.Font
|
||||
import de.bixilon.minosoft.gui.rendering.font.FontBindings
|
||||
import de.bixilon.minosoft.gui.rendering.shader.Shader
|
||||
import de.bixilon.minosoft.gui.rendering.textures.TextureArray
|
||||
import de.bixilon.minosoft.gui.rendering.hud.elements.HUDElement
|
||||
import de.bixilon.minosoft.gui.rendering.hud.elements.text.HUDTextElement
|
||||
import de.bixilon.minosoft.protocol.network.Connection
|
||||
import glm_.glm
|
||||
import glm_.mat4x4.Mat4
|
||||
import glm_.vec2.Vec2
|
||||
import org.lwjgl.opengl.GL11.GL_DEPTH_TEST
|
||||
import org.lwjgl.opengl.GL11.glDisable
|
||||
import org.lwjgl.opengl.GL13.GL_TEXTURE0
|
||||
import java.util.concurrent.ConcurrentLinkedQueue
|
||||
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
||||
|
||||
class HUDRenderer(private val connection: Connection, private val renderWindow: RenderWindow) : Renderer {
|
||||
private val font = Font()
|
||||
private val hudScale = HUDScale.MEDIUM
|
||||
var fps: Int = 0
|
||||
var frame = 0
|
||||
private lateinit var fontShader: Shader
|
||||
private lateinit var fontAtlasTexture: TextureArray
|
||||
private lateinit var hudMeshHUD: HUDFontMesh
|
||||
private var screenWidth = 0
|
||||
private var screenHeight = 0
|
||||
var chatMessages: ConcurrentLinkedQueue<Pair<ChatComponent, Long>> = ConcurrentLinkedQueue()
|
||||
private var showChat = true
|
||||
private var showDebugScreen = true
|
||||
private val fontBindingPerspectiveMatrices = mutableListOf(Mat4(), Mat4(), Mat4(), Mat4()) // according to FontBindings::ordinal
|
||||
class HUDRenderer(private val connection: Connection, renderWindow: RenderWindow) : Renderer {
|
||||
var hudScale = HUDScale.MEDIUM
|
||||
val hudElements: MutableMap<ModIdentifier, HUDElement> = mutableMapOf(
|
||||
ModIdentifier("minosoft:hud_text_renderer") to HUDTextElement(connection, this, renderWindow),
|
||||
)
|
||||
var lastTimePrepared = 0L
|
||||
|
||||
|
||||
override fun init(connection: Connection) {
|
||||
font.load(connection.version.assetsManager)
|
||||
fontAtlasTexture = font.createAtlasTexture()
|
||||
fontAtlasTexture.load()
|
||||
|
||||
fontShader = Shader("font_vertex.glsl", "font_fragment.glsl")
|
||||
fontShader.load()
|
||||
hudMeshHUD = HUDFontMesh(floatArrayOf())
|
||||
override fun init() {
|
||||
for (element in hudElements.values) {
|
||||
element.init()
|
||||
}
|
||||
}
|
||||
|
||||
fun drawChatComponent(position: Vec2, binding: FontBindings, text: ChatComponent, meshData: MutableList<Float>, maxSize: Vec2) {
|
||||
hudMeshHUD.unload()
|
||||
text.addVerticies(position, Vec2(0, 0), fontBindingPerspectiveMatrices[binding.ordinal], binding, font, hudScale, meshData, maxSize)
|
||||
}
|
||||
|
||||
fun screenChangeResizeCallback(width: Int, height: Int) {
|
||||
fontShader.use()
|
||||
screenWidth = width
|
||||
screenHeight = height
|
||||
|
||||
fontBindingPerspectiveMatrices[FontBindings.LEFT_UP.ordinal] = glm.ortho(0.0f, width.toFloat(), height.toFloat(), 0.0f)
|
||||
fontBindingPerspectiveMatrices[FontBindings.RIGHT_UP.ordinal] = glm.ortho(width.toFloat(), 0.0f, height.toFloat(), 0.0f)
|
||||
fontBindingPerspectiveMatrices[FontBindings.RIGHT_DOWN.ordinal] = glm.ortho(width.toFloat(), 0.0f, 0.0f, height.toFloat())
|
||||
fontBindingPerspectiveMatrices[FontBindings.LEFT_DOWN.ordinal] = glm.ortho(0.0f, width.toFloat(), 0.0f, height.toFloat())
|
||||
|
||||
prepare()
|
||||
override fun screenChangeResizeCallback(width: Int, height: Int) {
|
||||
for (element in hudElements.values) {
|
||||
element.screenChangeResizeCallback(width, height)
|
||||
}
|
||||
}
|
||||
|
||||
override fun draw() {
|
||||
fontAtlasTexture.use(GL_TEXTURE0)
|
||||
|
||||
fontShader.use()
|
||||
glDisable(GL_DEPTH_TEST)
|
||||
|
||||
frame++
|
||||
if (frame % 15 == 0) {
|
||||
if (System.currentTimeMillis() - lastTimePrepared > ProtocolDefinition.TICK_TIME) {
|
||||
prepare()
|
||||
update()
|
||||
lastTimePrepared = System.currentTimeMillis()
|
||||
}
|
||||
|
||||
hudMeshHUD.draw()
|
||||
for (element in hudElements.values) {
|
||||
element.draw()
|
||||
}
|
||||
}
|
||||
|
||||
fun prepare() {
|
||||
val runtime = Runtime.getRuntime()!!
|
||||
val meshData: MutableList<Float> = mutableListOf()
|
||||
val componentsBindingMap: Map<FontBindings, MutableList<Any>> = mapOf(
|
||||
FontBindings.LEFT_UP to mutableListOf(
|
||||
"§aMinosoft (0.1-pre1)",
|
||||
),
|
||||
FontBindings.RIGHT_UP to mutableListOf(),
|
||||
FontBindings.RIGHT_DOWN to mutableListOf(),
|
||||
FontBindings.LEFT_DOWN to mutableListOf(),
|
||||
)
|
||||
|
||||
if (showDebugScreen) {
|
||||
componentsBindingMap[FontBindings.LEFT_UP]!!.addAll(listOf(
|
||||
"§fFPS: §8$fps",
|
||||
"§fXYZ §8${"%.4f".format(renderWindow.camera.cameraPosition.x)} / ${"%.4f".format(renderWindow.camera.cameraPosition.y)} / ${"%.4f".format(renderWindow.camera.cameraPosition.z)}",
|
||||
"§fConnected to: §8${connection.address}",
|
||||
))
|
||||
componentsBindingMap[FontBindings.RIGHT_UP]!!.addAll(listOf(
|
||||
"§fJava: §8${Runtime.version()} ${System.getProperty("sun.arch.data.model")}bit",
|
||||
"§fMemory: §8${runtime.freeMemory() * 100 / runtime.maxMemory()}% ${(runtime.totalMemory() - runtime.freeMemory()) / (1024 * 1024)}/${runtime.maxMemory() / (1024 * 1024)}MB",
|
||||
"§fAllocated: §8${runtime.totalMemory() * 100 / runtime.maxMemory()}% ${runtime.totalMemory() / (1024 * 1024)}MB",
|
||||
" ",
|
||||
"CPU: §8${runtime.availableProcessors()}x TODO",
|
||||
"OS: §8${System.getProperty("os.name")}",
|
||||
" ",
|
||||
"Display: §8${screenWidth}x${screenHeight}",
|
||||
))
|
||||
for (element in hudElements.values) {
|
||||
element.prepare()
|
||||
}
|
||||
if (showChat) {
|
||||
for (entry in chatMessages) {
|
||||
if (System.currentTimeMillis() - entry.second > 10000) {
|
||||
chatMessages.remove(entry)
|
||||
continue
|
||||
}
|
||||
componentsBindingMap[FontBindings.LEFT_DOWN]!!.add(entry.first)
|
||||
}
|
||||
}
|
||||
for ((binding, components) in componentsBindingMap) {
|
||||
val offset = Vec2(3, 3)
|
||||
}
|
||||
|
||||
if (binding == FontBindings.RIGHT_DOWN || binding == FontBindings.LEFT_DOWN) {
|
||||
components.reverse()
|
||||
}
|
||||
|
||||
for ((_, component) in components.withIndex()) {
|
||||
val currentOffset = Vec2()
|
||||
val chatComponent = if (component is ChatComponent) {
|
||||
component
|
||||
} else {
|
||||
ChatComponent.valueOf(component)
|
||||
}
|
||||
drawChatComponent(offset, binding, chatComponent, meshData, currentOffset)
|
||||
offset += Vec2(0, currentOffset.y + 1)
|
||||
}
|
||||
hudMeshHUD = HUDFontMesh(meshData.toFloatArray())
|
||||
fun update() {
|
||||
for (element in hudElements.values) {
|
||||
element.update()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,10 @@
|
||||
package de.bixilon.minosoft.gui.rendering.hud.elements
|
||||
|
||||
interface HUDElement {
|
||||
|
||||
fun init()
|
||||
fun prepare()
|
||||
fun update()
|
||||
fun draw()
|
||||
fun screenChangeResizeCallback(width: Int, height: Int) {}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
package de.bixilon.minosoft.gui.rendering.hud.elements
|
||||
|
||||
class RenderStats {
|
||||
var fpsLastSecond = -1
|
||||
var minFrameTime = Long.MAX_VALUE
|
||||
var maxFrameTime = 0L
|
||||
var avgFrameTime = 0L
|
||||
var frames = 0L
|
||||
|
||||
private var lastFPSCalcTime = 0L
|
||||
private var framesLastSecond = 0
|
||||
|
||||
private var frameStartTime = 0L
|
||||
|
||||
fun startFrame() {
|
||||
frameStartTime = System.nanoTime()
|
||||
}
|
||||
|
||||
fun endDraw() {
|
||||
}
|
||||
|
||||
fun endFrame() {
|
||||
val frameEndTime = System.nanoTime()
|
||||
val frameTime = frameEndTime - frameStartTime
|
||||
if (frameTime < minFrameTime) {
|
||||
minFrameTime = frameTime
|
||||
}
|
||||
if (frameTime > maxFrameTime) {
|
||||
maxFrameTime = frameTime
|
||||
}
|
||||
|
||||
if (frameEndTime - lastFPSCalcTime > 1E9) {
|
||||
// 1 second
|
||||
fpsLastSecond = framesLastSecond
|
||||
|
||||
framesLastSecond = 0
|
||||
lastFPSCalcTime = frameEndTime
|
||||
}
|
||||
frames++
|
||||
framesLastSecond++
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package de.bixilon.minosoft.gui.rendering.hud.elements.text
|
||||
|
||||
import de.bixilon.minosoft.data.text.ChatComponent
|
||||
import de.bixilon.minosoft.gui.rendering.font.FontBindings
|
||||
import de.bixilon.minosoft.modding.event.EventInvokerCallback
|
||||
import de.bixilon.minosoft.modding.event.events.ChatMessageReceivingEvent
|
||||
import java.util.concurrent.ConcurrentLinkedQueue
|
||||
|
||||
class HUDChatElement(hudTextElement: HUDTextElement) : HUDText {
|
||||
private var showChat = true
|
||||
var chatMessages: ConcurrentLinkedQueue<Pair<ChatComponent, Long>> = ConcurrentLinkedQueue()
|
||||
|
||||
init {
|
||||
hudTextElement.connection.registerEvent(EventInvokerCallback<ChatMessageReceivingEvent> {
|
||||
chatMessages.add(Pair(it.message, System.currentTimeMillis()))
|
||||
})
|
||||
}
|
||||
|
||||
override fun prepare(chatComponents: Map<FontBindings, MutableList<Any>>) {
|
||||
if (showChat) {
|
||||
for (entry in chatMessages) {
|
||||
if (System.currentTimeMillis() - entry.second > 10000) {
|
||||
chatMessages.remove(entry)
|
||||
continue
|
||||
}
|
||||
chatComponents[FontBindings.LEFT_DOWN]!!.add(entry.first)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,113 @@
|
||||
package de.bixilon.minosoft.gui.rendering.hud.elements.text
|
||||
|
||||
import de.bixilon.minosoft.gui.rendering.font.FontBindings
|
||||
|
||||
class HUDDebugScreenElement(private val hudTextElement: HUDTextElement) : HUDText {
|
||||
private val runtime = Runtime.getRuntime()
|
||||
|
||||
override fun prepare(chatComponents: Map<FontBindings, MutableList<Any>>) {
|
||||
chatComponents[FontBindings.LEFT_UP]!!.addAll(listOf(
|
||||
"§fFPS: §8${getFPS()}",
|
||||
"§fTimings: §8avg ${getAvgFrameTime()}ms, min ${getMinFrameTime()}ms, max ${getMaxFrameTime()}ms",
|
||||
"§fXYZ §8${getLocation()}",
|
||||
"§fConnected to: §8${hudTextElement.connection.address}",
|
||||
))
|
||||
chatComponents[FontBindings.RIGHT_UP]!!.addAll(listOf(
|
||||
"§fJava: §8${Runtime.version()} ${System.getProperty("sun.arch.data.model")}bit",
|
||||
"§fMemory: §8${getUsedMemoryPercent()}% ${getFormattedUsedMemory()}/${getFormattedMaxMemory()}",
|
||||
"§fAllocated: §8${getAllocatedMemoryPercent()}% ${getFormattedAllocatedMemory()}",
|
||||
" ",
|
||||
"CPU: §8${runtime.availableProcessors()}x TODO",
|
||||
"OS: §8${System.getProperty("os.name")}",
|
||||
" ",
|
||||
"Display: §8${getScreenDimensions()}",
|
||||
))
|
||||
}
|
||||
|
||||
private fun nanoToMillis1d(nanos: Long): String {
|
||||
return "%.1f".format(nanos / 1000000f)
|
||||
}
|
||||
|
||||
private fun getFPS(): String {
|
||||
val renderStats = hudTextElement.renderWindow.renderStats
|
||||
return "${renderStats.fpsLastSecond}"
|
||||
}
|
||||
|
||||
private fun getAvgFrameTime(): String {
|
||||
return nanoToMillis1d(hudTextElement.renderWindow.renderStats.avgFrameTime)
|
||||
}
|
||||
|
||||
private fun getMinFrameTime(): String {
|
||||
return nanoToMillis1d(hudTextElement.renderWindow.renderStats.minFrameTime)
|
||||
}
|
||||
|
||||
private fun getMaxFrameTime(): String {
|
||||
return nanoToMillis1d(hudTextElement.renderWindow.renderStats.maxFrameTime)
|
||||
}
|
||||
|
||||
|
||||
private fun getUsedMemory(): Long {
|
||||
return runtime.totalMemory() - runtime.freeMemory()
|
||||
}
|
||||
|
||||
private fun getFormattedUsedMemory(): String {
|
||||
return formatBytes(getUsedMemory())
|
||||
}
|
||||
|
||||
private fun getAllocatedMemory(): Long {
|
||||
return runtime.totalMemory()
|
||||
}
|
||||
|
||||
private fun getFormattedAllocatedMemory(): String {
|
||||
return formatBytes(getAllocatedMemory())
|
||||
}
|
||||
|
||||
private fun getMaxMemory(): Long {
|
||||
return runtime.maxMemory()
|
||||
}
|
||||
|
||||
private fun getFormattedMaxMemory(): String {
|
||||
return formatBytes(getMaxMemory())
|
||||
}
|
||||
|
||||
private fun getUsedMemoryPercent(): Long {
|
||||
return getUsedMemory() * 100 / runtime.maxMemory()
|
||||
}
|
||||
|
||||
private fun getAllocatedMemoryPercent(): Long {
|
||||
return getAllocatedMemory() * 100 / runtime.maxMemory()
|
||||
}
|
||||
|
||||
private fun getLocation(): String {
|
||||
val cameraPosition = hudTextElement.renderWindow.camera.cameraPosition
|
||||
return "${formatCoordinate(cameraPosition.x)} / ${formatCoordinate(cameraPosition.y)} / ${formatCoordinate(cameraPosition.z)}"
|
||||
}
|
||||
|
||||
private fun getScreenDimensions(): String {
|
||||
return "${hudTextElement.renderWindow.screenWidth}x${hudTextElement.renderWindow.screenHeight}"
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
private val UNITS = listOf("B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB")
|
||||
fun formatBytes(bytes: Long): String {
|
||||
var lastFactor = 1L
|
||||
var currentFactor = 1024L
|
||||
for (unit in UNITS) {
|
||||
if (bytes < currentFactor) {
|
||||
if (bytes < (lastFactor * 10)) {
|
||||
return "${"%.1f".format(bytes / lastFactor.toFloat())}${unit}"
|
||||
}
|
||||
return "${bytes / lastFactor}${unit}"
|
||||
}
|
||||
lastFactor = currentFactor
|
||||
currentFactor *= 1024L
|
||||
}
|
||||
throw IllegalArgumentException()
|
||||
}
|
||||
|
||||
fun formatCoordinate(coordinate: Float): String {
|
||||
return "%.4f".format(coordinate)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package de.bixilon.minosoft.gui.rendering.hud
|
||||
package de.bixilon.minosoft.gui.rendering.hud.elements.text
|
||||
|
||||
import glm_.BYTES
|
||||
import org.lwjgl.opengl.GL11.GL_FLOAT
|
@ -0,0 +1,10 @@
|
||||
package de.bixilon.minosoft.gui.rendering.hud.elements.text
|
||||
|
||||
import de.bixilon.minosoft.gui.rendering.font.FontBindings
|
||||
|
||||
interface HUDText {
|
||||
|
||||
fun prepare(chatComponents: Map<FontBindings, MutableList<Any>>)
|
||||
fun update() {}
|
||||
fun draw() {}
|
||||
}
|
@ -0,0 +1,108 @@
|
||||
package de.bixilon.minosoft.gui.rendering.hud.elements.text
|
||||
|
||||
import de.bixilon.minosoft.data.mappings.ModIdentifier
|
||||
import de.bixilon.minosoft.data.text.ChatComponent
|
||||
import de.bixilon.minosoft.gui.rendering.RenderWindow
|
||||
import de.bixilon.minosoft.gui.rendering.font.Font
|
||||
import de.bixilon.minosoft.gui.rendering.font.FontBindings
|
||||
import de.bixilon.minosoft.gui.rendering.hud.HUDRenderer
|
||||
import de.bixilon.minosoft.gui.rendering.hud.elements.HUDElement
|
||||
import de.bixilon.minosoft.gui.rendering.shader.Shader
|
||||
import de.bixilon.minosoft.gui.rendering.textures.TextureArray
|
||||
import de.bixilon.minosoft.protocol.network.Connection
|
||||
import glm_.glm
|
||||
import glm_.mat4x4.Mat4
|
||||
import glm_.vec2.Vec2
|
||||
import org.lwjgl.opengl.GL11.GL_DEPTH_TEST
|
||||
import org.lwjgl.opengl.GL11.glDisable
|
||||
import org.lwjgl.opengl.GL13.GL_TEXTURE0
|
||||
|
||||
class HUDTextElement(val connection: Connection, val hudRenderer: HUDRenderer, val renderWindow: RenderWindow) : HUDElement {
|
||||
private val fontBindingPerspectiveMatrices = mutableListOf(Mat4(), Mat4(), Mat4(), Mat4()) // according to FontBindings::ordinal
|
||||
private lateinit var fontShader: Shader
|
||||
private lateinit var hudMeshHUD: HUDFontMesh
|
||||
private lateinit var fontAtlasTexture: TextureArray
|
||||
private val font = Font()
|
||||
private lateinit var componentsBindingMap: Map<FontBindings, MutableList<Any>>
|
||||
|
||||
var hudTextElements: MutableMap<ModIdentifier, HUDText> = mutableMapOf(
|
||||
ModIdentifier("minosoft:debug_screen") to HUDDebugScreenElement(this),
|
||||
ModIdentifier("minosoft:chat") to HUDChatElement(this),
|
||||
)
|
||||
|
||||
override fun screenChangeResizeCallback(width: Int, height: Int) {
|
||||
fontShader.use()
|
||||
|
||||
fontBindingPerspectiveMatrices[FontBindings.LEFT_UP.ordinal] = glm.ortho(0.0f, width.toFloat(), height.toFloat(), 0.0f)
|
||||
fontBindingPerspectiveMatrices[FontBindings.RIGHT_UP.ordinal] = glm.ortho(width.toFloat(), 0.0f, height.toFloat(), 0.0f)
|
||||
fontBindingPerspectiveMatrices[FontBindings.RIGHT_DOWN.ordinal] = glm.ortho(width.toFloat(), 0.0f, 0.0f, height.toFloat())
|
||||
fontBindingPerspectiveMatrices[FontBindings.LEFT_DOWN.ordinal] = glm.ortho(0.0f, width.toFloat(), 0.0f, height.toFloat())
|
||||
|
||||
prepare()
|
||||
}
|
||||
|
||||
fun drawChatComponent(position: Vec2, binding: FontBindings, text: ChatComponent, meshData: MutableList<Float>, maxSize: Vec2) {
|
||||
hudMeshHUD.unload()
|
||||
text.addVerticies(position, Vec2(0, 0), fontBindingPerspectiveMatrices[binding.ordinal], binding, font, hudRenderer.hudScale, meshData, maxSize)
|
||||
}
|
||||
|
||||
override fun prepare() {
|
||||
componentsBindingMap = mapOf(
|
||||
FontBindings.LEFT_UP to mutableListOf(
|
||||
"§aMinosoft (0.1-pre1)",
|
||||
),
|
||||
FontBindings.RIGHT_UP to mutableListOf(),
|
||||
FontBindings.RIGHT_DOWN to mutableListOf(),
|
||||
FontBindings.LEFT_DOWN to mutableListOf(),
|
||||
)
|
||||
for (hudTextElement in hudTextElements.values) {
|
||||
hudTextElement.prepare(componentsBindingMap)
|
||||
}
|
||||
}
|
||||
|
||||
override fun update() {
|
||||
for (hudTextElement in hudTextElements.values) {
|
||||
hudTextElement.update()
|
||||
}
|
||||
|
||||
val meshData: MutableList<Float> = mutableListOf()
|
||||
|
||||
for ((binding, components) in componentsBindingMap) {
|
||||
val offset = Vec2(3, 3)
|
||||
|
||||
if (binding == FontBindings.RIGHT_DOWN || binding == FontBindings.LEFT_DOWN) {
|
||||
components.reverse()
|
||||
}
|
||||
|
||||
for ((_, component) in components.withIndex()) {
|
||||
val currentOffset = Vec2()
|
||||
drawChatComponent(offset, binding, ChatComponent.valueOf(component), meshData, currentOffset)
|
||||
offset += Vec2(0, currentOffset.y + 1)
|
||||
}
|
||||
}
|
||||
hudMeshHUD.unload()
|
||||
hudMeshHUD = HUDFontMesh(meshData.toFloatArray())
|
||||
}
|
||||
|
||||
override fun init() {
|
||||
font.load(connection.version.assetsManager)
|
||||
fontShader = Shader("font_vertex.glsl", "font_fragment.glsl")
|
||||
fontShader.load()
|
||||
hudMeshHUD = HUDFontMesh(floatArrayOf())
|
||||
|
||||
|
||||
fontAtlasTexture = font.createAtlasTexture()
|
||||
fontAtlasTexture.load()
|
||||
}
|
||||
|
||||
override fun draw() {
|
||||
fontAtlasTexture.use(GL_TEXTURE0)
|
||||
fontShader.use()
|
||||
glDisable(GL_DEPTH_TEST)
|
||||
|
||||
for (hudTextElement in hudTextElements.values) {
|
||||
hudTextElement.draw()
|
||||
}
|
||||
hudMeshHUD.draw()
|
||||
}
|
||||
}
|
@ -135,11 +135,18 @@ public class Connection {
|
||||
version.load(latch); // ToDo: show gui loader
|
||||
this.customMapping.setVersion(version);
|
||||
this.customMapping.setParentMapping(version.getMapping());
|
||||
|
||||
if (!StaticConfiguration.HEADLESS_MODE) {
|
||||
this.rendering = new Rendering(this);
|
||||
this.rendering.start(latch);
|
||||
}
|
||||
latch.waitForChange();
|
||||
Log.info(String.format("Connecting to server: %s", address));
|
||||
this.network.connect(address);
|
||||
latch.countDown();
|
||||
} catch (Exception e) {
|
||||
Log.printException(e, LogLevels.DEBUG);
|
||||
Log.fatal(String.format("Could not load mapping for %s. This version seems to be unsupported!", version));
|
||||
Log.fatal(String.format("Could not load version %s. This version seems to be unsupported!", version));
|
||||
this.lastException = new MappingsLoadingException("Mappings could not be loaded", e);
|
||||
setConnectionState(ConnectionStates.FAILED_NO_RETRY);
|
||||
}
|
||||
@ -165,7 +172,6 @@ public class Connection {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
|
||||
public void handle(ClientboundPacket p) {
|
||||
this.handlingQueue.add(p);
|
||||
}
|
||||
@ -372,10 +378,6 @@ public class Connection {
|
||||
case FAILED_NO_RETRY -> handlePingCallbacks(null);
|
||||
case PLAY -> {
|
||||
Minosoft.CONNECTIONS.put(getConnectionId(), this);
|
||||
if (!StaticConfiguration.HEADLESS_MODE) {
|
||||
this.rendering = new Rendering(this);
|
||||
this.rendering.start();
|
||||
}
|
||||
|
||||
if (CLI.getCurrentConnection() == null) {
|
||||
CLI.setCurrentConnection(this);
|
||||
|
@ -56,8 +56,6 @@ public class PacketChatMessageReceiving extends ClientboundPacket {
|
||||
case ABOVE_HOTBAR -> "[HOTBAR] ";
|
||||
default -> "[CHAT] ";
|
||||
} + event.getMessage());
|
||||
|
||||
connection.getRenderer().getRenderWindow().getHudRenderer().getChatMessages().add(new kotlin.Pair<>(this.message, System.currentTimeMillis()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -82,6 +82,10 @@ public final class ProtocolDefinition {
|
||||
|
||||
public static final char[] OBFUSCATED_CHARS = "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~".toCharArray();
|
||||
|
||||
|
||||
public static final int TICKS_PER_SECOND = 20;
|
||||
public static final int TICK_TIME = 1000 / TICKS_PER_SECOND;
|
||||
|
||||
static {
|
||||
// java does (why ever) not allow to directly assign a null
|
||||
InetAddress tempInetAddress;
|
||||
|
@ -32,6 +32,14 @@ public class CountUpAndDownLatch {
|
||||
}
|
||||
}
|
||||
|
||||
public void waitUntilZero(long timeout) throws InterruptedException {
|
||||
synchronized (this.lock) {
|
||||
while (this.count > 0) {
|
||||
this.lock.wait(timeout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void countUp() {
|
||||
synchronized (this.lock) {
|
||||
this.total++;
|
||||
@ -41,6 +49,9 @@ public class CountUpAndDownLatch {
|
||||
}
|
||||
|
||||
public void countDown() {
|
||||
if (this.count == 0) {
|
||||
throw new IllegalStateException("Can not count down, counter is already 0");
|
||||
}
|
||||
synchronized (this.lock) {
|
||||
this.count--;
|
||||
this.lock.notifyAll();
|
||||
|
Loading…
x
Reference in New Issue
Block a user