mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-11 08:27:29 -04:00
model loading
This commit is contained in:
parent
d9e1c3b97f
commit
596866c3ee
@ -164,7 +164,7 @@ class MinecraftAssetsManager(
|
||||
}
|
||||
|
||||
private fun parseAssetsIndex(hash: String): Map<ResourceLocation, String> {
|
||||
return parseAssetsIndex(Util.readJsonFromStream(readAssetAsStream(hash)))
|
||||
return parseAssetsIndex(Util.readJsonFromStream(readAssetAsStream(hash), true))
|
||||
}
|
||||
|
||||
private fun parseAssetsIndex(json: JsonObject): Map<ResourceLocation, String> {
|
||||
|
@ -14,12 +14,9 @@ package de.bixilon.minosoft.data.direction
|
||||
|
||||
import de.bixilon.minosoft.data.Axes
|
||||
import de.bixilon.minosoft.data.registries.blocks.properties.serializer.BlockPropertiesSerializer
|
||||
import de.bixilon.minosoft.gui.rendering.block.models.BlockModelElement
|
||||
import de.bixilon.minosoft.gui.rendering.block.models.FaceSize
|
||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.get
|
||||
import de.bixilon.minosoft.util.KUtil
|
||||
import de.bixilon.minosoft.util.enum.ValuesEnum
|
||||
import glm_.vec2.Vec2i
|
||||
import glm_.vec3.Vec3
|
||||
import glm_.vec3.Vec3d
|
||||
import glm_.vec3.Vec3i
|
||||
@ -53,48 +50,6 @@ enum class Directions(
|
||||
}
|
||||
}
|
||||
|
||||
fun sidesNextTo(direction: Directions): Set<Directions> {
|
||||
return when (direction) {
|
||||
NORTH, SOUTH -> setOf(EAST, WEST)
|
||||
EAST, WEST -> setOf(NORTH, SOUTH)
|
||||
else -> emptySet()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the size of the face in this direction. null if the face is not touching the border (determinated by the block resolution)
|
||||
*/
|
||||
fun getFaceBorderSizes(start: Vec3, end: Vec3): FaceSize? {
|
||||
// check if face is touching the border of a block
|
||||
|
||||
if (!isBlockResolutionBorder(start, end)) {
|
||||
return null
|
||||
}
|
||||
return getFaceSize(start, end)
|
||||
}
|
||||
|
||||
fun getFaceSize(start: Vec3, end: Vec3): FaceSize {
|
||||
return when (this) {
|
||||
DOWN, UP -> FaceSize(Vec2i(start.x, start.z), Vec2i(end.x, end.z))
|
||||
NORTH, SOUTH -> FaceSize(Vec2i(start.x, start.y), Vec2i(end.x, end.y))
|
||||
EAST, WEST -> FaceSize(Vec2i(start.y, start.z), Vec2i(end.y, end.z))
|
||||
}
|
||||
}
|
||||
|
||||
private fun isBlockResolutionBorder(start: Vec3, end: Vec3): Boolean {
|
||||
return isCoordinateBorder(vector.x, start.x, end.x) || isCoordinateBorder(vector.y, start.y, end.y) || isCoordinateBorder(vector.z, start.z, end.z)
|
||||
}
|
||||
|
||||
private fun isCoordinateBorder(directionValue: Int, start: Float, end: Float): Boolean {
|
||||
if (directionValue == 1) {
|
||||
return start == BlockModelElement.BLOCK_RESOLUTION_FLOAT || end == BlockModelElement.BLOCK_RESOLUTION_FLOAT
|
||||
}
|
||||
if (directionValue == -1) {
|
||||
return start == 0.0f || end == 0.0f
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
operator fun get(axis: Axes): Int {
|
||||
return vector[axis]
|
||||
}
|
||||
@ -121,6 +76,13 @@ enum class Directions(
|
||||
return NAME_MAP[value] ?: throw IllegalArgumentException("No such property: $value")
|
||||
}
|
||||
|
||||
override fun get(name: String): Directions {
|
||||
if (name.lowercase() == "bottom") {
|
||||
return DOWN
|
||||
}
|
||||
return super.get(name)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun byId(id: Int): Directions {
|
||||
return VALUES[id]
|
||||
|
@ -19,7 +19,7 @@ import de.bixilon.minosoft.data.direction.Directions
|
||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.EMPTY
|
||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.ONE
|
||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.get
|
||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.toVec3
|
||||
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.toVec3
|
||||
import de.bixilon.minosoft.util.MMath.ceil
|
||||
import de.bixilon.minosoft.util.MMath.floor
|
||||
import glm_.Java.Companion.glm
|
||||
|
@ -94,7 +94,7 @@ open class Registry<T : RegistryItem>(
|
||||
}
|
||||
|
||||
open operator fun get(resourceLocation: String): T? {
|
||||
return get(ResourceLocation.getPathResourceLocation(resourceLocation))
|
||||
return get(resourceLocation.toResourceLocation())
|
||||
}
|
||||
|
||||
open operator fun get(resourceLocation: ResourceLocationAble): T? {
|
||||
|
@ -11,16 +11,22 @@
|
||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||
*/
|
||||
|
||||
package de.bixilon.minosoft.gui.rendering.block.mesh
|
||||
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
|
||||
|
||||
class ChunkSectionMeshCollection(
|
||||
renderWindow: RenderWindow,
|
||||
val opaqueMesh: ChunkSectionArrayMesh = ChunkSectionArrayMesh(renderWindow),
|
||||
var translucentMesh: ChunkSectionArrayMesh? = ChunkSectionArrayMesh(renderWindow),
|
||||
var transparentMesh: ChunkSectionArrayMesh? = ChunkSectionArrayMesh(renderWindow),
|
||||
class SectionPreparer(
|
||||
val renderWindow: RenderWindow,
|
||||
) {
|
||||
var lowestBlockHeight = 0
|
||||
var highestBlockHeight = 0
|
||||
|
||||
|
||||
fun prepare(section: ChunkSection): ChunkSectionMesh {
|
||||
val mesh = ChunkSectionMesh(renderWindow)
|
||||
|
||||
|
||||
|
||||
return mesh
|
||||
}
|
||||
}
|
@ -13,24 +13,65 @@
|
||||
|
||||
package de.bixilon.minosoft.gui.rendering.block
|
||||
|
||||
import de.bixilon.minosoft.data.assets.AssetsUtil
|
||||
import de.bixilon.minosoft.data.assets.Resources
|
||||
import de.bixilon.minosoft.data.direction.Directions
|
||||
import de.bixilon.minosoft.data.direction.FakeDirection
|
||||
import de.bixilon.minosoft.data.registries.ResourceLocation
|
||||
import de.bixilon.minosoft.data.world.ChunkSection
|
||||
import de.bixilon.minosoft.data.world.World
|
||||
import de.bixilon.minosoft.gui.rendering.RenderWindow
|
||||
import de.bixilon.minosoft.gui.rendering.Renderer
|
||||
import de.bixilon.minosoft.gui.rendering.RendererBuilder
|
||||
import de.bixilon.minosoft.gui.rendering.block.mesh.ChunkSectionMesh
|
||||
import de.bixilon.minosoft.gui.rendering.models.ModelLoader
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.RenderSystem
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.phases.OpaqueDrawable
|
||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.plus
|
||||
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
|
||||
import de.bixilon.minosoft.util.KUtil.toResourceLocation
|
||||
import glm_.vec2.Vec2i
|
||||
import java.io.FileInputStream
|
||||
import java.util.zip.GZIPInputStream
|
||||
import java.util.zip.ZipInputStream
|
||||
|
||||
class WorldRenderer(
|
||||
private val connection: PlayConnection,
|
||||
override val renderWindow: RenderWindow,
|
||||
) : Renderer {
|
||||
) : Renderer, OpaqueDrawable {
|
||||
override val renderSystem: RenderSystem = renderWindow.renderSystem
|
||||
private val shader = renderSystem.createShader("minosoft:world".toResourceLocation())
|
||||
private val world: World = connection.world
|
||||
private val sectionPreparer = SectionPreparer(renderWindow)
|
||||
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)
|
||||
modelLoader.load()
|
||||
|
||||
val dirt = connection.registries.blockRegistry["dirt"]?.defaultState
|
||||
val chunk = ChunkSection(Array(4096) { dirt })
|
||||
mesh = sectionPreparer.prepare(chunk)
|
||||
mesh.load()
|
||||
}
|
||||
|
||||
override fun postInit() {
|
||||
shader.load()
|
||||
renderWindow.textureManager.staticTextures.use(shader)
|
||||
renderWindow.textureManager.staticTextures.animator.use(shader)
|
||||
}
|
||||
|
||||
override fun setupOpaque() {
|
||||
super.setupOpaque()
|
||||
shader.use()
|
||||
}
|
||||
|
||||
override fun drawOpaque() {
|
||||
mesh.draw()
|
||||
}
|
||||
|
||||
|
||||
companion object : RendererBuilder<WorldRenderer> {
|
||||
|
@ -23,7 +23,7 @@ import de.bixilon.minosoft.gui.rendering.util.mesh.MeshStruct
|
||||
import glm_.vec2.Vec2
|
||||
import glm_.vec3.Vec3
|
||||
|
||||
class ChunkSectionArrayMesh(renderWindow: RenderWindow) : Mesh(renderWindow, SectionArrayMeshStruct, initialCacheSize = 100000) {
|
||||
class ChunkSectionMesh(renderWindow: RenderWindow) : Mesh(renderWindow, SectionArrayMeshStruct, initialCacheSize = 100000) {
|
||||
|
||||
fun addVertex(position: Vec3, uv: Vec2, texture: AbstractTexture, tintColor: RGBColor?, light: Int) {
|
||||
val color = tintColor ?: ChatColors.WHITE
|
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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.block.mesh
|
||||
|
||||
import de.bixilon.minosoft.data.registries.AABB
|
||||
import de.bixilon.minosoft.gui.rendering.RenderWindow
|
||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.EMPTY
|
||||
import glm_.vec3.Vec3i
|
||||
|
||||
class ChunkSectionMeshes(
|
||||
renderWindow: RenderWindow,
|
||||
val opaqueMesh: ChunkSectionMesh = ChunkSectionMesh(renderWindow),
|
||||
var translucentMesh: ChunkSectionMesh? = ChunkSectionMesh(renderWindow),
|
||||
var transparentMesh: ChunkSectionMesh? = ChunkSectionMesh(renderWindow),
|
||||
) {
|
||||
val minPosition = Vec3i.EMPTY
|
||||
val maxPosition = Vec3i.EMPTY
|
||||
|
||||
lateinit var aabb: AABB
|
||||
private set
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
/*
|
||||
* 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.block.models
|
||||
|
||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.rad
|
||||
import de.bixilon.minosoft.util.KUtil.listCast
|
||||
import de.bixilon.minosoft.util.KUtil.nullCast
|
||||
import de.bixilon.minosoft.util.KUtil.unsafeCast
|
||||
import de.bixilon.minosoft.util.nbt.tag.NBTUtil.asCompound
|
||||
import de.bixilon.minosoft.util.nbt.tag.NBTUtil.compoundCast
|
||||
import glm_.vec3.Vec3
|
||||
|
||||
open class BlockModel(
|
||||
val parent: BlockModel? = null,
|
||||
data: Map<String, Any>,
|
||||
) {
|
||||
val textures: Map<String, String>
|
||||
val elements: List<BlockModelElement>
|
||||
val rotation: Vec3 = Vec3(data["x"]?.unsafeCast<Double>() ?: parent?.rotation?.x ?: 0.0f, data["y"]?.unsafeCast<Double>() ?: parent?.rotation?.y ?: 0.0f, data["z"]?.unsafeCast<Double>() ?: parent?.rotation?.z ?: 0.0f).rad
|
||||
val uvLock: Boolean = data["uvlock"].nullCast<Boolean>() ?: parent?.uvLock ?: false
|
||||
val rescale: Boolean = data["rescale"].nullCast<Boolean>() ?: parent?.rescale ?: false
|
||||
val ambientOcclusion: Boolean = data["ambientocclusion"].nullCast<Boolean>() ?: parent?.ambientOcclusion ?: true
|
||||
|
||||
init {
|
||||
textures = data["textures"]?.compoundCast()?.let {
|
||||
val textures: MutableMap<String, String> = parent?.textures?.toMutableMap() ?: mutableMapOf()
|
||||
for ((type, value) in it) {
|
||||
textures[type] = value.unsafeCast()
|
||||
}
|
||||
for ((type, texture) in textures) {
|
||||
textures[type] = getTextureByType(textures, texture)
|
||||
}
|
||||
textures.toMap()
|
||||
} ?: parent?.textures ?: mapOf()
|
||||
|
||||
|
||||
elements = data["elements"]?.listCast()?.let {
|
||||
val elements: MutableList<BlockModelElement> = mutableListOf()
|
||||
for (element in it) {
|
||||
elements += BlockModelElement(element.asCompound())
|
||||
}
|
||||
elements.toList()
|
||||
} ?: parent?.elements ?: listOf()
|
||||
}
|
||||
|
||||
private fun getTextureByType(textures: Map<String, String>, type: String): String {
|
||||
var currentValue: String = type
|
||||
while (currentValue.startsWith("#")) {
|
||||
textures[currentValue.removePrefix("#")].let {
|
||||
currentValue = it ?: return currentValue
|
||||
}
|
||||
}
|
||||
return currentValue
|
||||
}
|
||||
}
|
@ -1,102 +0,0 @@
|
||||
/*
|
||||
* 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.block.models
|
||||
|
||||
import de.bixilon.minosoft.data.Axes
|
||||
import de.bixilon.minosoft.data.direction.Directions
|
||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.EMPTY
|
||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.rotate
|
||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.toVec3
|
||||
import de.bixilon.minosoft.util.KUtil.nullCast
|
||||
import de.bixilon.minosoft.util.KUtil.unsafeCast
|
||||
import de.bixilon.minosoft.util.nbt.tag.NBTUtil.asCompound
|
||||
import de.bixilon.minosoft.util.nbt.tag.NBTUtil.compoundCast
|
||||
import glm_.func.rad
|
||||
import glm_.vec3.Vec3
|
||||
|
||||
open class BlockModelElement(
|
||||
data: Map<String, Any>,
|
||||
) {
|
||||
val from: Vec3 = data["from"]?.toVec3() ?: Vec3.EMPTY
|
||||
val to: Vec3 = data["to"]?.toVec3() ?: Vec3(BLOCK_RESOLUTION)
|
||||
val shade: Boolean = data["shade"].nullCast<Boolean>() ?: true
|
||||
val faces: MutableMap<Directions, BlockModelFace> = mutableMapOf()
|
||||
val transformedPositions: Array<Vec3> = arrayOf(
|
||||
Vec3(from.x, from.y, from.z),
|
||||
Vec3(to.x, from.y, from.z),
|
||||
Vec3(from.x, from.y, to.z),
|
||||
Vec3(to.x, from.y, to.z),
|
||||
Vec3(from.x, to.y, from.z),
|
||||
Vec3(to.x, to.y, from.z),
|
||||
Vec3(from.x, to.y, to.z),
|
||||
Vec3(to.x, to.y, to.z),
|
||||
)
|
||||
|
||||
init {
|
||||
|
||||
data["rotation"]?.compoundCast()?.let {
|
||||
val axis = Axes[it["axis"].unsafeCast<String>()]
|
||||
val angle = it["angle"].unsafeCast<Double>().toFloat().rad
|
||||
val rescale = it["rescale"].nullCast<Boolean>() ?: false
|
||||
rotatePositions(transformedPositions, axis, angle, it["origin"]!!.toVec3(), rescale)
|
||||
}
|
||||
|
||||
data["faces"]?.compoundCast()?.let {
|
||||
for ((directionName, json) in it) {
|
||||
val direction = Directions[directionName]
|
||||
faces[direction] = BlockModelFace(json.asCompound(), from, to, direction)
|
||||
}
|
||||
}
|
||||
|
||||
// transformed positions
|
||||
for ((index, position) in transformedPositions.withIndex()) {
|
||||
transformedPositions[index] = transformPosition(position)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val BLOCK_RESOLUTION = 16
|
||||
const val BLOCK_RESOLUTION_FLOAT = BLOCK_RESOLUTION.toFloat()
|
||||
|
||||
val FACE_POSITION_MAP_TEMPLATE = arrayOf(
|
||||
intArrayOf(0, 2, 3, 1),
|
||||
intArrayOf(6, 4, 5, 7),
|
||||
intArrayOf(1, 5, 4, 0),
|
||||
intArrayOf(2, 6, 7, 3),
|
||||
intArrayOf(6, 2, 0, 4),
|
||||
intArrayOf(5, 1, 3, 7)
|
||||
)
|
||||
|
||||
fun rotatePositions(positions: Array<Vec3>, axis: Axes, angle: Float, origin: Vec3, rescale: Boolean) {
|
||||
// TODO: optimize for 90deg, 180deg, 270deg rotations
|
||||
if (angle == 0.0f) {
|
||||
return
|
||||
}
|
||||
for ((i, position) in positions.withIndex()) {
|
||||
var transformedPosition = position - origin
|
||||
transformedPosition = transformedPosition.rotate(angle, axis, rescale)
|
||||
positions[i] = transformedPosition + origin
|
||||
}
|
||||
}
|
||||
|
||||
fun transformPosition(position: Vec3): Vec3 {
|
||||
|
||||
fun positionToFloat(uv: Float): Float {
|
||||
return (uv - (BLOCK_RESOLUTION / 2)) / BLOCK_RESOLUTION
|
||||
}
|
||||
|
||||
return Vec3(positionToFloat(position.x), positionToFloat(position.y), positionToFloat(position.z))
|
||||
}
|
||||
}
|
||||
}
|
@ -1,156 +0,0 @@
|
||||
/*
|
||||
* 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.block.models
|
||||
|
||||
import de.bixilon.minosoft.data.direction.Directions
|
||||
import de.bixilon.minosoft.data.registries.AABB
|
||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil
|
||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.readUV
|
||||
import de.bixilon.minosoft.util.KUtil.nullCast
|
||||
import de.bixilon.minosoft.util.KUtil.toInt
|
||||
import de.bixilon.minosoft.util.KUtil.unsafeCast
|
||||
import glm_.func.cos
|
||||
import glm_.func.sin
|
||||
import glm_.vec2.Vec2
|
||||
import glm_.vec3.Vec3
|
||||
import java.util.*
|
||||
|
||||
class BlockModelFace {
|
||||
val textureName: String?
|
||||
val cullFace: Directions?
|
||||
val tint: Boolean
|
||||
val positions: List<Vec2>
|
||||
|
||||
|
||||
constructor(textureName: String?, cullFace: Directions?, tint: Boolean, positions: List<Vec2>) {
|
||||
this.textureName = textureName
|
||||
this.cullFace = cullFace
|
||||
this.tint = tint
|
||||
this.positions = positions
|
||||
}
|
||||
|
||||
constructor(data: Map<String, Any>, from: Vec3, to: Vec3, direction: Directions) {
|
||||
tint = data.containsKey("tintindex")
|
||||
textureName = data["texture"].unsafeCast<String>().removePrefix("#")
|
||||
cullFace = data["cullface"].nullCast<String>()?.let {
|
||||
if (it == "bottom") {
|
||||
Directions.DOWN
|
||||
} else {
|
||||
Directions[it]
|
||||
}
|
||||
}
|
||||
val positions = calculateTexturePositions(data, from, to, direction)
|
||||
val rotation = data["rotation"]?.toInt()?.div(90) ?: 0
|
||||
Collections.rotate(positions, rotation)
|
||||
this.positions = positions.toList()
|
||||
}
|
||||
|
||||
private fun calculateTexturePositions(data: Map<String, Any>?, from: Vec3, to: Vec3, direction: Directions): MutableList<Vec2> {
|
||||
val (textureTopLeft: Vec2, textureBottomRight: Vec2) = data?.get("uv")?.unsafeCast<List<Float>>()?.readUV() ?: getTexturePositionsFromRegion(AABB(from, to), direction)
|
||||
return mutableListOf(
|
||||
uvToFloat(Vec2(textureTopLeft.x, textureTopLeft.y)),
|
||||
uvToFloat(Vec2(textureTopLeft.x, textureBottomRight.y)),
|
||||
uvToFloat(Vec2(textureBottomRight.x, textureBottomRight.y)),
|
||||
uvToFloat(Vec2(textureBottomRight.x, textureTopLeft.y)),
|
||||
)
|
||||
}
|
||||
|
||||
private fun getTexturePositionsFromRegion(aabb: AABB, direction: Directions): Pair<Vec2, Vec2> {
|
||||
// ToDo: Remove the duplicated code in Directions
|
||||
return when (direction) {
|
||||
Directions.UP, Directions.DOWN -> Pair(Vec2(aabb.min.x.toInt(), aabb.max.z.toInt()), Vec2(aabb.max.x.toInt(), aabb.min.z.toInt()))
|
||||
Directions.NORTH, Directions.SOUTH -> Pair(Vec2(aabb.min.x.toInt(), aabb.max.y.toInt()), Vec2(aabb.max.x.toInt(), aabb.min.y.toInt()))
|
||||
Directions.EAST, Directions.WEST -> Pair(Vec2(aabb.min.z.toInt(), aabb.max.y.toInt()), Vec2(aabb.max.z.toInt(), aabb.min.y.toInt()))
|
||||
}
|
||||
}
|
||||
|
||||
constructor(other: BlockModelFace) {
|
||||
textureName = other.textureName
|
||||
cullFace = other.cullFace
|
||||
tint = other.tint
|
||||
this.positions = other.positions
|
||||
}
|
||||
|
||||
constructor(vertexPositions: List<Vec3>, direction: Directions) {
|
||||
textureName = null
|
||||
cullFace = null
|
||||
tint = false
|
||||
val template = BlockModelElement.FACE_POSITION_MAP_TEMPLATE[direction.ordinal]
|
||||
val positions: MutableList<Vec2> = mutableListOf()
|
||||
for (templatePosition in template) {
|
||||
positions += calculateTexturePosition(vertexPositions[templatePosition], direction)
|
||||
}
|
||||
this.positions = positions.toList()
|
||||
}
|
||||
|
||||
private fun calculateTexturePosition(position: Vec3, direction: Directions): Vec2 {
|
||||
return when (direction) {
|
||||
Directions.UP, Directions.DOWN -> Vec2(position.x, BlockModelElement.BLOCK_RESOLUTION - position.z)
|
||||
Directions.NORTH, Directions.SOUTH -> Vec2(position.x, position.y)
|
||||
Directions.EAST, Directions.WEST -> Vec2(position.z, BlockModelElement.BLOCK_RESOLUTION - position.y)
|
||||
}
|
||||
}
|
||||
|
||||
fun getTexturePositionArray(direction: Directions): Array<Vec2?> {
|
||||
val template = textureTemplate[direction.ordinal]
|
||||
val ret: MutableList<Vec2> = mutableListOf()
|
||||
for (i in template.indices) {
|
||||
ret += positions[template[i]]
|
||||
}
|
||||
return ret.toTypedArray()
|
||||
}
|
||||
|
||||
fun rotate(angle: Float): BlockModelFace {
|
||||
if (angle == 0.0f) {
|
||||
return this
|
||||
}
|
||||
val sin = angle.sin
|
||||
val cos = angle.cos
|
||||
val positions = this.positions.toMutableList()
|
||||
for ((i, position) in positions.withIndex()) {
|
||||
val offset = position - TEXTURE_MIDDLE
|
||||
positions[i] = VecUtil.getRotatedValues(offset.x, offset.y, sin, cos, false) + TEXTURE_MIDDLE
|
||||
}
|
||||
return BlockModelFace(textureName, cullFace, tint, positions.toList())
|
||||
}
|
||||
|
||||
fun scale(scaleFactor: Double): BlockModelFace {
|
||||
val positions = positions.toMutableList()
|
||||
for ((i, position) in positions.withIndex()) {
|
||||
positions[i] = position * scaleFactor
|
||||
}
|
||||
return BlockModelFace(textureName, cullFace, tint, positions.toList())
|
||||
}
|
||||
|
||||
companion object {
|
||||
private fun uvToFloat(uv: Float): Float {
|
||||
return (uv) / BlockModelElement.BLOCK_RESOLUTION
|
||||
}
|
||||
|
||||
fun uvToFloat(vec2: Vec2): Vec2 {
|
||||
return Vec2(uvToFloat(vec2.x), uvToFloat(BlockModelElement.BLOCK_RESOLUTION - vec2.y))
|
||||
}
|
||||
|
||||
val textureTemplate = arrayOf(
|
||||
arrayOf(0, 1, 2, 3),
|
||||
arrayOf(0, 1, 2, 3),
|
||||
arrayOf(3, 2, 1, 0),
|
||||
arrayOf(0, 1, 2, 3),
|
||||
arrayOf(2, 3, 0, 1),
|
||||
arrayOf(1, 0, 3, 2),
|
||||
)
|
||||
|
||||
val TEXTURE_MIDDLE = Vec2(0.5, 0.5)
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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 de.bixilon.minosoft.util.KUtil
|
||||
import de.bixilon.minosoft.util.enum.ValuesEnum
|
||||
|
||||
enum class GUILights {
|
||||
FRONT,
|
||||
SIDE,
|
||||
;
|
||||
|
||||
companion object : ValuesEnum<GUILights> {
|
||||
override val VALUES: Array<GUILights> = values()
|
||||
override val NAME_MAP: Map<String, GUILights> = KUtil.getEnumValues(VALUES)
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,105 @@
|
||||
/*
|
||||
* 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 de.bixilon.minosoft.data.registries.ResourceLocation
|
||||
import de.bixilon.minosoft.gui.rendering.models.builtin.BuiltinModels
|
||||
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.util.KUtil.fromJson
|
||||
import de.bixilon.minosoft.util.KUtil.toResourceLocation
|
||||
import de.bixilon.minosoft.util.KUtil.unsafeCast
|
||||
import de.bixilon.minosoft.util.Util
|
||||
import de.bixilon.minosoft.util.logging.Log
|
||||
import de.bixilon.minosoft.util.logging.LogLevels
|
||||
import de.bixilon.minosoft.util.logging.LogMessageType
|
||||
import de.bixilon.minosoft.util.nbt.tag.NBTUtil.asCompound
|
||||
import java.io.BufferedReader
|
||||
import java.io.InputStreamReader
|
||||
import java.util.zip.ZipEntry
|
||||
import java.util.zip.ZipInputStream
|
||||
|
||||
class ModelLoader(
|
||||
val jar: ZipInputStream,
|
||||
) {
|
||||
private val unbakedBlockModels: MutableMap<ResourceLocation, UnbakedModel> = BuiltinModels.BUILTIN_MODELS.toMutableMap()
|
||||
private val blockStateJsons: MutableMap<ResourceLocation, Map<String, Any>> = mutableMapOf()
|
||||
private val modelJsons: MutableMap<ResourceLocation, Map<String, Any>> = mutableMapOf()
|
||||
|
||||
private fun loadJsons() {
|
||||
// ToDo: Integrate in assets manager
|
||||
var entry: ZipEntry? = jar.nextEntry
|
||||
while (entry != null) {
|
||||
if (!entry.name.startsWith("assets/minecraft/models/") && !entry.name.startsWith("assets/minecraft/blockstates/")) {
|
||||
entry = jar.nextEntry
|
||||
continue
|
||||
}
|
||||
val name = entry.name.removePrefix("assets/minecraft/").removeSuffix(".json")
|
||||
val jsonString = Util.readReader(BufferedReader(InputStreamReader(jar)), false)
|
||||
|
||||
val json = jsonString.fromJson().asCompound()
|
||||
if (name.startsWith("models/")) {
|
||||
modelJsons[name.removePrefix("models/").toResourceLocation()] = json
|
||||
} else {
|
||||
blockStateJsons[name.removePrefix("blockstates/").toResourceLocation()] = json
|
||||
}
|
||||
|
||||
|
||||
entry = jar.nextEntry
|
||||
}
|
||||
}
|
||||
|
||||
fun load() {
|
||||
loadJsons()
|
||||
Log.log(LogMessageType.VERSION_LOADING, LogLevels.VERBOSE) { "Loaded ${blockStateJsons.size} block states and ${modelJsons.size} model jsons!" }
|
||||
|
||||
|
||||
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 model = UnbakedBlockModel(parent, data)
|
||||
|
||||
unbakedBlockModels[name] = model
|
||||
return model
|
||||
}
|
||||
|
||||
|
||||
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 parent = data["parent"]?.toResourceLocation()?.let { loadItemModel(it) }
|
||||
|
||||
val model = UnbakedItemModel(parent, data)
|
||||
|
||||
unbakedBlockModels[name] = model
|
||||
return model
|
||||
}
|
||||
|
||||
for ((name, json) in modelJsons) {
|
||||
if (name.path.startsWith("block/")) {
|
||||
loadBlockModel(name, json)
|
||||
} else if (name.path.startsWith("item/")) {
|
||||
loadItemModel(name, json)
|
||||
} else {
|
||||
TODO("Unknown block model type: $name")
|
||||
}
|
||||
}
|
||||
Log.log(LogMessageType.VERSION_LOADING, LogLevels.VERBOSE) { "Done loading models!" }
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* 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.builtin
|
||||
|
||||
import de.bixilon.minosoft.data.registries.ResourceLocation
|
||||
import de.bixilon.minosoft.gui.rendering.models.unbaked.UnbakedModel
|
||||
|
||||
object BuiltinModels {
|
||||
val BUILTIN_MODELS: Map<ResourceLocation, UnbakedModel> = mapOf(
|
||||
UnbakedBlockEntityModel.RESOURCE_LOCATION to UnbakedBlockEntityModel,
|
||||
UnbakedGeneratedModel.RESOURCE_LOCATION to UnbakedGeneratedModel,
|
||||
)
|
||||
}
|
@ -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.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.util.KUtil.toResourceLocation
|
||||
|
||||
@Deprecated("TODO")
|
||||
object UnbakedBlockEntityModel : UnbakedModel(null, mapOf()), CompanionResourceLocation {
|
||||
override val RESOURCE_LOCATION: ResourceLocation = "minecraft:builtin/entity".toResourceLocation()
|
||||
|
||||
}
|
@ -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.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.util.KUtil.toResourceLocation
|
||||
|
||||
@Deprecated("TODO")
|
||||
object UnbakedGeneratedModel : UnbakedModel(null, mapOf()), CompanionResourceLocation {
|
||||
override val RESOURCE_LOCATION: ResourceLocation = "minecraft:builtin/generated".toResourceLocation()
|
||||
|
||||
}
|
@ -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.display
|
||||
|
||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.EMPTY
|
||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.ONE
|
||||
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.toVec3
|
||||
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3iUtil.toVec3i
|
||||
import glm_.vec3.Vec3
|
||||
import glm_.vec3.Vec3i
|
||||
|
||||
data class ModelDisplay(
|
||||
val rotation: Vec3i,
|
||||
val translation: Vec3i,
|
||||
val scale: Vec3,
|
||||
) {
|
||||
companion object {
|
||||
operator fun invoke(data: Map<String, Any>): ModelDisplay {
|
||||
return ModelDisplay(
|
||||
rotation = data["rotation"]?.toVec3i() ?: Vec3i.EMPTY,
|
||||
translation = data["translation"]?.toVec3i() ?: Vec3i.EMPTY,
|
||||
scale = data["scale"]?.toVec3() ?: Vec3.ONE,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -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.display
|
||||
|
||||
import de.bixilon.minosoft.util.KUtil
|
||||
import de.bixilon.minosoft.util.KUtil.unsafeCast
|
||||
import de.bixilon.minosoft.util.enum.AliasableEnum
|
||||
import de.bixilon.minosoft.util.enum.ValuesEnum
|
||||
|
||||
enum class ModelDisplayPositions(vararg names: String = arrayOf()) : AliasableEnum {
|
||||
THIRD_PERSON_RIGHT_HAND("thirdperson_righthand"),
|
||||
THIRD_PERSON_LEFT_HAND("thirdperson_lefthand"),
|
||||
FIRST_PERSON_RIGHT_HAND("firstperson_righthand"),
|
||||
FIRST_PERSON_LEFT_HAND("firstperson_lefthand"),
|
||||
GUI,
|
||||
HEAD,
|
||||
GROUND,
|
||||
FIXED,
|
||||
;
|
||||
|
||||
override val names: Array<String> = names.unsafeCast()
|
||||
|
||||
companion object : ValuesEnum<ModelDisplayPositions> {
|
||||
override val VALUES: Array<ModelDisplayPositions> = values()
|
||||
override val NAME_MAP: Map<String, ModelDisplayPositions> = KUtil.getEnumValues(VALUES)
|
||||
|
||||
}
|
||||
}
|
@ -11,11 +11,6 @@
|
||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||
*/
|
||||
|
||||
package de.bixilon.minosoft.gui.rendering.block.models
|
||||
package de.bixilon.minosoft.gui.rendering.models.unbaked
|
||||
|
||||
import glm_.vec2.Vec2i
|
||||
|
||||
data class FaceSize(
|
||||
val start: Vec2i = Vec2i(0, 0),
|
||||
val end: Vec2i = Vec2i(BlockModelElement.BLOCK_RESOLUTION, BlockModelElement.BLOCK_RESOLUTION),
|
||||
)
|
||||
interface Model
|
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* 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.util.KUtil.toBoolean
|
||||
|
||||
class UnbakedBlockModel(
|
||||
parent: UnbakedModel?,
|
||||
json: Map<String, Any>,
|
||||
) : UnbakedModel(parent, json) {
|
||||
val ambientOcclusion: Boolean = json["ambientocclusion"]?.toBoolean() ?: parent?.let { return@let if (parent is UnbakedBlockModel) parent.ambientOcclusion else null } ?: true
|
||||
}
|
@ -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.unbaked
|
||||
|
||||
import de.bixilon.minosoft.gui.rendering.models.GUILights
|
||||
|
||||
class UnbakedItemModel(
|
||||
parent: UnbakedModel?,
|
||||
json: Map<String, Any>,
|
||||
) : UnbakedModel(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)
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* 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 UnbakedModel(
|
||||
parent: UnbakedModel?,
|
||||
json: Map<String, Any>,
|
||||
) : Model {
|
||||
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 = parent?.elements?.toMutableSet() ?: mutableSetOf()
|
||||
|
||||
json["elements"]?.listCast<Map<String, Any>>()?.let {
|
||||
for (element in it) {
|
||||
elements += UnbakedElement(data = element)
|
||||
}
|
||||
}
|
||||
|
||||
this.elements = elements
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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.element
|
||||
|
||||
import de.bixilon.minosoft.data.direction.Directions
|
||||
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.toVec3
|
||||
import de.bixilon.minosoft.util.KUtil.toBoolean
|
||||
import de.bixilon.minosoft.util.KUtil.unsafeCast
|
||||
import de.bixilon.minosoft.util.nbt.tag.NBTUtil.asCompound
|
||||
import de.bixilon.minosoft.util.nbt.tag.NBTUtil.compoundCast
|
||||
import glm_.vec3.Vec3
|
||||
|
||||
data class UnbakedElement(
|
||||
val from: Vec3,
|
||||
val to: Vec3,
|
||||
val rotation: UnbakedElementRotation?,
|
||||
val shade: Boolean,
|
||||
val faces: Set<UnbakedElementFace>,
|
||||
) {
|
||||
|
||||
companion object {
|
||||
operator fun invoke(data: Map<String, Any>): UnbakedElement {
|
||||
val faces: MutableSet<UnbakedElementFace> = mutableSetOf()
|
||||
|
||||
data["faces"].asCompound().let {
|
||||
for ((direction, faceData) in it) {
|
||||
faces += UnbakedElementFace(direction = Directions[direction], data = faceData.unsafeCast())
|
||||
}
|
||||
}
|
||||
|
||||
return UnbakedElement(
|
||||
from = data["from"].toVec3(),
|
||||
to = data["to"].toVec3(),
|
||||
rotation = data["rotation"]?.compoundCast()?.let { return@let UnbakedElementRotation(data = it) },
|
||||
shade = data["shade"]?.toBoolean() ?: true,
|
||||
faces = faces,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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.element
|
||||
|
||||
import de.bixilon.minosoft.data.direction.Directions
|
||||
import de.bixilon.minosoft.util.KUtil.toInt
|
||||
import de.bixilon.minosoft.util.nbt.tag.NBTUtil.listCast
|
||||
import glm_.vec2.Vec2
|
||||
|
||||
data class UnbakedElementFace(
|
||||
val direction: Directions,
|
||||
val uvStart: Vec2,
|
||||
val uvEnd: Vec2,
|
||||
val texture: String,
|
||||
val cullFace: Directions?,
|
||||
val rotation: Int,
|
||||
val tintIndex: Int,
|
||||
) {
|
||||
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)
|
||||
|
||||
return UnbakedElementFace(
|
||||
direction = direction,
|
||||
uvStart = uvStart,
|
||||
uvEnd = uvEnd,
|
||||
texture = data["texture"].toString(),
|
||||
cullFace = data["cullface"]?.toString()?.let { return@let Directions[it] },
|
||||
rotation = data["rotation"]?.toInt() ?: 0,
|
||||
tintIndex = data["tintindex"]?.toInt() ?: -1,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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.element
|
||||
|
||||
import de.bixilon.minosoft.data.Axes
|
||||
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.EMPTY
|
||||
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.toVec3
|
||||
import de.bixilon.minosoft.util.KUtil.toBoolean
|
||||
import de.bixilon.minosoft.util.KUtil.toFloat
|
||||
import glm_.vec3.Vec3
|
||||
|
||||
data class UnbakedElementRotation(
|
||||
val origin: Vec3,
|
||||
val axis: Axes,
|
||||
val angle: Float,
|
||||
val rescale: Boolean,
|
||||
) {
|
||||
companion object {
|
||||
|
||||
operator fun invoke(data: Map<String, Any>): UnbakedElementRotation {
|
||||
return UnbakedElementRotation(
|
||||
origin = data["origin"]?.toVec3() ?: Vec3.EMPTY,
|
||||
axis = Axes[data["axis"].toString()],
|
||||
angle = data["angle"].toFloat(),
|
||||
rescale = data["rescale"]?.toBoolean() ?: false,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -13,9 +13,6 @@
|
||||
|
||||
package de.bixilon.minosoft.gui.rendering.util
|
||||
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonObject
|
||||
import com.google.gson.JsonPrimitive
|
||||
import de.bixilon.minosoft.Minosoft
|
||||
import de.bixilon.minosoft.data.Axes
|
||||
import de.bixilon.minosoft.data.direction.AbstractDirection
|
||||
@ -23,9 +20,7 @@ import de.bixilon.minosoft.data.direction.Directions
|
||||
import de.bixilon.minosoft.data.registries.AABB
|
||||
import de.bixilon.minosoft.data.registries.blocks.RandomOffsetTypes
|
||||
import de.bixilon.minosoft.data.registries.blocks.types.Block
|
||||
import de.bixilon.minosoft.gui.rendering.block.models.BlockModelElement
|
||||
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
||||
import de.bixilon.minosoft.util.KUtil.unsafeCast
|
||||
import glm_.func.common.ceil
|
||||
import glm_.func.common.clamp
|
||||
import glm_.func.common.floor
|
||||
@ -58,19 +53,6 @@ object VecUtil {
|
||||
val Vec3d.Companion.ONE: Vec3d
|
||||
get() = Vec3d(1.0, 1.0, 1.0)
|
||||
|
||||
fun Any.toVec3(default: Vec3? = null): Vec3 {
|
||||
return when (this) {
|
||||
is List<*> -> Vec3(this[0] as Double, this[1] as Double, this[2] as Double)
|
||||
is JsonArray -> Vec3(this[0].asFloat, this[1].asFloat, this[2].asFloat)
|
||||
is JsonObject -> Vec3(this["x"]?.asFloat ?: 0, this["y"]?.asFloat ?: 0, this["z"]?.asFloat ?: 0)
|
||||
is Map<*, *> -> Vec3(this["x"]?.unsafeCast<Double>() ?: 0, this["y"]?.unsafeCast<Double>() ?: 0, this["z"]?.unsafeCast<Double>() ?: 0)
|
||||
is JsonPrimitive -> Vec3(this.asFloat)
|
||||
is Float -> Vec3(this)
|
||||
is Double -> Vec3(this)
|
||||
else -> default ?: throw IllegalArgumentException("Not a Vec3!")
|
||||
}
|
||||
}
|
||||
|
||||
fun Vec3.clear() {
|
||||
x = 0.0f
|
||||
y = 0.0f
|
||||
@ -204,10 +186,6 @@ object VecUtil {
|
||||
return this * cos + (axis cross this) * sin + axis * (axis dot this) * (1 - cos)
|
||||
}
|
||||
|
||||
fun List<Float>.readUV(): Pair<Vec2, Vec2> {
|
||||
return Pair(Vec2(this[0], BlockModelElement.BLOCK_RESOLUTION - this[1]), Vec2(this[2], BlockModelElement.BLOCK_RESOLUTION - this[3]))
|
||||
}
|
||||
|
||||
fun Int.chunkPosition(multiplier: Int): Int {
|
||||
return if (this >= 0) {
|
||||
this / multiplier
|
||||
|
@ -74,7 +74,7 @@ object Vec2Util {
|
||||
is List<*> -> Vec2i(this[0].toInt(), this[1].toInt())
|
||||
is Map<*, *> -> Vec2i(this["x"]?.toInt() ?: 0, this["y"]?.toInt() ?: 0)
|
||||
is Number -> Vec2i(this.toInt())
|
||||
else -> default ?: throw IllegalArgumentException("Not a Vec2i!")
|
||||
else -> default ?: throw IllegalArgumentException("Not a Vec2i: $this")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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.util.vec.vec3
|
||||
|
||||
import de.bixilon.minosoft.util.KUtil.toFloat
|
||||
import glm_.vec3.Vec3
|
||||
|
||||
object Vec3Util {
|
||||
|
||||
val Vec3.Companion.MIN: Vec3
|
||||
get() = Vec3(Float.MIN_VALUE, Float.MIN_VALUE, Float.MIN_VALUE)
|
||||
|
||||
val Vec3.Companion.EMPTY: Vec3
|
||||
get() = Vec3(0.0f, 0.0f, 0.0f)
|
||||
|
||||
val Vec3.Companion.MAX: Vec3
|
||||
get() = Vec3(Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE)
|
||||
|
||||
|
||||
fun Any?.toVec3(default: Vec3? = null): Vec3 {
|
||||
return when (this) {
|
||||
is List<*> -> Vec3(this[0].toFloat(), this[1].toFloat(), this[2].toFloat())
|
||||
is Map<*, *> -> Vec3(this["x"]?.toFloat() ?: 0.0f, this["y"]?.toFloat() ?: 0.0f, this["z"]?.toFloat() ?: 0.0f)
|
||||
is Number -> Vec3(this.toFloat())
|
||||
else -> default ?: throw IllegalArgumentException("Not a Vec3: $this")
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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.util.vec.vec3
|
||||
|
||||
import de.bixilon.minosoft.util.KUtil.toInt
|
||||
import glm_.vec3.Vec3
|
||||
import glm_.vec3.Vec3i
|
||||
|
||||
object Vec3iUtil {
|
||||
|
||||
val Vec3i.Companion.MIN: Vec3i
|
||||
get() = Vec3i(Int.MIN_VALUE, Int.MIN_VALUE, Int.MIN_VALUE)
|
||||
|
||||
val Vec3.Companion.EMPTY: Vec3i
|
||||
get() = Vec3i(0, 0, 0)
|
||||
|
||||
val Vec3.Companion.MAX: Vec3i
|
||||
get() = Vec3i(Int.MAX_VALUE, Int.MAX_VALUE, Int.MAX_VALUE)
|
||||
|
||||
|
||||
fun Any?.toVec3i(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 ?: throw IllegalArgumentException("Not a Vec3i: $this")
|
||||
}
|
||||
}
|
||||
}
|
@ -34,9 +34,9 @@ object ShutdownManager {
|
||||
connection.disconnect()
|
||||
}
|
||||
if (Minosoft.configInitialized) {
|
||||
Minosoft.config.saveToFile()
|
||||
// Minosoft.config.saveToFile()
|
||||
}
|
||||
DefaultThreadPool.shutdown()
|
||||
DefaultThreadPool.shutdownNow() // ToDo: Save config
|
||||
exitProcess(reason.exitCode)
|
||||
}
|
||||
|
||||
|
@ -339,10 +339,13 @@ public final class Util {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JsonObject readJsonFromStream(@NotNull InputStream stream) throws IOException {
|
||||
@Deprecated
|
||||
public static JsonObject readJsonFromStream(@NotNull InputStream stream, boolean close) throws IOException {
|
||||
InputStreamReader reader = new InputStreamReader(stream);
|
||||
JsonObject json = JsonParser.parseReader(reader).getAsJsonObject();
|
||||
reader.close();
|
||||
if (close) {
|
||||
reader.close();
|
||||
}
|
||||
return json;
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ interface ValuesEnum<T : Enum<*>> {
|
||||
}
|
||||
|
||||
operator fun get(name: String): T {
|
||||
return NAME_MAP[name]!!
|
||||
return NAME_MAP[name] ?: throw IllegalArgumentException("Can not find enum value: $name")
|
||||
}
|
||||
|
||||
fun next(current: T): T {
|
||||
|
Loading…
x
Reference in New Issue
Block a user