mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-12 00:47:26 -04:00
wip: multipart models
This commit is contained in:
parent
81dd2f7535
commit
486da0eda1
@ -134,11 +134,11 @@ enum class BlockProperties {
|
|||||||
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val PROPERTIES: Map<String, List<BlockProperties>> = run {
|
val PROPERTIES: Map<String, List<BlockProperties>> = run {
|
||||||
val map: MutableMap<String, MutableList<BlockProperties>> = mutableMapOf()
|
val map: MutableMap<String, MutableList<BlockProperties>> = mutableMapOf()
|
||||||
|
|
||||||
for (value in values()) {
|
for (value in values()) {
|
||||||
val list = map.getOrPut(value.group, { mutableListOf() })
|
val list = map.getOrPut(value.group) { mutableListOf() }
|
||||||
list.add(value)
|
list.add(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,8 +73,9 @@ class WorldRenderer(
|
|||||||
|
|
||||||
val random = Random(0L)
|
val random = Random(0L)
|
||||||
val blockState1 = connection.registries.blockRegistry["end_portal_frame"]?.defaultState
|
val blockState1 = connection.registries.blockRegistry["end_portal_frame"]?.defaultState
|
||||||
val blockState2 = connection.registries.blockRegistry["carved_pumpkin"]?.defaultState
|
val blockState2 = connection.registries.blockRegistry["oak_fence"]!!.defaultState//.withProperties(BlockProperties.FACING to Directions.SOUTH)
|
||||||
val section = ChunkSection(Array(4096) {
|
val section = ChunkSection(Array(4096) {
|
||||||
|
if (it < 256) return@Array blockState2 else return@Array null
|
||||||
when (random.nextInt(3)) {
|
when (random.nextInt(3)) {
|
||||||
1 -> blockState2
|
1 -> blockState2
|
||||||
2 -> blockState2
|
2 -> blockState2
|
||||||
|
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* Minosoft
|
||||||
|
* Copyright (C) 2021 Moritz Zwerger
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with this program. If not, see <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.registries.blocks.BlockState
|
||||||
|
import de.bixilon.minosoft.data.world.light.LightAccessor
|
||||||
|
import de.bixilon.minosoft.gui.rendering.block.mesh.ChunkSectionMesh
|
||||||
|
import de.bixilon.minosoft.gui.rendering.models.baked.block.BakedBlockModel
|
||||||
|
import glm_.vec3.Vec3i
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class MultipartBakedModel(
|
||||||
|
val models: Array<BakedBlockModel>,
|
||||||
|
) : BakedBlockModel {
|
||||||
|
|
||||||
|
override fun getLight(position: Vec3i, random: Random, side: Directions, lightAccessor: LightAccessor): Int {
|
||||||
|
return 0xFF
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun singleRender(position: Vec3i, mesh: ChunkSectionMesh, random: Random, neighbours: Array<BlockState?>, light: Int, ambientLight: IntArray) {
|
||||||
|
for (model in models) {
|
||||||
|
model.singleRender(position, mesh, random, neighbours, light, ambientLight)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -17,7 +17,6 @@ import de.bixilon.minosoft.data.direction.Directions
|
|||||||
import de.bixilon.minosoft.data.registries.blocks.BlockState
|
import de.bixilon.minosoft.data.registries.blocks.BlockState
|
||||||
import de.bixilon.minosoft.data.world.light.LightAccessor
|
import de.bixilon.minosoft.data.world.light.LightAccessor
|
||||||
import de.bixilon.minosoft.gui.rendering.block.mesh.ChunkSectionMesh
|
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 de.bixilon.minosoft.gui.rendering.models.baked.block.BakedBlockModel
|
||||||
import glm_.vec3.Vec3i
|
import glm_.vec3.Vec3i
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@ -52,10 +51,6 @@ class WeightedBakedModel(
|
|||||||
throw IllegalStateException("Could not find a model: This should never happen!")
|
throw IllegalStateException("Could not find a model: This 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 {
|
override fun getLight(position: Vec3i, random: Random, side: Directions, lightAccessor: LightAccessor): Int {
|
||||||
return getModel(random).getLight(position, random, side, lightAccessor)
|
return getModel(random).getLight(position, random, side, lightAccessor)
|
||||||
}
|
}
|
||||||
|
@ -17,15 +17,12 @@ import de.bixilon.minosoft.data.direction.Directions
|
|||||||
import de.bixilon.minosoft.data.registries.blocks.BlockState
|
import de.bixilon.minosoft.data.registries.blocks.BlockState
|
||||||
import de.bixilon.minosoft.data.world.light.LightAccessor
|
import de.bixilon.minosoft.data.world.light.LightAccessor
|
||||||
import de.bixilon.minosoft.gui.rendering.block.mesh.ChunkSectionMesh
|
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 de.bixilon.minosoft.gui.rendering.models.baked.BakedModel
|
||||||
import glm_.vec3.Vec3i
|
import glm_.vec3.Vec3i
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
interface BakedBlockModel : BakedModel {
|
interface BakedBlockModel : BakedModel {
|
||||||
|
|
||||||
fun getFaceSize(direction: Directions, random: Random): Array<FaceSize>
|
|
||||||
|
|
||||||
// ToDo: Tint
|
// ToDo: Tint
|
||||||
fun singleRender(position: Vec3i, mesh: ChunkSectionMesh, random: Random, neighbours: Array<BlockState?>, light: Int, ambientLight: IntArray)
|
fun singleRender(position: Vec3i, mesh: ChunkSectionMesh, random: Random, neighbours: Array<BlockState?>, light: Int, ambientLight: IntArray)
|
||||||
|
|
||||||
|
@ -17,7 +17,6 @@ import de.bixilon.minosoft.data.direction.Directions
|
|||||||
import de.bixilon.minosoft.data.registries.blocks.BlockState
|
import de.bixilon.minosoft.data.registries.blocks.BlockState
|
||||||
import de.bixilon.minosoft.data.world.light.LightAccessor
|
import de.bixilon.minosoft.data.world.light.LightAccessor
|
||||||
import de.bixilon.minosoft.gui.rendering.block.mesh.ChunkSectionMesh
|
import de.bixilon.minosoft.gui.rendering.block.mesh.ChunkSectionMesh
|
||||||
import de.bixilon.minosoft.gui.rendering.models.FaceSize
|
|
||||||
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3iUtil.toVec3
|
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3iUtil.toVec3
|
||||||
import glm_.vec3.Vec3i
|
import glm_.vec3.Vec3i
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@ -28,16 +27,12 @@ class BakedBlockStateModel(
|
|||||||
override val canGreedyMesh: Boolean = true
|
override val canGreedyMesh: Boolean = true
|
||||||
override val greedyMeshableFaces: BooleanArray = booleanArrayOf(true, false, true, true, true, true)
|
override val greedyMeshableFaces: BooleanArray = booleanArrayOf(true, false, true, true, true, true)
|
||||||
|
|
||||||
override fun getFaceSize(direction: Directions, random: Random): Array<FaceSize> {
|
|
||||||
return arrayOf() // ToDo
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun singleRender(position: Vec3i, mesh: ChunkSectionMesh, random: Random, neighbours: Array<BlockState?>, light: Int, ambientLight: IntArray) {
|
override fun singleRender(position: Vec3i, mesh: ChunkSectionMesh, random: Random, neighbours: Array<BlockState?>, light: Int, ambientLight: IntArray) {
|
||||||
val floatPosition = position.toVec3()
|
val floatPosition = position.toVec3()
|
||||||
for ((index, direction) in faces.withIndex()) {
|
for ((index, direction) in faces.withIndex()) {
|
||||||
val neighbour = neighbours[index]
|
val neighbour = neighbours[index]
|
||||||
if (neighbour != null) {
|
if (neighbour != null) {
|
||||||
continue
|
// continue
|
||||||
}
|
}
|
||||||
for (face in direction) {
|
for (face in direction) {
|
||||||
face.singleRender(floatPosition, mesh, neighbour, light, ambientLight)
|
face.singleRender(floatPosition, mesh, neighbour, light, ambientLight)
|
||||||
|
@ -0,0 +1,122 @@
|
|||||||
|
/*
|
||||||
|
* Minosoft
|
||||||
|
* Copyright (C) 2021 Moritz Zwerger
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with this program. If not, see <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
|
||||||
|
import de.bixilon.minosoft.util.nbt.tag.NBTUtil.compoundCast
|
||||||
|
|
||||||
|
class MultipartRootModel(
|
||||||
|
private val conditions: MutableMap<MutableSet<Set<Map<BlockProperties, Any>>>, Set<UnbakedBlockStateModel>>,
|
||||||
|
) : RootModel {
|
||||||
|
|
||||||
|
private fun Set<Map<BlockProperties, Any>>.matches(blockState: BlockState): Boolean {
|
||||||
|
var matches = false
|
||||||
|
|
||||||
|
for (propertyMap in this) {
|
||||||
|
var singleMatches = false
|
||||||
|
for ((property, value) in propertyMap) {
|
||||||
|
if (blockState.properties[property] == value) {
|
||||||
|
singleMatches = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (singleMatches) {
|
||||||
|
matches = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return matches
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun MutableSet<Set<Map<BlockProperties, Any>>>.matchesAny(blockState: BlockState): Boolean {
|
||||||
|
var matches = true
|
||||||
|
for (or in this) {
|
||||||
|
if (!or.matches(blockState)) {
|
||||||
|
matches = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return matches
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getModelForState(blockState: BlockState): UnbakedModel {
|
||||||
|
val models: MutableSet<UnbakedBlockStateModel> = mutableSetOf()
|
||||||
|
|
||||||
|
for ((condition, apply) in conditions) {
|
||||||
|
if (condition.matchesAny(blockState)) {
|
||||||
|
models += apply
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return UnbakedMultipartModel(models)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
private fun getCondition(data: MutableMap<String, Any>): MutableSet<Map<BlockProperties, Any>> {
|
||||||
|
val singleCondition: MutableSet<Map<BlockProperties, Any>> = mutableSetOf()
|
||||||
|
for ((propertyName, value) in data) {
|
||||||
|
val properties: MutableMap<BlockProperties, Any> = mutableMapOf()
|
||||||
|
|
||||||
|
for (propertyValue in value.toString().split("|")) {
|
||||||
|
properties += BlockProperties.parseProperty(propertyName, propertyValue)
|
||||||
|
}
|
||||||
|
singleCondition += properties
|
||||||
|
}
|
||||||
|
return singleCondition
|
||||||
|
}
|
||||||
|
|
||||||
|
operator fun invoke(models: Map<ResourceLocation, GenericUnbakedModel>, data: List<Any>): MultipartRootModel {
|
||||||
|
val conditions: MutableMap<MutableSet<Set<Map<BlockProperties, Any>>>, Set<UnbakedBlockStateModel>> = mutableMapOf()
|
||||||
|
|
||||||
|
|
||||||
|
for (modelData in data) {
|
||||||
|
check(modelData is Map<*, *>)
|
||||||
|
val condition: MutableSet<Set<Map<BlockProperties, Any>>> = mutableSetOf()
|
||||||
|
val applyData = modelData["apply"]!!
|
||||||
|
val apply: MutableSet<UnbakedBlockStateModel> = mutableSetOf()
|
||||||
|
if (applyData is Map<*, *>) {
|
||||||
|
apply += UnbakedBlockStateModel(models, applyData.unsafeCast())
|
||||||
|
} else if (applyData is List<*>) {
|
||||||
|
for (applyModelData in applyData) {
|
||||||
|
apply += UnbakedBlockStateModel(models, applyModelData.unsafeCast())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
modelData["when"]?.compoundCast()?.let {
|
||||||
|
val or = it["OR"]
|
||||||
|
if (or is List<*>) {
|
||||||
|
for (orData in or) {
|
||||||
|
condition += getCondition(orData.unsafeCast())
|
||||||
|
}
|
||||||
|
return@let
|
||||||
|
}
|
||||||
|
condition += getCondition(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
conditions[condition] = apply
|
||||||
|
}
|
||||||
|
|
||||||
|
return MultipartRootModel(conditions)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -28,10 +28,8 @@ interface RootModel {
|
|||||||
val variants = data["variants"]
|
val variants = data["variants"]
|
||||||
val multipart = data["multipart"]
|
val multipart = data["multipart"]
|
||||||
return when {
|
return when {
|
||||||
// ToDo: Single?
|
|
||||||
variants != null -> SimpleRootModel(models, variants.unsafeCast())
|
variants != null -> SimpleRootModel(models, variants.unsafeCast())
|
||||||
// ToDo: multipart != null -> MultipartUnbakedBlockStateModel(models, multipart.unsafeCast())
|
multipart != null -> MultipartRootModel(models, multipart.unsafeCast())
|
||||||
multipart != null -> null
|
|
||||||
else -> TODO("Don't know what type of block state model to choose: $data")
|
else -> TODO("Don't know what type of block state model to choose: $data")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,21 +38,9 @@ import glm_.vec2.Vec2
|
|||||||
import glm_.vec2.Vec2i
|
import glm_.vec2.Vec2i
|
||||||
import glm_.vec3.Vec3
|
import glm_.vec3.Vec3
|
||||||
import glm_.vec3.swizzle.xz
|
import glm_.vec3.swizzle.xz
|
||||||
import kotlin.collections.Map
|
|
||||||
import kotlin.collections.MutableList
|
|
||||||
import kotlin.collections.MutableMap
|
|
||||||
import kotlin.collections.component1
|
import kotlin.collections.component1
|
||||||
import kotlin.collections.component2
|
import kotlin.collections.component2
|
||||||
import kotlin.collections.drop
|
|
||||||
import kotlin.collections.iterator
|
|
||||||
import kotlin.collections.mutableListOf
|
|
||||||
import kotlin.collections.mutableMapOf
|
|
||||||
import kotlin.collections.plus
|
|
||||||
import kotlin.collections.plusAssign
|
|
||||||
import kotlin.collections.set
|
import kotlin.collections.set
|
||||||
import kotlin.collections.take
|
|
||||||
import kotlin.collections.toTypedArray
|
|
||||||
import kotlin.collections.withIndex
|
|
||||||
|
|
||||||
data class UnbakedBlockStateModel(
|
data class UnbakedBlockStateModel(
|
||||||
val model: UnbakedBlockModel,
|
val model: UnbakedBlockModel,
|
||||||
@ -114,7 +102,7 @@ data class UnbakedBlockStateModel(
|
|||||||
|
|
||||||
direction = Directions.byDirection(Vec3(face.direction.vectorf).apply { rotateAssign(rad) })
|
direction = Directions.byDirection(Vec3(face.direction.vectorf).apply { rotateAssign(rad) })
|
||||||
for ((index, position) in positions.withIndex()) {
|
for ((index, position) in positions.withIndex()) {
|
||||||
positions[index] = Vec3(position).apply { rotateAssign(rad) }
|
positions[index] = Vec3(position).apply { rotateAssign(rad, true) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,24 @@
|
|||||||
|
package de.bixilon.minosoft.gui.rendering.models.unbaked.block
|
||||||
|
|
||||||
|
import de.bixilon.minosoft.gui.rendering.RenderWindow
|
||||||
|
import de.bixilon.minosoft.gui.rendering.models.baked.BakedModel
|
||||||
|
import de.bixilon.minosoft.gui.rendering.models.baked.MultipartBakedModel
|
||||||
|
import de.bixilon.minosoft.gui.rendering.models.baked.block.BakedBlockModel
|
||||||
|
import de.bixilon.minosoft.gui.rendering.models.unbaked.UnbakedModel
|
||||||
|
import de.bixilon.minosoft.util.KUtil.unsafeCast
|
||||||
|
|
||||||
|
class UnbakedMultipartModel(
|
||||||
|
val models: Set<UnbakedBlockStateModel>,
|
||||||
|
) : UnbakedModel {
|
||||||
|
|
||||||
|
override fun bake(renderWindow: RenderWindow): BakedModel {
|
||||||
|
val baked: Array<BakedBlockModel?> = arrayOfNulls(this.models.size)
|
||||||
|
|
||||||
|
var index = 0
|
||||||
|
for (model in this.models) {
|
||||||
|
baked[index++] = model.bake(renderWindow)
|
||||||
|
}
|
||||||
|
|
||||||
|
return MultipartBakedModel(baked.unsafeCast())
|
||||||
|
}
|
||||||
|
}
|
@ -59,9 +59,17 @@ object Vec3Util {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Vec3.rotateAssign(rotation: Vec2) {
|
fun Vec3.rotateAssign(rotation: Vec2, centerBlock: Boolean = false) {
|
||||||
|
if (centerBlock) {
|
||||||
|
this -= 0.5f
|
||||||
|
}
|
||||||
|
|
||||||
rotateAssign(rotation.y, Axes.Y)
|
rotateAssign(rotation.y, Axes.Y)
|
||||||
rotateAssign(rotation.x, Axes.X)
|
rotateAssign(rotation.x, Axes.X)
|
||||||
|
|
||||||
|
if (centerBlock) {
|
||||||
|
this += 0.5f
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Vec3.rotateAssign(angle: Float, axis: Axes, origin: Vec3, rescale: Boolean) {
|
fun Vec3.rotateAssign(angle: Float, axis: Axes, origin: Vec3, rescale: Boolean) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user