mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-16 10:55:01 -04:00
wighted block state model/apply
This commit is contained in:
parent
955bf59ace
commit
0a435274b5
@ -76,7 +76,6 @@ class BlockStateApplyTest {
|
|||||||
x = 0,
|
x = 0,
|
||||||
y = 0,
|
y = 0,
|
||||||
uvLock = false,
|
uvLock = false,
|
||||||
weight = 1,
|
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,14 +17,14 @@ import de.bixilon.kotlinglm.vec3.Vec3i
|
|||||||
import de.bixilon.minosoft.data.registries.blocks.state.BlockState
|
import de.bixilon.minosoft.data.registries.blocks.state.BlockState
|
||||||
import de.bixilon.minosoft.gui.rendering.RenderContext
|
import de.bixilon.minosoft.gui.rendering.RenderContext
|
||||||
import de.bixilon.minosoft.gui.rendering.world.entities.BlockEntityRenderer
|
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
|
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
|
||||||
|
|
||||||
abstract class MeshedBlockEntity(connection: PlayConnection) : BlockEntity(connection) {
|
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
|
var renderer = this.renderer
|
||||||
if (renderer is MeshedBlockEntityRenderer<*> && renderer.blockState == blockState) {
|
if (renderer is MeshedEntityRenderer && renderer.blockState == blockState) {
|
||||||
return renderer
|
return renderer
|
||||||
}
|
}
|
||||||
renderer = createMeshedRenderer(context, blockState, blockPosition)
|
renderer = createMeshedRenderer(context, blockState, blockPosition)
|
||||||
@ -36,5 +36,5 @@ abstract class MeshedBlockEntity(connection: PlayConnection) : BlockEntity(conne
|
|||||||
throw IllegalAccessException()
|
throw IllegalAccessException()
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract fun createMeshedRenderer(context: RenderContext, blockState: BlockState, blockPosition: Vec3i): MeshedBlockEntityRenderer<*>
|
abstract fun createMeshedRenderer(context: RenderContext, blockState: BlockState, blockPosition: Vec3i): MeshedEntityRenderer<*>
|
||||||
}
|
}
|
||||||
|
@ -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.cast.CastUtil.unsafeCast
|
||||||
import de.bixilon.kutil.json.JsonUtil.asJsonObject
|
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.models.loader.BlockLoader
|
||||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureManager
|
import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureManager
|
||||||
|
|
||||||
interface BlockStateApply {
|
interface BlockStateApply {
|
||||||
|
|
||||||
fun bake(textures: TextureManager): BakedModel?
|
fun bake(textures: TextureManager): BlockRender?
|
||||||
|
|
||||||
companion object {
|
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 Map<*, *>) return SingleBlockStateApply.deserialize(loader, data.asJsonObject())
|
||||||
if (data is List<*>) return WeightedBlockStateApply.deserialize(loader, data.unsafeCast())
|
if (data is List<*>) return WeightedBlockStateApply.deserialize(loader, data.unsafeCast())
|
||||||
|
|
||||||
|
@ -34,7 +34,6 @@ import java.util.*
|
|||||||
data class SingleBlockStateApply(
|
data class SingleBlockStateApply(
|
||||||
val model: BlockModel,
|
val model: BlockModel,
|
||||||
val uvLock: Boolean = false,
|
val uvLock: Boolean = false,
|
||||||
val weight: Int = 1,
|
|
||||||
val x: Int = 0,
|
val x: Int = 0,
|
||||||
val y: Int = 0,
|
val y: Int = 0,
|
||||||
) : BlockStateApply {
|
) : BlockStateApply {
|
||||||
@ -84,11 +83,10 @@ data class SingleBlockStateApply(
|
|||||||
|
|
||||||
fun deserialize(model: BlockModel, data: JsonObject): SingleBlockStateApply {
|
fun deserialize(model: BlockModel, data: JsonObject): SingleBlockStateApply {
|
||||||
val uvLock = data["uvlock"]?.toBoolean() ?: false
|
val uvLock = data["uvlock"]?.toBoolean() ?: false
|
||||||
val weight = data["weight"]?.toInt() ?: 1
|
|
||||||
val x = data["x"]?.toInt()?.rotation() ?: 0
|
val x = data["x"]?.toInt()?.rotation() ?: 0
|
||||||
val y = data["y"]?.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 {
|
fun deserialize(loader: BlockLoader, data: JsonObject): SingleBlockStateApply {
|
||||||
|
@ -13,26 +13,48 @@
|
|||||||
|
|
||||||
package de.bixilon.minosoft.gui.rendering.models.block.state.apply
|
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.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.models.loader.BlockLoader
|
||||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureManager
|
import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureManager
|
||||||
|
|
||||||
data class WeightedBlockStateApply(
|
data class WeightedBlockStateApply(
|
||||||
val models: List<SingleBlockStateApply>
|
val models: List<WeightedApply>
|
||||||
) : BlockStateApply {
|
) : BlockStateApply {
|
||||||
|
|
||||||
override fun bake(textures: TextureManager): BakedModel {
|
override fun bake(textures: TextureManager): WeightedBlockRender? {
|
||||||
TODO("Not yet implemented")
|
val baked: Array<WeightedBlockRender.WeightedEntry?> = 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 {
|
companion object {
|
||||||
|
|
||||||
fun deserialize(loader: BlockLoader, data: List<JsonObject>): WeightedBlockStateApply {
|
fun deserialize(loader: BlockLoader, data: List<JsonObject>): WeightedBlockStateApply? {
|
||||||
val models: MutableList<SingleBlockStateApply> = mutableListOf()
|
if (data.isEmpty()) return null
|
||||||
|
val models: MutableList<WeightedApply> = mutableListOf()
|
||||||
|
|
||||||
for (entry in data) {
|
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)
|
return WeightedBlockStateApply(models)
|
||||||
|
@ -28,9 +28,9 @@ class BakedModel(
|
|||||||
val particle: AbstractTexture?,
|
val particle: AbstractTexture?,
|
||||||
) : BlockRender {
|
) : 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<BlockState?>, light: ByteArray, tints: IntArray?): Boolean {
|
override fun render(position: BlockPosition, mesh: WorldMesh, random: Random?, state: BlockState, neighbours: Array<BlockState?>, light: ByteArray, tints: IntArray?): Boolean {
|
||||||
val float = position.toVec3
|
val float = position.toVec3
|
||||||
|
|
||||||
val array = float.array
|
val array = float.array
|
||||||
|
@ -21,7 +21,7 @@ import de.bixilon.minosoft.gui.rendering.world.mesh.WorldMesh
|
|||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
interface BlockRender {
|
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<BlockState?>, light: ByteArray, tints: IntArray?): Boolean
|
fun render(position: BlockPosition, mesh: WorldMesh, random: Random?, state: BlockState, neighbours: Array<BlockState?>, light: ByteArray, tints: IntArray?): Boolean
|
||||||
}
|
}
|
||||||
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* 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<WeightedEntry>,
|
||||||
|
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<BlockState?>, 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,
|
||||||
|
)
|
||||||
|
}
|
@ -43,7 +43,7 @@ interface VariantBlockModel : DirectBlockModel {
|
|||||||
|
|
||||||
|
|
||||||
for ((variant, entry) in data) {
|
for ((variant, entry) in data) {
|
||||||
val apply = BlockStateApply.deserialize(loader, entry.asJsonObject())
|
val apply = BlockStateApply.deserialize(loader, entry.asJsonObject()) ?: continue
|
||||||
if (variant == "") {
|
if (variant == "") {
|
||||||
// no further conditions
|
// no further conditions
|
||||||
return SingleVariantBlockModel(apply)
|
return SingleVariantBlockModel(apply)
|
||||||
@ -51,6 +51,8 @@ interface VariantBlockModel : DirectBlockModel {
|
|||||||
variants[parseVariant(variant)] = apply
|
variants[parseVariant(variant)] = apply
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (variants.isEmpty()) return null
|
||||||
|
|
||||||
return PropertyVariantBlockModel(variants)
|
return PropertyVariantBlockModel(variants)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* 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<E : BlockEntity> : BlockEntityRenderer<E>, BlockRender
|
@ -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.Font
|
||||||
import de.bixilon.minosoft.gui.rendering.font.renderer.ChatComponentRenderer
|
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.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.VecUtil.toVec3
|
||||||
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.rotateAssign
|
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.SingleWorldMesh
|
||||||
import de.bixilon.minosoft.gui.rendering.world.mesh.WorldMesh
|
import de.bixilon.minosoft.gui.rendering.world.mesh.WorldMesh
|
||||||
import de.bixilon.minosoft.gui.rendering.world.preparer.cull.SolidCullSectionPreparer.Companion.SELF_LIGHT_INDEX
|
import de.bixilon.minosoft.gui.rendering.world.preparer.cull.SolidCullSectionPreparer.Companion.SELF_LIGHT_INDEX
|
||||||
@ -45,7 +44,7 @@ class SignBlockEntityRenderer(
|
|||||||
val sign: SignBlockEntity,
|
val sign: SignBlockEntity,
|
||||||
val context: RenderContext,
|
val context: RenderContext,
|
||||||
override val blockState: BlockState,
|
override val blockState: BlockState,
|
||||||
) : BlockEntityRenderer<SignBlockEntity>, BlockRender {
|
) : MeshedEntityRenderer<SignBlockEntity> {
|
||||||
override val enabled: Boolean get() = false
|
override val enabled: Boolean get() = false
|
||||||
|
|
||||||
private fun getRotation(): Float {
|
private fun getRotation(): Float {
|
||||||
@ -54,7 +53,7 @@ class SignBlockEntityRenderer(
|
|||||||
return rotation * 22.5f
|
return rotation * 22.5f
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun render(position: Vec3i, mesh: WorldMesh, random: Random, state: BlockState, neighbours: Array<BlockState?>, light: ByteArray, tints: IntArray?): Boolean {
|
override fun render(position: Vec3i, mesh: WorldMesh, random: Random?, state: BlockState, neighbours: Array<BlockState?>, light: ByteArray, tints: IntArray?): Boolean {
|
||||||
val block = this.blockState.block
|
val block = this.blockState.block
|
||||||
if (block is StandingSignBlock) {
|
if (block is StandingSignBlock) {
|
||||||
renderStandingText(position, mesh, light[SELF_LIGHT_INDEX].toInt())
|
renderStandingText(position, mesh, light[SELF_LIGHT_INDEX].toInt())
|
||||||
|
@ -56,10 +56,9 @@ class SolidCullSectionPreparer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun prepareSolid(chunkPosition: Vec2i, sectionHeight: Int, chunk: Chunk, section: ChunkSection, neighbourChunks: Array<Chunk>, neighbours: Array<ChunkSection?>, mesh: WorldMesh) {
|
override fun prepareSolid(chunkPosition: Vec2i, sectionHeight: Int, chunk: Chunk, section: ChunkSection, neighbourChunks: Array<Chunk>, neighbours: Array<ChunkSection?>, 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 isLowestSection = sectionHeight == chunk.minSection
|
||||||
val isHighestSection = sectionHeight == chunk.maxSection
|
val isHighestSection = sectionHeight == chunk.maxSection
|
||||||
val blocks = section.blocks
|
val blocks = section.blocks
|
||||||
@ -132,11 +131,8 @@ class SolidCullSectionPreparer(
|
|||||||
light[O_UP] = (light[O_UP].toInt() or 0xF0).toByte()
|
light[O_UP] = (light[O_UP].toInt() or 0xF0).toByte()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (randomness) {
|
random?.setSeed(position.positionHash)
|
||||||
random.setSeed(position.positionHash)
|
|
||||||
} else {
|
|
||||||
random.setSeed(0L)
|
|
||||||
}
|
|
||||||
val tints = tintColorCalculator.getAverageBlockTint(chunk, neighbourChunks, state, x, y, z)
|
val tints = tintColorCalculator.getAverageBlockTint(chunk, neighbourChunks, state, x, y, z)
|
||||||
var rendered = model.render(position, mesh, random, state, neighbourBlocks, light, tints)
|
var rendered = model.render(position, mesh, random, state, neighbourBlocks, light, tints)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user