diff --git a/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/models/BlockStateApplyTest.kt b/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/models/BlockStateApplyTest.kt index d4b59f5b2..59ff9e13f 100644 --- a/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/models/BlockStateApplyTest.kt +++ b/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/models/BlockStateApplyTest.kt @@ -76,7 +76,6 @@ class BlockStateApplyTest { x = 0, y = 0, uvLock = false, - weight = 1, )) } diff --git a/src/main/java/de/bixilon/minosoft/data/entities/block/MeshedBlockEntity.kt b/src/main/java/de/bixilon/minosoft/data/entities/block/MeshedBlockEntity.kt index cb9eed0c7..7f81b39fc 100644 --- a/src/main/java/de/bixilon/minosoft/data/entities/block/MeshedBlockEntity.kt +++ b/src/main/java/de/bixilon/minosoft/data/entities/block/MeshedBlockEntity.kt @@ -17,14 +17,14 @@ import de.bixilon.kotlinglm.vec3.Vec3i import de.bixilon.minosoft.data.registries.blocks.state.BlockState import de.bixilon.minosoft.gui.rendering.RenderContext import de.bixilon.minosoft.gui.rendering.world.entities.BlockEntityRenderer -import de.bixilon.minosoft.gui.rendering.world.entities.MeshedBlockEntityRenderer +import de.bixilon.minosoft.gui.rendering.world.entities.MeshedEntityRenderer import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection abstract class MeshedBlockEntity(connection: PlayConnection) : BlockEntity(connection) { - override fun getRenderer(context: RenderContext, blockState: BlockState, blockPosition: Vec3i, light: Int): MeshedBlockEntityRenderer<*>? { + override fun getRenderer(context: RenderContext, blockState: BlockState, blockPosition: Vec3i, light: Int): MeshedEntityRenderer<*> { var renderer = this.renderer - if (renderer is MeshedBlockEntityRenderer<*> && renderer.blockState == blockState) { + if (renderer is MeshedEntityRenderer && renderer.blockState == blockState) { return renderer } renderer = createMeshedRenderer(context, blockState, blockPosition) @@ -36,5 +36,5 @@ abstract class MeshedBlockEntity(connection: PlayConnection) : BlockEntity(conne throw IllegalAccessException() } - abstract fun createMeshedRenderer(context: RenderContext, blockState: BlockState, blockPosition: Vec3i): MeshedBlockEntityRenderer<*> + abstract fun createMeshedRenderer(context: RenderContext, blockState: BlockState, blockPosition: Vec3i): MeshedEntityRenderer<*> } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/models/block/state/apply/BlockStateApply.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/models/block/state/apply/BlockStateApply.kt index 50d3305ec..44bd6389b 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/models/block/state/apply/BlockStateApply.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/models/block/state/apply/BlockStateApply.kt @@ -15,17 +15,17 @@ package de.bixilon.minosoft.gui.rendering.models.block.state.apply import de.bixilon.kutil.cast.CastUtil.unsafeCast import de.bixilon.kutil.json.JsonUtil.asJsonObject -import de.bixilon.minosoft.gui.rendering.models.block.state.baked.BakedModel +import de.bixilon.minosoft.gui.rendering.models.block.state.render.BlockRender import de.bixilon.minosoft.gui.rendering.models.loader.BlockLoader import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureManager interface BlockStateApply { - fun bake(textures: TextureManager): BakedModel? + fun bake(textures: TextureManager): BlockRender? companion object { - fun deserialize(loader: BlockLoader, data: Any): BlockStateApply { + fun deserialize(loader: BlockLoader, data: Any): BlockStateApply? { if (data is Map<*, *>) return SingleBlockStateApply.deserialize(loader, data.asJsonObject()) if (data is List<*>) return WeightedBlockStateApply.deserialize(loader, data.unsafeCast()) diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/models/block/state/apply/SingleBlockStateApply.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/models/block/state/apply/SingleBlockStateApply.kt index 837b7f5d7..aca8b9a89 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/models/block/state/apply/SingleBlockStateApply.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/models/block/state/apply/SingleBlockStateApply.kt @@ -34,7 +34,6 @@ import java.util.* data class SingleBlockStateApply( val model: BlockModel, val uvLock: Boolean = false, - val weight: Int = 1, val x: Int = 0, val y: Int = 0, ) : BlockStateApply { @@ -84,11 +83,10 @@ data class SingleBlockStateApply( fun deserialize(model: BlockModel, data: JsonObject): SingleBlockStateApply { val uvLock = data["uvlock"]?.toBoolean() ?: false - val weight = data["weight"]?.toInt() ?: 1 val x = data["x"]?.toInt()?.rotation() ?: 0 val y = data["y"]?.toInt()?.rotation() ?: 0 - return SingleBlockStateApply(model, uvLock, weight, x, y) + return SingleBlockStateApply(model, uvLock, x, y) } fun deserialize(loader: BlockLoader, data: JsonObject): SingleBlockStateApply { diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/models/block/state/apply/WeightedBlockStateApply.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/models/block/state/apply/WeightedBlockStateApply.kt index 0b93c8d40..a3e894a49 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/models/block/state/apply/WeightedBlockStateApply.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/models/block/state/apply/WeightedBlockStateApply.kt @@ -13,26 +13,48 @@ package de.bixilon.minosoft.gui.rendering.models.block.state.apply +import de.bixilon.kutil.array.ArrayUtil.cast import de.bixilon.kutil.json.JsonObject -import de.bixilon.minosoft.gui.rendering.models.block.state.baked.BakedModel +import de.bixilon.kutil.primitive.IntUtil.toInt +import de.bixilon.minosoft.gui.rendering.models.block.state.render.WeightedBlockRender import de.bixilon.minosoft.gui.rendering.models.loader.BlockLoader import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureManager data class WeightedBlockStateApply( - val models: List + val models: List ) : BlockStateApply { - override fun bake(textures: TextureManager): BakedModel { - TODO("Not yet implemented") + override fun bake(textures: TextureManager): WeightedBlockRender? { + val baked: Array = arrayOfNulls(models.size) + var totalWeight = 0 + + for ((index, entry) in models.withIndex()) { + val model = entry.apply.bake(textures) ?: continue + baked[index] = WeightedBlockRender.WeightedEntry(entry.weight, model) + totalWeight += entry.weight + } + + if (totalWeight == 0) return null + + return WeightedBlockRender(baked.cast(), totalWeight) } + data class WeightedApply( + val weight: Int, + val apply: SingleBlockStateApply, + ) + companion object { - fun deserialize(loader: BlockLoader, data: List): WeightedBlockStateApply { - val models: MutableList = mutableListOf() + fun deserialize(loader: BlockLoader, data: List): WeightedBlockStateApply? { + if (data.isEmpty()) return null + val models: MutableList = mutableListOf() for (entry in data) { - models += SingleBlockStateApply.deserialize(loader, entry) + var weight = entry["weight"]?.toInt() ?: 1 + if (weight < 0) weight = 1 + val apply = SingleBlockStateApply.deserialize(loader, entry) + models += WeightedApply(weight, apply) } return WeightedBlockStateApply(models) diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/models/block/state/baked/BakedModel.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/models/block/state/baked/BakedModel.kt index cd61ef993..4fd91a2d6 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/models/block/state/baked/BakedModel.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/models/block/state/baked/BakedModel.kt @@ -28,9 +28,9 @@ class BakedModel( val particle: AbstractTexture?, ) : BlockRender { - override fun getParticleTexture(random: Random, position: Vec3i) = particle + override fun getParticleTexture(random: Random?, position: Vec3i) = particle - override fun render(position: BlockPosition, mesh: WorldMesh, random: Random, state: BlockState, neighbours: Array, light: ByteArray, tints: IntArray?): Boolean { + override fun render(position: BlockPosition, mesh: WorldMesh, random: Random?, state: BlockState, neighbours: Array, light: ByteArray, tints: IntArray?): Boolean { val float = position.toVec3 val array = float.array diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/models/block/state/render/BlockRender.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/models/block/state/render/BlockRender.kt index 84e729259..d143a4b07 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/models/block/state/render/BlockRender.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/models/block/state/render/BlockRender.kt @@ -21,7 +21,7 @@ import de.bixilon.minosoft.gui.rendering.world.mesh.WorldMesh import java.util.* interface BlockRender { - fun getParticleTexture(random: Random, position: Vec3i): AbstractTexture? = null + fun getParticleTexture(random: Random?, position: Vec3i): AbstractTexture? = null - fun render(position: BlockPosition, mesh: WorldMesh, random: Random, state: BlockState, neighbours: Array, light: ByteArray, tints: IntArray?): Boolean + fun render(position: BlockPosition, mesh: WorldMesh, random: Random?, state: BlockState, neighbours: Array, light: ByteArray, tints: IntArray?): Boolean } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/models/block/state/render/WeightedBlockRender.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/models/block/state/render/WeightedBlockRender.kt new file mode 100644 index 000000000..e8b27ccc3 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/models/block/state/render/WeightedBlockRender.kt @@ -0,0 +1,62 @@ +/* + * Minosoft + * Copyright (C) 2020-2023 Moritz Zwerger + * + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. If not, see . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.gui.rendering.models.block.state.render + +import de.bixilon.kotlinglm.vec3.Vec3i +import de.bixilon.kutil.exception.Broken +import de.bixilon.minosoft.data.registries.blocks.state.BlockState +import de.bixilon.minosoft.data.world.positions.BlockPosition +import de.bixilon.minosoft.data.world.positions.BlockPositionUtil.positionHash +import de.bixilon.minosoft.gui.rendering.models.block.state.baked.BakedModel +import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.AbstractTexture +import de.bixilon.minosoft.gui.rendering.world.mesh.WorldMesh +import java.util.* +import kotlin.math.abs + +class WeightedBlockRender( + val models: Array, + val totalWeight: Int, +) : BlockRender { + + + private fun getModel(random: Random?): BlockRender { + if (random == null) return models.first().model + + var weightLeft = abs(random.nextLong() % totalWeight) + + for ((weight, model) in models) { + weightLeft -= weight + if (weightLeft >= 0) continue + + return model + } + + Broken("Could not find a model: This should never happen!") + } + + override fun getParticleTexture(random: Random?, position: Vec3i): AbstractTexture? { + random?.setSeed(position.positionHash) + return getModel(random).getParticleTexture(random, position) + } + + override fun render(position: BlockPosition, mesh: WorldMesh, random: Random?, state: BlockState, neighbours: Array, light: ByteArray, tints: IntArray?): Boolean { + return getModel(random).render(position, mesh, random, state, neighbours, light, tints) + } + + + data class WeightedEntry( + val weight: Int, + val model: BakedModel, + ) +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/models/block/state/variant/VariantBlockModel.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/models/block/state/variant/VariantBlockModel.kt index 8acbf9461..c500b9c15 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/models/block/state/variant/VariantBlockModel.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/models/block/state/variant/VariantBlockModel.kt @@ -43,7 +43,7 @@ interface VariantBlockModel : DirectBlockModel { for ((variant, entry) in data) { - val apply = BlockStateApply.deserialize(loader, entry.asJsonObject()) + val apply = BlockStateApply.deserialize(loader, entry.asJsonObject()) ?: continue if (variant == "") { // no further conditions return SingleVariantBlockModel(apply) @@ -51,6 +51,8 @@ interface VariantBlockModel : DirectBlockModel { variants[parseVariant(variant)] = apply } + if (variants.isEmpty()) return null + return PropertyVariantBlockModel(variants) } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/world/entities/MeshedEntityRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/world/entities/MeshedEntityRenderer.kt new file mode 100644 index 000000000..6b0cabcdd --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/world/entities/MeshedEntityRenderer.kt @@ -0,0 +1,19 @@ +/* + * Minosoft + * Copyright (C) 2020-2023 Moritz Zwerger + * + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. If not, see . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.gui.rendering.world.entities + +import de.bixilon.minosoft.data.entities.block.BlockEntity +import de.bixilon.minosoft.gui.rendering.models.block.state.render.BlockRender + +interface MeshedEntityRenderer : BlockEntityRenderer, BlockRender diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/world/entities/renderer/sign/SignBlockEntityRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/world/entities/renderer/sign/SignBlockEntityRenderer.kt index 09bdcdc64..af4b56a4d 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/world/entities/renderer/sign/SignBlockEntityRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/world/entities/renderer/sign/SignBlockEntityRenderer.kt @@ -32,10 +32,9 @@ 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.block.element.ModelElement.Companion.BLOCK_SIZE -import de.bixilon.minosoft.gui.rendering.models.block.state.render.BlockRender 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.world.entities.BlockEntityRenderer +import de.bixilon.minosoft.gui.rendering.world.entities.MeshedEntityRenderer import de.bixilon.minosoft.gui.rendering.world.mesh.SingleWorldMesh import de.bixilon.minosoft.gui.rendering.world.mesh.WorldMesh import de.bixilon.minosoft.gui.rendering.world.preparer.cull.SolidCullSectionPreparer.Companion.SELF_LIGHT_INDEX @@ -45,7 +44,7 @@ class SignBlockEntityRenderer( val sign: SignBlockEntity, val context: RenderContext, override val blockState: BlockState, -) : BlockEntityRenderer, BlockRender { +) : MeshedEntityRenderer { override val enabled: Boolean get() = false private fun getRotation(): Float { @@ -54,7 +53,7 @@ class SignBlockEntityRenderer( return rotation * 22.5f } - override fun render(position: Vec3i, mesh: WorldMesh, random: Random, state: BlockState, neighbours: Array, light: ByteArray, tints: IntArray?): Boolean { + override fun render(position: Vec3i, mesh: WorldMesh, random: Random?, state: BlockState, neighbours: Array, light: ByteArray, tints: IntArray?): Boolean { val block = this.blockState.block if (block is StandingSignBlock) { renderStandingText(position, mesh, light[SELF_LIGHT_INDEX].toInt()) diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/world/preparer/cull/SolidCullSectionPreparer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/world/preparer/cull/SolidCullSectionPreparer.kt index c347040db..ffd2e7547 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/world/preparer/cull/SolidCullSectionPreparer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/world/preparer/cull/SolidCullSectionPreparer.kt @@ -56,10 +56,9 @@ class SolidCullSectionPreparer( } override fun prepareSolid(chunkPosition: Vec2i, sectionHeight: Int, chunk: Chunk, section: ChunkSection, neighbourChunks: Array, neighbours: Array, mesh: WorldMesh) { - val random = Random(0L) + val random = if (profile.antiMoirePattern) Random(0L) else null - val randomness = profile.antiMoirePattern val isLowestSection = sectionHeight == chunk.minSection val isHighestSection = sectionHeight == chunk.maxSection val blocks = section.blocks @@ -132,11 +131,8 @@ class SolidCullSectionPreparer( light[O_UP] = (light[O_UP].toInt() or 0xF0).toByte() } - if (randomness) { - random.setSeed(position.positionHash) - } else { - random.setSeed(0L) - } + random?.setSeed(position.positionHash) + val tints = tintColorCalculator.getAverageBlockTint(chunk, neighbourChunks, state, x, y, z) var rendered = model.render(position, mesh, random, state, neighbourBlocks, light, tints)