mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-17 19:35:00 -04:00
wip: fluid rendering
This commit is contained in:
parent
5fc6b606bb
commit
f2247e7fa3
@ -134,7 +134,7 @@ Not compatible (yet)
|
||||
1. Install Maven and java 11+ (On Ubuntu based distributions: `sudo apt install maven openjdk-11-jdk`). For Windows users, download and install java from oracle or openjdk. Also download maven and follow along
|
||||
2. Clone this repository (`git clone https://gitlab.bixilon.de/bixilon/minosoft.git`)
|
||||
3. Change directory (`cd minosoft`)
|
||||
4. Optional: Checkout the branch of the feature you want to test (`git checkout <branch>`)
|
||||
4. Optional: Checkout a current feature branch (Warning: might be unstable; might not even build) (`git checkout <branch>`)
|
||||
5. Build and run Minosoft with `mvn clean verify exec:java`. If any errors occur, feel free to open an issue. In this early stage it might be helpful to delete the config file
|
||||
6. (Optional) Build a fat jar with `mvn package`. You'll find the jar with all dependencies in `target/`. Then you don't need to recompile everytime
|
||||
|
||||
|
@ -1,24 +0,0 @@
|
||||
/*
|
||||
* Minosoft
|
||||
* Copyright (C) 2021 Moritz Zwerger
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||
*/
|
||||
|
||||
package de.bixilon.minosoft.data.direction
|
||||
|
||||
import glm_.vec3.Vec3
|
||||
import glm_.vec3.Vec3d
|
||||
import glm_.vec3.Vec3i
|
||||
|
||||
interface AbstractDirection {
|
||||
val vector: Vec3i
|
||||
val vectorf: Vec3
|
||||
val vectord: Vec3d
|
||||
}
|
@ -27,8 +27,8 @@ import kotlin.math.abs
|
||||
|
||||
enum class Directions(
|
||||
val horizontalId: Int,
|
||||
override val vector: Vec3i,
|
||||
) : AbstractDirection {
|
||||
val vector: Vec3i,
|
||||
) {
|
||||
DOWN(-1, Vec3i(0, -1, 0)),
|
||||
UP(-1, Vec3i(0, 1, 0)),
|
||||
NORTH(2, Vec3i(0, 0, -1)),
|
||||
@ -38,8 +38,8 @@ enum class Directions(
|
||||
|
||||
val negative = ordinal % 2 == 0
|
||||
|
||||
override val vectorf = Vec3(vector)
|
||||
override val vectord = Vec3d(vector)
|
||||
val vectorf = Vec3(vector)
|
||||
val vectord = Vec3d(vector)
|
||||
|
||||
val axis: Axes get() = Axes[this] // ToDo
|
||||
val debugColor = ChatColors[ordinal]
|
||||
|
@ -1,33 +0,0 @@
|
||||
/*
|
||||
* Minosoft
|
||||
* Copyright (C) 2021 Moritz Zwerger
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||
*/
|
||||
|
||||
package de.bixilon.minosoft.data.direction
|
||||
|
||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.plus
|
||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.toVec3
|
||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.toVec3d
|
||||
import glm_.vec3.Vec3
|
||||
import glm_.vec3.Vec3d
|
||||
import glm_.vec3.Vec3i
|
||||
|
||||
class FakeDirection(override val vector: Vec3i) : AbstractDirection {
|
||||
override val vectorf: Vec3 = vector.toVec3
|
||||
override val vectord: Vec3d = vector.toVec3d
|
||||
|
||||
companion object {
|
||||
val NORTH_WEST = FakeDirection(Directions.NORTH + Directions.WEST)
|
||||
val NORTH_EAST = FakeDirection(Directions.NORTH + Directions.EAST)
|
||||
val SOUTH_WEST = FakeDirection(Directions.SOUTH + Directions.WEST)
|
||||
val SOUTH_EAST = FakeDirection(Directions.SOUTH + Directions.EAST)
|
||||
}
|
||||
}
|
@ -16,10 +16,11 @@ package de.bixilon.minosoft.data.registries.blocks.types
|
||||
import de.bixilon.minosoft.data.registries.ResourceLocation
|
||||
import de.bixilon.minosoft.data.registries.blocks.BlockFactory
|
||||
import de.bixilon.minosoft.data.registries.fluid.DefaultFluids
|
||||
import de.bixilon.minosoft.data.registries.fluid.Fluid
|
||||
import de.bixilon.minosoft.data.registries.registries.Registries
|
||||
|
||||
open class KelpBlock(resourceLocation: ResourceLocation, registries: Registries, data: Map<String, Any>) : Block(resourceLocation, registries, data), FluidFillable {
|
||||
override val fluid: ResourceLocation = DefaultFluids.WATER
|
||||
override val fluid: Fluid = registries.fluidRegistry[DefaultFluids.WATER]!!
|
||||
|
||||
companion object : BlockFactory<KelpBlock> {
|
||||
|
||||
|
@ -15,8 +15,8 @@ package de.bixilon.minosoft.data.registries.fluid
|
||||
import de.bixilon.minosoft.data.direction.Directions
|
||||
import de.bixilon.minosoft.data.registries.ResourceLocation
|
||||
import de.bixilon.minosoft.data.registries.blocks.BlockState
|
||||
import de.bixilon.minosoft.data.registries.blocks.types.FluidBlock
|
||||
import de.bixilon.minosoft.data.registries.registries.Registries
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.AbstractTexture
|
||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.plus
|
||||
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3dUtil.EMPTY
|
||||
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
|
||||
@ -28,30 +28,26 @@ abstract class FlowableFluid(
|
||||
registries: Registries,
|
||||
data: Map<String, Any>,
|
||||
) : Fluid(resourceLocation, registries, data) {
|
||||
open val flowingTexture: ResourceLocation? = null
|
||||
abstract val flowingTextureName: ResourceLocation
|
||||
var flowingTexture: AbstractTexture? = null
|
||||
|
||||
|
||||
abstract fun getVelocityMultiplier(connection: PlayConnection, blockState: BlockState, blockPosition: Vec3i): Double
|
||||
|
||||
open fun getVelocity(connection: PlayConnection, blockState: BlockState, blockPosition: Vec3i): Vec3d {
|
||||
if (blockState.block !is FluidBlock || !blockState.block.fluid.matches(this)) {
|
||||
if (!this.matches(blockState)) {
|
||||
return Vec3d.EMPTY
|
||||
}
|
||||
val fluidHeight = getHeight(blockState)
|
||||
|
||||
val velocity = Vec3d.EMPTY
|
||||
|
||||
|
||||
for (direction in Directions.SIDES) {
|
||||
val neighbourBlockState = connection.world[blockPosition + direction] ?: continue
|
||||
if (neighbourBlockState.block !is FluidBlock) {
|
||||
if (!this.matches(neighbourBlockState)) {
|
||||
continue
|
||||
}
|
||||
val fluid = neighbourBlockState.block.fluid
|
||||
if (!matches(fluid)) {
|
||||
continue
|
||||
}
|
||||
val height = neighbourBlockState.block.fluid.getHeight(neighbourBlockState)
|
||||
val height = getHeight(neighbourBlockState)
|
||||
|
||||
var heightDifference = 0.0f
|
||||
|
||||
@ -64,11 +60,14 @@ abstract class FlowableFluid(
|
||||
if (heightDifference != 0.0f) {
|
||||
velocity += (direction.vectord * heightDifference)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ToDo: Falling fluid
|
||||
|
||||
if (velocity.x == 0.0 && velocity.y == 0.0 && velocity.z == 0.0) {
|
||||
return velocity
|
||||
}
|
||||
|
||||
return velocity.normalize()
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,8 @@ import de.bixilon.minosoft.data.registries.particle.ParticleType
|
||||
import de.bixilon.minosoft.data.registries.registries.Registries
|
||||
import de.bixilon.minosoft.data.registries.registries.registry.RegistryItem
|
||||
import de.bixilon.minosoft.data.registries.registries.registry.ResourceLocationDeserializer
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.AbstractTexture
|
||||
import de.bixilon.minosoft.gui.rendering.tint.TintProvider
|
||||
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
|
||||
import de.bixilon.minosoft.util.KUtil.nullCast
|
||||
import de.bixilon.minosoft.util.KUtil.unsafeCast
|
||||
@ -36,7 +38,9 @@ open class Fluid(
|
||||
registries: Registries,
|
||||
data: Map<String, Any>,
|
||||
) : RegistryItem() {
|
||||
open val stillTexture: ResourceLocation? = null
|
||||
open val tintProvider: TintProvider? = null
|
||||
open val stillTextureName: ResourceLocation? = null
|
||||
var stillTexture: AbstractTexture? = null
|
||||
val dripParticle: ParticleType? = null
|
||||
val bucketItem: Item? = null
|
||||
|
||||
|
@ -42,8 +42,8 @@ class LavaFluid(
|
||||
data: Map<String, Any>,
|
||||
) : FlowableFluid(resourceLocation, registries, data) {
|
||||
private val lavaParticleType: ParticleType? = null
|
||||
override val stillTexture: ResourceLocation = "minecraft:block/lava_still".toResourceLocation()
|
||||
override val flowingTexture: ResourceLocation = "minecraft:block/lava_flow".toResourceLocation()
|
||||
override val stillTextureName: ResourceLocation = "minecraft:block/lava_still".toResourceLocation()
|
||||
override val flowingTextureName: ResourceLocation = "minecraft:block/lava_flow".toResourceLocation()
|
||||
|
||||
init {
|
||||
this::lavaParticleType.inject(LavaParticle)
|
||||
|
@ -28,6 +28,8 @@ import de.bixilon.minosoft.data.registries.fluid.Fluid
|
||||
import de.bixilon.minosoft.data.registries.fluid.FluidFactory
|
||||
import de.bixilon.minosoft.data.registries.registries.Registries
|
||||
import de.bixilon.minosoft.gui.rendering.particle.types.render.texture.simple.water.UnderwaterParticle
|
||||
import de.bixilon.minosoft.gui.rendering.tint.TintProvider
|
||||
import de.bixilon.minosoft.gui.rendering.tint.WaterTintProvider
|
||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.plus
|
||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.toVec3d
|
||||
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
|
||||
@ -46,8 +48,9 @@ class WaterFluid(
|
||||
) : FlowableFluid(resourceLocation, registries, data) {
|
||||
private val depthStriderEnchantment: Enchantment? = null
|
||||
private val dolphinsGraceStatusEffect: StatusEffect? = null
|
||||
override val stillTexture: ResourceLocation = "minecraft:block/water_still".toResourceLocation()
|
||||
override val flowingTexture: ResourceLocation = "minecraft:block/water_flow".toResourceLocation()
|
||||
override val stillTextureName: ResourceLocation = "minecraft:block/water_still".toResourceLocation()
|
||||
override val flowingTextureName: ResourceLocation = "minecraft:block/water_flow".toResourceLocation()
|
||||
override val tintProvider: TintProvider = WaterTintProvider
|
||||
|
||||
|
||||
init {
|
||||
|
@ -171,6 +171,7 @@ open class Registry<T : RegistryItem>(
|
||||
this.valueIdMap.putAll(valueIdMap)
|
||||
}
|
||||
|
||||
@Deprecated("Too slow, should be used with a ToDo: RegistryIterator")
|
||||
fun forEachItem(lambda: (T) -> Unit) {
|
||||
for (item in resourceLocationMap.values) {
|
||||
lambda(item)
|
||||
|
@ -19,6 +19,7 @@ import de.bixilon.minosoft.data.text.RGBColor
|
||||
import de.bixilon.minosoft.gui.rendering.models.FaceProperties
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureTransparencies
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.AbstractTexture
|
||||
import de.bixilon.minosoft.gui.rendering.textures.TextureUtil.getMesh
|
||||
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.get
|
||||
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.rgb
|
||||
import de.bixilon.minosoft.gui.rendering.world.mesh.SingleWorldMesh
|
||||
@ -41,11 +42,7 @@ class BakedFace(
|
||||
get() = texture.transparency // ToDo
|
||||
|
||||
fun singleRender(position: FloatArray, mesh: WorldMesh, light: Int, ambientLight: FloatArray, tint: Int) {
|
||||
val meshToUse = when (texture.transparency) {
|
||||
TextureTransparencies.OPAQUE -> mesh.opaqueMesh
|
||||
TextureTransparencies.TRANSLUCENT -> mesh.translucentMesh
|
||||
TextureTransparencies.TRANSPARENT -> mesh.transparentMesh
|
||||
}!!
|
||||
val meshToUse = transparency.getMesh(mesh)
|
||||
// ToDo: Ambient light
|
||||
val color = Vec3(shade)
|
||||
if (tint >= 0) {
|
||||
|
@ -14,6 +14,9 @@
|
||||
package de.bixilon.minosoft.gui.rendering.textures
|
||||
|
||||
import de.bixilon.minosoft.data.registries.ResourceLocation
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureTransparencies
|
||||
import de.bixilon.minosoft.gui.rendering.world.mesh.SingleWorldMesh
|
||||
import de.bixilon.minosoft.gui.rendering.world.mesh.WorldMesh
|
||||
import de.bixilon.minosoft.util.KUtil.toResourceLocation
|
||||
|
||||
object TextureUtil {
|
||||
@ -32,4 +35,12 @@ object TextureUtil {
|
||||
|
||||
return "$namespace:$path".toResourceLocation()
|
||||
}
|
||||
|
||||
fun TextureTransparencies.getMesh(mesh: WorldMesh): SingleWorldMesh {
|
||||
return when (this) {
|
||||
TextureTransparencies.OPAQUE -> mesh.opaqueMesh
|
||||
TextureTransparencies.TRANSLUCENT -> mesh.translucentMesh
|
||||
TextureTransparencies.TRANSPARENT -> mesh.transparentMesh
|
||||
}!!
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ import de.bixilon.minosoft.data.registries.blocks.BlockState
|
||||
import de.bixilon.minosoft.data.registries.blocks.MinecraftBlocks
|
||||
import de.bixilon.minosoft.data.registries.blocks.properties.BlockProperties
|
||||
import de.bixilon.minosoft.data.registries.blocks.properties.Halves
|
||||
import de.bixilon.minosoft.data.registries.fluid.Fluid
|
||||
import de.bixilon.minosoft.data.text.RGBColor
|
||||
import de.bixilon.minosoft.data.text.RGBColor.Companion.asRGBColor
|
||||
import de.bixilon.minosoft.data.world.Chunk
|
||||
@ -43,8 +44,7 @@ class TintManager(private val connection: PlayConnection) {
|
||||
}
|
||||
}
|
||||
|
||||
fun getAverageTint(chunk: Chunk, neighbours: Array<Chunk>, blockState: BlockState, x: Int, y: Int, z: Int): IntArray? {
|
||||
val tintProvider = blockState.block.tintProvider ?: return null
|
||||
private fun getAverageTint(chunk: Chunk, neighbours: Array<Chunk>, blockState: BlockState, tintProvider: TintProvider, x: Int, y: Int, z: Int): IntArray? {
|
||||
val inChunkX = x and 0x0F
|
||||
val inChunkZ = z and 0x0F
|
||||
val biome = chunk.getBiome(inChunkX, y, inChunkZ)
|
||||
@ -56,6 +56,14 @@ class TintManager(private val connection: PlayConnection) {
|
||||
return tints
|
||||
}
|
||||
|
||||
fun getAverageTint(chunk: Chunk, neighbours: Array<Chunk>, blockState: BlockState, x: Int, y: Int, z: Int): IntArray? {
|
||||
return getAverageTint(chunk, neighbours, blockState, blockState.block.tintProvider ?: return null, x, y, z)
|
||||
}
|
||||
|
||||
fun getAverageTint(chunk: Chunk, neighbours: Array<Chunk>, blockState: BlockState, fluid: Fluid, x: Int, y: Int, z: Int): IntArray? {
|
||||
return getAverageTint(chunk, neighbours, blockState, fluid.tintProvider ?: return null, x, y, z)
|
||||
}
|
||||
|
||||
fun getTint(blockState: BlockState, biome: Biome?, x: Int, y: Int, z: Int): IntArray? {
|
||||
val tintProvider = blockState.block.tintProvider ?: return null
|
||||
connection.world.getBiome(x, y, z)
|
||||
|
@ -15,7 +15,6 @@ package de.bixilon.minosoft.gui.rendering.util
|
||||
|
||||
import de.bixilon.minosoft.Minosoft
|
||||
import de.bixilon.minosoft.data.Axes
|
||||
import de.bixilon.minosoft.data.direction.AbstractDirection
|
||||
import de.bixilon.minosoft.data.direction.Directions
|
||||
import de.bixilon.minosoft.data.registries.AABB
|
||||
import de.bixilon.minosoft.data.registries.blocks.RandomOffsetTypes
|
||||
@ -208,7 +207,7 @@ object VecUtil {
|
||||
return Vec3i((x + vec2.x), y, (z + vec2.y))
|
||||
}
|
||||
|
||||
infix operator fun Vec3i.plus(direction: AbstractDirection?): Vec3i {
|
||||
infix operator fun Vec3i.plus(direction: Directions?): Vec3i {
|
||||
return this + direction?.vector
|
||||
}
|
||||
|
||||
@ -220,7 +219,7 @@ object VecUtil {
|
||||
return Vec2i(x + vec3.x, y + vec3.z)
|
||||
}
|
||||
|
||||
infix operator fun Vec2i.plus(direction: AbstractDirection): Vec2i {
|
||||
infix operator fun Vec2i.plus(direction: Directions): Vec2i {
|
||||
return this + direction.vector
|
||||
}
|
||||
|
||||
@ -409,7 +408,7 @@ object VecUtil {
|
||||
}
|
||||
}
|
||||
|
||||
operator fun AbstractDirection.plus(direction: AbstractDirection): Vec3i {
|
||||
operator fun Directions.plus(direction: Directions): Vec3i {
|
||||
return this.vector + direction.vector
|
||||
}
|
||||
|
||||
|
@ -42,7 +42,7 @@ object Vec3Util {
|
||||
val Vec3.rgb: Int
|
||||
get() = ((r * RGBColor.COLOR_FLOAT_DIVIDER).toInt() shl 16) or ((g * RGBColor.COLOR_FLOAT_DIVIDER).toInt() shl 8) or (b * RGBColor.COLOR_FLOAT_DIVIDER).toInt()
|
||||
|
||||
fun rotateAssign(x: Float, y: Float, sin: Float, cos: Float, rescale: Boolean): Vec2 {
|
||||
fun rotate(x: Float, y: Float, sin: Float, cos: Float, rescale: Boolean): Vec2 {
|
||||
val result = Vec2(x * cos - y * sin, x * sin + y * cos)
|
||||
if (rescale) {
|
||||
return result / cos
|
||||
@ -56,9 +56,9 @@ object Vec3Util {
|
||||
return
|
||||
}
|
||||
when (axis) {
|
||||
Axes.X -> this.yz = rotateAssign(this.y, this.z, angle.sin, angle.cos, rescale)
|
||||
Axes.Y -> this.xz = rotateAssign(this.x, this.z, angle.sin, angle.cos, rescale)
|
||||
Axes.Z -> this.xy = rotateAssign(this.x, this.y, angle.sin, angle.cos, rescale)
|
||||
Axes.X -> this.yz = rotate(this.y, this.z, angle.sin, angle.cos, rescale)
|
||||
Axes.Y -> this.xz = rotate(this.x, this.z, angle.sin, angle.cos, rescale)
|
||||
Axes.Z -> this.xy = rotate(this.x, this.y, angle.sin, angle.cos, rescale)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,7 @@ import de.bixilon.minosoft.data.assets.AssetsUtil
|
||||
import de.bixilon.minosoft.data.assets.Resources
|
||||
import de.bixilon.minosoft.data.direction.Directions
|
||||
import de.bixilon.minosoft.data.registries.ResourceLocation
|
||||
import de.bixilon.minosoft.data.registries.fluid.FlowableFluid
|
||||
import de.bixilon.minosoft.data.world.Chunk
|
||||
import de.bixilon.minosoft.data.world.ChunkSection
|
||||
import de.bixilon.minosoft.data.world.World
|
||||
@ -35,6 +36,7 @@ import de.bixilon.minosoft.gui.rendering.system.base.RenderingCapabilities
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.phases.OpaqueDrawable
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.phases.TranslucentDrawable
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.phases.TransparentDrawable
|
||||
import de.bixilon.minosoft.gui.rendering.textures.TextureUtil.texture
|
||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.chunkPosition
|
||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.empty
|
||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.inChunkSectionPosition
|
||||
@ -131,6 +133,13 @@ class WorldRenderer(
|
||||
val zip = ZipInputStream(GZIPInputStream(FileInputStream(AssetsUtil.getAssetDiskPath(asset.clientJarHash!!, true))))
|
||||
val modelLoader = ModelLoader(zip, renderWindow)
|
||||
modelLoader.load()
|
||||
|
||||
connection.registries.fluidRegistry.forEachItem {
|
||||
if (it is FlowableFluid) {
|
||||
it.flowingTexture = renderWindow.textureManager.staticTextures.createTexture(it.flowingTextureName.texture())
|
||||
}
|
||||
it.stillTexture = it.stillTextureName?.let { texture -> renderWindow.textureManager.staticTextures.createTexture(texture.texture()) }
|
||||
}
|
||||
}
|
||||
|
||||
override fun postInit() {
|
||||
|
@ -1,31 +1,45 @@
|
||||
package de.bixilon.minosoft.gui.rendering.world.preparer.cull
|
||||
|
||||
import de.bixilon.minosoft.data.direction.Directions
|
||||
import de.bixilon.minosoft.data.registries.blocks.BlockState
|
||||
import de.bixilon.minosoft.data.registries.blocks.properties.BlockProperties
|
||||
import de.bixilon.minosoft.data.registries.blocks.types.FluidBlock
|
||||
import de.bixilon.minosoft.data.registries.blocks.types.FluidFillable
|
||||
import de.bixilon.minosoft.data.registries.fluid.DefaultFluids
|
||||
import de.bixilon.minosoft.data.registries.fluid.FlowableFluid
|
||||
import de.bixilon.minosoft.data.registries.fluid.Fluid
|
||||
import de.bixilon.minosoft.data.world.Chunk
|
||||
import de.bixilon.minosoft.data.world.ChunkSection
|
||||
import de.bixilon.minosoft.data.world.World
|
||||
import de.bixilon.minosoft.gui.rendering.RenderWindow
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.AbstractTexture
|
||||
import de.bixilon.minosoft.gui.rendering.textures.TextureUtil.getMesh
|
||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.plus
|
||||
import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2Util.EMPTY
|
||||
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.rotate
|
||||
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3iUtil.toVec3
|
||||
import de.bixilon.minosoft.gui.rendering.world.mesh.WorldMesh
|
||||
import de.bixilon.minosoft.gui.rendering.world.preparer.FluidSectionPreparer
|
||||
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
||||
import de.bixilon.minosoft.util.chunk.ChunkUtil.acquire
|
||||
import de.bixilon.minosoft.util.chunk.ChunkUtil.release
|
||||
import de.bixilon.minosoft.util.logging.Log
|
||||
import de.bixilon.minosoft.util.logging.LogLevels
|
||||
import de.bixilon.minosoft.util.logging.LogMessageType
|
||||
import glm_.func.cos
|
||||
import glm_.func.sin
|
||||
import glm_.vec2.Vec2
|
||||
import glm_.vec2.Vec2i
|
||||
import glm_.vec3.Vec3
|
||||
import glm_.vec3.Vec3i
|
||||
import kotlin.math.atan2
|
||||
|
||||
class FluidCullSectionPreparer(
|
||||
val renderWindow: RenderWindow,
|
||||
) : FluidSectionPreparer {
|
||||
private val world: World = renderWindow.connection.world
|
||||
private val water = renderWindow.connection.registries.fluidRegistry[DefaultFluids.WATER]
|
||||
private val tintColorCalculator = renderWindow.tintManager
|
||||
private val tintManager = renderWindow.tintManager
|
||||
|
||||
|
||||
// ToDo: Should this be combined with the solid renderer (but we'd need to render faces twice, because of cullface)
|
||||
override fun prepareFluid(chunkPosition: Vec2i, sectionHeight: Int, chunk: Chunk, section: ChunkSection, neighbours: Array<ChunkSection?>, neighbourChunks: Array<Chunk>): WorldMesh? {
|
||||
val mesh = WorldMesh(renderWindow, chunkPosition, sectionHeight, smallMesh = true)
|
||||
|
||||
@ -56,7 +70,147 @@ class FluidCullSectionPreparer(
|
||||
block is FluidFillable -> block.fluid
|
||||
else -> continue
|
||||
}
|
||||
Log.log(LogMessageType.OTHER, LogLevels.VERBOSE) { "Can not render fluid: $fluid" }
|
||||
position = Vec3i(offsetX + x, offsetY + y, offsetZ + z)
|
||||
tints = tintManager.getAverageTint(chunk, neighbourChunks, blockState, fluid, position.x, position.y, position.z)
|
||||
|
||||
val skipTop = fluid.matches(chunk.get(x, offsetY + y + 1, z))
|
||||
val skipBottom = !shouldRenderSide(position, Directions.DOWN)
|
||||
val skipNorth = !shouldRenderSide(position, Directions.NORTH)
|
||||
val skipSouth = !shouldRenderSide(position, Directions.SOUTH)
|
||||
val skipWest = !shouldRenderSide(position, Directions.WEST)
|
||||
val skipEast = !shouldRenderSide(position, Directions.EAST)
|
||||
|
||||
if (skipTop && skipBottom && skipNorth && skipSouth && skipWest && skipEast) {
|
||||
continue
|
||||
}
|
||||
val cornerHeights = floatArrayOf(
|
||||
getCornerHeight(position, fluid),
|
||||
getCornerHeight(position + Directions.EAST, fluid),
|
||||
getCornerHeight(position + Directions.EAST + Directions.SOUTH, fluid),
|
||||
getCornerHeight(position + Directions.SOUTH, fluid),
|
||||
)
|
||||
val floatPosition = position.toVec3()
|
||||
floatPosition.y += cornerHeights[0]
|
||||
if (!skipTop) {
|
||||
val velocity = if (fluid is FlowableFluid) fluid.getVelocity(renderWindow.connection, blockState, position) else null
|
||||
val still = velocity == null || velocity.x == 0.0 && velocity.z == 0.0
|
||||
val texture: AbstractTexture
|
||||
val minUV = Vec2.EMPTY
|
||||
val maxUV = Vec2(if (still) 1.0f else 0.5f) // Minecraft just uses half of the sprite
|
||||
|
||||
|
||||
val texturePositions = arrayOf(
|
||||
Vec2(maxUV.x, minUV.y),
|
||||
minUV,
|
||||
Vec2(minUV.x, maxUV.y),
|
||||
maxUV,
|
||||
)
|
||||
|
||||
|
||||
if (still) {
|
||||
texture = fluid.stillTexture!!
|
||||
} else {
|
||||
texture = (fluid as FlowableFluid).flowingTexture!!
|
||||
maxUV.x = 0.5f
|
||||
|
||||
val atan = atan2(velocity!!.x, velocity.z).toFloat()
|
||||
val sin = atan.sin
|
||||
val cos = atan.cos
|
||||
|
||||
for (i in 0 until 4) {
|
||||
texturePositions[i] = (rotate(texturePositions[i].x - TEXTURE_CENTER, texturePositions[i].y - TEXTURE_CENTER, sin, cos, false) + TEXTURE_CENTER)
|
||||
}
|
||||
}
|
||||
|
||||
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),
|
||||
)
|
||||
|
||||
|
||||
for ((positionIndex, textureIndex) in meshToUse.order) {
|
||||
meshToUse.addVertex(positions[positionIndex].array, texturePositions[textureIndex], texture, tints?.get(0) ?: 0xFFFFFF, chunk.getLight(position))
|
||||
}
|
||||
rendered = true
|
||||
}
|
||||
// ToDo: Sides: Minecraft uses (for water) a overlay texture (with cullface) that is used, when the face fits to a non opaque block
|
||||
// ToDo: Sides that are connecting with non full cubes (e.g. air) also have cullface disabled
|
||||
|
||||
|
||||
for (direction in 0 until 4) {
|
||||
var faceX = 0.0f
|
||||
var faceXEnd = 0.0f
|
||||
var faceZ = 0.0f
|
||||
var faceZEnd = 0.0f
|
||||
var v1 = 0.0f
|
||||
var v2 = 0.0f
|
||||
|
||||
when (direction) {
|
||||
0 -> {
|
||||
if (skipNorth) {
|
||||
continue
|
||||
}
|
||||
|
||||
faceXEnd = 1.0f
|
||||
v1 = cornerHeights[0]
|
||||
v2 = cornerHeights[1]
|
||||
}
|
||||
1 -> {
|
||||
if (skipSouth) {
|
||||
continue
|
||||
}
|
||||
faceX = 1.0f
|
||||
faceZ = 1.0f
|
||||
faceZEnd = 1.0f
|
||||
v1 = cornerHeights[2]
|
||||
v2 = cornerHeights[3]
|
||||
}
|
||||
2 -> {
|
||||
if (skipWest) {
|
||||
continue
|
||||
}
|
||||
faceZ = 1.0f
|
||||
v1 = cornerHeights[3]
|
||||
v2 = cornerHeights[0]
|
||||
}
|
||||
3 -> {
|
||||
if (skipEast) {
|
||||
continue
|
||||
}
|
||||
|
||||
faceX = 1.0f
|
||||
faceXEnd = 1.0f
|
||||
faceZEnd = 1.0f
|
||||
v1 = cornerHeights[1]
|
||||
v2 = cornerHeights[2]
|
||||
}
|
||||
}
|
||||
|
||||
val positions = arrayOf(
|
||||
Vec3(position.x + faceX, position.y + v1, position.z + faceZ),
|
||||
Vec3(position.x + faceX, position.y, position.z + faceZ),
|
||||
Vec3(position.x + faceXEnd, position.y, position.z + faceZEnd),
|
||||
Vec3(position.x + faceXEnd, position.y + v2, position.z + faceZEnd),
|
||||
)
|
||||
val texturePositions = arrayOf(
|
||||
Vec2(0.5f, v2 / 2),
|
||||
Vec2(0.5f, 0.0f),
|
||||
Vec2(0.0f, 0.0f),
|
||||
Vec2(0.0f, v1 / 2),
|
||||
)
|
||||
|
||||
val texture = (fluid as FlowableFluid).flowingTexture!!
|
||||
|
||||
val meshToUse = texture.transparency.getMesh(mesh)
|
||||
for ((positionIndex, textureIndex) in meshToUse.order) {
|
||||
meshToUse.addVertex(positions[positionIndex].array, texturePositions[textureIndex], texture, tints?.get(0) ?: 0xFFFFFF, 0xFF)
|
||||
}
|
||||
rendered = true
|
||||
}
|
||||
|
||||
|
||||
if (rendered) {
|
||||
@ -75,4 +229,51 @@ class FluidCullSectionPreparer(
|
||||
return mesh
|
||||
}
|
||||
|
||||
private fun isSideCovered(position: Vec3i, direction: Directions, height: Float): Boolean {
|
||||
return world[position + direction] != null
|
||||
}
|
||||
|
||||
private fun shouldRenderSide(position: Vec3i, direction: Directions, height: Float = 1.0f): Boolean {
|
||||
return !isSideCovered(position, direction, height) /* && fluid.matches(other) */
|
||||
}
|
||||
|
||||
private fun getCornerHeight(position: Vec3i, fluid: Fluid): Float {
|
||||
// ToDo: Optimize
|
||||
var totalHeight = 0.0f
|
||||
var count = 0
|
||||
|
||||
for (side in 0 until 4) {
|
||||
val blockPosition = position + Vec3i(-(side and 0x01), 0, -(side shr 1 and 0x01))
|
||||
if (fluid.matches(world[blockPosition + Directions.UP])) {
|
||||
return 1.0f
|
||||
}
|
||||
|
||||
val blockState = world[blockPosition]
|
||||
|
||||
if (blockState == null || !fluid.matches(blockState)) {
|
||||
if (blockState?.material?.solid != true) {
|
||||
count++
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
val height = fluid.getHeight(blockState)
|
||||
|
||||
if (height >= 0.8f) {
|
||||
totalHeight += height * 10.0f
|
||||
count += 10
|
||||
} else {
|
||||
totalHeight += height
|
||||
count++
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return totalHeight / count
|
||||
}
|
||||
|
||||
private companion object {
|
||||
private const val TEXTURE_CENTER = 1.0f / 2.0f
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ object SystemInformation {
|
||||
val SYSTEM_MEMORY = HARDWARE_SYSTEM_INFO.memory.total
|
||||
val OS_TEXT: String = "${System.getProperty("os.name")}: ${SYSTEM_INFO.operatingSystem.family} ${SYSTEM_INFO.operatingSystem.bitness}bit"
|
||||
|
||||
val PROCESSOR_TEXT = " ${RUNTIME.availableProcessors()}x ${HARDWARE_SYSTEM_INFO.processor.processorIdentifier.name.replace("\\s{2,}".toRegex(), "")}"
|
||||
val PROCESSOR_TEXT = "${RUNTIME.availableProcessors()}x ${HARDWARE_SYSTEM_INFO.processor.processorIdentifier.name.replace("\\s{2,}".toRegex(), "")}"
|
||||
|
||||
val MAX_MEMORY_TEXT: String = getFormattedMaxMemory()
|
||||
val PROCESSOR_SPEED = HARDWARE_SYSTEM_INFO.processor.maxFreq
|
||||
|
Loading…
x
Reference in New Issue
Block a user