mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-14 18:05:51 -04:00
physics: add ray casting
This commit is contained in:
parent
504185bee8
commit
49dcfdcc49
@ -288,7 +288,7 @@ abstract class Entity(
|
|||||||
if (hasGravity && !isFlying) {
|
if (hasGravity && !isFlying) {
|
||||||
newVelocity.y -= ProtocolDefinition.GRAVITY * deltaTime
|
newVelocity.y -= ProtocolDefinition.GRAVITY * deltaTime
|
||||||
}
|
}
|
||||||
newVelocity *= 0.25f.pow(deltaTime) // apply
|
newVelocity *= 0.25f.pow(deltaTime) // apply friction
|
||||||
if (newVelocity.length() < 0.05f) {
|
if (newVelocity.length() < 0.05f) {
|
||||||
newVelocity *= 0
|
newVelocity *= 0
|
||||||
}
|
}
|
||||||
|
@ -39,6 +39,7 @@ data class BlockState(
|
|||||||
val tintColor: RGBColor? = null,
|
val tintColor: RGBColor? = null,
|
||||||
val material: Material,
|
val material: Material,
|
||||||
val collisionShape: VoxelShape,
|
val collisionShape: VoxelShape,
|
||||||
|
val occlusionShape: VoxelShape,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
override fun hashCode(): Int {
|
||||||
@ -157,6 +158,14 @@ data class BlockState(
|
|||||||
VoxelShape.EMPTY
|
VoxelShape.EMPTY
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val occlusion = data["occlusion_shapes"]?.let {
|
||||||
|
if (it.isJsonPrimitive) {
|
||||||
|
versionMapping.shapes[it.asInt]
|
||||||
|
} else {
|
||||||
|
VoxelShape(versionMapping.shapes, it)
|
||||||
|
}
|
||||||
|
} ?: VoxelShape.EMPTY
|
||||||
|
|
||||||
owner.renderOverride?.let {
|
owner.renderOverride?.let {
|
||||||
renderers.clear()
|
renderers.clear()
|
||||||
renderers.addAll(it)
|
renderers.addAll(it)
|
||||||
@ -169,6 +178,7 @@ data class BlockState(
|
|||||||
tintColor = tintColor,
|
tintColor = tintColor,
|
||||||
material = material,
|
material = material,
|
||||||
collisionShape = collision,
|
collisionShape = collision,
|
||||||
|
occlusionShape = occlusion,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,10 +20,13 @@ import de.bixilon.minosoft.data.mappings.blocks.BlockState
|
|||||||
import de.bixilon.minosoft.data.world.biome.accessor.BiomeAccessor
|
import de.bixilon.minosoft.data.world.biome.accessor.BiomeAccessor
|
||||||
import de.bixilon.minosoft.data.world.biome.accessor.NullBiomeAccessor
|
import de.bixilon.minosoft.data.world.biome.accessor.NullBiomeAccessor
|
||||||
import de.bixilon.minosoft.data.world.light.WorldLightAccessor
|
import de.bixilon.minosoft.data.world.light.WorldLightAccessor
|
||||||
|
import de.bixilon.minosoft.gui.rendering.util.VecUtil
|
||||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.chunkPosition
|
import de.bixilon.minosoft.gui.rendering.util.VecUtil.chunkPosition
|
||||||
|
import de.bixilon.minosoft.gui.rendering.util.VecUtil.floor
|
||||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.inChunkPosition
|
import de.bixilon.minosoft.gui.rendering.util.VecUtil.inChunkPosition
|
||||||
import de.bixilon.minosoft.util.KUtil.synchronizedMapOf
|
import de.bixilon.minosoft.util.KUtil.synchronizedMapOf
|
||||||
import glm_.vec2.Vec2i
|
import glm_.vec2.Vec2i
|
||||||
|
import glm_.vec3.Vec3
|
||||||
import glm_.vec3.Vec3i
|
import glm_.vec3.Vec3i
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -110,4 +113,30 @@ class World : BiomeAccessor {
|
|||||||
|
|
||||||
return blocks.toMap()
|
return blocks.toMap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class RayCastHit(
|
||||||
|
val position: Vec3,
|
||||||
|
val distance: Float,
|
||||||
|
val i: Int,
|
||||||
|
)
|
||||||
|
|
||||||
|
fun raycast(origin: Vec3, direction: Vec3): RayCastHit {
|
||||||
|
val currentPosition = Vec3(origin)
|
||||||
|
fun getTotalDistance(): Float {
|
||||||
|
return (origin - currentPosition).length()
|
||||||
|
}
|
||||||
|
for (i in 0..MAX_STEPS) {
|
||||||
|
val blockPosition = currentPosition.floor
|
||||||
|
val distance = getBlockState(blockPosition)?.collisionShape?.plus(blockPosition)?.raycast(currentPosition, direction) ?: -1f
|
||||||
|
if (distance >= 0f) {
|
||||||
|
return RayCastHit(currentPosition + direction * distance, getTotalDistance() + distance, i)
|
||||||
|
}
|
||||||
|
currentPosition += direction * (VecUtil.getDistanceToNextIntegerAxis(currentPosition, direction) + 0.001)
|
||||||
|
}
|
||||||
|
return RayCastHit(currentPosition, getTotalDistance(), MAX_STEPS)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val MAX_STEPS = 100
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -103,20 +103,13 @@ class Camera(
|
|||||||
xOffset *= mouseSensitivity
|
xOffset *= mouseSensitivity
|
||||||
yOffset *= mouseSensitivity
|
yOffset *= mouseSensitivity
|
||||||
var yaw = xOffset.toFloat() + playerEntity.rotation.headYaw
|
var yaw = xOffset.toFloat() + playerEntity.rotation.headYaw
|
||||||
var pitch = yOffset.toFloat() + playerEntity.rotation.pitch
|
|
||||||
|
|
||||||
// make sure that when pitch is out of bounds, screen doesn't get flipped
|
|
||||||
if (pitch > 89.9) {
|
|
||||||
pitch = 89.9f
|
|
||||||
} else if (pitch < -89.9) {
|
|
||||||
pitch = -89.9f
|
|
||||||
}
|
|
||||||
if (yaw > 180) {
|
if (yaw > 180) {
|
||||||
yaw -= 360
|
yaw -= 360
|
||||||
} else if (yaw < -180) {
|
} else if (yaw < -180) {
|
||||||
yaw += 360
|
yaw += 360
|
||||||
}
|
}
|
||||||
yaw %= 180
|
yaw %= 180
|
||||||
|
val pitch = glm.clamp(yOffset.toFloat() + playerEntity.rotation.pitch, -89.9f, 89.9f)
|
||||||
setRotation(yaw, pitch)
|
setRotation(yaw, pitch)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,7 +146,7 @@ class Camera(
|
|||||||
movementFront.normalizeAssign() // when moving forwards, do not move down
|
movementFront.normalizeAssign() // when moving forwards, do not move down
|
||||||
}
|
}
|
||||||
if (renderWindow.inputHandler.isKeyBindingDown(KeyBindingsNames.MOVE_SPRINT)) {
|
if (renderWindow.inputHandler.isKeyBindingDown(KeyBindingsNames.MOVE_SPRINT)) {
|
||||||
cameraSpeed *= 5
|
cameraSpeed *= PLAYER_SPRINT_SPEED_MODIFIER
|
||||||
}
|
}
|
||||||
if (ProtocolDefinition.FAST_MOVEMENT) {
|
if (ProtocolDefinition.FAST_MOVEMENT) {
|
||||||
cameraSpeed *= 5
|
cameraSpeed *= 5
|
||||||
@ -183,12 +176,10 @@ class Camera(
|
|||||||
if (renderWindow.inputHandler.isKeyBindingDown(KeyBindingsNames.MOVE_FLY_DOWN)) {
|
if (renderWindow.inputHandler.isKeyBindingDown(KeyBindingsNames.MOVE_FLY_DOWN)) {
|
||||||
deltaMovement -= CAMERA_UP_VEC3 * cameraSpeed
|
deltaMovement -= CAMERA_UP_VEC3 * cameraSpeed
|
||||||
}
|
}
|
||||||
} else {
|
} else if (playerEntity.onGround && renderWindow.inputHandler.isKeyBindingDown(KeyBindingsNames.MOVE_JUMP)) {
|
||||||
if (playerEntity.onGround && renderWindow.inputHandler.isKeyBindingDown(KeyBindingsNames.MOVE_JUMP)) {
|
// TODO: jump delay, correct jump height
|
||||||
// TODO: jump delay, correct jump height
|
playerEntity.velocity.y += 0.75f * ProtocolDefinition.GRAVITY
|
||||||
playerEntity.velocity.y += 0.75f * ProtocolDefinition.GRAVITY
|
playerEntity.onGround = false
|
||||||
playerEntity.onGround = false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (deltaMovement != VecUtil.EMPTY_VEC3) {
|
if (deltaMovement != VecUtil.EMPTY_VEC3) {
|
||||||
playerEntity.move(deltaMovement, false)
|
playerEntity.move(deltaMovement, false)
|
||||||
@ -227,7 +218,7 @@ class Camera(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun positionChangeCallback() {
|
private fun positionChangeCallback() {
|
||||||
blockPosition = (cameraPosition - Vec3(0, PLAYER_HEIGHT, 0)).blockPosition
|
blockPosition = playerEntity.position.blockPosition
|
||||||
currentBiome = connection.world.getBiome(blockPosition)
|
currentBiome = connection.world.getBiome(blockPosition)
|
||||||
chunkPosition = blockPosition.chunkPosition
|
chunkPosition = blockPosition.chunkPosition
|
||||||
sectionHeight = blockPosition.sectionHeight
|
sectionHeight = blockPosition.sectionHeight
|
||||||
@ -258,7 +249,7 @@ class Camera(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun getAbsoluteCameraPosition(): Vec3 {
|
private fun getAbsoluteCameraPosition(): Vec3 {
|
||||||
return playerEntity.position + Vec3(0, PLAYER_HEIGHT, 0)
|
return playerEntity.position + Vec3(0, PLAYER_EYE_HEIGHT, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun checkPosition() {
|
fun checkPosition() {
|
||||||
@ -307,12 +298,13 @@ class Camera(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun setPosition(position: Vec3) {
|
fun setPosition(position: Vec3) {
|
||||||
cameraPosition = (position + Vec3(0, PLAYER_HEIGHT, 0))
|
|
||||||
playerEntity.position = position
|
playerEntity.position = position
|
||||||
|
cameraPosition = getAbsoluteCameraPosition()
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val CAMERA_UP_VEC3 = Vec3(0.0f, 1.0f, 0.0f)
|
private val CAMERA_UP_VEC3 = Vec3(0.0f, 1.0f, 0.0f)
|
||||||
private const val PLAYER_HEIGHT = 1.3 // player is 1.8 blocks high, the camera is normally at 0.5. 1.8 - 0.5 = 1.13
|
private const val PLAYER_EYE_HEIGHT = 1.3 // player is 1.8 blocks high, the camera is normally at 0.5. 1.8 - 0.5 = 1.13
|
||||||
|
private const val PLAYER_SPRINT_SPEED_MODIFIER = 1.30000001192092896
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ import de.bixilon.minosoft.gui.rendering.util.VecUtil
|
|||||||
import glm_.vec3.Vec3
|
import glm_.vec3.Vec3
|
||||||
import glm_.vec3.Vec3i
|
import glm_.vec3.Vec3i
|
||||||
|
|
||||||
class VoxelShape(val aabbs: MutableList<AABB> = mutableListOf()) {
|
class VoxelShape(private val aabbs: MutableList<AABB> = mutableListOf()) {
|
||||||
|
|
||||||
constructor(data: JsonElement, aabbs: List<AABB>) : this() {
|
constructor(data: JsonElement, aabbs: List<AABB>) : this() {
|
||||||
when (data) {
|
when (data) {
|
||||||
@ -24,6 +24,20 @@ class VoxelShape(val aabbs: MutableList<AABB> = mutableListOf()) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// somehow, the kotlin compiler gives an error if both constructors have the "same" signature JsonElement, List<>
|
||||||
|
constructor(voxelShapes: List<VoxelShape>, data: JsonElement) : this() {
|
||||||
|
when (data) {
|
||||||
|
is JsonArray -> {
|
||||||
|
for (index in data) {
|
||||||
|
this.aabbs.addAll(voxelShapes[index.asInt].aabbs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is JsonPrimitive -> {
|
||||||
|
this.aabbs.addAll(voxelShapes[data.asInt].aabbs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun intersect(other: AABB): Boolean {
|
fun intersect(other: AABB): Boolean {
|
||||||
for (aabb in aabbs) {
|
for (aabb in aabbs) {
|
||||||
if (aabb.intersect(other)) {
|
if (aabb.intersect(other)) {
|
||||||
@ -63,6 +77,19 @@ class VoxelShape(val aabbs: MutableList<AABB> = mutableListOf()) {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun raycast(position: Vec3, direction: Vec3): Float {
|
||||||
|
for (aabb in aabbs) {
|
||||||
|
if (position in aabb) {
|
||||||
|
return 0f
|
||||||
|
}
|
||||||
|
val current = aabb.raycast(position, direction)
|
||||||
|
if (current >= -0.1f) {
|
||||||
|
return 0f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1f
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val EMPTY = VoxelShape()
|
val EMPTY = VoxelShape()
|
||||||
val FULL = VoxelShape(mutableListOf(AABB(VecUtil.EMPTY_VEC3, VecUtil.ONES_VEC3)))
|
val FULL = VoxelShape(mutableListOf(AABB(VecUtil.EMPTY_VEC3, VecUtil.ONES_VEC3)))
|
||||||
|
@ -5,12 +5,15 @@ import com.google.gson.JsonElement
|
|||||||
import com.google.gson.JsonObject
|
import com.google.gson.JsonObject
|
||||||
import de.bixilon.minosoft.data.Axes
|
import de.bixilon.minosoft.data.Axes
|
||||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil
|
import de.bixilon.minosoft.gui.rendering.util.VecUtil
|
||||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.plus
|
import de.bixilon.minosoft.gui.rendering.util.VecUtil.choose
|
||||||
|
import de.bixilon.minosoft.gui.rendering.util.VecUtil.max
|
||||||
|
import de.bixilon.minosoft.gui.rendering.util.VecUtil.min
|
||||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.toVec3
|
import de.bixilon.minosoft.gui.rendering.util.VecUtil.toVec3
|
||||||
import glm_.Java.Companion.glm
|
import glm_.Java.Companion.glm
|
||||||
import glm_.vec3.Vec3
|
import glm_.vec3.Vec3
|
||||||
import glm_.vec3.Vec3i
|
import glm_.vec3.Vec3i
|
||||||
|
|
||||||
|
|
||||||
class AABB {
|
class AABB {
|
||||||
val min: Vec3
|
val min: Vec3
|
||||||
val max: Vec3
|
val max: Vec3
|
||||||
@ -43,7 +46,7 @@ class AABB {
|
|||||||
}
|
}
|
||||||
|
|
||||||
operator fun plus(vec3i: Vec3i): AABB {
|
operator fun plus(vec3i: Vec3i): AABB {
|
||||||
return AABB(vec3i plus min, vec3i plus max)
|
return plus(Vec3(vec3i))
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun plus(other: AABB): AABB {
|
operator fun plus(other: AABB): AABB {
|
||||||
@ -147,6 +150,36 @@ class AABB {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun raycast(position: Vec3, direction: Vec3): Float {
|
||||||
|
val tMins = getLengthMultipliers(position, direction, min)
|
||||||
|
val tMaxs = getLengthMultipliers(position, direction, max)
|
||||||
|
val tMin = tMins.max
|
||||||
|
val tMax = tMaxs.min
|
||||||
|
if (tMax < 0 || tMin > tMax) {
|
||||||
|
return -1f
|
||||||
|
}
|
||||||
|
return tMin
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getLengthMultipliers(position: Vec3, direction: Vec3, target: Vec3): Vec3 {
|
||||||
|
return Vec3(
|
||||||
|
getLengthMultiplier(position, direction, target, Axes.X),
|
||||||
|
getLengthMultiplier(position, direction, target, Axes.Y),
|
||||||
|
getLengthMultiplier(position, direction, target, Axes.Z),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getLengthMultiplier(position: Vec3, direction: Vec3, target: Vec3, axis: Axes): Float {
|
||||||
|
return (position.choose(axis) - target.choose(axis)) / direction.choose(axis)
|
||||||
|
}
|
||||||
|
|
||||||
|
operator fun contains(position: Vec3): Boolean {
|
||||||
|
return (
|
||||||
|
position.x in min.x..max.x &&
|
||||||
|
position.y in min.y..max.y &&
|
||||||
|
position.z in min.z..max.z )
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private fun getRange(min: Float, max: Float): IntRange {
|
private fun getRange(min: Float, max: Float): IntRange {
|
||||||
return IntRange(glm.floor(min).toInt(), glm.ceil(max).toInt())
|
return IntRange(glm.floor(min).toInt(), glm.ceil(max).toInt())
|
||||||
|
@ -20,6 +20,7 @@ import de.bixilon.minosoft.gui.rendering.hud.HUDRenderBuilder
|
|||||||
import de.bixilon.minosoft.gui.rendering.hud.HUDRenderer
|
import de.bixilon.minosoft.gui.rendering.hud.HUDRenderer
|
||||||
import de.bixilon.minosoft.gui.rendering.hud.nodes.properties.NodeAlignment
|
import de.bixilon.minosoft.gui.rendering.hud.nodes.properties.NodeAlignment
|
||||||
import de.bixilon.minosoft.gui.rendering.modding.events.ScreenResizeEvent
|
import de.bixilon.minosoft.gui.rendering.modding.events.ScreenResizeEvent
|
||||||
|
import de.bixilon.minosoft.gui.rendering.util.VecUtil.floor
|
||||||
import de.bixilon.minosoft.modding.event.CallbackEventInvoker
|
import de.bixilon.minosoft.modding.event.CallbackEventInvoker
|
||||||
import de.bixilon.minosoft.modding.loading.ModLoader
|
import de.bixilon.minosoft.modding.loading.ModLoader
|
||||||
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
||||||
@ -67,6 +68,9 @@ class HUDSystemDebugNode(hudRenderer: HUDRenderer) : DebugScreenNode(hudRenderer
|
|||||||
text("Mods: ${ModLoader.MOD_MAP.size} active, ${hudRenderer.connection.eventListenerSize} listeners")
|
text("Mods: ${ModLoader.MOD_MAP.size} active, ${hudRenderer.connection.eventListenerSize} listeners")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val targetPosition = text("TBA")
|
||||||
|
private val targetBlockState = text("TBA")
|
||||||
|
|
||||||
override fun init() {
|
override fun init() {
|
||||||
gpuText.sText = "GPU: " + (glGetString(GL_RENDERER) ?: "unknown")
|
gpuText.sText = "GPU: " + (glGetString(GL_RENDERER) ?: "unknown")
|
||||||
gpuVersionText.sText = "Version: " + (glGetString(GL_VERSION) ?: "unknown")
|
gpuVersionText.sText = "Version: " + (glGetString(GL_VERSION) ?: "unknown")
|
||||||
@ -82,7 +86,18 @@ class HUDSystemDebugNode(hudRenderer: HUDRenderer) : DebugScreenNode(hudRenderer
|
|||||||
}
|
}
|
||||||
memoryText.sText = "Memory: ${getUsedMemoryPercent()}% ${getFormattedUsedMemory()}/${SystemInformation.MAX_MEMORY_TEXT}"
|
memoryText.sText = "Memory: ${getUsedMemoryPercent()}% ${getFormattedUsedMemory()}/${SystemInformation.MAX_MEMORY_TEXT}"
|
||||||
allocatedMemoryText.sText = "Allocated: ${getAllocatedMemoryPercent()}% ${getFormattedAllocatedMemory()}"
|
allocatedMemoryText.sText = "Allocated: ${getAllocatedMemoryPercent()}% ${getFormattedAllocatedMemory()}"
|
||||||
|
val rayCastHit = hudRenderer.connection.renderer?.renderWindow?.inputHandler?.camera?.let {
|
||||||
|
hudRenderer.connection.world.raycast(it.cameraPosition, it.cameraFront)
|
||||||
|
}
|
||||||
|
val position = rayCastHit?.position?.floor
|
||||||
|
val blockState = position?.let { hudRenderer.connection.world.getBlockState(it) }
|
||||||
|
if (rayCastHit?.distance ?: Float.MAX_VALUE < 5) {
|
||||||
|
targetPosition.sText = "looking at $position"
|
||||||
|
targetBlockState.sText = blockState.toString()
|
||||||
|
} else {
|
||||||
|
targetPosition.sText = "No blocks in reach!"
|
||||||
|
targetBlockState.sText = ""
|
||||||
|
}
|
||||||
|
|
||||||
lastPrepareTime = System.currentTimeMillis()
|
lastPrepareTime = System.currentTimeMillis()
|
||||||
}
|
}
|
||||||
|
@ -24,8 +24,10 @@ import de.bixilon.minosoft.data.mappings.blocks.RandomOffsetTypes
|
|||||||
import de.bixilon.minosoft.gui.rendering.chunk.models.loading.BlockModelElement
|
import de.bixilon.minosoft.gui.rendering.chunk.models.loading.BlockModelElement
|
||||||
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
||||||
import glm_.func.common.clamp
|
import glm_.func.common.clamp
|
||||||
|
import glm_.func.common.floor
|
||||||
import glm_.func.cos
|
import glm_.func.cos
|
||||||
import glm_.func.sin
|
import glm_.func.sin
|
||||||
|
import glm_.glm
|
||||||
import glm_.vec2.Vec2
|
import glm_.vec2.Vec2
|
||||||
import glm_.vec2.Vec2i
|
import glm_.vec2.Vec2i
|
||||||
import glm_.vec3.Vec3
|
import glm_.vec3.Vec3
|
||||||
@ -212,4 +214,43 @@ object VecUtil {
|
|||||||
hash = hash * hash * 42317861L + hash * 11L
|
hash = hash * hash * 42317861L + hash * 11L
|
||||||
return hash shr 16
|
return hash shr 16
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getDistanceToNextIntegerAxis(position: Vec3, direction: Vec3): Float {
|
||||||
|
val directionXDistance = (direction * getLengthMultiplier(direction, position, Axes.X)).length()
|
||||||
|
val directionYDistance = (direction * getLengthMultiplier(direction, position, Axes.Y)).length()
|
||||||
|
val directionZDistance = (direction * getLengthMultiplier(direction, position, Axes.Z)).length()
|
||||||
|
return glm.min(directionXDistance, directionYDistance, directionZDistance)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getLengthMultiplier(direction: Vec3, position: Vec3, axis: Axes): Float {
|
||||||
|
return (getTarget(direction, position, axis) - position.choose(axis)) / direction.choose(axis)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getTarget(direction: Vec3, position: Vec3, axis: Axes): Int {
|
||||||
|
return if (direction.choose(axis) > 0) {
|
||||||
|
position.floor.choose(axis) + 1
|
||||||
|
} else {
|
||||||
|
position.floor.choose(axis)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Vec3.choose(axis: Axes): Float {
|
||||||
|
return Axes.choose(axis, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
val Vec3.min: Float get() = glm.min(this.x, this.y, this.z)
|
||||||
|
|
||||||
|
val Vec3.max: Float get() = glm.max(this.x, this.y, this.z)
|
||||||
|
|
||||||
|
val Vec3.signs: Vec3 get() {
|
||||||
|
return Vec3(glm.sign(this.x), glm.sign(this.y), glm.sign(this.z))
|
||||||
|
}
|
||||||
|
|
||||||
|
val Vec3.floor: Vec3i get() {
|
||||||
|
return Vec3i(this.x.floor, this.y.floor, this.z.floor)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Vec3i.choose(axis: Axes): Int {
|
||||||
|
return Axes.choose(axis, this)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
package de.bixilon.minosoft.util
|
package de.bixilon.minosoft.util
|
||||||
|
|
||||||
|
import glm_.glm
|
||||||
import glm_.vec2.Vec2i
|
import glm_.vec2.Vec2i
|
||||||
import kotlin.math.floor
|
import kotlin.math.floor
|
||||||
|
|
||||||
@ -73,6 +74,8 @@ object MMath {
|
|||||||
return ((value * 10).toInt() + 5) / 10
|
return ((value * 10).toInt() + 5) / 10
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val Float.round10: Float get() = (this * 10).toInt().toFloat() / 10f
|
||||||
|
|
||||||
fun round10Up(value: Float): Int {
|
fun round10Up(value: Float): Int {
|
||||||
val intValue = value.toInt()
|
val intValue = value.toInt()
|
||||||
val rest = value / intValue
|
val rest = value / intValue
|
||||||
@ -89,4 +92,12 @@ object MMath {
|
|||||||
fun fractionalPart(value: Double): Double {
|
fun fractionalPart(value: Double): Double {
|
||||||
return value - floor(value)
|
return value - floor(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun linearInterpolate(delta: Float, start: Float, end: Float): Float {
|
||||||
|
return start + delta * (end - start)
|
||||||
|
}
|
||||||
|
|
||||||
|
val Float.floor: Float get() = glm.floor(this)
|
||||||
|
|
||||||
|
val Float.fractionalPart: Float get() = this - floor
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user