diff --git a/src/main/java/de/bixilon/minosoft/data/registries/blocks/properties/BlockProperties.kt b/src/main/java/de/bixilon/minosoft/data/registries/blocks/properties/BlockProperties.kt index 3a37b2fc5..93c474450 100644 --- a/src/main/java/de/bixilon/minosoft/data/registries/blocks/properties/BlockProperties.kt +++ b/src/main/java/de/bixilon/minosoft/data/registries/blocks/properties/BlockProperties.kt @@ -134,11 +134,11 @@ enum class BlockProperties { companion object { - private val PROPERTIES: Map> = run { + val PROPERTIES: Map> = run { val map: MutableMap> = mutableMapOf() for (value in values()) { - val list = map.getOrPut(value.group, { mutableListOf() }) + val list = map.getOrPut(value.group) { mutableListOf() } list.add(value) } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/block/WorldRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/block/WorldRenderer.kt index 1752c5c11..467842cee 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/block/WorldRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/block/WorldRenderer.kt @@ -73,8 +73,9 @@ class WorldRenderer( val random = Random(0L) val blockState1 = connection.registries.blockRegistry["end_portal_frame"]?.defaultState - val blockState2 = connection.registries.blockRegistry["carved_pumpkin"]?.defaultState + val blockState2 = connection.registries.blockRegistry["oak_fence"]!!.defaultState//.withProperties(BlockProperties.FACING to Directions.SOUTH) val section = ChunkSection(Array(4096) { + if (it < 256) return@Array blockState2 else return@Array null when (random.nextInt(3)) { 1 -> blockState2 2 -> blockState2 diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/models/baked/MultipartBakedModel.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/models/baked/MultipartBakedModel.kt new file mode 100644 index 000000000..e91ff94c2 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/models/baked/MultipartBakedModel.kt @@ -0,0 +1,37 @@ +/* + * 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 . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.gui.rendering.models.baked + +import de.bixilon.minosoft.data.direction.Directions +import de.bixilon.minosoft.data.registries.blocks.BlockState +import de.bixilon.minosoft.data.world.light.LightAccessor +import de.bixilon.minosoft.gui.rendering.block.mesh.ChunkSectionMesh +import de.bixilon.minosoft.gui.rendering.models.baked.block.BakedBlockModel +import glm_.vec3.Vec3i +import java.util.* + +class MultipartBakedModel( + val models: Array, +) : BakedBlockModel { + + override fun getLight(position: Vec3i, random: Random, side: Directions, lightAccessor: LightAccessor): Int { + return 0xFF + } + + override fun singleRender(position: Vec3i, mesh: ChunkSectionMesh, random: Random, neighbours: Array, light: Int, ambientLight: IntArray) { + for (model in models) { + model.singleRender(position, mesh, random, neighbours, light, ambientLight) + } + } +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/models/baked/WeightedBakedModel.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/models/baked/WeightedBakedModel.kt index f341db116..e11d9eaf1 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/models/baked/WeightedBakedModel.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/models/baked/WeightedBakedModel.kt @@ -17,7 +17,6 @@ import de.bixilon.minosoft.data.direction.Directions import de.bixilon.minosoft.data.registries.blocks.BlockState import de.bixilon.minosoft.data.world.light.LightAccessor import de.bixilon.minosoft.gui.rendering.block.mesh.ChunkSectionMesh -import de.bixilon.minosoft.gui.rendering.models.FaceSize import de.bixilon.minosoft.gui.rendering.models.baked.block.BakedBlockModel import glm_.vec3.Vec3i import java.util.* @@ -52,10 +51,6 @@ class WeightedBakedModel( throw IllegalStateException("Could not find a model: This should never happen!") } - override fun getFaceSize(direction: Directions, random: Random): Array { - return getModel(random).getFaceSize(direction, random) - } - override fun getLight(position: Vec3i, random: Random, side: Directions, lightAccessor: LightAccessor): Int { return getModel(random).getLight(position, random, side, lightAccessor) } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/models/baked/block/BakedBlockModel.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/models/baked/block/BakedBlockModel.kt index 6ce1331f4..8275a8a13 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/models/baked/block/BakedBlockModel.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/models/baked/block/BakedBlockModel.kt @@ -17,15 +17,12 @@ import de.bixilon.minosoft.data.direction.Directions import de.bixilon.minosoft.data.registries.blocks.BlockState import de.bixilon.minosoft.data.world.light.LightAccessor import de.bixilon.minosoft.gui.rendering.block.mesh.ChunkSectionMesh -import de.bixilon.minosoft.gui.rendering.models.FaceSize import de.bixilon.minosoft.gui.rendering.models.baked.BakedModel import glm_.vec3.Vec3i import java.util.* interface BakedBlockModel : BakedModel { - fun getFaceSize(direction: Directions, random: Random): Array - // ToDo: Tint fun singleRender(position: Vec3i, mesh: ChunkSectionMesh, random: Random, neighbours: Array, light: Int, ambientLight: IntArray) diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/models/baked/block/BakedBlockStateModel.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/models/baked/block/BakedBlockStateModel.kt index a297462e9..728b0e0d3 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/models/baked/block/BakedBlockStateModel.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/models/baked/block/BakedBlockStateModel.kt @@ -17,7 +17,6 @@ import de.bixilon.minosoft.data.direction.Directions import de.bixilon.minosoft.data.registries.blocks.BlockState import de.bixilon.minosoft.data.world.light.LightAccessor import de.bixilon.minosoft.gui.rendering.block.mesh.ChunkSectionMesh -import de.bixilon.minosoft.gui.rendering.models.FaceSize import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3iUtil.toVec3 import glm_.vec3.Vec3i import java.util.* @@ -28,16 +27,12 @@ class BakedBlockStateModel( override val canGreedyMesh: Boolean = true override val greedyMeshableFaces: BooleanArray = booleanArrayOf(true, false, true, true, true, true) - override fun getFaceSize(direction: Directions, random: Random): Array { - return arrayOf() // ToDo - } - override fun singleRender(position: Vec3i, mesh: ChunkSectionMesh, random: Random, neighbours: Array, light: Int, ambientLight: IntArray) { val floatPosition = position.toVec3() for ((index, direction) in faces.withIndex()) { val neighbour = neighbours[index] if (neighbour != null) { - continue + // continue } for (face in direction) { face.singleRender(floatPosition, mesh, neighbour, light, ambientLight) diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/models/unbaked/block/MultipartRootModel.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/models/unbaked/block/MultipartRootModel.kt new file mode 100644 index 000000000..1678bcd0b --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/models/unbaked/block/MultipartRootModel.kt @@ -0,0 +1,122 @@ +/* + * 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 . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.gui.rendering.models.unbaked.block + +import de.bixilon.minosoft.data.registries.ResourceLocation +import de.bixilon.minosoft.data.registries.blocks.BlockState +import de.bixilon.minosoft.data.registries.blocks.properties.BlockProperties +import de.bixilon.minosoft.gui.rendering.models.unbaked.GenericUnbakedModel +import de.bixilon.minosoft.gui.rendering.models.unbaked.UnbakedModel +import de.bixilon.minosoft.util.KUtil.unsafeCast +import de.bixilon.minosoft.util.nbt.tag.NBTUtil.compoundCast + +class MultipartRootModel( + private val conditions: MutableMap>>, Set>, +) : RootModel { + + private fun Set>.matches(blockState: BlockState): Boolean { + var matches = false + + for (propertyMap in this) { + var singleMatches = false + for ((property, value) in propertyMap) { + if (blockState.properties[property] == value) { + singleMatches = true + break + } + } + if (singleMatches) { + matches = true + break + } + } + + return matches + } + + private fun MutableSet>>.matchesAny(blockState: BlockState): Boolean { + var matches = true + for (or in this) { + if (!or.matches(blockState)) { + matches = false + break + } + } + return matches + } + + override fun getModelForState(blockState: BlockState): UnbakedModel { + val models: MutableSet = mutableSetOf() + + for ((condition, apply) in conditions) { + if (condition.matchesAny(blockState)) { + models += apply + } + } + + return UnbakedMultipartModel(models) + } + + companion object { + + private fun getCondition(data: MutableMap): MutableSet> { + val singleCondition: MutableSet> = mutableSetOf() + for ((propertyName, value) in data) { + val properties: MutableMap = mutableMapOf() + + for (propertyValue in value.toString().split("|")) { + properties += BlockProperties.parseProperty(propertyName, propertyValue) + } + singleCondition += properties + } + return singleCondition + } + + operator fun invoke(models: Map, data: List): MultipartRootModel { + val conditions: MutableMap>>, Set> = mutableMapOf() + + + for (modelData in data) { + check(modelData is Map<*, *>) + val condition: MutableSet>> = mutableSetOf() + val applyData = modelData["apply"]!! + val apply: MutableSet = mutableSetOf() + if (applyData is Map<*, *>) { + apply += UnbakedBlockStateModel(models, applyData.unsafeCast()) + } else if (applyData is List<*>) { + for (applyModelData in applyData) { + apply += UnbakedBlockStateModel(models, applyModelData.unsafeCast()) + } + } + + modelData["when"]?.compoundCast()?.let { + val or = it["OR"] + if (or is List<*>) { + for (orData in or) { + condition += getCondition(orData.unsafeCast()) + } + return@let + } + condition += getCondition(it) + } + + + + conditions[condition] = apply + } + + return MultipartRootModel(conditions) + } + } +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/models/unbaked/block/RootModel.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/models/unbaked/block/RootModel.kt index 7f7728ac2..5afd12a2b 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/models/unbaked/block/RootModel.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/models/unbaked/block/RootModel.kt @@ -28,10 +28,8 @@ interface RootModel { val variants = data["variants"] val multipart = data["multipart"] return when { - // ToDo: Single? variants != null -> SimpleRootModel(models, variants.unsafeCast()) - // ToDo: multipart != null -> MultipartUnbakedBlockStateModel(models, multipart.unsafeCast()) - multipart != null -> null + multipart != null -> MultipartRootModel(models, multipart.unsafeCast()) else -> TODO("Don't know what type of block state model to choose: $data") } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/models/unbaked/block/UnbakedBlockStateModel.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/models/unbaked/block/UnbakedBlockStateModel.kt index 827f55a50..519ff4612 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/models/unbaked/block/UnbakedBlockStateModel.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/models/unbaked/block/UnbakedBlockStateModel.kt @@ -38,21 +38,9 @@ import glm_.vec2.Vec2 import glm_.vec2.Vec2i import glm_.vec3.Vec3 import glm_.vec3.swizzle.xz -import kotlin.collections.Map -import kotlin.collections.MutableList -import kotlin.collections.MutableMap import kotlin.collections.component1 import kotlin.collections.component2 -import kotlin.collections.drop -import kotlin.collections.iterator -import kotlin.collections.mutableListOf -import kotlin.collections.mutableMapOf -import kotlin.collections.plus -import kotlin.collections.plusAssign import kotlin.collections.set -import kotlin.collections.take -import kotlin.collections.toTypedArray -import kotlin.collections.withIndex data class UnbakedBlockStateModel( val model: UnbakedBlockModel, @@ -114,7 +102,7 @@ data class UnbakedBlockStateModel( direction = Directions.byDirection(Vec3(face.direction.vectorf).apply { rotateAssign(rad) }) for ((index, position) in positions.withIndex()) { - positions[index] = Vec3(position).apply { rotateAssign(rad) } + positions[index] = Vec3(position).apply { rotateAssign(rad, true) } } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/models/unbaked/block/UnbakedMultipartModel.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/models/unbaked/block/UnbakedMultipartModel.kt new file mode 100644 index 000000000..0f361b93b --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/models/unbaked/block/UnbakedMultipartModel.kt @@ -0,0 +1,24 @@ +package de.bixilon.minosoft.gui.rendering.models.unbaked.block + +import de.bixilon.minosoft.gui.rendering.RenderWindow +import de.bixilon.minosoft.gui.rendering.models.baked.BakedModel +import de.bixilon.minosoft.gui.rendering.models.baked.MultipartBakedModel +import de.bixilon.minosoft.gui.rendering.models.baked.block.BakedBlockModel +import de.bixilon.minosoft.gui.rendering.models.unbaked.UnbakedModel +import de.bixilon.minosoft.util.KUtil.unsafeCast + +class UnbakedMultipartModel( + val models: Set, +) : UnbakedModel { + + override fun bake(renderWindow: RenderWindow): BakedModel { + val baked: Array = arrayOfNulls(this.models.size) + + var index = 0 + for (model in this.models) { + baked[index++] = model.bake(renderWindow) + } + + return MultipartBakedModel(baked.unsafeCast()) + } +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/util/vec/vec3/Vec3Util.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/util/vec/vec3/Vec3Util.kt index 2dd37ccb3..f7025dadb 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/util/vec/vec3/Vec3Util.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/util/vec/vec3/Vec3Util.kt @@ -59,9 +59,17 @@ object Vec3Util { } } - fun Vec3.rotateAssign(rotation: Vec2) { + fun Vec3.rotateAssign(rotation: Vec2, centerBlock: Boolean = false) { + if (centerBlock) { + this -= 0.5f + } + rotateAssign(rotation.y, Axes.Y) rotateAssign(rotation.x, Axes.X) + + if (centerBlock) { + this += 0.5f + } } fun Vec3.rotateAssign(angle: Float, axis: Axes, origin: Vec3, rescale: Boolean) {