diff --git a/src/main/java/de/bixilon/minosoft/data/direction/Directions.kt b/src/main/java/de/bixilon/minosoft/data/direction/Directions.kt index e656fe01b..08dec8ae7 100644 --- a/src/main/java/de/bixilon/minosoft/data/direction/Directions.kt +++ b/src/main/java/de/bixilon/minosoft/data/direction/Directions.kt @@ -36,7 +36,7 @@ enum class Directions( override val vectorf = Vec3(vector) override val vectord = Vec3d(vector) - val axis: Axes get() = Axes.get(this) + val axis: Axes get() = Axes[this] // ToDo lateinit var inverted: Directions private set @@ -64,6 +64,17 @@ enum class Directions( } } + fun getPositions(from: Vec3, to: Vec3): Array { + return when (this) { + DOWN -> arrayOf(from, Vec3(to.x, from.y, from.y), Vec3(from.x, from.y, to.z), Vec3(to.x, from.y, to.z)) + UP -> arrayOf(to, Vec3(to.x, to.y, from.y), Vec3(from.x, to.y, to.z), Vec3(from.x, to.y, from.z)) + NORTH -> arrayOf(Vec3(to.x, to.y, from.y), Vec3(to.x, from.y, from.y), Vec3(from.x, to.y, from.z), from) + SOUTH -> arrayOf(Vec3(from.x, from.y, to.z), Vec3(to.x, from.y, to.y), Vec3(from.x, to.y, to.z), to) + WEST -> arrayOf(Vec3(from.x, to.y, to.z), Vec3(from.x, to.y, from.y), Vec3(from.x, from.y, to.z), from) + EAST -> arrayOf(Vec3(to.x, from.y, from.z), Vec3(to.x, to.y, from.y), Vec3(to.x, from.y, to.z), to) + } + } + companion object : BlockPropertiesSerializer, ValuesEnum { override val VALUES = values() diff --git a/src/main/java/de/bixilon/minosoft/data/registries/blocks/BlockState.kt b/src/main/java/de/bixilon/minosoft/data/registries/blocks/BlockState.kt index 728594638..ace802df1 100644 --- a/src/main/java/de/bixilon/minosoft/data/registries/blocks/BlockState.kt +++ b/src/main/java/de/bixilon/minosoft/data/registries/blocks/BlockState.kt @@ -21,6 +21,7 @@ import de.bixilon.minosoft.data.registries.registries.Registries import de.bixilon.minosoft.data.registries.sounds.SoundEvent import de.bixilon.minosoft.data.text.RGBColor import de.bixilon.minosoft.gui.rendering.TintColorCalculator +import de.bixilon.minosoft.gui.rendering.models.baked.block.BakedBlockModel import de.bixilon.minosoft.util.KUtil.toBoolean import de.bixilon.minosoft.util.KUtil.toInt import de.bixilon.minosoft.util.KUtil.unsafeCast @@ -45,6 +46,7 @@ data class BlockState( val soundEventVolume: Float = 1.0f, val soundEventPitch: Float = 1.0f, ) { + var model: BakedBlockModel? = null override fun hashCode(): Int { return Objects.hash(block, properties) 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 332fb7ff0..3a37b2fc5 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 @@ -113,6 +113,10 @@ enum class BlockProperties { ROTATION("rotation", IntBlockPropertiesSerializer), ORIENTATION("orientation", Orientations), + + // ToDo: used in models + MAP("map", BooleanBlockPropertiesSerializer), + ; val group: String diff --git a/src/main/java/de/bixilon/minosoft/data/registries/blocks/properties/MultipartDirectionParser.kt b/src/main/java/de/bixilon/minosoft/data/registries/blocks/properties/MultipartDirectionParser.kt index c6272377f..1e122cdb1 100644 --- a/src/main/java/de/bixilon/minosoft/data/registries/blocks/properties/MultipartDirectionParser.kt +++ b/src/main/java/de/bixilon/minosoft/data/registries/blocks/properties/MultipartDirectionParser.kt @@ -19,10 +19,10 @@ import java.util.* enum class MultipartDirectionParser( vararg val aliases: Any, ) { - NONE(false), + NONE(false, "false"), LOW, UP, - SIDE(true), + SIDE(true, "true"), TALL, ; diff --git a/src/main/java/de/bixilon/minosoft/data/registries/blocks/properties/serializer/BooleanBlockPropertiesSerializer.kt b/src/main/java/de/bixilon/minosoft/data/registries/blocks/properties/serializer/BooleanBlockPropertiesSerializer.kt index 71a1b425f..3fdbc06f3 100644 --- a/src/main/java/de/bixilon/minosoft/data/registries/blocks/properties/serializer/BooleanBlockPropertiesSerializer.kt +++ b/src/main/java/de/bixilon/minosoft/data/registries/blocks/properties/serializer/BooleanBlockPropertiesSerializer.kt @@ -13,16 +13,11 @@ package de.bixilon.minosoft.data.registries.blocks.properties.serializer +import de.bixilon.minosoft.util.KUtil.toBoolean + object BooleanBlockPropertiesSerializer : BlockPropertiesSerializer { override fun deserialize(value: Any): Boolean { - if (value is Boolean) { - return value - } - return when (value) { - "true" -> true - "false" -> false - else -> throw IllegalArgumentException("Not a boolean: $value") - } + return value.toBoolean() } } diff --git a/src/main/java/de/bixilon/minosoft/data/registries/blocks/properties/serializer/IntBlockPropertiesSerializer.kt b/src/main/java/de/bixilon/minosoft/data/registries/blocks/properties/serializer/IntBlockPropertiesSerializer.kt index e9e0f1b55..bb1933b6f 100644 --- a/src/main/java/de/bixilon/minosoft/data/registries/blocks/properties/serializer/IntBlockPropertiesSerializer.kt +++ b/src/main/java/de/bixilon/minosoft/data/registries/blocks/properties/serializer/IntBlockPropertiesSerializer.kt @@ -13,9 +13,11 @@ package de.bixilon.minosoft.data.registries.blocks.properties.serializer +import de.bixilon.minosoft.util.KUtil.toInt + object IntBlockPropertiesSerializer : BlockPropertiesSerializer { override fun deserialize(value: Any): Int { - return value as Int + return value.toInt() } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/block/SectionPreparer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/block/SectionPreparer.kt index 1e54d9d73..971780802 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/block/SectionPreparer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/block/SectionPreparer.kt @@ -16,6 +16,9 @@ package de.bixilon.minosoft.gui.rendering.block import de.bixilon.minosoft.data.world.ChunkSection import de.bixilon.minosoft.gui.rendering.RenderWindow import de.bixilon.minosoft.gui.rendering.block.mesh.ChunkSectionMesh +import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition +import glm_.vec3.Vec3i +import java.util.* class SectionPreparer( val renderWindow: RenderWindow, @@ -25,6 +28,16 @@ class SectionPreparer( fun prepare(section: ChunkSection): ChunkSectionMesh { val mesh = ChunkSectionMesh(renderWindow) + for (x in 0 until ProtocolDefinition.SECTION_MAX_X) { + for (y in 0 until ProtocolDefinition.SECTION_MAX_Y) { + for (z in 0 until ProtocolDefinition.SECTION_MAX_Z) { + val block = section.blocks[ChunkSection.getIndex(x, y, z)] + + block?.model?.singleRender(Vec3i(x, y, z), mesh, Random(0L), 0xFF, intArrayOf(0xF, 0xF, 0xF, 0xF)) + } + } + } + return mesh 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 5f2e38519..4c24beae2 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 @@ -43,25 +43,30 @@ class WorldRenderer( private val shader = renderSystem.createShader("minosoft:world".toResourceLocation()) private val world: World = connection.world private val sectionPreparer = SectionPreparer(renderWindow) + private val lightMap = LightMap(connection) private lateinit var mesh: ChunkSectionMesh override fun init() { val asset = Resources.getAssetVersionByVersion(connection.version) val zip = ZipInputStream(GZIPInputStream(FileInputStream(AssetsUtil.getAssetDiskPath(asset.clientJarHash!!, true)))) - val modelLoader = ModelLoader(zip) + val modelLoader = ModelLoader(zip, renderWindow) modelLoader.load() - - val dirt = connection.registries.blockRegistry["dirt"]?.defaultState - val chunk = ChunkSection(Array(4096) { dirt }) - mesh = sectionPreparer.prepare(chunk) - mesh.load() } override fun postInit() { + lightMap.init() + shader.load() renderWindow.textureManager.staticTextures.use(shader) renderWindow.textureManager.staticTextures.animator.use(shader) + lightMap.use(shader) + + + val blockState = connection.registries.blockRegistry["dispenser"]?.defaultState + val chunk = ChunkSection(Array(4096) { if (it < 1) blockState else null }) + mesh = sectionPreparer.prepare(chunk) + mesh.load() } override fun setupOpaque() { diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/models/FaceSize.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/models/FaceSize.kt new file mode 100644 index 000000000..fc44c3ae2 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/models/FaceSize.kt @@ -0,0 +1,21 @@ +/* + * 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 + +import glm_.vec3.Vec3 + +class FaceSize( + val start: Vec3, + val end: Vec3, +) diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/models/ModelLoader.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/models/ModelLoader.kt index de56ee3fa..1ee60adb3 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/models/ModelLoader.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/models/ModelLoader.kt @@ -14,10 +14,13 @@ package de.bixilon.minosoft.gui.rendering.models import de.bixilon.minosoft.data.registries.ResourceLocation +import de.bixilon.minosoft.data.registries.registries.Registries +import de.bixilon.minosoft.gui.rendering.RenderWindow import de.bixilon.minosoft.gui.rendering.models.builtin.BuiltinModels +import de.bixilon.minosoft.gui.rendering.models.unbaked.GenericUnbakedModel import de.bixilon.minosoft.gui.rendering.models.unbaked.UnbakedBlockModel import de.bixilon.minosoft.gui.rendering.models.unbaked.UnbakedItemModel -import de.bixilon.minosoft.gui.rendering.models.unbaked.UnbakedModel +import de.bixilon.minosoft.gui.rendering.models.unbaked.block.RootModel import de.bixilon.minosoft.util.KUtil.fromJson import de.bixilon.minosoft.util.KUtil.toResourceLocation import de.bixilon.minosoft.util.KUtil.unsafeCast @@ -33,11 +36,15 @@ import java.util.zip.ZipInputStream class ModelLoader( val jar: ZipInputStream, + val renderWindow: RenderWindow, ) { - private val unbakedBlockModels: MutableMap = BuiltinModels.BUILTIN_MODELS.toMutableMap() + private val unbakedBlockModels: MutableMap = BuiltinModels.BUILTIN_MODELS.toMutableMap() + private val unbakedBlockStateModels: MutableMap = mutableMapOf() private val blockStateJsons: MutableMap> = mutableMapOf() private val modelJsons: MutableMap> = mutableMapOf() + private val registry: Registries = renderWindow.connection.registries + private fun loadJsons() { // ToDo: Integrate in assets manager var entry: ZipEntry? = jar.nextEntry @@ -61,45 +68,77 @@ class ModelLoader( } } - fun load() { - loadJsons() - Log.log(LogMessageType.VERSION_LOADING, LogLevels.VERBOSE) { "Loaded ${blockStateJsons.size} block states and ${modelJsons.size} model jsons!" } + private fun cleanup() { + modelJsons.clear() + blockStateJsons.clear() + } + private fun loadBlockModel(name: ResourceLocation, data: Map? = null): GenericUnbakedModel { + unbakedBlockModels[name]?.let { return it.unsafeCast() } + val data = data ?: modelJsons[name] ?: error("Can not find json: $name") - fun loadBlockModel(name: ResourceLocation, json: Map? = null): UnbakedModel { - unbakedBlockModels[name]?.let { return it.unsafeCast() } - val data = json ?: modelJsons[name] ?: error("Can not find json: $name") + val parent = data["parent"]?.toResourceLocation()?.let { loadBlockModel(it) } - val parent = data["parent"]?.toResourceLocation()?.let { loadBlockModel(it) } + val model = UnbakedBlockModel(parent, data) - val model = UnbakedBlockModel(parent, data) + unbakedBlockModels[name] = model + return model + } - unbakedBlockModels[name] = model - return model - } + private fun loadItemModel(name: ResourceLocation, data: Map? = null): GenericUnbakedModel { + unbakedBlockModels[name]?.let { return it.unsafeCast() } + val data = data ?: modelJsons[name] ?: error("Can not find json: $name") + val parent = data["parent"]?.toResourceLocation()?.let { loadItemModel(it) } - fun loadItemModel(name: ResourceLocation, json: Map? = null): UnbakedModel { - unbakedBlockModels[name]?.let { return it.unsafeCast() } - val data = json ?: modelJsons[name] ?: error("Can not find json: $name") + val model = UnbakedItemModel(parent, data) - val parent = data["parent"]?.toResourceLocation()?.let { loadItemModel(it) } + unbakedBlockModels[name] = model + return model + } - val model = UnbakedItemModel(parent, data) - - unbakedBlockModels[name] = model - return model - } - - for ((name, json) in modelJsons) { + private fun loadModels() { + for ((name, data) in modelJsons) { if (name.path.startsWith("block/")) { - loadBlockModel(name, json) + loadBlockModel(name, data) } else if (name.path.startsWith("item/")) { - loadItemModel(name, json) + loadItemModel(name, data) } else { TODO("Unknown block model type: $name") } } - Log.log(LogMessageType.VERSION_LOADING, LogLevels.VERBOSE) { "Done loading models!" } + } + + private fun loadBlockStates() { + for ((name, data) in blockStateJsons) { + val model = RootModel(unbakedBlockModels, data) ?: continue + unbakedBlockStateModels[name] = model + } + } + + private fun bakeModels() { + for ((name, model) in unbakedBlockStateModels) { + val block = registry.blockRegistry[name] ?: continue + + for (state in block.states) { + state.model = model.getModelForState(state).bake(renderWindow).unsafeCast() + } + } + } + + fun load() { + loadJsons() + Log.log(LogMessageType.VERSION_LOADING, LogLevels.VERBOSE) { "Loaded ${blockStateJsons.size} block states and ${modelJsons.size} model jsons!" } + + loadModels() + Log.log(LogMessageType.VERSION_LOADING, LogLevels.VERBOSE) { "Done loading unbaked models!" } + + loadBlockStates() + Log.log(LogMessageType.VERSION_LOADING, LogLevels.VERBOSE) { "Done loading block states!" } + + bakeModels() + Log.log(LogMessageType.VERSION_LOADING, LogLevels.VERBOSE) { "Done baking models!" } + + cleanup() } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/models/baked/BakedModel.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/models/baked/BakedModel.kt new file mode 100644 index 000000000..eb2b120eb --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/models/baked/BakedModel.kt @@ -0,0 +1,16 @@ +/* + * 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 + +interface BakedModel 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 new file mode 100644 index 000000000..1d639e04e --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/models/baked/WeightedBakedModel.kt @@ -0,0 +1,65 @@ +/* + * 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.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.* +import kotlin.math.abs + +class WeightedBakedModel( + val models: Map, +) : BakedBlockModel { + val totalWeight: Int + + init { + var totalWeight = 0 + for ((_, weight) in models) { + totalWeight += weight + } + + this.totalWeight = totalWeight + } + + private fun getModel(random: Random): BakedBlockModel { + val totalWeight = abs(random.nextLong() % totalWeight) + + var weightLeft = totalWeight + + for ((model, weight) in models) { + weightLeft -= weight + if (weightLeft < 0) { + return model + } + } + TODO("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) + } + + override fun singleRender(position: Vec3i, mesh: ChunkSectionMesh, random: Random, light: Int, ambientLight: IntArray) { + getModel(random).singleRender(position, mesh, random, light, ambientLight) + } + +} 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 new file mode 100644 index 000000000..f02e236e1 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/models/baked/block/BakedBlockModel.kt @@ -0,0 +1,33 @@ +/* + * 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.block + +import de.bixilon.minosoft.data.direction.Directions +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, light: Int, ambientLight: IntArray) + + // ToDo: Get ambient light + fun getLight(position: Vec3i, random: Random, side: Directions, lightAccessor: LightAccessor): Int +} 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 new file mode 100644 index 000000000..98c260a0e --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/models/baked/block/BakedBlockStateModel.kt @@ -0,0 +1,43 @@ +/* + * 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.block + +import de.bixilon.minosoft.data.direction.Directions +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 glm_.vec3.Vec3i +import java.util.* + +class BakedBlockStateModel( + val faces: Array>, + val sizes: Array>, +) : BakedBlockModel { + + override fun getFaceSize(direction: Directions, random: Random): Array { + return sizes[direction.ordinal] + } + + override fun singleRender(position: Vec3i, mesh: ChunkSectionMesh, random: Random, light: Int, ambientLight: IntArray) { + for (direction in faces) { + for (face in direction) { + face.singleRender(position, mesh, light, ambientLight) + } + } + } + + override fun getLight(position: Vec3i, random: Random, side: Directions, lightAccessor: LightAccessor): Int { + TODO("Not yet implemented") + } +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/models/baked/block/BakedFace.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/models/baked/block/BakedFace.kt new file mode 100644 index 000000000..4ac3a8355 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/models/baked/block/BakedFace.kt @@ -0,0 +1,50 @@ +/* + * 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.block + +import de.bixilon.minosoft.data.direction.Directions +import de.bixilon.minosoft.gui.rendering.block.mesh.ChunkSectionMesh +import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.AbstractTexture +import glm_.vec2.Vec2 +import glm_.vec3.Vec3 +import glm_.vec3.Vec3i + +class BakedFace( + val positions: Array, + val uv: Array, + val shade: Boolean, + val tintIndex: Int, + val cullFace: Directions?, + val texture: AbstractTexture, +) { + fun singleRender(position: Vec3i, mesh: ChunkSectionMesh, light: Int, ambientLight: IntArray) { + val floatPosition = Vec3(position) + + for (index in DRAW_ORDER) { + mesh.addVertex(positions[index] + floatPosition, uv[index], texture, null, light) + } + } + + + companion object { + private val DRAW_ORDER = intArrayOf( + 0, + 1, + 3, + 3, + 2, + 0, + ) + } +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/models/baked/block/GreedyBakedBlockModel.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/models/baked/block/GreedyBakedBlockModel.kt new file mode 100644 index 000000000..e4066cb1b --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/models/baked/block/GreedyBakedBlockModel.kt @@ -0,0 +1,25 @@ +/* + * 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.block + +import de.bixilon.minosoft.data.direction.Directions +import de.bixilon.minosoft.gui.rendering.block.mesh.ChunkSectionMesh +import glm_.vec3.Vec3i + +interface GreedyBakedBlockModel { + val canGreedyMesh: Boolean + + // ToDo: Tint + fun greedyRender(start: Vec3i, end: Vec3i, side: Directions, mesh: ChunkSectionMesh, light: Int) +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/models/builtin/BuiltinModels.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/models/builtin/BuiltinModels.kt index 3e4e95f2d..9dd88a25e 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/models/builtin/BuiltinModels.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/models/builtin/BuiltinModels.kt @@ -14,10 +14,10 @@ package de.bixilon.minosoft.gui.rendering.models.builtin import de.bixilon.minosoft.data.registries.ResourceLocation -import de.bixilon.minosoft.gui.rendering.models.unbaked.UnbakedModel +import de.bixilon.minosoft.gui.rendering.models.unbaked.GenericUnbakedModel object BuiltinModels { - val BUILTIN_MODELS: Map = mapOf( + val BUILTIN_MODELS: Map = mapOf( UnbakedBlockEntityModel.RESOURCE_LOCATION to UnbakedBlockEntityModel, UnbakedGeneratedModel.RESOURCE_LOCATION to UnbakedGeneratedModel, ) diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/models/builtin/UnbakedBlockEntityModel.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/models/builtin/UnbakedBlockEntityModel.kt index c873d3679..d1dd92fb7 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/models/builtin/UnbakedBlockEntityModel.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/models/builtin/UnbakedBlockEntityModel.kt @@ -15,11 +15,17 @@ package de.bixilon.minosoft.gui.rendering.models.builtin import de.bixilon.minosoft.data.registries.CompanionResourceLocation import de.bixilon.minosoft.data.registries.ResourceLocation -import de.bixilon.minosoft.gui.rendering.models.unbaked.UnbakedModel +import de.bixilon.minosoft.gui.rendering.RenderWindow +import de.bixilon.minosoft.gui.rendering.models.baked.BakedModel +import de.bixilon.minosoft.gui.rendering.models.unbaked.GenericUnbakedModel import de.bixilon.minosoft.util.KUtil.toResourceLocation @Deprecated("TODO") -object UnbakedBlockEntityModel : UnbakedModel(null, mapOf()), CompanionResourceLocation { +object UnbakedBlockEntityModel : GenericUnbakedModel(null, mapOf()), CompanionResourceLocation { override val RESOURCE_LOCATION: ResourceLocation = "minecraft:builtin/entity".toResourceLocation() + override fun bake(renderWindow: RenderWindow): BakedModel { + TODO("Not yet implemented") + } + } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/models/builtin/UnbakedGeneratedModel.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/models/builtin/UnbakedGeneratedModel.kt index bcdc1b6ee..080557685 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/models/builtin/UnbakedGeneratedModel.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/models/builtin/UnbakedGeneratedModel.kt @@ -15,11 +15,17 @@ package de.bixilon.minosoft.gui.rendering.models.builtin import de.bixilon.minosoft.data.registries.CompanionResourceLocation import de.bixilon.minosoft.data.registries.ResourceLocation -import de.bixilon.minosoft.gui.rendering.models.unbaked.UnbakedModel +import de.bixilon.minosoft.gui.rendering.RenderWindow +import de.bixilon.minosoft.gui.rendering.models.baked.BakedModel +import de.bixilon.minosoft.gui.rendering.models.unbaked.GenericUnbakedModel import de.bixilon.minosoft.util.KUtil.toResourceLocation @Deprecated("TODO") -object UnbakedGeneratedModel : UnbakedModel(null, mapOf()), CompanionResourceLocation { +object UnbakedGeneratedModel : GenericUnbakedModel(null, mapOf()), CompanionResourceLocation { override val RESOURCE_LOCATION: ResourceLocation = "minecraft:builtin/generated".toResourceLocation() + override fun bake(renderWindow: RenderWindow): BakedModel { + TODO("Not yet implemented") + } + } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/models/unbaked/GenericUnbakedModel.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/models/unbaked/GenericUnbakedModel.kt new file mode 100644 index 000000000..af43393cf --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/models/unbaked/GenericUnbakedModel.kt @@ -0,0 +1,73 @@ +/* + * 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 + +import de.bixilon.minosoft.gui.rendering.models.display.ModelDisplay +import de.bixilon.minosoft.gui.rendering.models.display.ModelDisplayPositions +import de.bixilon.minosoft.gui.rendering.models.unbaked.element.UnbakedElement +import de.bixilon.minosoft.util.KUtil.unsafeCast +import de.bixilon.minosoft.util.nbt.tag.NBTUtil.compoundCast +import de.bixilon.minosoft.util.nbt.tag.NBTUtil.listCast + +abstract class GenericUnbakedModel( + parent: GenericUnbakedModel?, + json: Map, +) : UnbakedModel { + val display: Map + val elements: Set + + + init { + val display = parent?.display?.toMutableMap() ?: mutableMapOf() + + json["display"]?.compoundCast()?.let { + for ((name, value) in it) { + display[ModelDisplayPositions[name]] = ModelDisplay(data = value.unsafeCast()) + } + } + + this.display = display + } + + val textures: Map + + init { + val textures = parent?.textures?.toMutableMap() ?: mutableMapOf() + + json["textures"]?.compoundCast()?.let { + for ((name, value) in it) { + textures[name] = value.toString() + } + } + + this.textures = textures + } + + init { + val elements: MutableSet + + val elementJson = json["elements"]?.listCast>() + + if (elementJson != null) { + elements = mutableSetOf() + for (element in elementJson) { + elements += UnbakedElement(data = element) + } + } else { + elements = parent?.elements?.toMutableSet() ?: mutableSetOf() + } + + this.elements = elements + } +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/models/unbaked/UnbakedBlockModel.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/models/unbaked/UnbakedBlockModel.kt index 958a15093..4c38aa526 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/models/unbaked/UnbakedBlockModel.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/models/unbaked/UnbakedBlockModel.kt @@ -13,11 +13,17 @@ package de.bixilon.minosoft.gui.rendering.models.unbaked +import de.bixilon.minosoft.gui.rendering.RenderWindow +import de.bixilon.minosoft.gui.rendering.models.baked.BakedModel import de.bixilon.minosoft.util.KUtil.toBoolean class UnbakedBlockModel( - parent: UnbakedModel?, + parent: GenericUnbakedModel?, json: Map, -) : UnbakedModel(parent, json) { +) : GenericUnbakedModel(parent, json) { val ambientOcclusion: Boolean = json["ambientocclusion"]?.toBoolean() ?: parent?.let { return@let if (parent is UnbakedBlockModel) parent.ambientOcclusion else null } ?: true + + override fun bake(renderWindow: RenderWindow): BakedModel { + return object : BakedModel {} // ToDo + } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/models/unbaked/UnbakedItemModel.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/models/unbaked/UnbakedItemModel.kt index f97cfb646..9f3b74fd0 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/models/unbaked/UnbakedItemModel.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/models/unbaked/UnbakedItemModel.kt @@ -13,13 +13,19 @@ package de.bixilon.minosoft.gui.rendering.models.unbaked +import de.bixilon.minosoft.gui.rendering.RenderWindow import de.bixilon.minosoft.gui.rendering.models.GUILights +import de.bixilon.minosoft.gui.rendering.models.baked.BakedModel class UnbakedItemModel( - parent: UnbakedModel?, + parent: GenericUnbakedModel?, json: Map, -) : UnbakedModel(parent, json) { +) : GenericUnbakedModel(parent, json) { val guiLight: GUILights = json["gui_light"]?.toString()?.let { GUILights[it] } ?: parent?.let { return@let if (parent is UnbakedItemModel) parent.guiLight else null } ?: GUILights.SIDE // ToDo: Overrides (predicates) + + override fun bake(renderWindow: RenderWindow): BakedModel { + return object : BakedModel {} // ToDo + } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/models/unbaked/UnbakedModel.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/models/unbaked/UnbakedModel.kt index b58079e59..dc455e0b2 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/models/unbaked/UnbakedModel.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/models/unbaked/UnbakedModel.kt @@ -13,56 +13,10 @@ package de.bixilon.minosoft.gui.rendering.models.unbaked -import de.bixilon.minosoft.gui.rendering.models.display.ModelDisplay -import de.bixilon.minosoft.gui.rendering.models.display.ModelDisplayPositions -import de.bixilon.minosoft.gui.rendering.models.unbaked.element.UnbakedElement -import de.bixilon.minosoft.util.KUtil.unsafeCast -import de.bixilon.minosoft.util.nbt.tag.NBTUtil.compoundCast -import de.bixilon.minosoft.util.nbt.tag.NBTUtil.listCast +import de.bixilon.minosoft.gui.rendering.RenderWindow +import de.bixilon.minosoft.gui.rendering.models.baked.BakedModel -abstract class UnbakedModel( - parent: UnbakedModel?, - json: Map, -) : Model { - val display: Map - val elements: Set +interface UnbakedModel : Model { - - init { - val display = parent?.display?.toMutableMap() ?: mutableMapOf() - - json["display"]?.compoundCast()?.let { - for ((name, value) in it) { - display[ModelDisplayPositions[name]] = ModelDisplay(data = value.unsafeCast()) - } - } - - this.display = display - } - - val textures: Map - - init { - val textures = parent?.textures?.toMutableMap() ?: mutableMapOf() - - json["textures"]?.compoundCast()?.let { - for ((name, value) in it) { - textures[name] = value.toString() - } - } - - this.textures = textures - } - - init { - val elements = parent?.elements?.toMutableSet() ?: mutableSetOf() - - json["elements"]?.listCast>()?.let { - for (element in it) { - elements += UnbakedElement(data = element) - } - } - - this.elements = elements - } + fun bake(renderWindow: RenderWindow): BakedModel } 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 new file mode 100644 index 000000000..7f7728ac2 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/models/unbaked/block/RootModel.kt @@ -0,0 +1,39 @@ +/* + * 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.gui.rendering.models.unbaked.GenericUnbakedModel +import de.bixilon.minosoft.gui.rendering.models.unbaked.UnbakedModel +import de.bixilon.minosoft.util.KUtil.unsafeCast + +interface RootModel { + + fun getModelForState(blockState: BlockState): UnbakedModel + + companion object { + operator fun invoke(models: Map, data: Map): 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 + 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/SimpleRootModel.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/models/unbaked/block/SimpleRootModel.kt new file mode 100644 index 000000000..95e9865e1 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/models/unbaked/block/SimpleRootModel.kt @@ -0,0 +1,77 @@ +/* + * 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 + +class SimpleRootModel( + private val conditions: Map, UnbakedModel>, +) : RootModel { + + private fun Map.matches(blockState: BlockState): Boolean { + for ((property, value) in this) { + blockState.properties[property]?.let { + if (value != it) { + return false + } + } + } + return true + } + + override fun getModelForState(blockState: BlockState): UnbakedModel { + for ((condition, model) in conditions) { + if (condition.matches(blockState)) { + return model + } + } + TODO("Could not find model for $blockState") + } + + companion object { + operator fun invoke(models: Map, data: Map): SimpleRootModel { + val conditions: MutableMap, UnbakedModel> = mutableMapOf() + + + for ((conditionString, value) in data) { + val condition: MutableMap = mutableMapOf() + + if (conditionString.isNotBlank()) { + for (pair in conditionString.split(",")) { + val (propertyName, propertyStringValue) = pair.split("=") + + val (property, propertyValue) = BlockProperties.parseProperty(propertyName, propertyStringValue) + + condition[property] = propertyValue + } + } + + val model = when (value) { + is Map<*, *> -> UnbakedBlockStateModel(models, value.unsafeCast()) + is List<*> -> WeightedUnbakedBlockStateModel(models, value.unsafeCast()) + else -> TODO("Can not create model: $value") + } + + conditions[condition] = model + } + + return SimpleRootModel(conditions) + } + } +} 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 new file mode 100644 index 000000000..d00e4744c --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/models/unbaked/block/UnbakedBlockStateModel.kt @@ -0,0 +1,124 @@ +/* + * 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.direction.Directions +import de.bixilon.minosoft.data.registries.ResourceLocation +import de.bixilon.minosoft.gui.rendering.RenderWindow +import de.bixilon.minosoft.gui.rendering.models.FaceSize +import de.bixilon.minosoft.gui.rendering.models.baked.block.BakedBlockModel +import de.bixilon.minosoft.gui.rendering.models.baked.block.BakedBlockStateModel +import de.bixilon.minosoft.gui.rendering.models.baked.block.BakedFace +import de.bixilon.minosoft.gui.rendering.models.unbaked.GenericUnbakedModel +import de.bixilon.minosoft.gui.rendering.models.unbaked.UnbakedBlockModel +import de.bixilon.minosoft.gui.rendering.models.unbaked.UnbakedModel +import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.AbstractTexture +import de.bixilon.minosoft.gui.rendering.textures.TextureUtil.texture +import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3iUtil.toVec3iN +import de.bixilon.minosoft.util.KUtil.toBoolean +import de.bixilon.minosoft.util.KUtil.toInt +import de.bixilon.minosoft.util.KUtil.toResourceLocation +import de.bixilon.minosoft.util.KUtil.unsafeCast +import glm_.vec2.Vec2 +import glm_.vec3.Vec3i + +data class UnbakedBlockStateModel( + val model: UnbakedBlockModel, + val rotation: Vec3i?, + val uvLock: Boolean, + val weight: Int, +) : UnbakedModel { + + override fun bake(renderWindow: RenderWindow): BakedBlockModel { + val textureArray = renderWindow.textureManager.staticTextures + + val resolvedTextures: MutableMap = mutableMapOf() + + + fun resolveTexture(key: String, value: String): AbstractTexture { + resolvedTextures[key]?.let { return it } + + val variable = value.removePrefix("#") + var texture: AbstractTexture? = null + if (variable.length != value.length) { + // resolve variable first + texture = resolveTexture(variable, model.textures[variable]!!) + } + + if (texture == null) { + texture = textureArray.createTexture(value.toResourceLocation().texture()) + } + + resolvedTextures[key] = texture + return texture + } + + + for ((key, value) in model.textures) { + resolveTexture(key, value) + } + + + val faces: Array> = Array(Directions.VALUES.size) { mutableListOf() } + val sizes: Array> = Array(Directions.VALUES.size) { mutableListOf() } + + for (element in model.elements) { + for (face in element.faces) { + val texture = resolvedTextures[face.texture.removePrefix("#")]!! // ToDo: Allow direct texture names? + val positions = face.direction.getPositions(element.from, element.to) + + val texturePositions = arrayOf( + face.uvStart, + Vec2(face.uvStart.x, face.uvEnd.y), + Vec2(face.uvEnd.x, face.uvStart.y), + face.uvEnd, + ) + + faces[face.direction.ordinal] += BakedFace( + positions = positions, + uv = texturePositions, + shade = element.shade, + tintIndex = face.tintIndex, + cullFace = face.cullFace, + texture = texture, + ) + } + } + + val finalFaces: Array?> = Array(faces.size) { null } + + for ((index, faceArray) in faces.withIndex()) { + finalFaces[index] = faceArray.toTypedArray() + } + + val finalSizes: Array?> = Array(sizes.size) { null } + + for ((index, sizeArray) in sizes.withIndex()) { + finalSizes[index] = sizeArray.toTypedArray() + } + + return BakedBlockStateModel(finalFaces.unsafeCast(), finalSizes.unsafeCast()) + } + + companion object { + operator fun invoke(models: Map, data: Map): UnbakedBlockStateModel { + return UnbakedBlockStateModel( + model = models[data["model"].toResourceLocation()].unsafeCast(), + rotation = data.toVec3iN(), + uvLock = data["uvlock"]?.toBoolean() ?: false, + weight = data["weight"]?.toInt() ?: 1, + ) + } + } +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/models/unbaked/block/WeightedUnbakedBlockStateModel.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/models/unbaked/block/WeightedUnbakedBlockStateModel.kt new file mode 100644 index 000000000..d6920926d --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/models/unbaked/block/WeightedUnbakedBlockStateModel.kt @@ -0,0 +1,49 @@ +/* + * 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.gui.rendering.RenderWindow +import de.bixilon.minosoft.gui.rendering.models.baked.BakedModel +import de.bixilon.minosoft.gui.rendering.models.baked.WeightedBakedModel +import de.bixilon.minosoft.gui.rendering.models.baked.block.BakedBlockModel +import de.bixilon.minosoft.gui.rendering.models.unbaked.GenericUnbakedModel +import de.bixilon.minosoft.gui.rendering.models.unbaked.UnbakedModel + +class WeightedUnbakedBlockStateModel( + val models: List, +) : UnbakedModel { + + override fun bake(renderWindow: RenderWindow): BakedModel { + val baked: MutableMap = mutableMapOf() + + for (model in models) { + baked[model.bake(renderWindow)] = model.weight + } + + return WeightedBakedModel(baked) + } + + companion object { + operator fun invoke(models: Map, data: List>): WeightedUnbakedBlockStateModel { + val weightedModels: MutableList = mutableListOf() + + for (entry in data) { + weightedModels += UnbakedBlockStateModel(models, entry) + } + + return WeightedUnbakedBlockStateModel(weightedModels) + } + } +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/models/unbaked/element/UnbakedElement.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/models/unbaked/element/UnbakedElement.kt index d105d20f8..3f605f2b2 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/models/unbaked/element/UnbakedElement.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/models/unbaked/element/UnbakedElement.kt @@ -30,6 +30,8 @@ data class UnbakedElement( ) { companion object { + const val BLOCK_RESOLUTION = 16.0f + operator fun invoke(data: Map): UnbakedElement { val faces: MutableSet = mutableSetOf() @@ -40,8 +42,8 @@ data class UnbakedElement( } return UnbakedElement( - from = data["from"].toVec3(), - to = data["to"].toVec3(), + from = data["from"].toVec3() / BLOCK_RESOLUTION, + to = data["to"].toVec3() / BLOCK_RESOLUTION, rotation = data["rotation"]?.compoundCast()?.let { return@let UnbakedElementRotation(data = it) }, shade = data["shade"]?.toBoolean() ?: true, faces = faces, diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/models/unbaked/element/UnbakedElementFace.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/models/unbaked/element/UnbakedElementFace.kt index e8469aea0..076f3019a 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/models/unbaked/element/UnbakedElementFace.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/models/unbaked/element/UnbakedElementFace.kt @@ -14,6 +14,7 @@ package de.bixilon.minosoft.gui.rendering.models.unbaked.element import de.bixilon.minosoft.data.direction.Directions +import de.bixilon.minosoft.gui.rendering.models.unbaked.element.UnbakedElement.Companion.BLOCK_RESOLUTION import de.bixilon.minosoft.util.KUtil.toInt import de.bixilon.minosoft.util.nbt.tag.NBTUtil.listCast import glm_.vec2.Vec2 @@ -30,8 +31,8 @@ data class UnbakedElementFace( companion object { operator fun invoke(direction: Directions, data: Map): UnbakedElementFace { val uv = data["uv"]?.listCast() - val uvStart = Vec2(uv?.get(0) ?: 0.0f, uv?.get(2) ?: 0.0f) - val uvEnd = Vec2(uv?.get(1) ?: 16.0f, uv?.get(3) ?: 16.0f) + val uvStart = Vec2(uv?.get(0) ?: 0.0f, uv?.get(2) ?: 0.0f) / BLOCK_RESOLUTION + val uvEnd = Vec2(uv?.get(1) ?: 16.0f, uv?.get(3) ?: 16.0f) / BLOCK_RESOLUTION return UnbakedElementFace( direction = direction, diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/util/vec/vec3/Vec3iUtil.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/util/vec/vec3/Vec3iUtil.kt index 152b753cb..4d2712eef 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/util/vec/vec3/Vec3iUtil.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/util/vec/vec3/Vec3iUtil.kt @@ -14,7 +14,6 @@ package de.bixilon.minosoft.gui.rendering.util.vec.vec3 import de.bixilon.minosoft.util.KUtil.toInt -import glm_.vec3.Vec3 import glm_.vec3.Vec3i object Vec3iUtil { @@ -22,10 +21,10 @@ object Vec3iUtil { val Vec3i.Companion.MIN: Vec3i get() = Vec3i(Int.MIN_VALUE, Int.MIN_VALUE, Int.MIN_VALUE) - val Vec3.Companion.EMPTY: Vec3i + val Vec3i.Companion.EMPTY: Vec3i get() = Vec3i(0, 0, 0) - val Vec3.Companion.MAX: Vec3i + val Vec3i.Companion.MAX: Vec3i get() = Vec3i(Int.MAX_VALUE, Int.MAX_VALUE, Int.MAX_VALUE) @@ -37,4 +36,13 @@ object Vec3iUtil { else -> default ?: throw IllegalArgumentException("Not a Vec3i: $this") } } + + fun Any?.toVec3iN(default: Vec3i? = null): Vec3i? { + return when (this) { + is List<*> -> Vec3i(this[0].toInt(), this[1].toInt(), this[2].toInt()) + is Map<*, *> -> Vec3i(this["x"]?.toInt() ?: 0.0f, this["y"]?.toInt() ?: 0.0f, this["z"]?.toInt() ?: 0.0f) + is Number -> Vec3i(this.toInt()) + else -> default + } + } } diff --git a/src/main/java/de/bixilon/minosoft/util/KUtil.kt b/src/main/java/de/bixilon/minosoft/util/KUtil.kt index b9e2f6d71..24f9d7be4 100644 --- a/src/main/java/de/bixilon/minosoft/util/KUtil.kt +++ b/src/main/java/de/bixilon/minosoft/util/KUtil.kt @@ -465,4 +465,28 @@ object KUtil { } return null } + + fun Any?.autoType(): Any? { + if (this == null) { + return this + } + if (this is Number) { + return this + } + val string = this.toString() + + if (string == "true") { + return true + } + if (string == "false") { + return false + } + + // ToDo: Optimize + if (string.matches("\\d+".toRegex())) { + return string.toInt() + } + + return string + } }