mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-09 15:29:20 -04:00
wip: model baking
This commit is contained in:
parent
596866c3ee
commit
8ac5e14ddf
@ -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<Vec3> {
|
||||
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<Directions> {
|
||||
override val VALUES = values()
|
||||
|
@ -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)
|
||||
|
@ -113,6 +113,10 @@ enum class BlockProperties {
|
||||
ROTATION("rotation", IntBlockPropertiesSerializer),
|
||||
ORIENTATION("orientation", Orientations),
|
||||
|
||||
|
||||
// ToDo: used in models
|
||||
MAP("map", BooleanBlockPropertiesSerializer),
|
||||
|
||||
;
|
||||
|
||||
val group: String
|
||||
|
@ -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,
|
||||
;
|
||||
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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() {
|
||||
|
@ -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 <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
|
||||
|
||||
import glm_.vec3.Vec3
|
||||
|
||||
class FaceSize(
|
||||
val start: Vec3,
|
||||
val end: Vec3,
|
||||
)
|
@ -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<ResourceLocation, UnbakedModel> = BuiltinModels.BUILTIN_MODELS.toMutableMap()
|
||||
private val unbakedBlockModels: MutableMap<ResourceLocation, GenericUnbakedModel> = BuiltinModels.BUILTIN_MODELS.toMutableMap()
|
||||
private val unbakedBlockStateModels: MutableMap<ResourceLocation, RootModel> = mutableMapOf()
|
||||
private val blockStateJsons: MutableMap<ResourceLocation, Map<String, Any>> = mutableMapOf()
|
||||
private val modelJsons: MutableMap<ResourceLocation, Map<String, Any>> = 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<String, Any>? = 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<String, Any>? = 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<String, Any>? = 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<String, Any>? = 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()
|
||||
}
|
||||
}
|
||||
|
@ -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 <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.baked
|
||||
|
||||
interface BakedModel
|
@ -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 <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.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, Int>,
|
||||
) : 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<FaceSize> {
|
||||
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)
|
||||
}
|
||||
|
||||
}
|
@ -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 <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.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<FaceSize>
|
||||
|
||||
// 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
|
||||
}
|
@ -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 <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.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<Array<BakedFace>>,
|
||||
val sizes: Array<Array<FaceSize>>,
|
||||
) : BakedBlockModel {
|
||||
|
||||
override fun getFaceSize(direction: Directions, random: Random): Array<FaceSize> {
|
||||
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")
|
||||
}
|
||||
}
|
@ -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 <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.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<Vec3>,
|
||||
val uv: Array<Vec2>,
|
||||
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,
|
||||
)
|
||||
}
|
||||
}
|
@ -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 <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.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)
|
||||
}
|
@ -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<ResourceLocation, UnbakedModel> = mapOf(
|
||||
val BUILTIN_MODELS: Map<ResourceLocation, GenericUnbakedModel> = mapOf(
|
||||
UnbakedBlockEntityModel.RESOURCE_LOCATION to UnbakedBlockEntityModel,
|
||||
UnbakedGeneratedModel.RESOURCE_LOCATION to UnbakedGeneratedModel,
|
||||
)
|
||||
|
@ -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")
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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")
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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 <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.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<String, Any>,
|
||||
) : UnbakedModel {
|
||||
val display: Map<ModelDisplayPositions, ModelDisplay>
|
||||
val elements: Set<UnbakedElement>
|
||||
|
||||
|
||||
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<String, String>
|
||||
|
||||
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<UnbakedElement>
|
||||
|
||||
val elementJson = json["elements"]?.listCast<Map<String, Any>>()
|
||||
|
||||
if (elementJson != null) {
|
||||
elements = mutableSetOf()
|
||||
for (element in elementJson) {
|
||||
elements += UnbakedElement(data = element)
|
||||
}
|
||||
} else {
|
||||
elements = parent?.elements?.toMutableSet() ?: mutableSetOf()
|
||||
}
|
||||
|
||||
this.elements = elements
|
||||
}
|
||||
}
|
@ -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<String, Any>,
|
||||
) : 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
|
||||
}
|
||||
}
|
||||
|
@ -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<String, Any>,
|
||||
) : 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
|
||||
}
|
||||
}
|
||||
|
@ -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<String, Any>,
|
||||
) : Model {
|
||||
val display: Map<ModelDisplayPositions, ModelDisplay>
|
||||
val elements: Set<UnbakedElement>
|
||||
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<String, String>
|
||||
|
||||
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<Map<String, Any>>()?.let {
|
||||
for (element in it) {
|
||||
elements += UnbakedElement(data = element)
|
||||
}
|
||||
}
|
||||
|
||||
this.elements = elements
|
||||
}
|
||||
fun bake(renderWindow: RenderWindow): BakedModel
|
||||
}
|
||||
|
@ -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 <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.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<ResourceLocation, GenericUnbakedModel>, data: Map<String, Any>): 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")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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 <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.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<Map<BlockProperties, Any>, UnbakedModel>,
|
||||
) : RootModel {
|
||||
|
||||
private fun Map<BlockProperties, Any>.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<ResourceLocation, GenericUnbakedModel>, data: Map<String, Any>): SimpleRootModel {
|
||||
val conditions: MutableMap<Map<BlockProperties, Any>, UnbakedModel> = mutableMapOf()
|
||||
|
||||
|
||||
for ((conditionString, value) in data) {
|
||||
val condition: MutableMap<BlockProperties, Any> = 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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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 <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.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<String, AbstractTexture> = 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<MutableList<BakedFace>> = Array(Directions.VALUES.size) { mutableListOf() }
|
||||
val sizes: Array<MutableList<FaceSize>> = 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<BakedFace>?> = Array(faces.size) { null }
|
||||
|
||||
for ((index, faceArray) in faces.withIndex()) {
|
||||
finalFaces[index] = faceArray.toTypedArray()
|
||||
}
|
||||
|
||||
val finalSizes: Array<Array<FaceSize>?> = 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<ResourceLocation, GenericUnbakedModel>, data: Map<String, Any>): UnbakedBlockStateModel {
|
||||
return UnbakedBlockStateModel(
|
||||
model = models[data["model"].toResourceLocation()].unsafeCast(),
|
||||
rotation = data.toVec3iN(),
|
||||
uvLock = data["uvlock"]?.toBoolean() ?: false,
|
||||
weight = data["weight"]?.toInt() ?: 1,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -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 <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.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<UnbakedBlockStateModel>,
|
||||
) : UnbakedModel {
|
||||
|
||||
override fun bake(renderWindow: RenderWindow): BakedModel {
|
||||
val baked: MutableMap<BakedBlockModel, Int> = mutableMapOf()
|
||||
|
||||
for (model in models) {
|
||||
baked[model.bake(renderWindow)] = model.weight
|
||||
}
|
||||
|
||||
return WeightedBakedModel(baked)
|
||||
}
|
||||
|
||||
companion object {
|
||||
operator fun invoke(models: Map<ResourceLocation, GenericUnbakedModel>, data: List<Map<String, Any>>): WeightedUnbakedBlockStateModel {
|
||||
val weightedModels: MutableList<UnbakedBlockStateModel> = mutableListOf()
|
||||
|
||||
for (entry in data) {
|
||||
weightedModels += UnbakedBlockStateModel(models, entry)
|
||||
}
|
||||
|
||||
return WeightedUnbakedBlockStateModel(weightedModels)
|
||||
}
|
||||
}
|
||||
}
|
@ -30,6 +30,8 @@ data class UnbakedElement(
|
||||
) {
|
||||
|
||||
companion object {
|
||||
const val BLOCK_RESOLUTION = 16.0f
|
||||
|
||||
operator fun invoke(data: Map<String, Any>): UnbakedElement {
|
||||
val faces: MutableSet<UnbakedElementFace> = 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,
|
||||
|
@ -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<String, Any>): UnbakedElementFace {
|
||||
val uv = data["uv"]?.listCast<Number>()
|
||||
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,
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user