Merge branch 'fix/offset_world_coordinates'

Closes #108, GH-13
This commit is contained in:
Bixilon 2023-05-25 19:55:30 +02:00
commit f5fe58c1a4
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
60 changed files with 606 additions and 329 deletions

View File

@ -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")

View File

@ -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()

View File

@ -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

View File

@ -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

View File

@ -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()

View File

@ -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)
}

View File

@ -14,57 +14,42 @@
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
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.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
import kotlin.math.abs
class WorldBorder {
var center = Vec2d.EMPTY
var diameter = DEFAULT_DIAMETER
var warningTime = 0
var warningBlocks = 0
var portalBound = 0
var state = WorldBorderState.STATIC
private set
private var interpolationStart = -1L
private var interpolationEnd = -1L
private var oldDiameter = DEFAULT_DIAMETER
private var newDiameter = DEFAULT_DIAMETER
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)
}
fun isOutside(position: Vec3): Boolean {
return isOutside(position.x.toDouble(), position.z.toDouble())
}
fun isOutside(position: Vec3d): Boolean {
return isOutside(position.x, position.z)
}
fun isOutside(x: Double, z: Double): Boolean {
lock.acquire()
val radius = diameter / 2
val inside = x in (center.x - radius)..(radius + center.x) && z in (center.y - radius)..(radius + center.y)
lock.release()
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)
return !inside
}
operator fun contains(position:BlockPosition) = !isOutside(position)
operator fun contains(position: BlockPosition) = !isOutside(position)
operator fun contains(position: Vec3d) = !isOutside(position)
@ -73,76 +58,32 @@ class WorldBorder {
}
fun getDistanceTo(x: Double, z: Double): Double {
lock.acquire()
val radius = diameter / 2
val center = center
val radius = area.radius
val closestDistance = minOf(
radius - abs(x) - abs(center.x),
radius - abs(z) - abs(center.y),
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(oldDiameter: Double, newDiameter: Double, millis: Long) {
if (millis == 0L) {
stopInterpolating()
diameter = newDiameter
fun interpolate(oldRadius: Double, newRadius: Double, millis: Long) {
if (millis <= 0L || oldRadius == newRadius) {
area = StaticBorderArea(newRadius)
return
}
lock.lock()
val time = millis()
interpolationStart = time
interpolationEnd = time + millis
this.oldDiameter = oldDiameter
this.newDiameter = newDiameter
lock.unlock()
area = DynamicBorderArea(this, oldRadius, newRadius, millis)
}
fun tick() {
lock.lock()
if (interpolationStart < 0L) {
lock.unlock()
return
}
val time = millis()
if (interpolationEnd <= time) {
state = WorldBorderState.STATIC
interpolationStart = -1L
lock.unlock()
return
}
val oldDiameter = diameter
val remaining = interpolationEnd - time
val totalTime = (interpolationEnd - interpolationStart)
val diameter = interpolateLinear(remaining.toDouble() / totalTime.toDouble(), this.newDiameter, this.oldDiameter)
this.diameter = diameter
state = if (oldDiameter > diameter) {
WorldBorderState.SHRINKING
} else if (oldDiameter < diameter) {
WorldBorderState.GROWING
} else {
interpolationStart = -1L
WorldBorderState.STATIC
}
lock.unlock()
area.tick()
}
fun reset() {
lock.lock()
diameter = DEFAULT_DIAMETER
interpolationStart = -1L
lock.unlock()
area = StaticBorderArea(MAX_RADIUS)
}
companion object {
const val DEFAULT_DIAMETER = World.MAX_SIZE.toDouble() * 2
const val MAX_RADIUS = (World.MAX_SIZE - ProtocolDefinition.SECTION_WIDTH_X).toDouble()
}
}

View File

@ -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 <https://www.gnu.org/licenses/>.
*
* 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
}

View File

@ -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 <https://www.gnu.org/licenses/>.
*
* 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?
}
}

View File

@ -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 <https://www.gnu.org/licenses/>.
*
* 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
}

View File

@ -31,6 +31,7 @@ class Camera(
val view = ViewManager(this)
val offset = WorldOffset(this)
fun init() {
matrixHandler.init()

View File

@ -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
@ -113,11 +113,13 @@ class MatrixHandler(
val fov = calculateFOV()
val view = camera.view.view
val eyePosition = view.eyePosition
context.camera.offset.draw()
val matrixPosition = Vec3(eyePosition - context.camera.offset.offset)
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 +128,18 @@ class MatrixHandler(
previousFOV = fov
updateFront(front)
updateViewMatrix(eyePosition, front)
updateViewMatrix(matrixPosition, front)
updateViewProjectionMatrix()
val usePosition = if (view.updateFrustum) eyePosition else connection.camera.entity.renderInfo.eyePosition
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 +150,7 @@ class MatrixHandler(
)
)
updateShaders(usePosition)
updateShaders(useMatrixPosition)
upToDate = true
}

View File

@ -0,0 +1,48 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*
* 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.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.EMPTY)
private set
override fun draw() {
val blockPosition = camera.view.view.eyePosition.blockPosition
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
}
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 THRESHOLD = (World.MAX_RENDER_DISTANCE / 8) * ProtocolDefinition.SECTION_WIDTH_X // only if value is lower that that value coordinates will be back offset
}
}

View File

@ -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<Vec3>, val planes: Array<Vec4>)

View File

@ -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,7 @@ interface CameraView {
val updateFrustum: Boolean get() = true
val eyePosition: Vec3
val eyePosition: Vec3d
val rotation: EntityRotation
val front: Vec3

View File

@ -15,11 +15,13 @@ 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.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 +30,7 @@ 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 rotation = EntityRotation.EMPTY
override var front = Vec3.EMPTY
@ -44,7 +46,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,7 +56,7 @@ 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
@ -73,7 +75,7 @@ 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.rotation = previous?.rotation ?: EntityRotation.EMPTY
this.front = previous?.front ?: Vec3.EMPTY
}

View File

@ -15,6 +15,7 @@ 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
@ -22,6 +23,7 @@ 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.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 +39,7 @@ 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 rotation = EntityRotation.EMPTY
override var front = Vec3.EMPTY

View File

@ -15,12 +15,14 @@ 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.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 +30,7 @@ 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 rotation = EntityRotation.EMPTY
override var front = Vec3.EMPTY
@ -53,8 +55,8 @@ 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)

View File

@ -61,6 +61,8 @@ class EntityRenderer(
var visibleCount: Int = 0
private set
private var reset = false
override fun init(latch: CountUpAndDownLatch) {
connection.events.listen<EntitySpawnEvent> { 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() {

View File

@ -23,4 +23,6 @@ interface ModelUpdater : Drawable {
fun prepare() = Unit
fun unload() = Unit
fun reset() = Unit
}

View File

@ -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
}

View File

@ -47,6 +47,11 @@ abstract class EntityModel<E : Entity>(
return update
}
override fun reset() {
update = true
hitbox.reset()
}
override fun prepareAsync() {
if (!update) {
return

View File

@ -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)
}

View File

@ -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 "")
}

View File

@ -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.*

View File

@ -20,5 +20,5 @@ import java.util.*
interface SingleBlockRenderable {
fun singleRender(position: Vec3i, mesh: WorldMesh, random: Random, blockState: BlockState, neighbours: Array<BlockState?>, light: ByteArray, tints: IntArray?): Boolean
fun singleRender(position: Vec3i, offset: FloatArray, mesh: WorldMesh, random: Random, blockState: BlockState, neighbours: Array<BlockState?>, light: ByteArray, tints: IntArray?): Boolean
}

View File

@ -32,10 +32,10 @@ class MultipartBakedModel(
return sizes[direction.ordinal]
}
override fun singleRender(position: Vec3i, mesh: WorldMesh, random: Random, blockState: BlockState, neighbours: Array<BlockState?>, light: ByteArray, tints: IntArray?): Boolean {
override fun singleRender(position: Vec3i, offset: FloatArray, mesh: WorldMesh, random: Random, blockState: BlockState, neighbours: Array<BlockState?>, 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
}
}

View File

@ -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<BlockState?>, 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<BlockState?>, 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? {

View File

@ -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<BlockState?>, light: ByteArray, tints: IntArray?): Boolean {
val floatPosition = position.toVec3()
override fun singleRender(position: Vec3i, offset: FloatArray, mesh: WorldMesh, random: Random, blockState: BlockState, neighbours: Array<BlockState?>, light: ByteArray, tints: IntArray?): Boolean {
val floatPosition = offset.toVec3()
if (blockState.block is RandomOffsetBlock) {
blockState.block.randomOffset?.let { floatPosition += position.getWorldOffset(it) }
}

View File

@ -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())

View File

@ -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

View File

@ -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

View File

@ -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)
}
}
}

View File

@ -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<CloudArray?>>()) {
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
}

View File

@ -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) {

View File

@ -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)
}
@ -218,7 +231,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
@ -236,8 +249,8 @@ class CloudRenderer(
setYOffset()
for (array in layers) {
array.draw()
for (layer in layers) {
layer.draw()
}
}

View File

@ -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

View File

@ -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<PlaySoundEvent> { world.playSound(it.soundEvent, it.position, it.volume, it.pitch) },
CallbackEventListener.of<ExplosionEvent> { world.playSound(ENTITY_GENERIC_EXPLODE, Vec3(it.position), 4.0f, (1.0f + (random.nextFloat() - random.nextFloat()) * 0.2f) * 0.7f) },
CallbackEventListener.of<ExplosionEvent> { 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())
}
}

View File

@ -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

View File

@ -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)

View File

@ -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])
}
}

View File

@ -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),
@ -265,7 +266,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) {

View File

@ -13,51 +13,99 @@
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(),
-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(),
+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(),
-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(),
))
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<Vec2> {
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),
)
}
private fun textureIndex(index: Int): Int {
return when (index) {
1 -> 2
2 -> 1
3 -> 0
else -> 3
}
}
private fun addVertexX(x: Float, width: Float, positions: Array<Vec2>, 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)
}
}
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)
}
private fun addVertexZ(z: Float, width: Float, positions: Array<Vec2>, index: Boolean) {
for ((position, texture) in order) {
val (x, y) = positions[position]
val texture = if (index) textureIndex(texture) else texture
addVertex(x, y, z, textureIndex(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() {
val width = width()
x(width)
z(width)
}
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)
}

View File

@ -14,40 +14,46 @@
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.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 +61,53 @@ 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.area.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()
}
override fun prepareDrawAsync() {
if (skipAll) return
val center = border.center
val radius = border.area.radius()
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 +120,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
update()
val distance = border.getDistanceTo(context.connection.player.physics.position)
val strength = 1.0f - (distance.toFloat().clamp(0.0f, 100.0f) / 100.0f)
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<WorldBorderRenderer> {
@ -99,7 +137,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()

View File

@ -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)
}

View File

@ -31,7 +31,8 @@ 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.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)
}
}
@ -186,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()
}

View File

@ -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<BlockState?>, light: ByteArray, tints: IntArray?): Boolean {
override fun singleRender(position: Vec3i, offset: FloatArray, mesh: WorldMesh, random: Random, blockState: BlockState, neighbours: Array<BlockState?>, 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

View File

@ -38,7 +38,7 @@ class DoubleChestRenderer(
light: Int,
) : StorageBlockEntityRenderer<StorageBlockEntity>(
blockState,
SkeletalInstance(context, model, blockPosition.toVec3, (blockState.getFacing()).rotatedMatrix),
SkeletalInstance(context, model, (blockPosition - context.camera.offset.offset).toVec3, (blockState.getFacing()).rotatedMatrix),
light,
) {

View File

@ -38,7 +38,7 @@ class SingleChestRenderer(
light: Int,
) : StorageBlockEntityRenderer<StorageBlockEntity>(
blockState,
SkeletalInstance(context, model, blockPosition.toVec3, blockState.getFacing().rotatedMatrix),
SkeletalInstance(context, model, (blockPosition - context.camera.offset.offset).toVec3, blockState.getFacing().rotatedMatrix),
light,
) {

View File

@ -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 }
@ -77,7 +76,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
}
@ -113,7 +116,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
}
@ -139,7 +144,7 @@ class BlockOutlineRenderer(
this.nextMesh = mesh
this.position = target.blockPosition
this.position = offsetPosition
this.state = target.state
this.reload = false
}

View File

@ -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,

View File

@ -76,15 +76,21 @@ class SolidCullSectionPreparer(
val neighbourBlocks: Array<BlockState?> = 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) {

View File

@ -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)
}

View File

@ -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)" }
}
}

View File

@ -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)" }
}
}

View File

@ -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
@ -22,14 +23,13 @@ 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.area = StaticBorderArea(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 (radius=$radius)" }
}
}

View File

@ -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()

View File

@ -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()

View File

@ -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)
);

View File

@ -14,19 +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;
out vec3 finFragmentPosition; // fog
#define DENSITY 2.0f
#define HEIGHT 150.0f
#include "minosoft:uv"
#include "minosoft:color"
@ -34,23 +36,22 @@ out vec3 finFragmentPosition;
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);
finFragmentPosition = position;
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;
}