From 1556fed1e4f8109d1908052339467941c9bc8efd Mon Sep 17 00:00:00 2001 From: Bixilon Date: Tue, 23 May 2023 15:45:03 +0200 Subject: [PATCH 01/21] wip position offsetting, GH-13 and #108 --- .../data/entities/EntityRenderInfo.kt | 18 ++++----- .../minosoft/gui/rendering/camera/Camera.kt | 1 + .../gui/rendering/camera/MatrixHandler.kt | 4 +- .../gui/rendering/camera/WorldOffset.kt | 37 +++++++++++++++++++ .../gui/rendering/camera/view/CameraView.kt | 12 +++++- .../gui/rendering/camera/view/DebugView.kt | 14 +++++-- .../camera/view/person/FirstPersonView.kt | 7 +++- .../camera/view/person/ThirdPersonView.kt | 11 ++++-- .../overlay/overlays/simple/WallOverlay.kt | 2 +- .../rendering/models/SingleBlockRenderable.kt | 2 +- .../models/baked/MultipartBakedModel.kt | 4 +- .../models/baked/WeightedBakedModel.kt | 4 +- .../baked/block/BakedBlockStateModel.kt | 6 +-- .../skeletal/instance/SkeletalInstance.kt | 5 ++- .../gui/rendering/sky/clouds/CloudRenderer.kt | 2 +- .../gui/rendering/util/vec/vec3/Vec3Util.kt | 4 ++ .../gui/rendering/world/WorldRenderer.kt | 2 +- .../world/border/WorldBorderRenderer.kt | 6 +-- .../world/chunk/ChunkBorderRenderer.kt | 2 +- .../renderer/sign/SignBlockEntityRenderer.kt | 18 ++++----- .../preparer/cull/SolidCullSectionPreparer.kt | 11 +++++- 21 files changed, 124 insertions(+), 48 deletions(-) create mode 100644 src/main/java/de/bixilon/minosoft/gui/rendering/camera/WorldOffset.kt diff --git a/src/main/java/de/bixilon/minosoft/data/entities/EntityRenderInfo.kt b/src/main/java/de/bixilon/minosoft/data/entities/EntityRenderInfo.kt index be8640a86..852ba9672 100644 --- a/src/main/java/de/bixilon/minosoft/data/entities/EntityRenderInfo.kt +++ b/src/main/java/de/bixilon/minosoft/data/entities/EntityRenderInfo.kt @@ -13,23 +13,23 @@ package de.bixilon.minosoft.data.entities -import de.bixilon.kotlinglm.vec3.Vec3 +import de.bixilon.kotlinglm.vec3.Vec3d import de.bixilon.kutil.math.interpolation.FloatInterpolation.interpolateLinear import de.bixilon.minosoft.data.Tickable import de.bixilon.minosoft.data.entities.entities.Entity import de.bixilon.minosoft.data.registries.shapes.aabb.AABB import de.bixilon.minosoft.gui.rendering.renderer.drawable.Drawable -import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util -import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.blockPosition +import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3dUtil +import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3dUtil.blockPosition import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition class EntityRenderInfo(private val entity: Entity) : Drawable, Tickable { - private var position0 = Vec3(entity.physics.position) + private var position0 = Vec3d(entity.physics.position) private var position1 = position0 - var position: Vec3 = position0 + var position: Vec3d = position0 private set - var eyePosition: Vec3 = position + var eyePosition: Vec3d = position private set var cameraAABB: AABB = AABB.EMPTY private set @@ -44,8 +44,8 @@ class EntityRenderInfo(private val entity: Entity) : Drawable, Tickable { private fun interpolatePosition(delta: Float) { // TODO: Only interpolate if changed - position = Vec3Util.interpolateLinear(delta, position0, position1) - eyePosition = position + Vec3(0.0f, entity.eyeHeight, 0.0f) + position = Vec3dUtil.interpolateLinear(delta.toDouble(), position0, position1) + eyePosition = position + Vec3d(0.0, entity.eyeHeight, 0.0) cameraAABB = entity.defaultAABB + position eyeBlockPosition = position1.blockPosition } @@ -62,7 +62,7 @@ class EntityRenderInfo(private val entity: Entity) : Drawable, Tickable { override fun tick() { position0 = position1 - position1 = Vec3(entity.physics.position) + position1 = Vec3d(entity.physics.position) rotation0 = rotation1 rotation1 = entity.physics.rotation diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/camera/Camera.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/camera/Camera.kt index 346fa5ac6..66100a1fb 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/camera/Camera.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/camera/Camera.kt @@ -31,6 +31,7 @@ class Camera( val view = ViewManager(this) + val offset = WorldOffset(this) fun init() { matrixHandler.init() diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/camera/MatrixHandler.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/camera/MatrixHandler.kt index 7cf128de4..ff3485447 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/camera/MatrixHandler.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/camera/MatrixHandler.kt @@ -112,7 +112,7 @@ class MatrixHandler( shaking.draw() val fov = calculateFOV() val view = camera.view.view - val eyePosition = view.eyePosition + val eyePosition = view.matrixPosition val front = view.front if (upToDate && eyePosition == this.eyePosition && front == this.front && fov == previousFOV && shaking.isEmpty) { return @@ -129,7 +129,7 @@ class MatrixHandler( updateViewMatrix(eyePosition, front) updateViewProjectionMatrix() - val usePosition = if (view.updateFrustum) eyePosition else connection.camera.entity.renderInfo.eyePosition + val usePosition = if (view.updateFrustum) eyePosition else Vec3(connection.camera.entity.renderInfo.eyePosition - camera.offset.offset) if (view.updateFrustum) { frustum.recalculate() diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/camera/WorldOffset.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/camera/WorldOffset.kt new file mode 100644 index 000000000..9d1cbe9c6 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/camera/WorldOffset.kt @@ -0,0 +1,37 @@ +/* + * Minosoft + * Copyright (C) 2020-2023 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 . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.gui.rendering.camera + +import de.bixilon.kotlinglm.vec3.Vec3i +import de.bixilon.kutil.observer.DataObserver.Companion.observed +import de.bixilon.minosoft.data.world.World +import de.bixilon.minosoft.gui.rendering.renderer.drawable.Drawable +import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3iUtil.EMPTY +import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition + +class WorldOffset(private val camera: Camera) : Drawable { + var offset by observed(Vec3i.EMPTY) + private set + + override fun draw() { + val previous = offset + val position = camera.view.view.eyePosition + } + + + companion object { + const val MAX_DISTANCE = (World.MAX_RENDER_DISTANCE * 2) * ProtocolDefinition.SECTION_WIDTH_X // coordinates higher than that value are not allowed + const val MIN_DISTANCE = MAX_DISTANCE - (World.MAX_RENDER_DISTANCE / 4) * ProtocolDefinition.SECTION_WIDTH_X // only if value is lower that that value coordinates will be back offset + } +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/camera/view/CameraView.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/camera/view/CameraView.kt index 228aab6e4..652fcb72f 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/camera/view/CameraView.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/camera/view/CameraView.kt @@ -15,6 +15,7 @@ package de.bixilon.minosoft.gui.rendering.camera.view import de.bixilon.kotlinglm.vec2.Vec2d import de.bixilon.kotlinglm.vec3.Vec3 +import de.bixilon.kotlinglm.vec3.Vec3d import de.bixilon.minosoft.data.entities.EntityRotation import de.bixilon.minosoft.gui.rendering.RenderContext import de.bixilon.minosoft.input.camera.MovementInputActions @@ -30,7 +31,8 @@ interface CameraView { val updateFrustum: Boolean get() = true - val eyePosition: Vec3 + val eyePosition: Vec3d + val matrixPosition: Vec3 val rotation: EntityRotation val front: Vec3 @@ -47,4 +49,12 @@ interface CameraView { fun draw() = Unit + + + companion object { + + fun CameraView.matrix(eye: Vec3d): Vec3 { + return Vec3(eye - context.camera.offset.offset) + } + } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/camera/view/DebugView.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/camera/view/DebugView.kt index b99775863..950ba83ac 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/camera/view/DebugView.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/camera/view/DebugView.kt @@ -15,11 +15,14 @@ package de.bixilon.minosoft.gui.rendering.camera.view import de.bixilon.kotlinglm.vec2.Vec2d import de.bixilon.kotlinglm.vec3.Vec3 +import de.bixilon.kotlinglm.vec3.Vec3d import de.bixilon.minosoft.data.entities.EntityRotation import de.bixilon.minosoft.gui.rendering.RenderContext import de.bixilon.minosoft.gui.rendering.camera.Camera import de.bixilon.minosoft.gui.rendering.camera.CameraDefinition.CAMERA_UP_VEC3 +import de.bixilon.minosoft.gui.rendering.camera.view.CameraView.Companion.matrix import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.EMPTY +import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3dUtil.EMPTY import de.bixilon.minosoft.input.camera.MovementInputActions import de.bixilon.minosoft.input.camera.PlayerMovementInput @@ -28,7 +31,8 @@ class DebugView(private val camera: Camera) : CameraView { override val updateFrustum: Boolean get() = false override val shaking: Boolean get() = false - override var eyePosition = Vec3.EMPTY + override var eyePosition = Vec3d.EMPTY + override var matrixPosition = Vec3.EMPTY override var rotation = EntityRotation.EMPTY override var front = Vec3.EMPTY @@ -44,7 +48,7 @@ class DebugView(private val camera: Camera) : CameraView { speedMultiplier *= 2 } - val movement = Vec3.EMPTY + val movement = Vec3d.EMPTY if (input.forwards != 0.0f) { movement += front * input.forwards @@ -54,13 +58,14 @@ class DebugView(private val camera: Camera) : CameraView { movement += cameraRight * input.sideways } - if (movement.length2() != 0.0f) { + if (movement.length2() != 0.0) { movement.normalizeAssign() } movement *= speedMultiplier movement *= delta eyePosition = eyePosition + movement + this.matrixPosition = matrix(this.eyePosition) } override fun onMouse(delta: Vec2d) { @@ -73,7 +78,8 @@ class DebugView(private val camera: Camera) : CameraView { } override fun onAttach(previous: CameraView?) { - this.eyePosition = previous?.eyePosition ?: Vec3.EMPTY + this.eyePosition = previous?.eyePosition ?: Vec3d.EMPTY + this.matrixPosition = matrix(this.eyePosition) this.rotation = previous?.rotation ?: EntityRotation.EMPTY this.front = previous?.front ?: Vec3.EMPTY } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/camera/view/person/FirstPersonView.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/camera/view/person/FirstPersonView.kt index 4e6825a0d..cd94fdb22 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/camera/view/person/FirstPersonView.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/camera/view/person/FirstPersonView.kt @@ -15,13 +15,16 @@ package de.bixilon.minosoft.gui.rendering.camera.view.person import de.bixilon.kotlinglm.vec2.Vec2d import de.bixilon.kotlinglm.vec3.Vec3 +import de.bixilon.kotlinglm.vec3.Vec3d import de.bixilon.minosoft.data.abilities.Gamemodes import de.bixilon.minosoft.data.entities.EntityRotation import de.bixilon.minosoft.data.entities.entities.player.PlayerEntity import de.bixilon.minosoft.gui.rendering.RenderContext import de.bixilon.minosoft.gui.rendering.camera.Camera import de.bixilon.minosoft.gui.rendering.camera.view.CameraView +import de.bixilon.minosoft.gui.rendering.camera.view.CameraView.Companion.matrix import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.EMPTY +import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3dUtil.EMPTY class FirstPersonView(override val camera: Camera) : PersonView { override val context: RenderContext get() = camera.context @@ -37,7 +40,8 @@ class FirstPersonView(override val camera: Camera) : PersonView { } override val renderOverlays: Boolean get() = true - override var eyePosition: Vec3 = Vec3.EMPTY + override var eyePosition: Vec3d = Vec3d.EMPTY + override var matrixPosition: Vec3 = Vec3.EMPTY override var rotation = EntityRotation.EMPTY override var front = Vec3.EMPTY @@ -52,6 +56,7 @@ class FirstPersonView(override val camera: Camera) : PersonView { private fun update() { val entity = context.connection.camera.entity this.eyePosition = entity.renderInfo.eyePosition + this.matrixPosition = matrix(this.eyePosition) this.rotation = entity.physics.rotation this.front = this.rotation.front } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/camera/view/person/ThirdPersonView.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/camera/view/person/ThirdPersonView.kt index 7b1d04099..b07f4b2e2 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/camera/view/person/ThirdPersonView.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/camera/view/person/ThirdPersonView.kt @@ -15,12 +15,15 @@ package de.bixilon.minosoft.gui.rendering.camera.view.person import de.bixilon.kotlinglm.vec2.Vec2d import de.bixilon.kotlinglm.vec3.Vec3 +import de.bixilon.kotlinglm.vec3.Vec3d import de.bixilon.minosoft.data.entities.EntityRotation import de.bixilon.minosoft.gui.rendering.RenderContext import de.bixilon.minosoft.gui.rendering.camera.Camera import de.bixilon.minosoft.gui.rendering.camera.view.CameraView +import de.bixilon.minosoft.gui.rendering.camera.view.CameraView.Companion.matrix import de.bixilon.minosoft.gui.rendering.util.VecUtil.toVec3d import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.EMPTY +import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3dUtil.EMPTY import de.bixilon.minosoft.input.camera.MovementInputActions import de.bixilon.minosoft.input.camera.PlayerMovementInput @@ -28,7 +31,8 @@ import de.bixilon.minosoft.input.camera.PlayerMovementInput class ThirdPersonView(override val camera: Camera) : PersonView { override val context: RenderContext get() = camera.context - override var eyePosition: Vec3 = Vec3.EMPTY + override var eyePosition: Vec3d = Vec3d.EMPTY + override var matrixPosition: Vec3 = Vec3.EMPTY override var rotation = EntityRotation.EMPTY override var front = Vec3.EMPTY @@ -53,11 +57,12 @@ class ThirdPersonView(override val camera: Camera) : PersonView { update(entity.renderInfo.eyePosition, front) } - private fun update(position: Vec3, front: Vec3) { - val target = camera.context.connection.camera.target.raycastBlock(position.toVec3d, (-front).toVec3d).first + private fun update(position: Vec3d, front: Vec3) { + val target = camera.context.connection.camera.target.raycastBlock(position, (-front).toVec3d).first val distance = target?.distance?.let { minOf(it, MAX_DISTANCE) } ?: MAX_DISTANCE this.eyePosition = position + (-front * distance) + this.matrixPosition = matrix(this.eyePosition) } override fun onAttach(previous: CameraView?) { diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/framebuffer/world/overlay/overlays/simple/WallOverlay.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/framebuffer/world/overlay/overlays/simple/WallOverlay.kt index c956ab768..2c426025b 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/framebuffer/world/overlay/overlays/simple/WallOverlay.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/framebuffer/world/overlay/overlays/simple/WallOverlay.kt @@ -26,7 +26,7 @@ import de.bixilon.minosoft.data.world.positions.BlockPositionUtil.positionHash import de.bixilon.minosoft.gui.rendering.RenderContext import de.bixilon.minosoft.gui.rendering.framebuffer.world.overlay.OverlayFactory import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.AbstractTexture -import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.blockPosition +import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3dUtil.blockPosition import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3iUtil.EMPTY import java.util.* diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/models/SingleBlockRenderable.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/models/SingleBlockRenderable.kt index c9271e1c1..be9c1a23b 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/models/SingleBlockRenderable.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/models/SingleBlockRenderable.kt @@ -20,5 +20,5 @@ import java.util.* interface SingleBlockRenderable { - fun singleRender(position: Vec3i, mesh: WorldMesh, random: Random, blockState: BlockState, neighbours: Array, light: ByteArray, tints: IntArray?): Boolean + fun singleRender(position: Vec3i, offset: FloatArray, mesh: WorldMesh, random: Random, blockState: BlockState, neighbours: Array, light: ByteArray, tints: IntArray?): Boolean } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/models/baked/MultipartBakedModel.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/models/baked/MultipartBakedModel.kt index e50d968e9..530b9167a 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/models/baked/MultipartBakedModel.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/models/baked/MultipartBakedModel.kt @@ -32,10 +32,10 @@ class MultipartBakedModel( return sizes[direction.ordinal] } - override fun singleRender(position: Vec3i, mesh: WorldMesh, random: Random, blockState: BlockState, neighbours: Array, light: ByteArray, tints: IntArray?): Boolean { + override fun singleRender(position: Vec3i, offset: FloatArray, mesh: WorldMesh, random: Random, blockState: BlockState, neighbours: Array, light: ByteArray, tints: IntArray?): Boolean { var rendered = false for (model in models) { - if (model.singleRender(position, mesh, random, blockState, neighbours, light, tints) && !rendered) { + if (model.singleRender(position, offset, mesh, random, blockState, neighbours, light, tints) && !rendered) { rendered = true } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/models/baked/WeightedBakedModel.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/models/baked/WeightedBakedModel.kt index 58f391683..758508d9c 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/models/baked/WeightedBakedModel.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/models/baked/WeightedBakedModel.kt @@ -59,8 +59,8 @@ class WeightedBakedModel( Broken("Could not find a model: This should never happen!") } - override fun singleRender(position: Vec3i, mesh: WorldMesh, random: Random, blockState: BlockState, neighbours: Array, light: ByteArray, tints: IntArray?): Boolean { - return getModel(random)?.singleRender(position, mesh, random, blockState, neighbours, light, tints) ?: false + override fun singleRender(position: Vec3i, offset: FloatArray, mesh: WorldMesh, random: Random, blockState: BlockState, neighbours: Array, light: ByteArray, tints: IntArray?): Boolean { + return getModel(random)?.singleRender(position, offset, mesh, random, blockState, neighbours, light, tints) ?: false } override fun getParticleTexture(random: Random, blockPosition: Vec3i): AbstractTexture? { diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/models/baked/block/BakedBlockStateModel.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/models/baked/block/BakedBlockStateModel.kt index 0bdf8fa5d..60c37aeb0 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/models/baked/block/BakedBlockStateModel.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/models/baked/block/BakedBlockStateModel.kt @@ -25,7 +25,7 @@ import de.bixilon.minosoft.gui.rendering.models.properties.AbstractFacePropertie import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.AbstractTexture import de.bixilon.minosoft.gui.rendering.tint.TintManager import de.bixilon.minosoft.gui.rendering.util.VecUtil.getWorldOffset -import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3iUtil.toVec3 +import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.toVec3 import de.bixilon.minosoft.gui.rendering.world.mesh.WorldMesh import de.bixilon.minosoft.gui.rendering.world.preparer.cull.SolidCullSectionPreparer import java.util.* @@ -40,8 +40,8 @@ class BakedBlockStateModel( return touchingFaceProperties[direction.ordinal] } - override fun singleRender(position: Vec3i, mesh: WorldMesh, random: Random, blockState: BlockState, neighbours: Array, light: ByteArray, tints: IntArray?): Boolean { - val floatPosition = position.toVec3() + override fun singleRender(position: Vec3i, offset: FloatArray, mesh: WorldMesh, random: Random, blockState: BlockState, neighbours: Array, light: ByteArray, tints: IntArray?): Boolean { + val floatPosition = offset.toVec3() if (blockState.block is RandomOffsetBlock) { blockState.block.randomOffset?.let { floatPosition += position.getWorldOffset(it) } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/instance/SkeletalInstance.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/instance/SkeletalInstance.kt index 20145c271..471f6b2cb 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/instance/SkeletalInstance.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/instance/SkeletalInstance.kt @@ -16,6 +16,7 @@ package de.bixilon.minosoft.gui.rendering.skeletal.instance import de.bixilon.kotlinglm.func.rad import de.bixilon.kotlinglm.mat4x4.Mat4 import de.bixilon.kotlinglm.vec3.Vec3 +import de.bixilon.kotlinglm.vec3.Vec3d import de.bixilon.kutil.time.TimeUtil.millis import de.bixilon.minosoft.data.entities.EntityRotation import de.bixilon.minosoft.gui.rendering.RenderContext @@ -71,9 +72,9 @@ class SkeletalInstance( context.skeletalManager.draw(this, light) } - fun updatePosition(position: Vec3, rotation: EntityRotation) { + fun updatePosition(position: Vec3d, rotation: EntityRotation) { val matrix = Mat4() - .translateAssign(position) + .translateAssign(Vec3(position - context.camera.offset.offset)) .rotateAssign((180.0f - rotation.yaw).rad, Vec3(0, 1, 0)) .translateAssign(Vec3(-0.5, 0.0f, -0.5)) // move to bottom center diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/sky/clouds/CloudRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/sky/clouds/CloudRenderer.kt index 31e582280..27a5bdcf7 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/sky/clouds/CloudRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/sky/clouds/CloudRenderer.kt @@ -218,7 +218,7 @@ class CloudRenderer( private fun setYOffset() { - val y = context.connection.camera.entity.renderInfo.eyePosition.y + val y = (context.connection.camera.entity.renderInfo.eyePosition.y - context.camera.offset.offset.y).toFloat() var yOffset = 0.0f if (baseHeight - y > maxDistance) { yOffset = y - baseHeight + maxDistance diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/util/vec/vec3/Vec3Util.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/util/vec/vec3/Vec3Util.kt index d83199a88..f17081d0d 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/util/vec/vec3/Vec3Util.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/util/vec/vec3/Vec3Util.kt @@ -156,4 +156,8 @@ object Vec3Util { return Vec3(interpolate(start.x, end.x), interpolate(start.y, end.y), interpolate(start.z, end.z)) } + + fun FloatArray.toVec3(): Vec3 { + return Vec3(this[0], this[1], this[2]) + } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/world/WorldRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/world/WorldRenderer.kt index 47e7f4ad1..309fb03f6 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/world/WorldRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/world/WorldRenderer.kt @@ -265,7 +265,7 @@ class WorldRenderer( private fun onFrustumChange() { var sortQueue = false - val cameraPosition = connection.player.renderInfo.eyePosition + val cameraPosition = Vec3(connection.player.renderInfo.eyePosition - context.camera.offset.offset) val cameraChunkPosition = cameraPosition.blockPosition.chunkPosition val cameraSectionHeight = this.cameraSectionHeight if (this.cameraPosition != cameraPosition) { diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/world/border/WorldBorderRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/world/border/WorldBorderRenderer.kt index 16259693f..2289f4320 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/world/border/WorldBorderRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/world/border/WorldBorderRenderer.kt @@ -74,10 +74,10 @@ class WorldBorderRenderer( } val textureOffset = (offsetReset - time) / ANIMATION_SPEED.toFloat() shader.textureOffset = 1.0f - textureOffset - shader.cameraHeight = context.connection.camera.entity.renderInfo.eyePosition.y + shader.cameraHeight = (context.connection.camera.entity.renderInfo.eyePosition.y - context.camera.offset.offset.y).toFloat() - val distance = border.getDistanceTo(context.connection.player.physics.position) - val strength = 1.0f - (distance.toFloat().clamp(0.0f, 100.0f) / 100.0f) + val distance = border.getDistanceTo(context.connection.player.physics.position).toFloat() + val strength = 1.0f - (distance.clamp(0.0f, 100.0f) / 100.0f) var color = when (border.state) { WorldBorderState.GROWING -> GROWING_COLOR WorldBorderState.SHRINKING -> SHRINKING_COLOR diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/world/chunk/ChunkBorderRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/world/chunk/ChunkBorderRenderer.kt index 88b66b498..ffe9ea7f0 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/world/chunk/ChunkBorderRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/world/chunk/ChunkBorderRenderer.kt @@ -31,7 +31,7 @@ import de.bixilon.minosoft.gui.rendering.renderer.renderer.RendererBuilder import de.bixilon.minosoft.gui.rendering.system.base.RenderSystem import de.bixilon.minosoft.gui.rendering.system.base.phases.OpaqueDrawable import de.bixilon.minosoft.gui.rendering.util.mesh.LineMesh -import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.blockPosition +import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3dUtil.blockPosition import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3iUtil.chunkPosition import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3iUtil.sectionHeight import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/world/entities/renderer/sign/SignBlockEntityRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/world/entities/renderer/sign/SignBlockEntityRenderer.kt index 967ced78a..9b1ef0ee0 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/world/entities/renderer/sign/SignBlockEntityRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/world/entities/renderer/sign/SignBlockEntityRenderer.kt @@ -32,8 +32,8 @@ import de.bixilon.minosoft.gui.rendering.RenderContext import de.bixilon.minosoft.gui.rendering.font.Font import de.bixilon.minosoft.gui.rendering.font.renderer.ChatComponentRenderer import de.bixilon.minosoft.gui.rendering.models.unbaked.element.UnbakedElement -import de.bixilon.minosoft.gui.rendering.util.VecUtil.toVec3 import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.rotateAssign +import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.toVec3 import de.bixilon.minosoft.gui.rendering.world.entities.OnlyMeshedBlockEntityRenderer import de.bixilon.minosoft.gui.rendering.world.mesh.SingleWorldMesh import de.bixilon.minosoft.gui.rendering.world.mesh.WorldMesh @@ -52,19 +52,19 @@ class SignBlockEntityRenderer( return rotation * 22.5f } - override fun singleRender(position: Vec3i, mesh: WorldMesh, random: Random, blockState: BlockState, neighbours: Array, light: ByteArray, tints: IntArray?): Boolean { + override fun singleRender(position: Vec3i, offset: FloatArray, mesh: WorldMesh, random: Random, blockState: BlockState, neighbours: Array, light: ByteArray, tints: IntArray?): Boolean { val block = this.blockState.block if (block is StandingSignBlock) { - renderStandingText(position, mesh, light[SolidCullSectionPreparer.SELF_LIGHT_INDEX].toInt()) + renderStandingText(offset, mesh, light[SolidCullSectionPreparer.SELF_LIGHT_INDEX].toInt()) } else if (block is WallSignBlock) { - renderWallText(position, mesh, light[SolidCullSectionPreparer.SELF_LIGHT_INDEX].toInt()) + renderWallText(offset, mesh, light[SolidCullSectionPreparer.SELF_LIGHT_INDEX].toInt()) } return true } - private fun renderText(position: Vec3i, rotationVector: Vec3, yRotation: Float, mesh: WorldMesh, light: Int) { - val textPosition = position.toVec3 + rotationVector + private fun renderText(offset: FloatArray, rotationVector: Vec3, yRotation: Float, mesh: WorldMesh, light: Int) { + val textPosition = offset.toVec3() + rotationVector val textMesh = mesh.textMesh!! var primitives = 0 @@ -79,15 +79,15 @@ class SignBlockEntityRenderer( } } - private fun renderStandingText(position: Vec3i, mesh: WorldMesh, light: Int) { + private fun renderStandingText(offset: FloatArray, mesh: WorldMesh, light: Int) { val yRotation = getRotation() val rotationVector = Vec3(X_OFFSET, 17.5f / UnbakedElement.BLOCK_RESOLUTION - Y_OFFSET, 9.0f / UnbakedElement.BLOCK_RESOLUTION + Z_OFFSET) rotationVector.signRotate(yRotation.rad) - renderText(position, rotationVector, yRotation, mesh, light) + renderText(offset, rotationVector, yRotation, mesh, light) } - private fun renderWallText(position: Vec3i, mesh: WorldMesh, light: Int) { + private fun renderWallText(position: FloatArray, mesh: WorldMesh, light: Int) { val yRotation = -when (val rotation = this.blockState.getFacing()) { Directions.SOUTH -> 0.0f Directions.EAST -> 90.0f diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/world/preparer/cull/SolidCullSectionPreparer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/world/preparer/cull/SolidCullSectionPreparer.kt index 7251ae05d..d14b3593d 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/world/preparer/cull/SolidCullSectionPreparer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/world/preparer/cull/SolidCullSectionPreparer.kt @@ -76,15 +76,21 @@ class SolidCullSectionPreparer( val neighbourBlocks: Array = arrayOfNulls(Directions.SIZE) val light = ByteArray(Directions.SIZE + 1) // last index (6) for the current block + val cameraOffset = context.camera.offset.offset + val offsetX = chunkPosition.x * ProtocolDefinition.SECTION_WIDTH_X val offsetY = sectionHeight * ProtocolDefinition.SECTION_HEIGHT_Y val offsetZ = chunkPosition.y * ProtocolDefinition.SECTION_WIDTH_Z + val floatOffset = FloatArray(3) + for (y in blocks.minPosition.y..blocks.maxPosition.y) { position.y = offsetY + y + floatOffset[1] = (position.y - cameraOffset.y).toFloat() val fastBedrock = y == 0 && isLowestSection && fastBedrock for (x in blocks.minPosition.x..blocks.maxPosition.x) { position.x = offsetX + x + floatOffset[0] = (position.x - cameraOffset.x).toFloat() for (z in blocks.minPosition.z..blocks.maxPosition.z) { val baseIndex = (z shl 4) or x val index = (y shl 8) or baseIndex @@ -94,6 +100,7 @@ class SolidCullSectionPreparer( } light[SELF_LIGHT_INDEX] = sectionLight[index] position.z = offsetZ + z + floatOffset[2] = (position.z - cameraOffset.z).toFloat() val maxHeight = chunk.light.heightmap[baseIndex] if (position.y >= maxHeight) { @@ -158,10 +165,10 @@ class SolidCullSectionPreparer( random.setSeed(0L) } tints = tintColorCalculator.getAverageBlockTint(chunk, neighbourChunks, blockState, x, y, z) - rendered = model.singleRender(position, mesh, random, blockState, neighbourBlocks, light, tints) + rendered = model.singleRender(position, floatOffset, mesh, random, blockState, neighbourBlocks, light, tints) if (blockEntityModel is MeshedBlockEntityRenderer<*>) { - rendered = blockEntityModel.singleRender(position, mesh, random, blockState, neighbourBlocks, light, tints) || rendered + rendered = blockEntityModel.singleRender(position, floatOffset, mesh, random, blockState, neighbourBlocks, light, tints) || rendered } if (rendered) { From 4794d1cf618aba8b4f32e0921f4081b005ca251e Mon Sep 17 00:00:00 2001 From: Bixilon Date: Tue, 23 May 2023 17:08:44 +0200 Subject: [PATCH 02/21] rendering: use position offset --- .../gui/rendering/camera/MatrixHandler.kt | 22 ++++++++++--------- .../gui/rendering/camera/WorldOffset.kt | 3 +-- .../gui/rendering/camera/frustum/Frustum.kt | 18 ++++++++++----- .../events/CameraPositionChangeEvent.kt | 8 +++---- .../gui/rendering/particle/ParticleMesh.kt | 7 +++--- .../gui/rendering/sky/box/SkyboxRenderer.kt | 2 +- .../renderer/storage/DoubleChestRenderer.kt | 2 +- .../renderer/storage/SingleChestRenderer.kt | 2 +- .../world/outline/BlockOutlineRenderer.kt | 8 ++++--- 9 files changed, 41 insertions(+), 31 deletions(-) diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/camera/MatrixHandler.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/camera/MatrixHandler.kt index ff3485447..23b7487ec 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/camera/MatrixHandler.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/camera/MatrixHandler.kt @@ -32,7 +32,7 @@ import de.bixilon.minosoft.gui.rendering.events.ResizeWindowEvent import de.bixilon.minosoft.gui.rendering.shader.types.CameraPositionShader import de.bixilon.minosoft.gui.rendering.shader.types.ViewProjectionShader import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.EMPTY -import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.blockPosition +import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3dUtil.blockPosition import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3iUtil.chunkPosition import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3iUtil.sectionHeight import de.bixilon.minosoft.modding.event.listener.CallbackEventListener.Companion.listen @@ -45,9 +45,9 @@ class MatrixHandler( private val connection = context.connection private val profile = context.connection.profiles.rendering.camera val shaking = CameraShaking(camera, profile.shaking) - val frustum = Frustum(this, connection.world) + val frustum = Frustum(camera, this, connection.world) - private var eyePosition = Vec3.EMPTY + private var matrixPosition = Vec3.EMPTY private var previousFOV = 0.0f private var front = Vec3.EMPTY @@ -112,12 +112,13 @@ class MatrixHandler( shaking.draw() val fov = calculateFOV() val view = camera.view.view - val eyePosition = view.matrixPosition + val eyePosition = view.eyePosition + val matrixPosition = view.matrixPosition val front = view.front - if (upToDate && eyePosition == this.eyePosition && front == this.front && fov == previousFOV && shaking.isEmpty) { + if (upToDate && matrixPosition == this.matrixPosition && front == this.front && fov == previousFOV && shaking.isEmpty) { return } - this.eyePosition = eyePosition + this.matrixPosition = matrixPosition this.front = front val cameraBlockPosition = eyePosition.blockPosition if (fov != previousFOV) { @@ -126,17 +127,18 @@ class MatrixHandler( previousFOV = fov updateFront(front) - updateViewMatrix(eyePosition, front) + updateViewMatrix(matrixPosition, front) updateViewProjectionMatrix() - val usePosition = if (view.updateFrustum) eyePosition else Vec3(connection.camera.entity.renderInfo.eyePosition - camera.offset.offset) + val useMatrixPosition = if (view.updateFrustum) matrixPosition else Vec3(connection.camera.entity.renderInfo.eyePosition - camera.offset.offset) + val useEyePosition = if (view.updateFrustum) eyePosition else connection.camera.entity.renderInfo.eyePosition if (view.updateFrustum) { frustum.recalculate() camera.visibilityGraph.updateCamera(cameraBlockPosition.chunkPosition, cameraBlockPosition.sectionHeight) } - connection.events.fire(CameraPositionChangeEvent(context, usePosition)) + connection.events.fire(CameraPositionChangeEvent(context, useEyePosition)) connection.events.fire( CameraMatrixChangeEvent( @@ -147,7 +149,7 @@ class MatrixHandler( ) ) - updateShaders(usePosition) + updateShaders(useMatrixPosition) upToDate = true } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/camera/WorldOffset.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/camera/WorldOffset.kt index 9d1cbe9c6..956b5e673 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/camera/WorldOffset.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/camera/WorldOffset.kt @@ -17,11 +17,10 @@ import de.bixilon.kotlinglm.vec3.Vec3i import de.bixilon.kutil.observer.DataObserver.Companion.observed import de.bixilon.minosoft.data.world.World import de.bixilon.minosoft.gui.rendering.renderer.drawable.Drawable -import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3iUtil.EMPTY import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition class WorldOffset(private val camera: Camera) : Drawable { - var offset by observed(Vec3i.EMPTY) + var offset by observed(Vec3i(100, 100, 100)) private set override fun draw() { diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/camera/frustum/Frustum.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/camera/frustum/Frustum.kt index eb3a8dcb7..3e2116006 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/camera/frustum/Frustum.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/camera/frustum/Frustum.kt @@ -25,6 +25,7 @@ import de.bixilon.kutil.enums.ValuesEnum import de.bixilon.minosoft.data.registries.shapes.aabb.AABB import de.bixilon.minosoft.data.world.World import de.bixilon.minosoft.gui.rendering.RenderConstants +import de.bixilon.minosoft.gui.rendering.camera.Camera import de.bixilon.minosoft.gui.rendering.camera.MatrixHandler import de.bixilon.minosoft.gui.rendering.util.VecUtil.of import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3iUtil.EMPTY @@ -33,6 +34,7 @@ import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition // Big thanks to: https://gist.github.com/podgorskiy/e698d18879588ada9014768e3e82a644 class Frustum( + private val camera: Camera, private val matrixHandler: MatrixHandler, private val world: World, ) { @@ -152,7 +154,8 @@ class Frustum( } fun containsChunkSection(chunkPosition: Vec2i, sectionHeight: Int, minPosition: Vec3i = CHUNK_NIN_POSITION, maxPosition: Vec3i = ProtocolDefinition.CHUNK_SECTION_SIZE): Boolean { - val base = Vec3i.of(chunkPosition, sectionHeight) + val offset = camera.offset.offset + val base = Vec3i.of(chunkPosition, sectionHeight) - offset val min = base + minPosition val max = base + maxPosition + 1 return containsRegion(Vec3(min), Vec3(max)) @@ -160,18 +163,21 @@ class Frustum( fun containsChunk(chunkPosition: Vec2i): Boolean { val dimension = world.dimension - val minY = dimension.minY - val maxY = dimension.maxY - val base = Vec2i(chunkPosition.x * ProtocolDefinition.SECTION_WIDTH_X, chunkPosition.y * ProtocolDefinition.SECTION_WIDTH_Z) + val offset = camera.offset.offset + val minY = dimension.minY - offset.y + val maxY = dimension.maxY - offset.y + val base = Vec2i(chunkPosition.x * ProtocolDefinition.SECTION_WIDTH_X - offset.x, chunkPosition.y * ProtocolDefinition.SECTION_WIDTH_Z - offset.z) return containsRegion(Vec3(base.x, minY, base.y), Vec3(base.x + ProtocolDefinition.SECTION_WIDTH_X, maxY, base.y + ProtocolDefinition.SECTION_WIDTH_Z)) } fun containsRegion(min: Vec3i, max: Vec3i): Boolean { - return containsRegion(Vec3(min), Vec3(max)) + val offset = camera.offset.offset + return containsRegion(Vec3(min - offset), Vec3(max - offset)) } fun containsAABB(aabb: AABB): Boolean { - return containsRegion(Vec3(aabb.min), Vec3(aabb.max)) + val offset = camera.offset.offset + return containsRegion(Vec3(aabb.min - offset), Vec3(aabb.max - offset)) } private data class FrustumData(val normals: Array, val planes: Array) diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/events/CameraPositionChangeEvent.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/events/CameraPositionChangeEvent.kt index 75e1dcea6..8e339c532 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/events/CameraPositionChangeEvent.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/events/CameraPositionChangeEvent.kt @@ -13,13 +13,13 @@ package de.bixilon.minosoft.gui.rendering.events -import de.bixilon.kotlinglm.vec3.Vec3 +import de.bixilon.kotlinglm.vec3.Vec3d import de.bixilon.minosoft.gui.rendering.RenderContext class CameraPositionChangeEvent( context: RenderContext, - newPosition: Vec3, + newPosition: Vec3d, ) : RenderEvent(context) { - val newPosition: Vec3 = newPosition - get() = Vec3(field) + val newPosition: Vec3d = newPosition + get() = Vec3d(field) } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/particle/ParticleMesh.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/particle/ParticleMesh.kt index d87e7bdaa..32a3f3fef 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/particle/ParticleMesh.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/particle/ParticleMesh.kt @@ -35,9 +35,10 @@ class ParticleMesh(context: RenderContext, data: AbstractFloatList) : Mesh(conte } val maxTransformedUV = texture.renderData.transformUV(uvMax) val data = data - data.add(position.x.toFloat()) - data.add(position.y.toFloat()) - data.add(position.z.toFloat()) + val offset = context.camera.offset.offset + data.add((position.x - offset.x).toFloat()) + data.add((position.y - offset.y).toFloat()) + data.add((position.z - offset.z).toFloat()) data.add(minTransformedUV) data.add(maxTransformedUV) data.add(texture.renderData.shaderTextureId.buffer()) diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/sky/box/SkyboxRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/sky/box/SkyboxRenderer.kt index a2a023227..8aa109cc9 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/sky/box/SkyboxRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/sky/box/SkyboxRenderer.kt @@ -45,8 +45,8 @@ import de.bixilon.minosoft.gui.rendering.events.CameraPositionChangeEvent import de.bixilon.minosoft.gui.rendering.sky.SkyChildRenderer import de.bixilon.minosoft.gui.rendering.sky.SkyRenderer import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.AbstractTexture -import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.blockPosition import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.interpolateLinear +import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3dUtil.blockPosition import de.bixilon.minosoft.modding.event.listener.CallbackEventListener.Companion.listen import java.util.* import kotlin.math.PI diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/world/entities/renderer/storage/DoubleChestRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/world/entities/renderer/storage/DoubleChestRenderer.kt index cd41c6df3..6ecfe1257 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/world/entities/renderer/storage/DoubleChestRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/world/entities/renderer/storage/DoubleChestRenderer.kt @@ -38,7 +38,7 @@ class DoubleChestRenderer( light: Int, ) : StorageBlockEntityRenderer( blockState, - SkeletalInstance(context, model, blockPosition.toVec3, (blockState.getFacing()).rotatedMatrix), + SkeletalInstance(context, model, (blockPosition - context.camera.offset.offset).toVec3, (blockState.getFacing()).rotatedMatrix), light, ) { diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/world/entities/renderer/storage/SingleChestRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/world/entities/renderer/storage/SingleChestRenderer.kt index f774ae9fd..141d17403 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/world/entities/renderer/storage/SingleChestRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/world/entities/renderer/storage/SingleChestRenderer.kt @@ -38,7 +38,7 @@ class SingleChestRenderer( light: Int, ) : StorageBlockEntityRenderer( blockState, - SkeletalInstance(context, model, blockPosition.toVec3, blockState.getFacing().rotatedMatrix), + SkeletalInstance(context, model, (blockPosition - context.camera.offset.offset).toVec3, blockState.getFacing().rotatedMatrix), light, ) { diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/world/outline/BlockOutlineRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/world/outline/BlockOutlineRenderer.kt index 6751524ff..effcc7b3d 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/world/outline/BlockOutlineRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/world/outline/BlockOutlineRenderer.kt @@ -113,7 +113,9 @@ class BlockOutlineRenderer( } } - if (target.blockPosition == position && target.state == state && !reload) { // TODO: also compare shapes, some blocks dynamically change it (e.g. scaffolding) + val offsetPosition = (target.blockPosition - context.camera.offset.offset) + + if (offsetPosition == position && target.state == state && !reload) { // TODO: also compare shapes, some blocks dynamically change it (e.g. scaffolding) return } @@ -123,7 +125,7 @@ class BlockOutlineRenderer( val mesh = LineMesh(context) - val blockOffset = target.blockPosition.toVec3d + val blockOffset = offsetPosition.toVec3d if (target.state.block is RandomOffsetBlock) { target.state.block.randomOffset?.let { blockOffset += target.blockPosition.getWorldOffset(it) } } @@ -139,7 +141,7 @@ class BlockOutlineRenderer( this.nextMesh = mesh - this.position = target.blockPosition + this.position = offsetPosition this.state = target.state this.reload = false } From 553084744fbf08558e09c4ed3a98fb9f77bd7e52 Mon Sep 17 00:00:00 2001 From: Bixilon Date: Tue, 23 May 2023 19:11:43 +0200 Subject: [PATCH 03/21] rendering: use position offset more, fixes --- .../gui/rendering/camera/MatrixHandler.kt | 3 +- .../gui/rendering/camera/WorldOffset.kt | 10 ++++- .../gui/rendering/camera/view/CameraView.kt | 9 ----- .../gui/rendering/camera/view/DebugView.kt | 4 -- .../camera/view/person/FirstPersonView.kt | 3 -- .../camera/view/person/ThirdPersonView.kt | 3 -- .../gui/rendering/sky/clouds/CloudArray.kt | 3 +- .../gui/rendering/sky/clouds/CloudMesh.kt | 7 ++-- .../gui/rendering/world/WorldRenderer.kt | 1 + .../world/border/WorldBorderRenderer.kt | 4 +- .../world/chunk/ChunkBorderRenderer.kt | 40 ++++++++++--------- .../preparer/cull/FluidCullSectionPreparer.kt | 24 ++++++----- 12 files changed, 57 insertions(+), 54 deletions(-) diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/camera/MatrixHandler.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/camera/MatrixHandler.kt index 23b7487ec..04f23479b 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/camera/MatrixHandler.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/camera/MatrixHandler.kt @@ -113,7 +113,8 @@ class MatrixHandler( val fov = calculateFOV() val view = camera.view.view val eyePosition = view.eyePosition - val matrixPosition = view.matrixPosition + context.camera.offset.draw() + val matrixPosition = Vec3(eyePosition - context.camera.offset.offset) val front = view.front if (upToDate && matrixPosition == this.matrixPosition && front == this.front && fov == previousFOV && shaking.isEmpty) { return diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/camera/WorldOffset.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/camera/WorldOffset.kt index 956b5e673..dc62f6933 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/camera/WorldOffset.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/camera/WorldOffset.kt @@ -17,15 +17,23 @@ import de.bixilon.kotlinglm.vec3.Vec3i import de.bixilon.kutil.observer.DataObserver.Companion.observed import de.bixilon.minosoft.data.world.World import de.bixilon.minosoft.gui.rendering.renderer.drawable.Drawable +import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3dUtil.blockPosition +import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3iUtil.EMPTY import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition class WorldOffset(private val camera: Camera) : Drawable { - var offset by observed(Vec3i(100, 100, 100)) + var offset by observed(Vec3i.EMPTY) private set override fun draw() { val previous = offset val position = camera.view.view.eyePosition + + val mod = (position.blockPosition / MAX_DISTANCE) * MAX_DISTANCE + if (mod != previous) { + this.offset = mod + } + // TODO: optimize this and use MIN_DISTANCE } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/camera/view/CameraView.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/camera/view/CameraView.kt index 652fcb72f..5e3371634 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/camera/view/CameraView.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/camera/view/CameraView.kt @@ -32,7 +32,6 @@ interface CameraView { val updateFrustum: Boolean get() = true val eyePosition: Vec3d - val matrixPosition: Vec3 val rotation: EntityRotation val front: Vec3 @@ -49,12 +48,4 @@ interface CameraView { fun draw() = Unit - - - companion object { - - fun CameraView.matrix(eye: Vec3d): Vec3 { - return Vec3(eye - context.camera.offset.offset) - } - } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/camera/view/DebugView.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/camera/view/DebugView.kt index 950ba83ac..881f5f5ab 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/camera/view/DebugView.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/camera/view/DebugView.kt @@ -20,7 +20,6 @@ import de.bixilon.minosoft.data.entities.EntityRotation import de.bixilon.minosoft.gui.rendering.RenderContext import de.bixilon.minosoft.gui.rendering.camera.Camera import de.bixilon.minosoft.gui.rendering.camera.CameraDefinition.CAMERA_UP_VEC3 -import de.bixilon.minosoft.gui.rendering.camera.view.CameraView.Companion.matrix import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.EMPTY import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3dUtil.EMPTY import de.bixilon.minosoft.input.camera.MovementInputActions @@ -32,7 +31,6 @@ class DebugView(private val camera: Camera) : CameraView { override val shaking: Boolean get() = false override var eyePosition = Vec3d.EMPTY - override var matrixPosition = Vec3.EMPTY override var rotation = EntityRotation.EMPTY override var front = Vec3.EMPTY @@ -65,7 +63,6 @@ class DebugView(private val camera: Camera) : CameraView { movement *= delta eyePosition = eyePosition + movement - this.matrixPosition = matrix(this.eyePosition) } override fun onMouse(delta: Vec2d) { @@ -79,7 +76,6 @@ class DebugView(private val camera: Camera) : CameraView { override fun onAttach(previous: CameraView?) { this.eyePosition = previous?.eyePosition ?: Vec3d.EMPTY - this.matrixPosition = matrix(this.eyePosition) this.rotation = previous?.rotation ?: EntityRotation.EMPTY this.front = previous?.front ?: Vec3.EMPTY } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/camera/view/person/FirstPersonView.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/camera/view/person/FirstPersonView.kt index cd94fdb22..ce29e5eb9 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/camera/view/person/FirstPersonView.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/camera/view/person/FirstPersonView.kt @@ -22,7 +22,6 @@ import de.bixilon.minosoft.data.entities.entities.player.PlayerEntity import de.bixilon.minosoft.gui.rendering.RenderContext import de.bixilon.minosoft.gui.rendering.camera.Camera import de.bixilon.minosoft.gui.rendering.camera.view.CameraView -import de.bixilon.minosoft.gui.rendering.camera.view.CameraView.Companion.matrix import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.EMPTY import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3dUtil.EMPTY @@ -41,7 +40,6 @@ class FirstPersonView(override val camera: Camera) : PersonView { override val renderOverlays: Boolean get() = true override var eyePosition: Vec3d = Vec3d.EMPTY - override var matrixPosition: Vec3 = Vec3.EMPTY override var rotation = EntityRotation.EMPTY override var front = Vec3.EMPTY @@ -56,7 +54,6 @@ class FirstPersonView(override val camera: Camera) : PersonView { private fun update() { val entity = context.connection.camera.entity this.eyePosition = entity.renderInfo.eyePosition - this.matrixPosition = matrix(this.eyePosition) this.rotation = entity.physics.rotation this.front = this.rotation.front } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/camera/view/person/ThirdPersonView.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/camera/view/person/ThirdPersonView.kt index b07f4b2e2..804fcb585 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/camera/view/person/ThirdPersonView.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/camera/view/person/ThirdPersonView.kt @@ -20,7 +20,6 @@ import de.bixilon.minosoft.data.entities.EntityRotation import de.bixilon.minosoft.gui.rendering.RenderContext import de.bixilon.minosoft.gui.rendering.camera.Camera import de.bixilon.minosoft.gui.rendering.camera.view.CameraView -import de.bixilon.minosoft.gui.rendering.camera.view.CameraView.Companion.matrix import de.bixilon.minosoft.gui.rendering.util.VecUtil.toVec3d import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.EMPTY import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3dUtil.EMPTY @@ -32,7 +31,6 @@ class ThirdPersonView(override val camera: Camera) : PersonView { override val context: RenderContext get() = camera.context override var eyePosition: Vec3d = Vec3d.EMPTY - override var matrixPosition: Vec3 = Vec3.EMPTY override var rotation = EntityRotation.EMPTY override var front = Vec3.EMPTY @@ -62,7 +60,6 @@ class ThirdPersonView(override val camera: Camera) : PersonView { val distance = target?.distance?.let { minOf(it, MAX_DISTANCE) } ?: MAX_DISTANCE this.eyePosition = position + (-front * distance) - this.matrixPosition = matrix(this.eyePosition) } override fun onAttach(previous: CameraView?) { diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/sky/clouds/CloudArray.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/sky/clouds/CloudArray.kt index 48d6cb2f6..9b5a09ff5 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/sky/clouds/CloudArray.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/sky/clouds/CloudArray.kt @@ -27,6 +27,7 @@ class CloudArray( } private fun build() { + val offset = layer.clouds.context.camera.offset.offset val matrix = layer.clouds.matrix val matrixOffset = (offset * ARRAY_SIZE) and 0xFF @@ -47,7 +48,7 @@ class CloudArray( matrix[matrixX - 1, matrixZ + 0], // WEST matrix[matrixX + 1, matrixZ + 0], // EAST ) - mesh.createCloud(start, start + CLOUD_SIZE, layer.height.first, layer.height.last, layer.clouds.flat, cull) + mesh.createCloud(start, start + CLOUD_SIZE, offset, layer.height.first, layer.height.last, layer.clouds.flat, cull) } } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/sky/clouds/CloudMesh.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/sky/clouds/CloudMesh.kt index 103b21bf8..18291d78c 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/sky/clouds/CloudMesh.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/sky/clouds/CloudMesh.kt @@ -16,6 +16,7 @@ package de.bixilon.minosoft.gui.rendering.sky.clouds import de.bixilon.kotlinglm.vec2.Vec2 import de.bixilon.kotlinglm.vec2.Vec2i import de.bixilon.kotlinglm.vec3.Vec3 +import de.bixilon.kotlinglm.vec3.Vec3i import de.bixilon.minosoft.data.direction.Directions import de.bixilon.minosoft.gui.rendering.RenderContext import de.bixilon.minosoft.gui.rendering.system.base.MeshUtil.buffer @@ -30,9 +31,9 @@ class CloudMesh(context: RenderContext) : Mesh(context, CloudMeshStruct, context } - fun createCloud(start: Vec2i, end: Vec2i, yStart: Int, yEnd: Int, flat: Boolean, culling: BooleanArray) { - val start = Vec3(start.x, yStart, start.y) + CLOUD_OFFSET - val end = Vec3(end.x, yEnd, end.y) + CLOUD_OFFSET + fun createCloud(start: Vec2i, end: Vec2i, offset: Vec3i, yStart: Int, yEnd: Int, flat: Boolean, culling: BooleanArray) { + val start = Vec3(start.x - offset.x, yStart - offset.y, start.y - offset.z) + CLOUD_OFFSET + val end = Vec3(end.x - offset.x, yEnd - offset.y, end.y - offset.z) + CLOUD_OFFSET addYQuad(Vec2(start.x, start.z), start.y, Vec2(end.x, end.z)) { position, _ -> addVertex(position, Directions.DOWN) } if (!flat) { diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/world/WorldRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/world/WorldRenderer.kt index 309fb03f6..4ac0d2218 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/world/WorldRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/world/WorldRenderer.kt @@ -113,6 +113,7 @@ class WorldRenderer( paused = false } } + context.camera.offset::offset.observe(this) { silentlyClearChunkCache() } context.inputHandler.registerKeyCallback("minosoft:clear_chunk_cache".toResourceLocation(), KeyBinding( KeyActions.MODIFIER to setOf(KeyCodes.KEY_F3), diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/world/border/WorldBorderRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/world/border/WorldBorderRenderer.kt index 2289f4320..3bda890f0 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/world/border/WorldBorderRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/world/border/WorldBorderRenderer.kt @@ -15,6 +15,7 @@ package de.bixilon.minosoft.gui.rendering.world.border import de.bixilon.kotlinglm.func.common.clamp import de.bixilon.kotlinglm.vec2.Vec2 +import de.bixilon.kotlinglm.vec2.Vec2d import de.bixilon.kutil.latch.CountUpAndDownLatch import de.bixilon.kutil.time.TimeUtil.millis import de.bixilon.minosoft.data.registries.identified.Namespaces.minosoft @@ -86,7 +87,8 @@ class WorldBorderRenderer( color = color.with(alpha = (strength * strength)) shader.tintColor = color shader.radius = border.diameter.toFloat() / 2.0f - shader.center = Vec2(border.center) + val offset = context.camera.offset.offset + shader.center = Vec2(border.center - Vec2d(offset.x, offset.z)) } override fun drawTranslucent() { diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/world/chunk/ChunkBorderRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/world/chunk/ChunkBorderRenderer.kt index ffe9ea7f0..c0bf9beed 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/world/chunk/ChunkBorderRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/world/chunk/ChunkBorderRenderer.kt @@ -32,6 +32,7 @@ import de.bixilon.minosoft.gui.rendering.system.base.RenderSystem import de.bixilon.minosoft.gui.rendering.system.base.phases.OpaqueDrawable import de.bixilon.minosoft.gui.rendering.util.mesh.LineMesh import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3dUtil.blockPosition +import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3iUtil.EMPTY import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3iUtil.chunkPosition import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3iUtil.sectionHeight import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection @@ -45,6 +46,7 @@ class ChunkBorderRenderer( ) : AsyncRenderer, OpaqueDrawable, MeshSwapper { private val profile = connection.profiles.rendering override val renderSystem: RenderSystem = context.renderSystem + private var offset = Vec3i.EMPTY private var chunkPosition: Vec2i? = null private var sectionHeight: Int = Int.MIN_VALUE @@ -77,52 +79,54 @@ class ChunkBorderRenderer( val eyePosition = connection.camera.entity.renderInfo.eyePosition.blockPosition val chunkPosition = eyePosition.chunkPosition val sectionHeight = eyePosition.sectionHeight - if (chunkPosition == this.chunkPosition && sectionHeight == this.sectionHeight && mesh != null) { + val offset = context.camera.offset.offset + if (chunkPosition == this.chunkPosition && sectionHeight == this.sectionHeight && this.offset == offset && mesh != null) { return } unload = true val mesh = LineMesh(context) val dimension = context.connection.world.dimension - val basePosition = chunkPosition * Vec2i(ProtocolDefinition.SECTION_WIDTH_X, ProtocolDefinition.SECTION_WIDTH_Z) + val basePosition = chunkPosition * Vec2i(ProtocolDefinition.SECTION_WIDTH_X, ProtocolDefinition.SECTION_WIDTH_Z) - Vec2i(offset.x, offset.z) - mesh.drawInnerChunkLines(basePosition, dimension) + mesh.drawInnerChunkLines(Vec3i(basePosition.x, -offset.y, basePosition.y), dimension) if (sectionHeight in dimension.minSection until dimension.maxSection) { mesh.drawSectionLines(Vec3i(basePosition.x, sectionHeight * ProtocolDefinition.SECTION_HEIGHT_Y, basePosition.y)) } - mesh.drawOuterChunkLines(chunkPosition, dimension) + mesh.drawOuterChunkLines(chunkPosition, offset, dimension) - this.nextMesh = mesh this.chunkPosition = chunkPosition this.sectionHeight = sectionHeight + this.offset = offset + this.nextMesh = mesh } - private fun LineMesh.drawOuterChunkLines(chunkPosition: Vec2i, dimension: DimensionProperties) { + private fun LineMesh.drawOuterChunkLines(chunkPosition: Vec2i, offset: Vec3i, dimension: DimensionProperties) { for (x in -OUTER_CHUNK_SIZE..OUTER_CHUNK_SIZE + 1) { for (z in -OUTER_CHUNK_SIZE..OUTER_CHUNK_SIZE + 1) { if ((x == 0 || x == 1) && (z == 0 || z == 1)) { continue } - val chunkBase = (chunkPosition + Vec2i(x, z)) * Vec2i(ProtocolDefinition.SECTION_WIDTH_X, ProtocolDefinition.SECTION_WIDTH_Z) - drawLine(Vec3(chunkBase.x + 0, dimension.minY, chunkBase.y), Vec3(chunkBase.x + 0, dimension.maxY + 1, chunkBase.y), OUTER_CHUNK_LINE_WIDTH, OUTER_CHUNK_COLOR) + val chunkBase = (chunkPosition + Vec2i(x, z)) * Vec2i(ProtocolDefinition.SECTION_WIDTH_X, ProtocolDefinition.SECTION_WIDTH_Z) - Vec2i(offset.x, offset.z) + drawLine(Vec3(chunkBase.x + 0, dimension.minY - offset.y, chunkBase.y), Vec3(chunkBase.x + 0, dimension.maxY - offset.y + 1, chunkBase.y), OUTER_CHUNK_LINE_WIDTH, OUTER_CHUNK_COLOR) } } } - private fun LineMesh.drawInnerChunkLines(basePosition: Vec2i, dimension: DimensionProperties) { - drawLine(Vec3(basePosition.x + 0, dimension.minY, basePosition.y), Vec3(basePosition.x + 0, dimension.maxY + 1, basePosition.y), INNER_CHUNK_LINE_WIDTH, INNER_CHUNK_COLOR) - drawLine(Vec3(basePosition.x, dimension.minY, basePosition.y + ProtocolDefinition.SECTION_WIDTH_Z), Vec3(basePosition.x, dimension.maxY + 1, basePosition.y + ProtocolDefinition.SECTION_WIDTH_Z), INNER_CHUNK_LINE_WIDTH, INNER_CHUNK_COLOR) - drawLine(Vec3(basePosition.x + ProtocolDefinition.SECTION_WIDTH_X, dimension.minY, basePosition.y + 0), Vec3(basePosition.x + ProtocolDefinition.SECTION_WIDTH_X, dimension.maxY + 1, basePosition.y + 0), INNER_CHUNK_LINE_WIDTH, INNER_CHUNK_COLOR) - drawLine(Vec3(basePosition.x + ProtocolDefinition.SECTION_WIDTH_X, dimension.minY, basePosition.y + ProtocolDefinition.SECTION_WIDTH_Z), Vec3(basePosition.x + ProtocolDefinition.SECTION_WIDTH_X, dimension.maxY + 1, basePosition.y + ProtocolDefinition.SECTION_WIDTH_Z), INNER_CHUNK_LINE_WIDTH, INNER_CHUNK_COLOR) + private fun LineMesh.drawInnerChunkLines(basePosition: Vec3i, dimension: DimensionProperties) { + drawLine(Vec3(basePosition.x + 0, basePosition.y + dimension.minY, basePosition.z), Vec3(basePosition.x + 0, basePosition.y + dimension.maxY + 1, basePosition.z), INNER_CHUNK_LINE_WIDTH, INNER_CHUNK_COLOR) + drawLine(Vec3(basePosition.x, basePosition.y + dimension.minY, basePosition.z + ProtocolDefinition.SECTION_WIDTH_Z), Vec3(basePosition.x, basePosition.y + dimension.maxY + 1, basePosition.z + ProtocolDefinition.SECTION_WIDTH_Z), INNER_CHUNK_LINE_WIDTH, INNER_CHUNK_COLOR) + drawLine(Vec3(basePosition.x + ProtocolDefinition.SECTION_WIDTH_X, basePosition.y + dimension.minY, basePosition.z + 0), Vec3(basePosition.x + ProtocolDefinition.SECTION_WIDTH_X, basePosition.y + dimension.maxY + 1, basePosition.z + 0), INNER_CHUNK_LINE_WIDTH, INNER_CHUNK_COLOR) + drawLine(Vec3(basePosition.x + ProtocolDefinition.SECTION_WIDTH_X, basePosition.y + dimension.minY, basePosition.z + ProtocolDefinition.SECTION_WIDTH_Z), Vec3(basePosition.x + ProtocolDefinition.SECTION_WIDTH_X, basePosition.y + dimension.maxY + 1, basePosition.z + ProtocolDefinition.SECTION_WIDTH_Z), INNER_CHUNK_LINE_WIDTH, INNER_CHUNK_COLOR) for (sectionHeight in dimension.minSection..dimension.maxSection) { - val y = sectionHeight * ProtocolDefinition.SECTION_HEIGHT_Y - drawLine(Vec3(basePosition.x, y, basePosition.y), Vec3(basePosition.x + ProtocolDefinition.SECTION_WIDTH_X, y, basePosition.y), INNER_CHUNK_LINE_WIDTH, INNER_CHUNK_COLOR) - drawLine(Vec3(basePosition.x, y, basePosition.y), Vec3(basePosition.x, y, basePosition.y + ProtocolDefinition.SECTION_WIDTH_Z), INNER_CHUNK_LINE_WIDTH, INNER_CHUNK_COLOR) - drawLine(Vec3(basePosition.x + ProtocolDefinition.SECTION_WIDTH_X, y, basePosition.y + ProtocolDefinition.SECTION_WIDTH_Z), Vec3(basePosition.x + ProtocolDefinition.SECTION_WIDTH_X, y, basePosition.y), INNER_CHUNK_LINE_WIDTH, INNER_CHUNK_COLOR) - drawLine(Vec3(basePosition.x + ProtocolDefinition.SECTION_WIDTH_X, y, basePosition.y + ProtocolDefinition.SECTION_WIDTH_Z), Vec3(basePosition.x, y, basePosition.y + ProtocolDefinition.SECTION_WIDTH_Z), INNER_CHUNK_LINE_WIDTH, INNER_CHUNK_COLOR) + val y = basePosition.y + sectionHeight * ProtocolDefinition.SECTION_HEIGHT_Y + drawLine(Vec3(basePosition.x, y, basePosition.z), Vec3(basePosition.x + ProtocolDefinition.SECTION_WIDTH_X, y, basePosition.z), INNER_CHUNK_LINE_WIDTH, INNER_CHUNK_COLOR) + drawLine(Vec3(basePosition.x, y, basePosition.z), Vec3(basePosition.x, y, basePosition.z + ProtocolDefinition.SECTION_WIDTH_Z), INNER_CHUNK_LINE_WIDTH, INNER_CHUNK_COLOR) + drawLine(Vec3(basePosition.x + ProtocolDefinition.SECTION_WIDTH_X, y, basePosition.z + ProtocolDefinition.SECTION_WIDTH_Z), Vec3(basePosition.x + ProtocolDefinition.SECTION_WIDTH_X, y, basePosition.z), INNER_CHUNK_LINE_WIDTH, INNER_CHUNK_COLOR) + drawLine(Vec3(basePosition.x + ProtocolDefinition.SECTION_WIDTH_X, y, basePosition.z + ProtocolDefinition.SECTION_WIDTH_Z), Vec3(basePosition.x, y, basePosition.z + ProtocolDefinition.SECTION_WIDTH_Z), INNER_CHUNK_LINE_WIDTH, INNER_CHUNK_COLOR) } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/world/preparer/cull/FluidCullSectionPreparer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/world/preparer/cull/FluidCullSectionPreparer.kt index f7f8f710a..e16a5e5ae 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/world/preparer/cull/FluidCullSectionPreparer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/world/preparer/cull/FluidCullSectionPreparer.kt @@ -68,6 +68,8 @@ class FluidCullSectionPreparer( var rendered = false var tint: Int + val cameraOffset = context.camera.offset.offset + val offsetX = chunkPosition.x * ProtocolDefinition.SECTION_WIDTH_X val offsetY = sectionHeight * ProtocolDefinition.SECTION_HEIGHT_Y val offsetZ = chunkPosition.y * ProtocolDefinition.SECTION_WIDTH_Z @@ -130,6 +132,8 @@ class FluidCullSectionPreparer( getCornerHeight(chunk, chunkPosition, position + Directions.SOUTH, fluid), ) + val offsetPosition = Vec3(position - cameraOffset) + if (!skip[Directions.O_UP]) { val velocity = fluid.getVelocity(blockState, position, chunk) val still = velocity.x == 0.0 && velocity.z == 0.0 @@ -164,10 +168,10 @@ class FluidCullSectionPreparer( val meshToUse = texture.transparency.getMesh(mesh) val positions = arrayOf( - Vec3(position.x, position.y + cornerHeights[0], position.z), - Vec3(position.x + 1, position.y + cornerHeights[1], position.z), - Vec3(position.x + 1, position.y + cornerHeights[2], position.z + 1), - Vec3(position.x, position.y + cornerHeights[3], position.z + 1), + Vec3(offsetPosition.x, offsetPosition.y + cornerHeights[0], offsetPosition.z), + Vec3(offsetPosition.x + 1, offsetPosition.y + cornerHeights[1], offsetPosition.z), + Vec3(offsetPosition.x + 1, offsetPosition.y + cornerHeights[2], offsetPosition.z + 1), + Vec3(offsetPosition.x, offsetPosition.y + cornerHeights[3], offsetPosition.z + 1), ) @@ -182,9 +186,9 @@ class FluidCullSectionPreparer( if (skip[Directions.SIDE_OFFSET + direction]) { continue } - var faceX = position.x.toFloat() + var faceX = offsetPosition.x var faceXEnd = faceX - var faceZ = position.z.toFloat() + var faceZ = offsetPosition.z var faceZEnd = faceZ var v1 = 0.0f var v2 = 0.0f @@ -222,10 +226,10 @@ class FluidCullSectionPreparer( val positions = arrayOf( - Vec3(faceX, position.y + v1, faceZ), - Vec3(faceX, position.y, faceZ), - Vec3(faceXEnd, position.y, faceZEnd), - Vec3(faceXEnd, position.y + v2, faceZEnd), + Vec3(faceX, offsetPosition.y + v1, faceZ), + Vec3(faceX, offsetPosition.y, faceZ), + Vec3(faceXEnd, offsetPosition.y, faceZEnd), + Vec3(faceXEnd, offsetPosition.y + v2, faceZEnd), ) val texturePositions = arrayOf( TEXTURE_1, From 6e2cebf7a6b85a31212a8f8ee8470ffc7b6772e8 Mon Sep 17 00:00:00 2001 From: Bixilon Date: Tue, 23 May 2023 19:33:16 +0200 Subject: [PATCH 04/21] restore command stack on error This should fix some errors with broken signature on commands --- .../bixilon/minosoft/commands/MsgCommandIT.kt | 4 ++-- .../de/bixilon/minosoft/commands/TPCommandIT.kt | 2 +- .../minosoft/commands/nodes/CommandNode.kt | 15 +++++++++------ .../minosoft/commands/stack/CommandStack.kt | 17 +++++++++++++++-- .../connection/play/util/ConnectionUtil.kt | 8 +++++++- 5 files changed, 34 insertions(+), 12 deletions(-) diff --git a/src/integration-test/kotlin/de/bixilon/minosoft/commands/MsgCommandIT.kt b/src/integration-test/kotlin/de/bixilon/minosoft/commands/MsgCommandIT.kt index 885134772..18a0367c6 100644 --- a/src/integration-test/kotlin/de/bixilon/minosoft/commands/MsgCommandIT.kt +++ b/src/integration-test/kotlin/de/bixilon/minosoft/commands/MsgCommandIT.kt @@ -51,7 +51,7 @@ class MsgCommandIT { fun validateStack() { var stack: CommandStack? = null - val node = createNode { stack = it.copy() } + val node = createNode { stack = it.fork() } node.execute("msg Bixilon hi there!") assertEquals(stack!!["msg"], "msg") @@ -70,7 +70,7 @@ class MsgCommandIT { fun redirectStack() { var stack: CommandStack? = null - val node = createNode { stack = it.copy() } + val node = createNode { stack = it.fork() } node.execute("redirect Bixilon hi there!") diff --git a/src/integration-test/kotlin/de/bixilon/minosoft/commands/TPCommandIT.kt b/src/integration-test/kotlin/de/bixilon/minosoft/commands/TPCommandIT.kt index d1d2b0def..ecc21f81c 100644 --- a/src/integration-test/kotlin/de/bixilon/minosoft/commands/TPCommandIT.kt +++ b/src/integration-test/kotlin/de/bixilon/minosoft/commands/TPCommandIT.kt @@ -51,7 +51,7 @@ class TPCommandIT { fun relativeStack() { var stack: CommandStack? = null - val node = createNode { stack = it.copy() } + val node = createNode { stack = it.fork() } node.execute("tp @s ~ ~10 ~") diff --git a/src/main/java/de/bixilon/minosoft/commands/nodes/CommandNode.kt b/src/main/java/de/bixilon/minosoft/commands/nodes/CommandNode.kt index 053081cfa..833c1ad22 100644 --- a/src/main/java/de/bixilon/minosoft/commands/nodes/CommandNode.kt +++ b/src/main/java/de/bixilon/minosoft/commands/nodes/CommandNode.kt @@ -41,7 +41,7 @@ abstract class CommandNode( val stackSize = stack.size var childError: Throwable? = null - var errorStack = -1 + var errorStack: CommandStack? = null for (child in (redirect?.children ?: children)) { reader.pointer = pointer @@ -53,12 +53,13 @@ abstract class CommandNode( } return } catch (error: Throwable) { - if (stack.size > errorStack) { - errorStack = stack.size + if (errorStack == null || stack.size > errorStack.size) { + errorStack = stack.fork() childError = error } } } + errorStack?.let { stack.join(it) } throw childError ?: return } @@ -71,7 +72,7 @@ abstract class CommandNode( val stackSize = stack.size var childError: Throwable? = null - var errorStack = -1 + var errorStack: CommandStack? = null var parserSucceeds = 0 for (child in (redirect?.children ?: children)) { @@ -92,8 +93,8 @@ abstract class CommandNode( return childSuggestions } catch (error: Throwable) { - if (stack.size > errorStack) { - errorStack = stack.size + if (errorStack == null || stack.size > errorStack.size) { + errorStack = stack.fork() childError = error } } @@ -103,6 +104,8 @@ abstract class CommandNode( if (!reader.canPeek(pointer) && executable) { return emptyList() } + errorStack?.let { stack.join(it) } + throw childError ?: return emptyList() } diff --git a/src/main/java/de/bixilon/minosoft/commands/stack/CommandStack.kt b/src/main/java/de/bixilon/minosoft/commands/stack/CommandStack.kt index c771fa0d9..e0aa2975c 100644 --- a/src/main/java/de/bixilon/minosoft/commands/stack/CommandStack.kt +++ b/src/main/java/de/bixilon/minosoft/commands/stack/CommandStack.kt @@ -26,11 +26,14 @@ import java.time.Instant class CommandStack( connection: PlayConnection? = null, - val print: PrintTarget = SystemPrintTarget, + print: PrintTarget = SystemPrintTarget, ) { private val stack: MutableList = mutableListOf() val size: Int get() = stack.size + var print = print + private set + var executor: Entity? = null lateinit var connection: PlayConnection @@ -70,7 +73,7 @@ class CommandStack( } - fun copy(): CommandStack { + fun fork(): CommandStack { val stack = CommandStack(null, print) stack.stack += this.stack stack.executor = this.executor @@ -80,4 +83,14 @@ class CommandStack( return stack } + + fun join(stack: CommandStack) { + this.stack.clear() + this.stack += stack.stack + this.print = stack.print + this.executor = stack.executor + if (stack::connection.isInitialized) { + this.connection = stack.connection + } + } } diff --git a/src/main/java/de/bixilon/minosoft/protocol/network/connection/play/util/ConnectionUtil.kt b/src/main/java/de/bixilon/minosoft/protocol/network/connection/play/util/ConnectionUtil.kt index 902891d85..dcc5e030a 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/network/connection/play/util/ConnectionUtil.kt +++ b/src/main/java/de/bixilon/minosoft/protocol/network/connection/play/util/ConnectionUtil.kt @@ -34,6 +34,7 @@ import de.bixilon.minosoft.protocol.packets.c2s.play.chat.ChatMessageC2SP import de.bixilon.minosoft.protocol.packets.c2s.play.chat.CommandC2SP import de.bixilon.minosoft.protocol.packets.c2s.play.chat.SignedChatMessageC2SP import de.bixilon.minosoft.util.logging.Log +import de.bixilon.minosoft.util.logging.LogLevels import de.bixilon.minosoft.util.logging.LogMessageType import java.security.SecureRandom import java.time.Instant @@ -72,7 +73,11 @@ class ConnectionUtil( val keyManagement = connection.player.keyManagement keyManagement.acquire() try { - val key = keyManagement.key ?: return connection.sendPacket(SignedChatMessageC2SP(message.encodeNetwork(), time = Instant.EPOCH, salt = 0, signature = null, false, Acknowledgement.EMPTY)) + val key = keyManagement.key + if (key == null) { + connection.sendPacket(SignedChatMessageC2SP(message.encodeNetwork(), time = Instant.EPOCH, salt = 0, signature = null, false, Acknowledgement.EMPTY)) + return + } sendSignedMessage(key, trimmed) } finally { keyManagement.release() @@ -104,6 +109,7 @@ class ConnectionUtil( ChatUtil.validateChatMessage(connection, trimmed) if (stack.size == 0) { connection.sendPacket(CommandC2SP(trimmed, Instant.EPOCH, 0L, emptyMap(), false, Acknowledgement.EMPTY)) // TODO: remove + Log.log(LogMessageType.OTHER, LogLevels.VERBOSE) { "Command $trimmed failed to pars!" } throw IllegalArgumentException("Empty command stack! Did the command fail to parse?") } val time = Instant.now() From 544b3a3407eb664fc87ca8a42c2b1dc47c626275 Mon Sep 17 00:00:00 2001 From: Bixilon Date: Tue, 23 May 2023 20:08:09 +0200 Subject: [PATCH 05/21] chunk border, block outline: use polygon offset --- .../gui/rendering/world/chunk/ChunkBorderRenderer.kt | 6 +++++- .../gui/rendering/world/outline/BlockOutlineRenderer.kt | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/world/chunk/ChunkBorderRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/world/chunk/ChunkBorderRenderer.kt index c0bf9beed..9d3418e80 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/world/chunk/ChunkBorderRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/world/chunk/ChunkBorderRenderer.kt @@ -190,7 +190,11 @@ class ChunkBorderRenderer( } override fun setupOpaque() { - context.renderSystem.reset() + context.renderSystem.reset( + polygonOffset = true, + polygonOffsetFactor = -1.0f, + polygonOffsetUnit = -2.0f, + ) context.shaderManager.genericColorShader.use() } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/world/outline/BlockOutlineRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/world/outline/BlockOutlineRenderer.kt index effcc7b3d..009d83743 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/world/outline/BlockOutlineRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/world/outline/BlockOutlineRenderer.kt @@ -77,7 +77,11 @@ class BlockOutlineRenderer( } override fun setupOther() { - context.renderSystem.reset() + context.renderSystem.reset( + polygonOffset = true, + polygonOffsetFactor = -3.0f, + polygonOffsetUnit = -3.0f, + ) if (profile.showThroughWalls) { context.renderSystem.depth = DepthFunctions.ALWAYS } From cb121b115bc7830cadd4e29ee1e56d59c36525d6 Mon Sep 17 00:00:00 2001 From: Bixilon Date: Tue, 23 May 2023 20:42:32 +0200 Subject: [PATCH 06/21] entity renderer: use camera world offset --- .../gui/rendering/camera/WorldOffset.kt | 2 +- .../gui/rendering/entity/EntityRenderer.kt | 10 ++++++++++ .../gui/rendering/entity/ModelUpdater.kt | 2 ++ .../gui/rendering/entity/hitbox/EntityHitbox.kt | 14 ++++++++------ .../gui/rendering/entity/models/EntityModel.kt | 5 +++++ .../gui/rendering/sky/clouds/CloudLayer.kt | 12 ++++++++++-- .../gui/rendering/sky/clouds/CloudRenderer.kt | 17 +++++++++++++++-- .../gui/rendering/util/mesh/LineMesh.kt | 8 +++++--- .../world/outline/BlockOutlineRenderer.kt | 1 - 9 files changed, 56 insertions(+), 15 deletions(-) diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/camera/WorldOffset.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/camera/WorldOffset.kt index dc62f6933..0065bc6a4 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/camera/WorldOffset.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/camera/WorldOffset.kt @@ -38,7 +38,7 @@ class WorldOffset(private val camera: Camera) : Drawable { companion object { - const val MAX_DISTANCE = (World.MAX_RENDER_DISTANCE * 2) * ProtocolDefinition.SECTION_WIDTH_X // coordinates higher than that value are not allowed + const val MAX_DISTANCE = World.MAX_RENDER_DISTANCE * ProtocolDefinition.SECTION_WIDTH_X // coordinates higher than that value are not allowed const val MIN_DISTANCE = MAX_DISTANCE - (World.MAX_RENDER_DISTANCE / 4) * ProtocolDefinition.SECTION_WIDTH_X // only if value is lower that that value coordinates will be back offset } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/entity/EntityRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/entity/EntityRenderer.kt index 7069f8432..03735da0c 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/entity/EntityRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/entity/EntityRenderer.kt @@ -61,6 +61,8 @@ class EntityRenderer( var visibleCount: Int = 0 private set + private var reset = false + override fun init(latch: CountUpAndDownLatch) { connection.events.listen { event -> if (event.entity is LocalPlayerEntity) return@listen @@ -75,6 +77,7 @@ class EntityRenderer( } profile.hitbox::enabled.observe(this) { this.hitboxes = it } + context.camera.offset::offset.observe(this) { reset = true } context.inputHandler.registerKeyCallback( HITBOX_TOGGLE_KEY_COMBINATION, @@ -104,8 +107,12 @@ class EntityRenderer( override fun prePrepareDraw() { val count = AtomicInteger() + val reset = reset runAsync { it.entity.draw(millis()) + if (reset) { + it.reset() + } it.update = it.checkUpdate() it.prepareAsync() if (it.visible) { @@ -113,6 +120,9 @@ class EntityRenderer( } } this.visibleCount = count.get() + if (reset) { + this.reset = false + } } override fun postPrepareDraw() { diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/entity/ModelUpdater.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/entity/ModelUpdater.kt index eafeb15e7..44b66bab0 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/entity/ModelUpdater.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/entity/ModelUpdater.kt @@ -23,4 +23,6 @@ interface ModelUpdater : Drawable { fun prepare() = Unit fun unload() = Unit + + fun reset() = Unit } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/entity/hitbox/EntityHitbox.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/entity/hitbox/EntityHitbox.kt index 77ff044be..6f17896a2 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/entity/hitbox/EntityHitbox.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/entity/hitbox/EntityHitbox.kt @@ -14,6 +14,7 @@ package de.bixilon.minosoft.gui.rendering.entity.hitbox import de.bixilon.kotlinglm.vec3.Vec3 +import de.bixilon.kotlinglm.vec3.Vec3d import de.bixilon.minosoft.data.entities.entities.LivingEntity import de.bixilon.minosoft.data.registries.shapes.aabb.AABB import de.bixilon.minosoft.data.text.formatting.color.ChatColors @@ -31,7 +32,6 @@ class EntityHitbox( private var aabb: AABB = model.aabb private var data: HitboxData? = null - private var update = true var enabled: Boolean = true get() = field && model.renderer.hitboxes @@ -52,7 +52,6 @@ class EntityHitbox( } this.data = data this.aabb = aabb - update = true return true } @@ -80,18 +79,21 @@ class EntityHitbox( } else { mesh.drawAABB(aabb = shrunk, color = data.color, margin = 0.1f) } - val center = Vec3(shrunk.center) + val offset = model.context.camera.offset.offset + val center = Vec3(shrunk.center - offset) + + data.velocity?.let { mesh.drawLine(center, center + Vec3(it) * 3, color = ChatColors.YELLOW) } val eyeHeight = shrunk.min.y + model.entity.eyeHeight - val eyeAABB = AABB(Vec3(shrunk.min.x, eyeHeight, shrunk.min.z), Vec3(shrunk.max.x, eyeHeight, shrunk.max.z)).hShrink(RenderConstants.DEFAULT_LINE_WIDTH) + val eyeAABB = AABB(Vec3d(shrunk.min.x, eyeHeight, shrunk.min.z), Vec3d(shrunk.max.x, eyeHeight, shrunk.max.z)).hShrink(-RenderConstants.DEFAULT_LINE_WIDTH) mesh.drawAABB(eyeAABB, RenderConstants.DEFAULT_LINE_WIDTH, ChatColors.DARK_RED) - val eyeStart = Vec3(center.x, eyeHeight, center.z) + val eyeStart = Vec3(center.x, eyeHeight - offset.y, center.z) - mesh.drawLine(eyeStart, eyeStart + Vec3(data.rotation.front) * 5.0f, color = ChatColors.BLUE) + mesh.drawLine(eyeStart, eyeStart + data.rotation.front * 5.0f, color = ChatColors.BLUE) this.mesh = mesh } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/entity/models/EntityModel.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/entity/models/EntityModel.kt index f99ba27b5..74711a38e 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/entity/models/EntityModel.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/entity/models/EntityModel.kt @@ -47,6 +47,11 @@ abstract class EntityModel( return update } + override fun reset() { + update = true + hitbox.reset() + } + override fun prepareAsync() { if (!update) { return diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/sky/clouds/CloudLayer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/sky/clouds/CloudLayer.kt index 88a77e64e..b06c2f441 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/sky/clouds/CloudLayer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/sky/clouds/CloudLayer.kt @@ -77,6 +77,10 @@ class CloudLayer( if (offset.y != 0) pushZ(offset.y == 1) } + fun reset() { + + } + private fun reset(cloudPosition: Vec2i) { for (array in arrays.unsafeCast>()) { array?.unload() @@ -92,9 +96,13 @@ class CloudLayer( return this shr 4 } - private fun updatePosition() { + private fun calculateCloudPosition(): Vec2i { val offset = this.offset.toInt() - val position = clouds.connection.player.physics.positionInfo.chunkPosition + Vec2i(offset / CloudArray.CLOUD_SIZE, 0) + return clouds.connection.player.physics.positionInfo.chunkPosition + Vec2i(offset / CloudArray.CLOUD_SIZE, 0) + } + + private fun updatePosition() { + val position = calculateCloudPosition() if (position == this.position) { return } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/sky/clouds/CloudRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/sky/clouds/CloudRenderer.kt index 27a5bdcf7..aa6f6af02 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/sky/clouds/CloudRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/sky/clouds/CloudRenderer.kt @@ -63,12 +63,16 @@ class CloudRenderer( var delta = 0.0f private set + private var reset = false + override val skipOpaque: Boolean get() = !sky.effects.clouds || !sky.profile.clouds.enabled || connection.profiles.block.viewDistance < 3 || layers.isEmpty() override fun asyncInit(latch: CountUpAndDownLatch) { matrix.load(connection.assetsManager) + + context.camera.offset::offset.observe(this) { reset() } } private fun getCloudHeight(index: Int): IntRange { @@ -103,6 +107,10 @@ class CloudRenderer( sky.profile.clouds::flat.observe(this, instant = true) { this.flat = it } } + private fun reset() { + reset = true + } + private fun updateLayers(layers: Int) { while (layers < this.layers.size) { toUnload += this.layers.removeLast() @@ -117,6 +125,11 @@ class CloudRenderer( if (!sky.effects.clouds) { return } + if (reset) { + updateLayers(0) + updateLayers(nextLayers) + reset = false + } if (layers.size != nextLayers) { updateLayers(nextLayers) } @@ -236,8 +249,8 @@ class CloudRenderer( setYOffset() - for (array in layers) { - array.draw() + for (layer in layers) { + layer.draw() } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/util/mesh/LineMesh.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/util/mesh/LineMesh.kt index 45dabcb9a..fd9a0a9e3 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/util/mesh/LineMesh.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/util/mesh/LineMesh.kt @@ -80,8 +80,9 @@ open class LineMesh(context: RenderContext) : GenericColorMesh(context) { fun drawLazyAABB(aabb: AABB, color: RGBColor) { data.ensureSize(6 * order.size * GenericColorMeshStruct.FLOATS_PER_VERTEX) + val offset = context.camera.offset.offset for (direction in Directions.VALUES) { - val positions = direction.getPositions(Vec3(aabb.min), Vec3(aabb.max)) + val positions = direction.getPositions(Vec3(aabb.min - offset), Vec3(aabb.max - offset)) for ((positionIndex, _) in order) { addVertex(positions[positionIndex], color) } @@ -90,8 +91,9 @@ open class LineMesh(context: RenderContext) : GenericColorMesh(context) { fun drawAABB(aabb: AABB, lineWidth: Float = RenderConstants.DEFAULT_LINE_WIDTH, color: RGBColor, margin: Float = 0.0f, shape: AbstractVoxelShape? = null) { data.ensureSize(12 * 4 * order.size * GenericColorMeshStruct.FLOATS_PER_VERTEX) - val min = aabb.min - margin - val max = aabb.max + margin + val offset = context.camera.offset.offset + val min = aabb.min - margin - offset + val max = aabb.max + margin - offset fun tryDrawLine(start: Vec3, end: Vec3) { tryDrawLine(start, end, lineWidth, color, shape) diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/world/outline/BlockOutlineRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/world/outline/BlockOutlineRenderer.kt index 009d83743..4acccfda5 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/world/outline/BlockOutlineRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/world/outline/BlockOutlineRenderer.kt @@ -63,7 +63,6 @@ class BlockOutlineRenderer( override var unload: Boolean = false override fun init(latch: CountUpAndDownLatch) { - val profile = connection.profiles.block this.profile::enabled.observe(this) { reload = true } this.profile::collisions.observe(this) { reload = true } this.profile::outlineColor.observe(this) { reload = true } From 5b4da9c4f1311677500d812c92efe7e0bfd30b9f Mon Sep 17 00:00:00 2001 From: Bixilon Date: Tue, 23 May 2023 20:48:43 +0200 Subject: [PATCH 07/21] profiles: print message on profile save --- .../de/bixilon/minosoft/config/profile/ProfileManager.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/bixilon/minosoft/config/profile/ProfileManager.kt b/src/main/java/de/bixilon/minosoft/config/profile/ProfileManager.kt index 10cfd7d35..0f6a58e38 100644 --- a/src/main/java/de/bixilon/minosoft/config/profile/ProfileManager.kt +++ b/src/main/java/de/bixilon/minosoft/config/profile/ProfileManager.kt @@ -181,6 +181,7 @@ interface ProfileManager { profile.ignoreReloads.incrementAndGet() FileUtil.safeSaveToFile(file, jsonString) profile.saved = true + Log.log(LogMessageType.PROFILES, LogLevels.VERBOSE) { "Saved profile ${profile.name} ($namespace)" } } catch (exception: Exception) { exception.printStackTrace() exception.crash() @@ -257,13 +258,14 @@ interface ProfileManager { } fun watchProfile(profileName: String, path: File = getPath(profileName).toFile()) { - FileWatcherService.register(FileWatcher(path.toPath(), arrayOf(StandardWatchEventKinds.ENTRY_MODIFY, StandardWatchEventKinds.ENTRY_CREATE)) { _, it -> + FileWatcherService.register(FileWatcher(path.toPath(), arrayOf(StandardWatchEventKinds.ENTRY_MODIFY, StandardWatchEventKinds.ENTRY_CREATE)) { a, _ -> val profile = profiles[profileName] ?: return@FileWatcher if (profile.ignoreReloads.get() > 0) { profile.ignoreReloads.decrementAndGet() return@FileWatcher } try { + profile.reloading = true val data = readAndMigrate(path.toPath()).second updateValue(profile, data) } catch (exception: Exception) { @@ -272,7 +274,7 @@ interface ProfileManager { } finally { profile.reloading = false } - Log.log(LogMessageType.PROFILES, LogLevels.INFO) { "Reloaded profile: $profileName ($it)" } + Log.log(LogMessageType.PROFILES, LogLevels.INFO) { "Reloaded profile: $profileName ($namespace);" } }) } From 155b83d5b79a33fab15d3f9696eadffd6f73e933 Mon Sep 17 00:00:00 2001 From: Bixilon Date: Tue, 23 May 2023 21:00:39 +0200 Subject: [PATCH 08/21] improve world offset calculation --- .../gui/rendering/camera/WorldOffset.kt | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/camera/WorldOffset.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/camera/WorldOffset.kt index 0065bc6a4..5cd8c7547 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/camera/WorldOffset.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/camera/WorldOffset.kt @@ -26,19 +26,23 @@ class WorldOffset(private val camera: Camera) : Drawable { private set override fun draw() { - val previous = offset - val position = camera.view.view.eyePosition + val blockPosition = camera.view.view.eyePosition.blockPosition - val mod = (position.blockPosition / MAX_DISTANCE) * MAX_DISTANCE - if (mod != previous) { - this.offset = mod + val previous = offset / MAX_DISTANCE + val maxOffset = (blockPosition + THRESHOLD) / MAX_DISTANCE + val minOffset = (blockPosition - THRESHOLD) / MAX_DISTANCE + if (maxOffset == previous || minOffset == previous) { + // we need to get away further + // this makes the "border" not just 1 pixel wide, it is 256 blocks wide + return } - // TODO: optimize this and use MIN_DISTANCE + this.offset = (blockPosition / MAX_DISTANCE) * MAX_DISTANCE + // Log.log(LogMessageType.OTHER, LogLevels.VERBOSE) { "Offset changed: $offset" } } companion object { const val MAX_DISTANCE = World.MAX_RENDER_DISTANCE * ProtocolDefinition.SECTION_WIDTH_X // coordinates higher than that value are not allowed - const val MIN_DISTANCE = MAX_DISTANCE - (World.MAX_RENDER_DISTANCE / 4) * ProtocolDefinition.SECTION_WIDTH_X // only if value is lower that that value coordinates will be back offset + const val THRESHOLD = (World.MAX_RENDER_DISTANCE / 8) * ProtocolDefinition.SECTION_WIDTH_X // only if value is lower that that value coordinates will be back offset } } From 71efb16e582a6c52deac2eac1daaebcc27f65d59 Mon Sep 17 00:00:00 2001 From: Bixilon Date: Wed, 24 May 2023 19:21:22 +0200 Subject: [PATCH 09/21] fix block outline rendering (high coordinates) drawVoxelShape already takes doubles, so it is already offset. --- .../gui/rendering/world/outline/BlockOutlineRenderer.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/world/outline/BlockOutlineRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/world/outline/BlockOutlineRenderer.kt index 4acccfda5..a1ee6b15b 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/world/outline/BlockOutlineRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/world/outline/BlockOutlineRenderer.kt @@ -128,7 +128,7 @@ class BlockOutlineRenderer( val mesh = LineMesh(context) - val blockOffset = offsetPosition.toVec3d + val blockOffset = target.blockPosition.toVec3d if (target.state.block is RandomOffsetBlock) { target.state.block.randomOffset?.let { blockOffset += target.blockPosition.getWorldOffset(it) } } From 592b22db764f756b5a4d1a519adba0bbe01ceb11 Mon Sep 17 00:00:00 2001 From: Bixilon Date: Wed, 24 May 2023 19:27:15 +0200 Subject: [PATCH 10/21] fix target handler tests --- .../bixilon/minosoft/camera/target/TargetHandlerTest.kt | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/integration-test/kotlin/de/bixilon/minosoft/camera/target/TargetHandlerTest.kt b/src/integration-test/kotlin/de/bixilon/minosoft/camera/target/TargetHandlerTest.kt index 48313c1e3..32679918e 100644 --- a/src/integration-test/kotlin/de/bixilon/minosoft/camera/target/TargetHandlerTest.kt +++ b/src/integration-test/kotlin/de/bixilon/minosoft/camera/target/TargetHandlerTest.kt @@ -13,7 +13,6 @@ package de.bixilon.minosoft.camera.target -import de.bixilon.kotlinglm.vec3.Vec3 import de.bixilon.kotlinglm.vec3.Vec3d import de.bixilon.kotlinglm.vec3.Vec3i import de.bixilon.kutil.observer.DataObserver @@ -24,7 +23,6 @@ import de.bixilon.minosoft.data.entities.EntityRotation import de.bixilon.minosoft.data.physics.PhysicsTestUtil.createPlayer import de.bixilon.minosoft.data.registries.blocks.DirtTest0 import de.bixilon.minosoft.data.registries.blocks.types.stone.StoneTest0 -import de.bixilon.minosoft.gui.rendering.util.VecUtil.toVec3 import de.bixilon.minosoft.protocol.network.connection.play.ConnectionTestUtil.createConnection import org.testng.Assert.* import org.testng.annotations.Test @@ -44,7 +42,7 @@ class TargetHandlerTest { connection.world[7, 69, 6] = DirtTest0.state connection.world[8, 69, 6] = StoneTest0.state - player.renderInfo::eyePosition.forceSet(player.physics.position.toVec3 + Vec3(0.0, 1.5, 0.0)) + player.renderInfo::eyePosition.forceSet(player.physics.position + Vec3d(0.0, 1.5, 0.0)) player.renderInfo::rotation.forceSet(player.physics.rotation) connection.camera.target.update() @@ -68,7 +66,7 @@ class TargetHandlerTest { connection.world[8, 70, 2] = StoneTest0.state - player.renderInfo::eyePosition.forceSet(player.physics.position.toVec3 + Vec3(0.0, 1.5, 0.0)) + player.renderInfo::eyePosition.forceSet(player.physics.position + Vec3d(0.0, 1.5, 0.0)) player.renderInfo::rotation.forceSet(player.physics.rotation) connection.camera.target.update() @@ -92,7 +90,7 @@ class TargetHandlerTest { connection.world[9, 70, 2] = StoneTest0.state - player.renderInfo::eyePosition.forceSet(player.physics.position.toVec3 + Vec3(0.0, 1.5, 0.0)) + player.renderInfo::eyePosition.forceSet(player.physics.position + Vec3d(0.0, 1.5, 0.0)) player.renderInfo::rotation.forceSet(player.physics.rotation) connection.camera.target.update() From a3deac5df011a83c01d3d65c229dfc1eb40db88a Mon Sep 17 00:00:00 2001 From: Bixilon Date: Wed, 24 May 2023 19:42:39 +0200 Subject: [PATCH 11/21] world border: remove camera offset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This breaks it even harder… --- .../gui/rendering/world/border/WorldBorderRenderer.kt | 6 ++---- .../minosoft/rendering/shader/world/border/border.vsh | 2 -- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/world/border/WorldBorderRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/world/border/WorldBorderRenderer.kt index 3bda890f0..aaf213714 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/world/border/WorldBorderRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/world/border/WorldBorderRenderer.kt @@ -15,7 +15,6 @@ package de.bixilon.minosoft.gui.rendering.world.border import de.bixilon.kotlinglm.func.common.clamp import de.bixilon.kotlinglm.vec2.Vec2 -import de.bixilon.kotlinglm.vec2.Vec2d import de.bixilon.kutil.latch.CountUpAndDownLatch import de.bixilon.kutil.time.TimeUtil.millis import de.bixilon.minosoft.data.registries.identified.Namespaces.minosoft @@ -75,7 +74,7 @@ class WorldBorderRenderer( } val textureOffset = (offsetReset - time) / ANIMATION_SPEED.toFloat() shader.textureOffset = 1.0f - textureOffset - shader.cameraHeight = (context.connection.camera.entity.renderInfo.eyePosition.y - context.camera.offset.offset.y).toFloat() + shader.cameraHeight = context.connection.camera.entity.renderInfo.eyePosition.y.toFloat() val distance = border.getDistanceTo(context.connection.player.physics.position).toFloat() val strength = 1.0f - (distance.clamp(0.0f, 100.0f) / 100.0f) @@ -87,8 +86,7 @@ class WorldBorderRenderer( color = color.with(alpha = (strength * strength)) shader.tintColor = color shader.radius = border.diameter.toFloat() / 2.0f - val offset = context.camera.offset.offset - shader.center = Vec2(border.center - Vec2d(offset.x, offset.z)) + shader.center = Vec2(border.center) } override fun drawTranslucent() { diff --git a/src/main/resources/assets/minosoft/rendering/shader/world/border/border.vsh b/src/main/resources/assets/minosoft/rendering/shader/world/border/border.vsh index 0fb35a12d..34049f497 100644 --- a/src/main/resources/assets/minosoft/rendering/shader/world/border/border.vsh +++ b/src/main/resources/assets/minosoft/rendering/shader/world/border/border.vsh @@ -25,7 +25,6 @@ uniform float uCameraHeight; flat out uint finTextureIndex; out vec3 finTextureCoordinates; -out vec3 finFragmentPosition; #include "minosoft:uv" @@ -43,7 +42,6 @@ void main() { position.x += uCenter.x; position.z += uCenter.y; gl_Position = uViewProjectionMatrix * vec4(position, 1.0f); - finFragmentPosition = position; finTextureIndex = uIndexLayer >> 28u; vec2 uv = CONST_UV[floatBitsToUint(uvIndex)]; From 8758c467592e9bf6754ca57b585d2ec817bcb0ac Mon Sep 17 00:00:00 2001 From: Bixilon Date: Wed, 24 May 2023 21:53:06 +0200 Subject: [PATCH 12/21] improve world border appearance --- .../gui/rendering/world/border/WorldBorderRenderer.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/world/border/WorldBorderRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/world/border/WorldBorderRenderer.kt index aaf213714..51f040bc0 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/world/border/WorldBorderRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/world/border/WorldBorderRenderer.kt @@ -76,8 +76,8 @@ class WorldBorderRenderer( shader.textureOffset = 1.0f - textureOffset shader.cameraHeight = context.connection.camera.entity.renderInfo.eyePosition.y.toFloat() - val distance = border.getDistanceTo(context.connection.player.physics.position).toFloat() - val strength = 1.0f - (distance.clamp(0.0f, 100.0f) / 100.0f) + val distance = border.getDistanceTo(context.connection.player.physics.position).toFloat() - 1.0f // 1 block padding + val strength = 1.0f - (distance.clamp(0.0f, MAX_DISTANCE) / MAX_DISTANCE) // slowly fade in var color = when (border.state) { WorldBorderState.GROWING -> GROWING_COLOR WorldBorderState.SHRINKING -> SHRINKING_COLOR @@ -99,7 +99,7 @@ class WorldBorderRenderer( val SHRINKING_COLOR = "#FF3030".asColor() val STATIC_COLOR = "#20A0FF".asColor() const val ANIMATION_SPEED = 2000 - const val MAX_DISTANCE = 1000 + const val MAX_DISTANCE = 100.0f private val TEXTURE = "minecraft:misc/forcefield".toResourceLocation().texture() From d2501ec3a1e28360745b1d852807db7856b466ff Mon Sep 17 00:00:00 2001 From: Bixilon Date: Thu, 25 May 2023 13:42:02 +0200 Subject: [PATCH 13/21] gradle: log current os --- build.gradle.kts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build.gradle.kts b/build.gradle.kts index a0e870834..d3122cb9c 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -52,6 +52,8 @@ val kutilVersion = getProperty("kutil.version") val os = properties["platform"]?.let { OSTypes[it] } ?: PlatformInfo.OS val architecture = properties["architecture"]?.let { Architectures[it] } ?: PlatformInfo.ARCHITECTURE +logger.info("Building for ${os.name.lowercase()}, ${architecture.name.lowercase()}") + repositories { mavenCentral() maven("https://oss.sonatype.org/content/repositories/snapshots") From 753aed865045595f5c347071de66e2208309e978 Mon Sep 17 00:00:00 2001 From: Bixilon Date: Thu, 25 May 2023 14:29:18 +0200 Subject: [PATCH 14/21] audio: use doubles internally --- .../minosoft/data/world/audio/AbstractAudioPlayer.kt | 10 +++++----- .../minosoft/data/world/audio/WorldAudioPlayer.kt | 4 ++-- .../minosoft/gui/rendering/sound/AudioPlayer.kt | 12 +++++++----- .../gui/rendering/sound/DefaultAudioBehavior.kt | 7 +++---- .../minosoft/modding/event/events/PlaySoundEvent.kt | 12 ++++++------ .../packets/s2c/play/sound/NamedSoundS2CP.kt | 8 ++++---- .../packets/s2c/play/sound/SoundEventS2CP.kt | 6 +++--- 7 files changed, 30 insertions(+), 29 deletions(-) diff --git a/src/main/java/de/bixilon/minosoft/data/world/audio/AbstractAudioPlayer.kt b/src/main/java/de/bixilon/minosoft/data/world/audio/AbstractAudioPlayer.kt index c164467a4..a2073cbf5 100644 --- a/src/main/java/de/bixilon/minosoft/data/world/audio/AbstractAudioPlayer.kt +++ b/src/main/java/de/bixilon/minosoft/data/world/audio/AbstractAudioPlayer.kt @@ -13,21 +13,21 @@ package de.bixilon.minosoft.data.world.audio -import de.bixilon.kotlinglm.vec3.Vec3 +import de.bixilon.kotlinglm.vec3.Vec3d import de.bixilon.kotlinglm.vec3.Vec3i import de.bixilon.minosoft.data.registries.identified.ResourceLocation -import de.bixilon.minosoft.gui.rendering.util.VecUtil.centerf +import de.bixilon.minosoft.gui.rendering.util.VecUtil.center interface AbstractAudioPlayer { fun playSoundEvent(sound: ResourceLocation, position: Vec3i? = null, volume: Float = 1.0f, pitch: Float = 1.0f) { - playSound(sound, position?.centerf, volume, pitch) + playSound(sound, position?.center, volume, pitch) } - fun playSound(sound: ResourceLocation, position: Vec3? = null, volume: Float = 1.0f, pitch: Float = 1.0f) + fun playSound(sound: ResourceLocation, position: Vec3d? = null, volume: Float = 1.0f, pitch: Float = 1.0f) fun play2DSound(sound: ResourceLocation, volume: Float = 1.0f, pitch: Float = 1.0f) { - playSound(sound, null as Vec3?, volume, pitch) + playSound(sound, null as Vec3d?, volume, pitch) } fun stopAllSounds() diff --git a/src/main/java/de/bixilon/minosoft/data/world/audio/WorldAudioPlayer.kt b/src/main/java/de/bixilon/minosoft/data/world/audio/WorldAudioPlayer.kt index 3cd49f834..0d4d093cd 100644 --- a/src/main/java/de/bixilon/minosoft/data/world/audio/WorldAudioPlayer.kt +++ b/src/main/java/de/bixilon/minosoft/data/world/audio/WorldAudioPlayer.kt @@ -13,14 +13,14 @@ package de.bixilon.minosoft.data.world.audio -import de.bixilon.kotlinglm.vec3.Vec3 +import de.bixilon.kotlinglm.vec3.Vec3d import de.bixilon.minosoft.data.registries.identified.ResourceLocation @Deprecated("") interface WorldAudioPlayer : AbstractAudioPlayer { val audioPlayer: AbstractAudioPlayer? - override fun playSound(sound: ResourceLocation, position: Vec3?, volume: Float, pitch: Float) { + override fun playSound(sound: ResourceLocation, position: Vec3d?, volume: Float, pitch: Float) { audioPlayer?.playSound(sound, position, volume, pitch) } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/sound/AudioPlayer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/sound/AudioPlayer.kt index 8d9e6026d..1c435e37a 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/sound/AudioPlayer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/sound/AudioPlayer.kt @@ -14,6 +14,7 @@ package de.bixilon.minosoft.gui.rendering.sound import de.bixilon.kotlinglm.vec3.Vec3 +import de.bixilon.kotlinglm.vec3.Vec3d import de.bixilon.kutil.collections.CollectionUtil.synchronizedListOf import de.bixilon.kutil.collections.CollectionUtil.toSynchronizedList import de.bixilon.kutil.concurrent.queue.Queue @@ -25,6 +26,7 @@ import de.bixilon.minosoft.gui.rendering.Rendering import de.bixilon.minosoft.gui.rendering.camera.CameraDefinition.CAMERA_UP_VEC3 import de.bixilon.minosoft.gui.rendering.events.CameraPositionChangeEvent import de.bixilon.minosoft.gui.rendering.sound.sounds.Sound +import de.bixilon.minosoft.gui.rendering.util.VecUtil.toVec3 import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.EMPTY import de.bixilon.minosoft.modding.event.listener.CallbackEventListener.Companion.listen import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection @@ -121,7 +123,7 @@ class AudioPlayer( latch.dec() } - override fun playSound(sound: ResourceLocation, position: Vec3?, volume: Float, pitch: Float) { + override fun playSound(sound: ResourceLocation, position: Vec3d?, volume: Float, pitch: Float) { if (!initialized) { return } @@ -180,9 +182,9 @@ class AudioPlayer( return source } - private fun shouldPlay(sound: Sound, position: Vec3?): Boolean { + private fun shouldPlay(sound: Sound, position: Vec3d?): Boolean { if (position == null) return true - val distance = (this.listener.position - position).length2() + val distance = (this.listener.position - position.toVec3).length2() if (distance >= sound.attenuationDistance * sound.attenuationDistance) { return false } @@ -190,7 +192,7 @@ class AudioPlayer( return true } - private fun playSound(sound: Sound, position: Vec3? = null, volume: Float = 1.0f, pitch: Float = 1.0f) { + private fun playSound(sound: Sound, position: Vec3d? = null, volume: Float = 1.0f, pitch: Float = 1.0f) { if (!profile.enabled) { return } @@ -205,7 +207,7 @@ class AudioPlayer( } position?.let { source.relative = false - source.position = it + source.position = it.toVec3 } ?: let { source.position = Vec3.EMPTY source.relative = true diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/sound/DefaultAudioBehavior.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/sound/DefaultAudioBehavior.kt index f64bed425..869eb0bd1 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/sound/DefaultAudioBehavior.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/sound/DefaultAudioBehavior.kt @@ -1,6 +1,6 @@ /* * Minosoft - * Copyright (C) 2020-2022 Moritz Zwerger + * Copyright (C) 2020-2023 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. * @@ -13,7 +13,6 @@ package de.bixilon.minosoft.gui.rendering.sound -import de.bixilon.kotlinglm.vec3.Vec3 import de.bixilon.minosoft.modding.event.events.ExplosionEvent import de.bixilon.minosoft.modding.event.events.PlaySoundEvent import de.bixilon.minosoft.modding.event.listener.CallbackEventListener @@ -29,9 +28,9 @@ object DefaultAudioBehavior { val world = connection.world val invokers = listOf( CallbackEventListener.of { world.playSound(it.soundEvent, it.position, it.volume, it.pitch) }, - CallbackEventListener.of { world.playSound(ENTITY_GENERIC_EXPLODE, Vec3(it.position), 4.0f, (1.0f + (random.nextFloat() - random.nextFloat()) * 0.2f) * 0.7f) }, + CallbackEventListener.of { world.playSound(ENTITY_GENERIC_EXPLODE, it.position, 4.0f, (1.0f + (random.nextFloat() - random.nextFloat()) * 0.2f) * 0.7f) }, ) - connection.register(*invokers.toTypedArray()) + connection.events.register(*invokers.toTypedArray()) } } diff --git a/src/main/java/de/bixilon/minosoft/modding/event/events/PlaySoundEvent.kt b/src/main/java/de/bixilon/minosoft/modding/event/events/PlaySoundEvent.kt index c8861f16d..d2d36b9ca 100644 --- a/src/main/java/de/bixilon/minosoft/modding/event/events/PlaySoundEvent.kt +++ b/src/main/java/de/bixilon/minosoft/modding/event/events/PlaySoundEvent.kt @@ -13,7 +13,7 @@ package de.bixilon.minosoft.modding.event.events -import de.bixilon.kotlinglm.vec3.Vec3 +import de.bixilon.kotlinglm.vec3.Vec3d import de.bixilon.minosoft.data.SoundCategories import de.bixilon.minosoft.data.registries.identified.ResourceLocation import de.bixilon.minosoft.modding.event.events.connection.play.PlayConnectionEvent @@ -24,15 +24,15 @@ import de.bixilon.minosoft.protocol.packets.s2c.play.sound.SoundEventS2CP class PlaySoundEvent( connection: PlayConnection, val category: SoundCategories?, - position: Vec3, + position: Vec3d, val soundEvent: ResourceLocation, val volume: Float, val pitch: Float, ) : PlayConnectionEvent(connection), CancelableEvent { - val position: Vec3 = position - get() = Vec3(field) + val position: Vec3d = position + get() = Vec3d(field) - constructor(connection: PlayConnection, packet: SoundEventS2CP) : this(connection, packet.category, Vec3(packet.position), packet.sound, packet.volume, packet.pitch.toFloat()) + constructor(connection: PlayConnection, packet: SoundEventS2CP) : this(connection, packet.category, packet.position, packet.sound, packet.volume, packet.pitch) - constructor(connection: PlayConnection, packet: NamedSoundS2CP) : this(connection, packet.category, packet.position, packet.soundEvent!!, packet.volume, packet.pitch.toFloat()) + constructor(connection: PlayConnection, packet: NamedSoundS2CP) : this(connection, packet.category, packet.position, packet.soundEvent!!, packet.volume, packet.pitch) } diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/sound/NamedSoundS2CP.kt b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/sound/NamedSoundS2CP.kt index d277dc699..35af3fadd 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/sound/NamedSoundS2CP.kt +++ b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/sound/NamedSoundS2CP.kt @@ -12,7 +12,7 @@ */ package de.bixilon.minosoft.protocol.packets.s2c.play.sound -import de.bixilon.kotlinglm.vec3.Vec3 +import de.bixilon.kotlinglm.vec3.Vec3d import de.bixilon.minosoft.data.SoundCategories import de.bixilon.minosoft.data.registries.identified.ResourceLocation import de.bixilon.minosoft.modding.event.events.PlaySoundEvent @@ -33,7 +33,7 @@ class NamedSoundS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket { val soundEvent: ResourceLocation? val volume: Float val pitch: Float - lateinit var position: Vec3 + lateinit var position: Vec3d private set lateinit var category: SoundCategories private set @@ -49,13 +49,13 @@ class NamedSoundS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket { buffer.readString() // parrot entity type } if (buffer.versionId < V_16W02A) { - position = Vec3(buffer.readInt() * 8, buffer.readInt() * 8, buffer.readInt() * 8) // ToDo: check if it is not * 4 + position = Vec3d(buffer.readInt() * 4, buffer.readInt() * 4, buffer.readInt() * 4) } if (buffer.versionId >= V_16W02A && (buffer.versionId !in V_17W15A until V_17W18A)) { this.category = SoundCategories[buffer.readVarInt()] } if (buffer.versionId >= V_16W02A) { - position = Vec3(buffer.readFixedPointNumberInt() * 4, buffer.readFixedPointNumberInt() * 4, buffer.readFixedPointNumberInt() * 4) + position = Vec3d(buffer.readFixedPointNumberInt() * 4, buffer.readFixedPointNumberInt() * 4, buffer.readFixedPointNumberInt() * 4) } volume = buffer.readFloat() pitch = buffer.readSoundPitch() diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/sound/SoundEventS2CP.kt b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/sound/SoundEventS2CP.kt index 9125f935e..2e95fd043 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/sound/SoundEventS2CP.kt +++ b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/sound/SoundEventS2CP.kt @@ -12,7 +12,7 @@ */ package de.bixilon.minosoft.protocol.packets.s2c.play.sound -import de.bixilon.kotlinglm.vec3.Vec3i +import de.bixilon.kotlinglm.vec3.Vec3d import de.bixilon.minosoft.data.SoundCategories import de.bixilon.minosoft.data.registries.identified.ResourceLocation import de.bixilon.minosoft.modding.event.events.PlaySoundEvent @@ -33,7 +33,7 @@ import de.bixilon.minosoft.util.logging.LogMessageType class SoundEventS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket { var category: SoundCategories? = null private set - val position: Vec3i + val position: Vec3d val sound: ResourceLocation val volume: Float val pitch: Float @@ -65,7 +65,7 @@ class SoundEventS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket { if (buffer.versionId >= V_16W02A && (buffer.versionId !in V_17W15A until V_17W18A)) { this.category = SoundCategories[buffer.readVarInt()] } - position = Vec3i(buffer.readFixedPointNumberInt() * 4, buffer.readFixedPointNumberInt() * 4, buffer.readFixedPointNumberInt() * 4) + position = Vec3d(buffer.readFixedPointNumberInt() * 4, buffer.readFixedPointNumberInt() * 4, buffer.readFixedPointNumberInt() * 4) volume = buffer.readFloat() pitch = buffer.readSoundPitch() From 29838bd5d3e5fa07a3085ca8614434c65a1ccd77 Mon Sep 17 00:00:00 2001 From: Bixilon Date: Thu, 25 May 2023 15:25:08 +0200 Subject: [PATCH 15/21] world border: replace diameter with radius --- .../minosoft/data/world/border/WorldBorder.kt | 41 ++++++++++--------- .../play/border/InitializeWorldBorderS2CP.kt | 8 ++-- .../play/border/InterpolateWorldBorderS2CP.kt | 8 ++-- .../s2c/play/border/SizeWorldBorderS2CP.kt | 6 +-- 4 files changed, 33 insertions(+), 30 deletions(-) diff --git a/src/main/java/de/bixilon/minosoft/data/world/border/WorldBorder.kt b/src/main/java/de/bixilon/minosoft/data/world/border/WorldBorder.kt index 15830ac0c..60e99f7d8 100644 --- a/src/main/java/de/bixilon/minosoft/data/world/border/WorldBorder.kt +++ b/src/main/java/de/bixilon/minosoft/data/world/border/WorldBorder.kt @@ -19,7 +19,6 @@ import de.bixilon.kotlinglm.vec3.Vec3d import de.bixilon.kotlinglm.vec3.Vec3i import de.bixilon.kutil.concurrent.lock.simple.SimpleLock import de.bixilon.kutil.math.interpolation.DoubleInterpolation.interpolateLinear -import de.bixilon.kutil.time.TimeUtil import de.bixilon.kutil.time.TimeUtil.millis import de.bixilon.minosoft.data.world.World import de.bixilon.minosoft.data.world.positions.BlockPosition @@ -28,7 +27,7 @@ import kotlin.math.abs class WorldBorder { var center = Vec2d.EMPTY - var diameter = DEFAULT_DIAMETER + var radius = DEFAULT_RADIUS var warningTime = 0 var warningBlocks = 0 var portalBound = 0 @@ -36,10 +35,14 @@ class WorldBorder { var state = WorldBorderState.STATIC private set - private var interpolationStart = -1L - private var interpolationEnd = -1L - private var oldDiameter = DEFAULT_DIAMETER - private var newDiameter = DEFAULT_DIAMETER + var interpolationStart = -1L + private set + var interpolationEnd = -1L + private set + var oldRadius = DEFAULT_RADIUS + private set + var newRadius = DEFAULT_RADIUS + private set val lock = SimpleLock() @@ -57,7 +60,7 @@ class WorldBorder { fun isOutside(x: Double, z: Double): Boolean { lock.acquire() - val radius = diameter / 2 + val radius = radius val inside = x in (center.x - radius)..(radius + center.x) && z in (center.y - radius)..(radius + center.y) lock.release() return !inside @@ -74,7 +77,7 @@ class WorldBorder { fun getDistanceTo(x: Double, z: Double): Double { lock.acquire() - val radius = diameter / 2 + val radius = radius val closestDistance = minOf( radius - abs(x) - abs(center.x), @@ -90,17 +93,17 @@ class WorldBorder { lock.unlock() } - fun interpolate(oldDiameter: Double, newDiameter: Double, millis: Long) { + fun interpolate(oldRadius: Double, newRadius: Double, millis: Long) { if (millis == 0L) { stopInterpolating() - diameter = newDiameter + radius = newRadius } lock.lock() val time = millis() interpolationStart = time interpolationEnd = time + millis - this.oldDiameter = oldDiameter - this.newDiameter = newDiameter + this.oldRadius = oldRadius + this.newRadius = newRadius lock.unlock() } @@ -117,16 +120,16 @@ class WorldBorder { lock.unlock() return } - val oldDiameter = diameter + val oldRadius = radius val remaining = interpolationEnd - time val totalTime = (interpolationEnd - interpolationStart) - val diameter = interpolateLinear(remaining.toDouble() / totalTime.toDouble(), this.newDiameter, this.oldDiameter) - this.diameter = diameter + val radius = interpolateLinear(remaining.toDouble() / totalTime.toDouble(), this.newRadius, this.oldRadius) + this.radius = radius - state = if (oldDiameter > diameter) { + state = if (oldRadius > radius) { WorldBorderState.SHRINKING - } else if (oldDiameter < diameter) { + } else if (oldRadius < radius) { WorldBorderState.GROWING } else { interpolationStart = -1L @@ -137,12 +140,12 @@ class WorldBorder { fun reset() { lock.lock() - diameter = DEFAULT_DIAMETER + radius = DEFAULT_RADIUS interpolationStart = -1L lock.unlock() } companion object { - const val DEFAULT_DIAMETER = World.MAX_SIZE.toDouble() * 2 + const val DEFAULT_RADIUS = World.MAX_SIZE.toDouble() } } diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/border/InitializeWorldBorderS2CP.kt b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/border/InitializeWorldBorderS2CP.kt index a30c7fb99..08b50af3d 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/border/InitializeWorldBorderS2CP.kt +++ b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/border/InitializeWorldBorderS2CP.kt @@ -23,8 +23,8 @@ import de.bixilon.minosoft.util.logging.LogMessageType @LoadPacket(parent = true) class InitializeWorldBorderS2CP(buffer: PlayInByteBuffer) : WorldBorderS2CP { val center = buffer.readVec2d() - val oldDiameter = buffer.readDouble() - val newDiameter = buffer.readDouble() + val oldRadius = buffer.readDouble() / 2.0 + val newRadius = buffer.readDouble() / 2.0 val millis = buffer.readVarLong() val portalBound = buffer.readVarInt() val warningTime = buffer.readVarInt() @@ -32,13 +32,13 @@ class InitializeWorldBorderS2CP(buffer: PlayInByteBuffer) : WorldBorderS2CP { override fun handle(connection: PlayConnection) { connection.world.border.center = center - connection.world.border.interpolate(oldDiameter, newDiameter, millis) + connection.world.border.interpolate(oldRadius, newRadius, millis) connection.world.border.portalBound = portalBound connection.world.border.warningTime = warningTime connection.world.border.warningBlocks = warningBlocks } override fun log(reducedLog: Boolean) { - Log.log(LogMessageType.NETWORK_PACKETS_IN, level = LogLevels.VERBOSE) { "Initialize world border (center=$center, oldDiameter=$oldDiameter, newDiameter=$newDiameter, speed=$millis, portalBound=$portalBound, warningTime=$warningTime, warningBlocks=$warningBlocks)" } + Log.log(LogMessageType.NETWORK_PACKETS_IN, level = LogLevels.VERBOSE) { "Initialize world border (center=$center, oldRadius=$oldRadius, newRadius=$newRadius, speed=$millis, portalBound=$portalBound, warningTime=$warningTime, warningBlocks=$warningBlocks)" } } } diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/border/InterpolateWorldBorderS2CP.kt b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/border/InterpolateWorldBorderS2CP.kt index 7335eb9cb..409a828a6 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/border/InterpolateWorldBorderS2CP.kt +++ b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/border/InterpolateWorldBorderS2CP.kt @@ -22,15 +22,15 @@ import de.bixilon.minosoft.util.logging.LogMessageType @LoadPacket(parent = true) class InterpolateWorldBorderS2CP(buffer: PlayInByteBuffer) : WorldBorderS2CP { - val oldDiameter = buffer.readDouble() - val newDiameter = buffer.readDouble() + val oldRadius = buffer.readDouble() / 2.0 + val newRadius = buffer.readDouble() / 2.0 val millis = buffer.readVarLong() override fun handle(connection: PlayConnection) { - connection.world.border.interpolate(oldDiameter, newDiameter, millis) + connection.world.border.interpolate(oldRadius, newRadius, millis) } override fun log(reducedLog: Boolean) { - Log.log(LogMessageType.NETWORK_PACKETS_IN, level = LogLevels.VERBOSE) { "Interpolate size world border (oldDiameter=$oldDiameter, newDiameter=$newDiameter, millis=$millis)" } + Log.log(LogMessageType.NETWORK_PACKETS_IN, level = LogLevels.VERBOSE) { "Interpolate size world border (oldRadius=$oldRadius, newRadius=$newRadius, millis=$millis)" } } } diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/border/SizeWorldBorderS2CP.kt b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/border/SizeWorldBorderS2CP.kt index bf618b6e0..67dd16f23 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/border/SizeWorldBorderS2CP.kt +++ b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/border/SizeWorldBorderS2CP.kt @@ -22,14 +22,14 @@ import de.bixilon.minosoft.util.logging.LogMessageType @LoadPacket(parent = true) class SizeWorldBorderS2CP(buffer: PlayInByteBuffer) : WorldBorderS2CP { - val diameter = buffer.readDouble() + val radius = buffer.readDouble() / 2.0 override fun handle(connection: PlayConnection) { connection.world.border.stopInterpolating() - connection.world.border.diameter = diameter + connection.world.border.radius = radius } override fun log(reducedLog: Boolean) { - Log.log(LogMessageType.NETWORK_PACKETS_IN, level = LogLevels.VERBOSE) { "Size set world border (diameter=$diameter)" } + Log.log(LogMessageType.NETWORK_PACKETS_IN, level = LogLevels.VERBOSE) { "Size set world border (diameter=$radius)" } } } From 3f3013489623c0387bb5c892805ceef5025d844c Mon Sep 17 00:00:00 2001 From: Bixilon Date: Thu, 25 May 2023 16:03:19 +0200 Subject: [PATCH 16/21] log shader code on error --- .../gui/rendering/exceptions/ShaderLoadingException.kt | 3 +++ .../gui/rendering/system/opengl/OpenGLNativeShader.kt | 5 +++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/exceptions/ShaderLoadingException.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/exceptions/ShaderLoadingException.kt index cb6511332..062170b29 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/exceptions/ShaderLoadingException.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/exceptions/ShaderLoadingException.kt @@ -12,7 +12,10 @@ */ package de.bixilon.minosoft.gui.rendering.exceptions +import de.bixilon.minosoft.config.StaticConfiguration + class ShaderLoadingException : Exception { constructor() constructor(message: String) : super(message) + constructor(message: String, code: String) : super(message + if (StaticConfiguration.DEBUG_MODE) "\n\n\n" + code else "") } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/system/opengl/OpenGLNativeShader.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/system/opengl/OpenGLNativeShader.kt index 1fcf3667d..49d967725 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/system/opengl/OpenGLNativeShader.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/system/opengl/OpenGLNativeShader.kt @@ -53,12 +53,13 @@ class OpenGLNativeShader( throw ShaderLoadingException() } - glShaderSource(program, code.code) + val glsl = code.code + glShaderSource(program, glsl) glCompileShader(program) if (glGetShaderi(program, GL_COMPILE_STATUS) == GL_FALSE) { - throw ShaderLoadingException(getShaderInfoLog(program)) + throw ShaderLoadingException(getShaderInfoLog(program), glsl) } return program From f3fab7dad807a705c54fc28a86b28c3dae4bd3de Mon Sep 17 00:00:00 2001 From: Bixilon Date: Thu, 25 May 2023 18:34:06 +0200 Subject: [PATCH 17/21] fix some world border bugs --- .../bixilon/minosoft/data/world/border/WorldBorder.kt | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/java/de/bixilon/minosoft/data/world/border/WorldBorder.kt b/src/main/java/de/bixilon/minosoft/data/world/border/WorldBorder.kt index 60e99f7d8..4844e696f 100644 --- a/src/main/java/de/bixilon/minosoft/data/world/border/WorldBorder.kt +++ b/src/main/java/de/bixilon/minosoft/data/world/border/WorldBorder.kt @@ -67,7 +67,7 @@ class WorldBorder { } - operator fun contains(position:BlockPosition) = !isOutside(position) + operator fun contains(position: BlockPosition) = !isOutside(position) operator fun contains(position: Vec3d) = !isOutside(position) @@ -94,7 +94,7 @@ class WorldBorder { } fun interpolate(oldRadius: Double, newRadius: Double, millis: Long) { - if (millis == 0L) { + if (millis <= 0L) { stopInterpolating() radius = newRadius } @@ -115,6 +115,7 @@ class WorldBorder { } val time = millis() if (interpolationEnd <= time) { + this.radius = newRadius // also get the last interpolation step state = WorldBorderState.STATIC interpolationStart = -1L lock.unlock() @@ -124,12 +125,12 @@ class WorldBorder { val remaining = interpolationEnd - time val totalTime = (interpolationEnd - interpolationStart) - val radius = interpolateLinear(remaining.toDouble() / totalTime.toDouble(), this.newRadius, this.oldRadius) + val radius = interpolateLinear(remaining.toDouble() / totalTime.toDouble(), this.oldRadius, this.newRadius) this.radius = radius - state = if (oldRadius > radius) { + state = if (oldRadius > newRadius) { WorldBorderState.SHRINKING - } else if (oldRadius < radius) { + } else if (oldRadius < newRadius) { WorldBorderState.GROWING } else { interpolationStart = -1L From f1d6ce0bd585ef3d44ef69c3c1cf03aa0b2fe127 Mon Sep 17 00:00:00 2001 From: Bixilon Date: Thu, 25 May 2023 18:57:50 +0200 Subject: [PATCH 18/21] limit world border to max distance --- .../java/de/bixilon/minosoft/data/world/World.kt | 2 +- .../minosoft/data/world/border/WorldBorder.kt | 15 ++++++--------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/main/java/de/bixilon/minosoft/data/world/World.kt b/src/main/java/de/bixilon/minosoft/data/world/World.kt index f6384f338..8e16a1231 100644 --- a/src/main/java/de/bixilon/minosoft/data/world/World.kt +++ b/src/main/java/de/bixilon/minosoft/data/world/World.kt @@ -239,7 +239,7 @@ class World( } companion object { - const val MAX_SIZE = 29999999 + const val MAX_SIZE = 30_000_000 const val MAX_SIZEf = MAX_SIZE.toFloat() const val MAX_SIZEd = MAX_SIZE.toDouble() const val MAX_RENDER_DISTANCE = 64 diff --git a/src/main/java/de/bixilon/minosoft/data/world/border/WorldBorder.kt b/src/main/java/de/bixilon/minosoft/data/world/border/WorldBorder.kt index 4844e696f..3805de8c8 100644 --- a/src/main/java/de/bixilon/minosoft/data/world/border/WorldBorder.kt +++ b/src/main/java/de/bixilon/minosoft/data/world/border/WorldBorder.kt @@ -14,7 +14,6 @@ package de.bixilon.minosoft.data.world.border import de.bixilon.kotlinglm.vec2.Vec2d -import de.bixilon.kotlinglm.vec3.Vec3 import de.bixilon.kotlinglm.vec3.Vec3d import de.bixilon.kotlinglm.vec3.Vec3i import de.bixilon.kutil.concurrent.lock.simple.SimpleLock @@ -23,6 +22,7 @@ import de.bixilon.kutil.time.TimeUtil.millis import de.bixilon.minosoft.data.world.World import de.bixilon.minosoft.data.world.positions.BlockPosition import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2dUtil.EMPTY +import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition import kotlin.math.abs class WorldBorder { @@ -50,10 +50,6 @@ class WorldBorder { return isOutside(blockPosition.x.toDouble(), blockPosition.z.toDouble()) && isOutside(blockPosition.x + 1.0, blockPosition.z + 1.0) } - fun isOutside(position: Vec3): Boolean { - return isOutside(position.x.toDouble(), position.z.toDouble()) - } - fun isOutside(position: Vec3d): Boolean { return isOutside(position.x, position.z) } @@ -61,7 +57,7 @@ class WorldBorder { fun isOutside(x: Double, z: Double): Boolean { lock.acquire() val radius = radius - val inside = x in (center.x - radius)..(radius + center.x) && z in (center.y - radius)..(radius + center.y) + val inside = x in maxOf(-MAX_RADIUS, center.x - radius)..minOf(MAX_RADIUS, center.x + radius) && z in maxOf(-MAX_RADIUS, center.y - radius)..minOf(MAX_RADIUS, center.y + radius) lock.release() return !inside } @@ -80,8 +76,8 @@ class WorldBorder { val radius = radius val closestDistance = minOf( - radius - abs(x) - abs(center.x), - radius - abs(z) - abs(center.y), + minOf(MAX_RADIUS, radius - abs(center.x)) - abs(x), + minOf(MAX_RADIUS, radius - abs(center.y)) - abs(z), ) lock.release() return closestDistance @@ -147,6 +143,7 @@ class WorldBorder { } companion object { - const val DEFAULT_RADIUS = World.MAX_SIZE.toDouble() + const val MAX_RADIUS = (World.MAX_SIZE - ProtocolDefinition.SECTION_WIDTH_X).toDouble() + const val DEFAULT_RADIUS = MAX_RADIUS } } From 17374f7756379c1ffac184a84d6c1f1c82f29f94 Mon Sep 17 00:00:00 2001 From: Bixilon Date: Thu, 25 May 2023 19:08:06 +0200 Subject: [PATCH 19/21] render world border (again) With position offset and all fixes included --- .../rendering/world/border/WorldBorderMesh.kt | 112 +++++++++++++----- .../world/border/WorldBorderRenderer.kt | 94 +++++++++++---- .../world/border/WorldBorderShader.kt | 8 +- .../rendering/shader/includes/uv.glsl | 8 +- .../rendering/shader/world/border/border.vsh | 29 +++-- 5 files changed, 175 insertions(+), 76 deletions(-) diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/world/border/WorldBorderMesh.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/world/border/WorldBorderMesh.kt index 9bbb66a30..aed79875f 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/world/border/WorldBorderMesh.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/world/border/WorldBorderMesh.kt @@ -13,51 +13,103 @@ package de.bixilon.minosoft.gui.rendering.world.border +import de.bixilon.kotlinglm.vec2.Vec2 +import de.bixilon.kotlinglm.vec2.Vec2d import de.bixilon.kotlinglm.vec3.Vec3 +import de.bixilon.kotlinglm.vec3.Vec3i +import de.bixilon.minosoft.data.world.World +import de.bixilon.minosoft.data.world.border.WorldBorder import de.bixilon.minosoft.gui.rendering.RenderContext import de.bixilon.minosoft.gui.rendering.system.base.MeshUtil.buffer -import de.bixilon.minosoft.gui.rendering.system.base.buffer.vertex.PrimitiveTypes import de.bixilon.minosoft.gui.rendering.util.mesh.Mesh import de.bixilon.minosoft.gui.rendering.util.mesh.MeshStruct +import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition -class WorldBorderMesh(context: RenderContext) : Mesh(context, WorldBorderMeshStruct, PrimitiveTypes.TRIANGLE, initialCacheSize = 6 * 2 * 3 * WorldBorderMeshStruct.FLOATS_PER_VERTEX) { +class WorldBorderMesh( + context: RenderContext, + val offset: Vec3i, + val center: Vec2d, + val radius: Double, +) : Mesh(context, WorldBorderMeshStruct, initialCacheSize = 6 * 2 * 3 * WorldBorderMeshStruct.FLOATS_PER_VERTEX) { - init { - data.add( - floatArrayOf( - -1.0f, +1.0f, -1.0f, 1.buffer(), - +1.0f, -1.0f, -1.0f, 0.buffer(), - -1.0f, -1.0f, -1.0f, 3.buffer(), - +1.0f, -1.0f, -1.0f, 0.buffer(), - -1.0f, +1.0f, -1.0f, 1.buffer(), - +1.0f, +1.0f, -1.0f, 2.buffer(), + private fun x() { + val width = minOf(radius.toFloat(), World.MAX_RENDER_DISTANCE.toFloat() * ProtocolDefinition.SECTION_WIDTH_X) + val left = (center.y - width).toFloat() + val right = (center.y + width).toFloat() - -1.0f, -1.0f, +1.0f, 3.buffer(), - -1.0f, +1.0f, -1.0f, 2.buffer(), - -1.0f, -1.0f, -1.0f, 0.buffer(), - -1.0f, +1.0f, -1.0f, 2.buffer(), - -1.0f, -1.0f, +1.0f, 3.buffer(), - -1.0f, +1.0f, +1.0f, 1.buffer(), + val positions = arrayOf( + Vec2(left, -1.0f), + Vec2(left, +1.0f), + Vec2(right, +1.0f), + Vec2(right, -1.0f), + ) - +1.0f, -1.0f, -1.0f, 3.buffer(), - +1.0f, +1.0f, +1.0f, 2.buffer(), - +1.0f, -1.0f, +1.0f, 0.buffer(), - +1.0f, +1.0f, +1.0f, 2.buffer(), - +1.0f, -1.0f, -1.0f, 3.buffer(), - +1.0f, +1.0f, -1.0f, 1.buffer(), + val x = (maxOf(-WorldBorder.MAX_RADIUS, center.x - radius) - offset.x).toFloat() + for ((position, texture) in order) { + val (z, y) = positions[position] + addVertex(x, y, z, texture, width) + } - -1.0f, -1.0f, +1.0f, 0.buffer(), - +1.0f, +1.0f, +1.0f, 1.buffer(), - -1.0f, +1.0f, +1.0f, 2.buffer(), - +1.0f, +1.0f, +1.0f, 1.buffer(), - -1.0f, -1.0f, +1.0f, 0.buffer(), - +1.0f, -1.0f, +1.0f, 3.buffer(), - )) + val x1 = (minOf(WorldBorder.MAX_RADIUS, center.x + radius) - offset.x).toFloat() + for ((position, texture) in order) { + val (z, y) = positions[position] + addVertex(x1, y, z, when (texture) { + 1 -> 2 + 2 -> 1 + 3 -> 0 + else -> 3 + }, width) + } } + private fun z() { + val width = minOf(radius.toFloat(), World.MAX_RENDER_DISTANCE.toFloat() * ProtocolDefinition.SECTION_WIDTH_X) + val left = (center.x - width).toFloat() + val right = (center.x + width).toFloat() + + val positions = arrayOf( + Vec2(left, -1.0f), + Vec2(left, +1.0f), + Vec2(right, +1.0f), + Vec2(right, -1.0f), + ) + + val z = (maxOf(-WorldBorder.MAX_RADIUS, center.y - radius) - offset.z).toFloat() + for ((position, texture) in order) { + val (x, y) = positions[position] + addVertex(x, y, z, when (texture) { + 1 -> 2 + 2 -> 1 + 3 -> 0 + else -> 3 + }, width) + } + + val z1 = (minOf(WorldBorder.MAX_RADIUS, center.y + radius) - offset.z).toFloat() + for ((position, texture) in order) { + val (x, y) = positions[position] + addVertex(x, y, z1, texture, width) + } + } + + fun build() { + x() + z() + } + + private fun addVertex(x: Float, y: Float, z: Float, uvIndex: Int, width: Float) { + data.add(x) + data.add(y) + data.add(z) + data.add(uvIndex.buffer()) + data.add(width) + } + + data class WorldBorderMeshStruct( val position: Vec3, val uvIndex: Int, + val width: Float, ) { companion object : MeshStruct(WorldBorderMeshStruct::class) } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/world/border/WorldBorderRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/world/border/WorldBorderRenderer.kt index 51f040bc0..a493b55eb 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/world/border/WorldBorderRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/world/border/WorldBorderRenderer.kt @@ -14,40 +14,47 @@ package de.bixilon.minosoft.gui.rendering.world.border import de.bixilon.kotlinglm.func.common.clamp -import de.bixilon.kotlinglm.vec2.Vec2 import de.bixilon.kutil.latch.CountUpAndDownLatch +import de.bixilon.kutil.math.interpolation.DoubleInterpolation.interpolateLinear +import de.bixilon.kutil.observer.DataObserver.Companion.observe import de.bixilon.kutil.time.TimeUtil.millis import de.bixilon.minosoft.data.registries.identified.Namespaces.minosoft +import de.bixilon.minosoft.data.text.formatting.color.RGBColor import de.bixilon.minosoft.data.text.formatting.color.RGBColor.Companion.asColor import de.bixilon.minosoft.data.world.border.WorldBorderState import de.bixilon.minosoft.gui.rendering.RenderContext +import de.bixilon.minosoft.gui.rendering.renderer.renderer.AsyncRenderer import de.bixilon.minosoft.gui.rendering.renderer.renderer.Renderer import de.bixilon.minosoft.gui.rendering.renderer.renderer.RendererBuilder import de.bixilon.minosoft.gui.rendering.system.base.BlendingFunctions import de.bixilon.minosoft.gui.rendering.system.base.RenderSystem +import de.bixilon.minosoft.gui.rendering.system.base.phases.SkipAll import de.bixilon.minosoft.gui.rendering.system.base.phases.TranslucentDrawable import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.AbstractTexture import de.bixilon.minosoft.gui.rendering.textures.TextureUtil.texture +import de.bixilon.minosoft.gui.rendering.util.mesh.Mesh import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection import de.bixilon.minosoft.util.KUtil.toResourceLocation class WorldBorderRenderer( override val context: RenderContext, -) : Renderer, TranslucentDrawable { +) : Renderer, AsyncRenderer, TranslucentDrawable, SkipAll { override val renderSystem: RenderSystem = context.renderSystem private val shader = renderSystem.createShader(minosoft("world/border")) { WorldBorderShader(it) } - private val borderMesh = WorldBorderMesh(context) + private var borderMesh: WorldBorderMesh? = null private val border = context.connection.world.border private lateinit var texture: AbstractTexture private var offsetReset = millis() - override val skipTranslucent: Boolean + override val skipAll: Boolean get() = border.getDistanceTo(context.connection.player.physics.position) > MAX_DISTANCE + private var reload = false override fun init(latch: CountUpAndDownLatch) { + shader.native.defines["MAX_DISTANCE"] = MAX_DISTANCE shader.load() - borderMesh.load() texture = context.textureManager.staticTextures.createTexture(TEXTURE) + context.camera.offset::offset.observe(this) { reload = true } } override fun postInit(latch: CountUpAndDownLatch) { @@ -55,7 +62,62 @@ class WorldBorderRenderer( shader.textureIndexLayer = texture.renderData.shaderTextureId } + private fun calculateColor(): RGBColor { + val distance = border.getDistanceTo(context.connection.player.physics.position).toFloat() - 1.0f // 1 block padding + val strength = 1.0f - distance.clamp(0.0f, MAX_DISTANCE) / MAX_DISTANCE // slowly fade in + val color = when (border.state) { + WorldBorderState.GROWING -> GROWING_COLOR + WorldBorderState.SHRINKING -> SHRINKING_COLOR + WorldBorderState.STATIC -> STATIC_COLOR + } + return color.with(alpha = (strength * strength)) + } + + private fun update() { + if (this.borderMesh == null) return + + val time = millis() + if (offsetReset - time > ANIMATION_SPEED) { + offsetReset = time + } + val textureOffset = (offsetReset - time) / ANIMATION_SPEED.toFloat() + shader.textureOffset = 1.0f - textureOffset + + shader.tintColor = calculateColor() + } + + private fun getRadius(): Double { + val start = border.interpolationStart + if (start < 0L) return border.radius + + val progress = (millis() - start).toDouble() / (border.interpolationEnd - start) + + return interpolateLinear(progress, border.oldRadius, border.newRadius) + } + + + override fun prepareDrawAsync() { + if (skipAll) return + + val center = border.center + val radius = getRadius() + + val previous = this.borderMesh + // if (previous != null && !reload && center == previous.center && radius == previous.radius) return + + context.queue += { previous?.unload() } + + val offset = context.camera.offset.offset + + val mesh = WorldBorderMesh(context, offset, center, radius) + mesh.build() + + this.borderMesh = mesh + this.reload = false + } + override fun setupTranslucent() { + val mesh = this.borderMesh ?: return renderSystem.reset( blending = true, sourceRGB = BlendingFunctions.SOURCE_ALPHA, @@ -68,29 +130,15 @@ class WorldBorderRenderer( polygonOffsetUnit = -3.0f, ) shader.use() - val time = millis() - if (offsetReset - time > ANIMATION_SPEED) { - offsetReset = time - } - val textureOffset = (offsetReset - time) / ANIMATION_SPEED.toFloat() - shader.textureOffset = 1.0f - textureOffset - shader.cameraHeight = context.connection.camera.entity.renderInfo.eyePosition.y.toFloat() + update() - val distance = border.getDistanceTo(context.connection.player.physics.position).toFloat() - 1.0f // 1 block padding - val strength = 1.0f - (distance.clamp(0.0f, MAX_DISTANCE) / MAX_DISTANCE) // slowly fade in - var color = when (border.state) { - WorldBorderState.GROWING -> GROWING_COLOR - WorldBorderState.SHRINKING -> SHRINKING_COLOR - WorldBorderState.STATIC -> STATIC_COLOR + if (mesh.state == Mesh.MeshStates.PREPARING) { + mesh.load() } - color = color.with(alpha = (strength * strength)) - shader.tintColor = color - shader.radius = border.diameter.toFloat() / 2.0f - shader.center = Vec2(border.center) } override fun drawTranslucent() { - borderMesh.draw() + borderMesh?.draw() } companion object : RendererBuilder { diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/world/border/WorldBorderShader.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/world/border/WorldBorderShader.kt index caa4c95f0..e9ec90662 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/world/border/WorldBorderShader.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/world/border/WorldBorderShader.kt @@ -14,21 +14,20 @@ package de.bixilon.minosoft.gui.rendering.world.border import de.bixilon.kotlinglm.mat4x4.Mat4 -import de.bixilon.kotlinglm.vec2.Vec2 import de.bixilon.kotlinglm.vec3.Vec3 import de.bixilon.minosoft.data.text.formatting.color.ChatColors import de.bixilon.minosoft.gui.rendering.camera.FogManager import de.bixilon.minosoft.gui.rendering.shader.Shader +import de.bixilon.minosoft.gui.rendering.shader.types.CameraPositionShader import de.bixilon.minosoft.gui.rendering.shader.types.FogShader import de.bixilon.minosoft.gui.rendering.shader.types.TextureShader import de.bixilon.minosoft.gui.rendering.shader.types.ViewProjectionShader import de.bixilon.minosoft.gui.rendering.system.base.shader.NativeShader import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureManager -import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2Util.EMPTY class WorldBorderShader( override val native: NativeShader, -) : Shader(), TextureShader, ViewProjectionShader, FogShader { +) : Shader(), TextureShader, ViewProjectionShader, FogShader, CameraPositionShader { override var textures: TextureManager by textureManager() override var viewProjectionMatrix: Mat4 by viewProjectionMatrix() override var cameraPosition: Vec3 by cameraPosition() @@ -38,7 +37,4 @@ class WorldBorderShader( var textureIndexLayer by uniform("uIndexLayer", 0, NativeShader::setUInt) var textureOffset by uniform("uTextureOffset", 0.0f) - var radius by uniform("uRadius", 0.0f) - var center by uniform("uCenter", Vec2.EMPTY) - var cameraHeight by uniform("uCameraHeight", 0.0f) } diff --git a/src/main/resources/assets/minosoft/rendering/shader/includes/uv.glsl b/src/main/resources/assets/minosoft/rendering/shader/includes/uv.glsl index 211f9353d..345208cbc 100644 --- a/src/main/resources/assets/minosoft/rendering/shader/includes/uv.glsl +++ b/src/main/resources/assets/minosoft/rendering/shader/includes/uv.glsl @@ -1,6 +1,6 @@ -const vec2 CONST_UV[4] = vec2[4]( - vec2(+ 0.0f, + 1.0f), - vec2(+ 1.0f, + 0.0f), +const vec2 CONST_UV[4] = vec2[]( vec2(+ 0.0f, + 0.0f), - vec2(+ 1.0f, + 1.0f) + vec2(+ 0.0f, + 1.0f), + vec2(+ 1.0f, + 1.0f), + vec2(+ 1.0f, + 0.0f) ); diff --git a/src/main/resources/assets/minosoft/rendering/shader/world/border/border.vsh b/src/main/resources/assets/minosoft/rendering/shader/world/border/border.vsh index 34049f497..61409d4b6 100644 --- a/src/main/resources/assets/minosoft/rendering/shader/world/border/border.vsh +++ b/src/main/resources/assets/minosoft/rendering/shader/world/border/border.vsh @@ -14,18 +14,21 @@ #version 330 core layout (location = 0) in vec3 vinPosition; -layout (location = 1) in float uvIndex; +layout (location = 1) in float vinUVIndex; +layout (location = 2) in float vinWidth; uniform mat4 uViewProjectionMatrix; uniform uint uIndexLayer; uniform float uTextureOffset; -uniform float uRadius; -uniform vec2 uCenter; -uniform float uCameraHeight; + +uniform vec3 uCameraPosition; flat out uint finTextureIndex; out vec3 finTextureCoordinates; +out vec3 finFragmentPosition; // fog +#define DENSITY 2.0f +#define HEIGHT 150.0f #include "minosoft:uv" #include "minosoft:color" @@ -33,22 +36,22 @@ out vec3 finTextureCoordinates; void main() { vec3 position = vinPosition; - position = position * uRadius; if (position.y < 0.0f) { - position.y = uCameraHeight - 300; + position.y = uCameraPosition.y - HEIGHT; } else if (position.y > 0.0f) { - position.y = uCameraHeight + 300; + position.y = uCameraPosition.y + HEIGHT; } - position.x += uCenter.x; - position.z += uCenter.y; gl_Position = uViewProjectionMatrix * vec4(position, 1.0f); finTextureIndex = uIndexLayer >> 28u; - vec2 uv = CONST_UV[floatBitsToUint(uvIndex)]; - uv.x *= (uRadius / 5.0f); - uv.y *= (300 / 5.0f); - finTextureCoordinates = vec3(uv, ((uIndexLayer >> 12) & 0xFFFFu)); + vec2 uv = CONST_UV[floatBitsToUint(vinUVIndex)]; + uv.x *= (vinWidth / DENSITY); // TODO: insert width + uv.y *= (HEIGHT / DENSITY); + + finTextureCoordinates = vec3(uv, ((uIndexLayer >> 12u) & 0xFFFFu)); finTextureCoordinates.x += uTextureOffset; finTextureCoordinates.y += uTextureOffset; + + finFragmentPosition = position.xyz; } From 802dc48a075cd38d9d4f598c58c49a0abdabf781 Mon Sep 17 00:00:00 2001 From: Bixilon Date: Thu, 25 May 2023 19:30:24 +0200 Subject: [PATCH 20/21] improve world border mesh code --- .../rendering/world/border/WorldBorderMesh.kt | 84 +++++++++---------- .../world/border/WorldBorderRenderer.kt | 2 +- 2 files changed, 41 insertions(+), 45 deletions(-) diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/world/border/WorldBorderMesh.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/world/border/WorldBorderMesh.kt index aed79875f..a183f31ca 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/world/border/WorldBorderMesh.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/world/border/WorldBorderMesh.kt @@ -32,69 +32,65 @@ class WorldBorderMesh( val radius: Double, ) : Mesh(context, WorldBorderMeshStruct, initialCacheSize = 6 * 2 * 3 * WorldBorderMeshStruct.FLOATS_PER_VERTEX) { - private fun x() { - val width = minOf(radius.toFloat(), World.MAX_RENDER_DISTANCE.toFloat() * ProtocolDefinition.SECTION_WIDTH_X) - val left = (center.y - width).toFloat() - val right = (center.y + width).toFloat() - val positions = arrayOf( + private fun width(): Float { + return minOf(radius.toFloat(), World.MAX_RENDER_DISTANCE.toFloat() * ProtocolDefinition.SECTION_WIDTH_X) + } + + private fun positions(width: Float, center: Double): Array { + val left = (center - width).toFloat() + val right = (center + width).toFloat() + + return arrayOf( Vec2(left, -1.0f), Vec2(left, +1.0f), Vec2(right, +1.0f), Vec2(right, -1.0f), ) + } - val x = (maxOf(-WorldBorder.MAX_RADIUS, center.x - radius) - offset.x).toFloat() - for ((position, texture) in order) { - val (z, y) = positions[position] - addVertex(x, y, z, texture, width) - } - - val x1 = (minOf(WorldBorder.MAX_RADIUS, center.x + radius) - offset.x).toFloat() - for ((position, texture) in order) { - val (z, y) = positions[position] - addVertex(x1, y, z, when (texture) { - 1 -> 2 - 2 -> 1 - 3 -> 0 - else -> 3 - }, width) + private fun textureIndex(index: Int): Int { + return when (index) { + 1 -> 2 + 2 -> 1 + 3 -> 0 + else -> 3 } } - private fun z() { - val width = minOf(radius.toFloat(), World.MAX_RENDER_DISTANCE.toFloat() * ProtocolDefinition.SECTION_WIDTH_X) - val left = (center.x - width).toFloat() - val right = (center.x + width).toFloat() + private fun addVertexX(x: Float, width: Float, positions: Array, index: Boolean) { + for ((position, texture) in order) { + val (z, y) = positions[position] + val texture = if (index) textureIndex(texture) else texture + addVertex(x, y, z, textureIndex(texture), width) + } + } - val positions = arrayOf( - Vec2(left, -1.0f), - Vec2(left, +1.0f), - Vec2(right, +1.0f), - Vec2(right, -1.0f), - ) + private fun x(width: Float) { + val positions = positions(width, center.y) + addVertexX((maxOf(-WorldBorder.MAX_RADIUS, center.x - radius) - offset.x).toFloat(), width, positions, false) + addVertexX((minOf(WorldBorder.MAX_RADIUS, center.x + radius) - offset.x).toFloat(), width, positions, true) + } - val z = (maxOf(-WorldBorder.MAX_RADIUS, center.y - radius) - offset.z).toFloat() + private fun addVertexZ(z: Float, width: Float, positions: Array, index: Boolean) { for ((position, texture) in order) { val (x, y) = positions[position] - addVertex(x, y, z, when (texture) { - 1 -> 2 - 2 -> 1 - 3 -> 0 - else -> 3 - }, width) + val texture = if (index) textureIndex(texture) else texture + addVertex(x, y, z, textureIndex(texture), width) } + } - val z1 = (minOf(WorldBorder.MAX_RADIUS, center.y + radius) - offset.z).toFloat() - for ((position, texture) in order) { - val (x, y) = positions[position] - addVertex(x, y, z1, texture, width) - } + private fun z(width: Float) { + val positions = positions(width, center.x) + + addVertexZ((maxOf(-WorldBorder.MAX_RADIUS, center.y - radius) - offset.z).toFloat(), width, positions, true) + addVertexZ((minOf(WorldBorder.MAX_RADIUS, center.y + radius) - offset.z).toFloat(), width, positions, false) } fun build() { - x() - z() + val width = width() + x(width) + z(width) } private fun addVertex(x: Float, y: Float, z: Float, uvIndex: Int, width: Float) { diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/world/border/WorldBorderRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/world/border/WorldBorderRenderer.kt index a493b55eb..c6e77566d 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/world/border/WorldBorderRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/world/border/WorldBorderRenderer.kt @@ -103,7 +103,7 @@ class WorldBorderRenderer( val radius = getRadius() val previous = this.borderMesh - // if (previous != null && !reload && center == previous.center && radius == previous.radius) return + if (previous != null && !reload && center == previous.center && radius == previous.radius) return context.queue += { previous?.unload() } From 47f6dd7e05862684f5445aba312a626d4576d0ef Mon Sep 17 00:00:00 2001 From: Bixilon Date: Thu, 25 May 2023 19:49:22 +0200 Subject: [PATCH 21/21] abstract world border area Sooooo much cleaner now --- .../minosoft/data/world/border/WorldBorder.kt | 90 ++++--------------- .../data/world/border/area/BorderArea.kt | 27 ++++++ .../world/border/area/DynamicBorderArea.kt | 57 ++++++++++++ .../world/border/area/StaticBorderArea.kt | 24 +++++ .../world/border/WorldBorderRenderer.kt | 14 +-- .../s2c/play/border/SizeWorldBorderS2CP.kt | 6 +- 6 files changed, 128 insertions(+), 90 deletions(-) create mode 100644 src/main/java/de/bixilon/minosoft/data/world/border/area/BorderArea.kt create mode 100644 src/main/java/de/bixilon/minosoft/data/world/border/area/DynamicBorderArea.kt create mode 100644 src/main/java/de/bixilon/minosoft/data/world/border/area/StaticBorderArea.kt diff --git a/src/main/java/de/bixilon/minosoft/data/world/border/WorldBorder.kt b/src/main/java/de/bixilon/minosoft/data/world/border/WorldBorder.kt index 3805de8c8..dc94f97b5 100644 --- a/src/main/java/de/bixilon/minosoft/data/world/border/WorldBorder.kt +++ b/src/main/java/de/bixilon/minosoft/data/world/border/WorldBorder.kt @@ -16,10 +16,10 @@ package de.bixilon.minosoft.data.world.border import de.bixilon.kotlinglm.vec2.Vec2d import de.bixilon.kotlinglm.vec3.Vec3d import de.bixilon.kotlinglm.vec3.Vec3i -import de.bixilon.kutil.concurrent.lock.simple.SimpleLock -import de.bixilon.kutil.math.interpolation.DoubleInterpolation.interpolateLinear -import de.bixilon.kutil.time.TimeUtil.millis import de.bixilon.minosoft.data.world.World +import de.bixilon.minosoft.data.world.border.area.BorderArea +import de.bixilon.minosoft.data.world.border.area.DynamicBorderArea +import de.bixilon.minosoft.data.world.border.area.StaticBorderArea import de.bixilon.minosoft.data.world.positions.BlockPosition import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2dUtil.EMPTY import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition @@ -27,24 +27,11 @@ import kotlin.math.abs class WorldBorder { var center = Vec2d.EMPTY - var radius = DEFAULT_RADIUS var warningTime = 0 var warningBlocks = 0 var portalBound = 0 - var state = WorldBorderState.STATIC - private set - - var interpolationStart = -1L - private set - var interpolationEnd = -1L - private set - var oldRadius = DEFAULT_RADIUS - private set - var newRadius = DEFAULT_RADIUS - private set - - val lock = SimpleLock() + var area: BorderArea = StaticBorderArea(MAX_RADIUS) fun isOutside(blockPosition: Vec3i): Boolean { return isOutside(blockPosition.x.toDouble(), blockPosition.z.toDouble()) && isOutside(blockPosition.x + 1.0, blockPosition.z + 1.0) @@ -55,10 +42,9 @@ class WorldBorder { } fun isOutside(x: Double, z: Double): Boolean { - lock.acquire() - val radius = radius + val center = center + val radius = area.radius val inside = x in maxOf(-MAX_RADIUS, center.x - radius)..minOf(MAX_RADIUS, center.x + radius) && z in maxOf(-MAX_RADIUS, center.y - radius)..minOf(MAX_RADIUS, center.y + radius) - lock.release() return !inside } @@ -72,78 +58,32 @@ class WorldBorder { } fun getDistanceTo(x: Double, z: Double): Double { - lock.acquire() - val radius = radius + val center = center + val radius = area.radius - val closestDistance = minOf( + return minOf( minOf(MAX_RADIUS, radius - abs(center.x)) - abs(x), minOf(MAX_RADIUS, radius - abs(center.y)) - abs(z), ) - lock.release() - return closestDistance - } - - fun stopInterpolating() { - lock.lock() - interpolationStart = -1L - lock.unlock() } fun interpolate(oldRadius: Double, newRadius: Double, millis: Long) { - if (millis <= 0L) { - stopInterpolating() - radius = newRadius + if (millis <= 0L || oldRadius == newRadius) { + area = StaticBorderArea(newRadius) + return } - lock.lock() - val time = millis() - interpolationStart = time - interpolationEnd = time + millis - this.oldRadius = oldRadius - this.newRadius = newRadius - lock.unlock() + area = DynamicBorderArea(this, oldRadius, newRadius, millis) } fun tick() { - lock.lock() - if (interpolationStart < 0L) { - lock.unlock() - return - } - val time = millis() - if (interpolationEnd <= time) { - this.radius = newRadius // also get the last interpolation step - state = WorldBorderState.STATIC - interpolationStart = -1L - lock.unlock() - return - } - val oldRadius = radius - - val remaining = interpolationEnd - time - val totalTime = (interpolationEnd - interpolationStart) - val radius = interpolateLinear(remaining.toDouble() / totalTime.toDouble(), this.oldRadius, this.newRadius) - this.radius = radius - - state = if (oldRadius > newRadius) { - WorldBorderState.SHRINKING - } else if (oldRadius < newRadius) { - WorldBorderState.GROWING - } else { - interpolationStart = -1L - WorldBorderState.STATIC - } - lock.unlock() + area.tick() } fun reset() { - lock.lock() - radius = DEFAULT_RADIUS - interpolationStart = -1L - lock.unlock() + area = StaticBorderArea(MAX_RADIUS) } companion object { const val MAX_RADIUS = (World.MAX_SIZE - ProtocolDefinition.SECTION_WIDTH_X).toDouble() - const val DEFAULT_RADIUS = MAX_RADIUS } } diff --git a/src/main/java/de/bixilon/minosoft/data/world/border/area/BorderArea.kt b/src/main/java/de/bixilon/minosoft/data/world/border/area/BorderArea.kt new file mode 100644 index 000000000..c7e692ae4 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/data/world/border/area/BorderArea.kt @@ -0,0 +1,27 @@ +/* + * Minosoft + * Copyright (C) 2020-2023 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 . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.data.world.border.area + +import de.bixilon.kutil.time.TimeUtil.millis +import de.bixilon.minosoft.data.Tickable +import de.bixilon.minosoft.data.world.border.WorldBorderState + +interface BorderArea : Tickable { + val radius: Double + + val state: WorldBorderState + + + fun radius(time: Long = millis()): Double = radius +} diff --git a/src/main/java/de/bixilon/minosoft/data/world/border/area/DynamicBorderArea.kt b/src/main/java/de/bixilon/minosoft/data/world/border/area/DynamicBorderArea.kt new file mode 100644 index 000000000..c34c07000 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/data/world/border/area/DynamicBorderArea.kt @@ -0,0 +1,57 @@ +/* + * Minosoft + * Copyright (C) 2020-2023 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 . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.data.world.border.area + +import de.bixilon.kutil.math.interpolation.DoubleInterpolation.interpolateLinear +import de.bixilon.kutil.time.TimeUtil.millis +import de.bixilon.minosoft.data.world.border.WorldBorder +import de.bixilon.minosoft.data.world.border.WorldBorderState + +class DynamicBorderArea( + val border: WorldBorder, + val oldRadius: Double, + val newRadius: Double, + val millis: Long, +) : BorderArea { + val start: Long = millis() + val end = start + millis + + override var state: WorldBorderState = state() + override var radius: Double = oldRadius + + override fun radius(time: Long): Double { + return interpolateLinear(progress(time), oldRadius, newRadius) + } + + private fun progress(time: Long): Double { + return (time - start).toDouble() / (end - start) + } + + override fun tick() { + val time = millis() + if (end <= time) { + border.area = StaticBorderArea(newRadius) + return + } + + this.radius = interpolateLinear(progress(time), this.oldRadius, this.newRadius) + this.state = state() + } + + private fun state() = when { + oldRadius > newRadius -> WorldBorderState.SHRINKING + oldRadius < newRadius -> WorldBorderState.GROWING + else -> WorldBorderState.STATIC // impossible? + } +} diff --git a/src/main/java/de/bixilon/minosoft/data/world/border/area/StaticBorderArea.kt b/src/main/java/de/bixilon/minosoft/data/world/border/area/StaticBorderArea.kt new file mode 100644 index 000000000..8f904cd90 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/data/world/border/area/StaticBorderArea.kt @@ -0,0 +1,24 @@ +/* + * Minosoft + * Copyright (C) 2020-2023 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 . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.data.world.border.area + +import de.bixilon.minosoft.data.world.border.WorldBorderState + +class StaticBorderArea( + override val radius: Double, +) : BorderArea { + override val state: WorldBorderState get() = WorldBorderState.STATIC + + override fun tick() = Unit +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/world/border/WorldBorderRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/world/border/WorldBorderRenderer.kt index c6e77566d..76323bf93 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/world/border/WorldBorderRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/world/border/WorldBorderRenderer.kt @@ -15,7 +15,6 @@ package de.bixilon.minosoft.gui.rendering.world.border import de.bixilon.kotlinglm.func.common.clamp import de.bixilon.kutil.latch.CountUpAndDownLatch -import de.bixilon.kutil.math.interpolation.DoubleInterpolation.interpolateLinear import de.bixilon.kutil.observer.DataObserver.Companion.observe import de.bixilon.kutil.time.TimeUtil.millis import de.bixilon.minosoft.data.registries.identified.Namespaces.minosoft @@ -65,7 +64,7 @@ class WorldBorderRenderer( private fun calculateColor(): RGBColor { val distance = border.getDistanceTo(context.connection.player.physics.position).toFloat() - 1.0f // 1 block padding val strength = 1.0f - distance.clamp(0.0f, MAX_DISTANCE) / MAX_DISTANCE // slowly fade in - val color = when (border.state) { + val color = when (border.area.state) { WorldBorderState.GROWING -> GROWING_COLOR WorldBorderState.SHRINKING -> SHRINKING_COLOR WorldBorderState.STATIC -> STATIC_COLOR @@ -86,21 +85,12 @@ class WorldBorderRenderer( shader.tintColor = calculateColor() } - private fun getRadius(): Double { - val start = border.interpolationStart - if (start < 0L) return border.radius - - val progress = (millis() - start).toDouble() / (border.interpolationEnd - start) - - return interpolateLinear(progress, border.oldRadius, border.newRadius) - } - override fun prepareDrawAsync() { if (skipAll) return val center = border.center - val radius = getRadius() + val radius = border.area.radius() val previous = this.borderMesh if (previous != null && !reload && center == previous.center && radius == previous.radius) return diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/border/SizeWorldBorderS2CP.kt b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/border/SizeWorldBorderS2CP.kt index 67dd16f23..c42872c75 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/border/SizeWorldBorderS2CP.kt +++ b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/border/SizeWorldBorderS2CP.kt @@ -13,6 +13,7 @@ package de.bixilon.minosoft.protocol.packets.s2c.play.border +import de.bixilon.minosoft.data.world.border.area.StaticBorderArea import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection import de.bixilon.minosoft.protocol.packets.factory.LoadPacket import de.bixilon.minosoft.protocol.protocol.buffers.play.PlayInByteBuffer @@ -25,11 +26,10 @@ class SizeWorldBorderS2CP(buffer: PlayInByteBuffer) : WorldBorderS2CP { val radius = buffer.readDouble() / 2.0 override fun handle(connection: PlayConnection) { - connection.world.border.stopInterpolating() - connection.world.border.radius = radius + connection.world.border.area = StaticBorderArea(radius) } override fun log(reducedLog: Boolean) { - Log.log(LogMessageType.NETWORK_PACKETS_IN, level = LogLevels.VERBOSE) { "Size set world border (diameter=$radius)" } + Log.log(LogMessageType.NETWORK_PACKETS_IN, level = LogLevels.VERBOSE) { "Size set world border (radius=$radius)" } } }