refactor block models

This commit is contained in:
Bixilon 2021-06-30 18:32:20 +02:00
parent 266d12b3a4
commit 4cf21f5271
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
14 changed files with 151 additions and 134 deletions

View File

@ -36,7 +36,7 @@ enum class Axes {
override val VALUES: Array<Axes> = values()
override val NAME_MAP: Map<String, Axes> = KUtil.getEnumValues(VALUES)
fun byDirection(direction: Directions): Axes {
operator fun get(direction: Directions): Axes {
return when (direction) {
Directions.EAST, Directions.WEST -> X
Directions.UP, Directions.DOWN -> Y

View File

@ -39,7 +39,7 @@ enum class Directions(
override val vectorf = Vec3(vector)
override val vectord = Vec3d(vector)
val axis: Axes get() = Axes.byDirection(this)
val axis: Axes get() = Axes.get(this)
lateinit var inverted: Directions
private set

View File

@ -27,9 +27,9 @@ import de.bixilon.minosoft.data.registries.versions.Registries
import de.bixilon.minosoft.data.text.RGBColor
import de.bixilon.minosoft.gui.rendering.TintColorCalculator
import de.bixilon.minosoft.gui.rendering.block.models.BlockModel
import de.bixilon.minosoft.gui.rendering.block.renderable.BlockRenderer
import de.bixilon.minosoft.gui.rendering.block.renderable.MultipartRenderer
import de.bixilon.minosoft.gui.rendering.block.renderable.WorldEntryRenderer
import de.bixilon.minosoft.gui.rendering.block.renderable.block.BlockRenderer
import de.bixilon.minosoft.gui.rendering.block.renderable.block.MultipartRenderer
import glm_.vec3.Vec3i
import java.util.*
import kotlin.math.abs

View File

@ -20,8 +20,8 @@ import de.bixilon.minosoft.data.registries.VoxelShape
import de.bixilon.minosoft.data.registries.blocks.BlockState
import de.bixilon.minosoft.data.registries.fluid.Fluid
import de.bixilon.minosoft.data.registries.versions.Registries
import de.bixilon.minosoft.gui.rendering.block.renderable.FluidRenderer
import de.bixilon.minosoft.gui.rendering.block.renderable.WorldEntryRenderer
import de.bixilon.minosoft.gui.rendering.block.renderable.fluid.FluidRenderer
import de.bixilon.minosoft.gui.rendering.util.VecUtil.EMPTY
import de.bixilon.minosoft.protocol.network.connection.PlayConnection
import glm_.vec3.Vec3

View File

@ -14,56 +14,43 @@
package de.bixilon.minosoft.gui.rendering.block.models
import com.google.gson.JsonObject
import glm_.glm
import de.bixilon.minosoft.gui.rendering.util.VecUtil.rad
import glm_.vec3.Vec3
open class BlockModel(val parent: BlockModel? = null, json: JsonObject) {
val textures: MutableMap<String, String> = parent?.textures?.toMutableMap() ?: mutableMapOf()
var elements: MutableList<BlockModelElement> = parent?.elements?.toMutableList() ?: mutableListOf()
var rotation: Vec3
private var uvLock = false // ToDo
private var rescale = false // ToDo
open class BlockModel(
val parent: BlockModel? = null,
data: JsonObject,
) {
val textures: Map<String, String>
val elements: List<BlockModelElement>
val rotation: Vec3 = Vec3(data["x"]?.asFloat ?: parent?.rotation?.x ?: 0.0f, data["y"]?.asFloat ?: parent?.rotation?.y ?: 0.0f, data["z"]?.asFloat ?: parent?.rotation?.z ?: 0.0f).rad
val uvLock: Boolean = data["uvlock"]?.asBoolean ?: parent?.uvLock ?: false
val rescale: Boolean = data["rescale"]?.asBoolean ?: parent?.rescale ?: false
val ambientOcclusion: Boolean = data["ambientocclusion"]?.asBoolean ?: parent?.ambientOcclusion ?: true
init {
json["textures"]?.asJsonObject?.let {
textures = data["textures"]?.asJsonObject?.let {
val textures: MutableMap<String, String> = parent?.textures?.toMutableMap() ?: mutableMapOf()
for ((type, value) in it.entrySet()) {
textures[type] = value.asString
}
}
for ((type, texture) in textures) {
getTextureByType(texture).let {
textures[type] = it
textures[type] = getTextureByType(textures, texture)
}
textures.toMap()
} ?: parent?.textures ?: mapOf()
elements = data["elements"]?.asJsonArray?.let {
val elements: MutableList<BlockModelElement> = mutableListOf()
for (element in it) {
elements += BlockModelElement(element.asJsonObject)
}
json["elements"]?.let { it ->
elements.clear()
for (element in it.asJsonArray) {
val blockModelElement = BlockModelElement(element.asJsonObject)
elements.add(blockModelElement)
}
}
var rotateX = parent?.rotation?.x ?: 0.0f
var rotateY = parent?.rotation?.y ?: 0.0f
var rotateZ = parent?.rotation?.z ?: 0.0f
json["x"]?.let {
rotateX = it.asFloat
}
json["y"]?.let {
rotateY = it.asFloat
}
json["z"]?.let {
rotateZ = it.asFloat
}
json["uvlock"]?.let {
uvLock = it.asBoolean
}
json["rescale"]?.let {
rescale = it.asBoolean
}
rotation = glm.radians(Vec3(rotateX, rotateY, rotateZ))
elements.toList()
} ?: parent?.elements ?: listOf()
}
private fun getTextureByType(type: String): String {
private fun getTextureByType(textures: Map<String, String>, type: String): String {
var currentValue: String = type
while (currentValue.startsWith("#")) {
textures[currentValue.removePrefix("#")].let {

View File

@ -21,37 +21,37 @@ import de.bixilon.minosoft.gui.rendering.util.VecUtil.rotate
import de.bixilon.minosoft.gui.rendering.util.VecUtil.toVec3
import glm_.func.rad
import glm_.vec3.Vec3
import java.util.*
open class BlockModelElement(data: JsonObject) {
val faces: MutableMap<Directions, BlockModelFace> = mutableMapOf()
var transformedPositions: Array<Vec3>
val from: Vec3 = data["from"]?.asJsonArray?.toVec3() ?: Vec3.EMPTY
val to: Vec3 = data["to"]?.asJsonArray?.toVec3() ?: Vec3(BLOCK_RESOLUTION)
open class BlockModelElement(
data: JsonObject,
) {
val from: Vec3 = data["from"]?.toVec3() ?: Vec3.EMPTY
val to: Vec3 = data["to"]?.toVec3() ?: Vec3(BLOCK_RESOLUTION)
val shade: Boolean = data["shade"]?.asBoolean ?: true
init {
transformedPositions = arrayOf(
Vec3(from),
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),
Vec3(to.x, to.y, to.z),
)
init {
data["rotation"]?.asJsonObject?.let {
val axis = Axes.valueOf(it["axis"].asString.uppercase(Locale.getDefault()))
val axis = Axes[it["axis"].asString]
val angle = it["angle"].asFloat.rad
val rescale = it["rescale"]?.asBoolean ?: false
rotatePositions(transformedPositions, axis, angle, it["origin"].asJsonArray.toVec3(), rescale)
rotatePositions(transformedPositions, axis, angle, it["origin"].toVec3(), rescale)
}
data["faces"]?.asJsonObject?.let {
for ((directionName, json) in it.entrySet()) {
val direction = Directions.valueOf(directionName.uppercase(Locale.getDefault()))
val direction = Directions[directionName]
faces[direction] = BlockModelFace(json.asJsonObject, from, to, direction)
}
}
@ -88,9 +88,11 @@ open class BlockModelElement(data: JsonObject) {
}
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))
}
}

View File

@ -28,7 +28,15 @@ class BlockModelFace {
val textureName: String?
val cullFace: Directions?
val tint: Boolean
private val positions: MutableList<Vec2>
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: JsonObject, from: Vec3, to: Vec3, direction: Directions) {
tint = data.has("tintindex")
@ -37,12 +45,13 @@ class BlockModelFace {
if (it == "bottom") {
Directions.DOWN
} else {
Directions.valueOf(it.uppercase(Locale.getDefault()))
Directions[it]
}
}
positions = calculateTexturePositions(data, from, to, direction)
val positions = calculateTexturePositions(data, from, to, direction)
val rotation = data["rotation"]?.asInt?.div(90) ?: 0
Collections.rotate(positions, rotation)
this.positions = positions.toList()
}
private fun calculateTexturePositions(data: JsonObject?, from: Vec3, to: Vec3, direction: Directions): MutableList<Vec2> {
@ -64,21 +73,11 @@ class BlockModelFace {
}
}
constructor(parent: BlockModelFace) {
textureName = parent.textureName
cullFace = parent.cullFace
tint = parent.tint
positions = mutableListOf()
for (position in parent.positions) {
positions.add(Vec2(position))
}
}
constructor(from: Vec3, to: Vec3, direction: Directions) {
textureName = null
cullFace = null
tint = false
positions = calculateTexturePositions(null, from, to, direction)
constructor(other: BlockModelFace) {
textureName = other.textureName
cullFace = other.cullFace
tint = other.tint
this.positions = other.positions
}
constructor(vertexPositions: List<Vec3>, direction: Directions) {
@ -86,10 +85,11 @@ class BlockModelFace {
cullFace = null
tint = false
val template = BlockModelElement.FACE_POSITION_MAP_TEMPLATE[direction.ordinal]
positions = mutableListOf()
val positions: MutableList<Vec2> = mutableListOf()
for (templatePosition in template) {
positions.add(calculateTexturePosition(vertexPositions[templatePosition], direction))
positions += calculateTexturePosition(vertexPositions[templatePosition], direction)
}
this.positions = positions.toList()
}
private fun calculateTexturePosition(position: Vec3, direction: Directions): Vec2 {
@ -102,29 +102,33 @@ class BlockModelFace {
fun getTexturePositionArray(direction: Directions): Array<Vec2?> {
val template = textureTemplate[direction.ordinal]
val result = arrayOfNulls<Vec2>(template.size)
val ret: MutableList<Vec2> = mutableListOf()
for (i in template.indices) {
result[i] = positions[template[i]]
ret += positions[template[i]]
}
return result
return ret.toTypedArray()
}
fun rotate(angle: Float) {
fun rotate(angle: Float): BlockModelFace {
if (angle == 0.0f) {
return
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) {
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 {

View File

@ -1,6 +1,6 @@
/*
* Minosoft
* Copyright (C) 2021 Moritz Zwerger, Lukas Eisenhauer
* 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.
*
@ -11,7 +11,7 @@
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.gui.rendering.block.renderable
package de.bixilon.minosoft.gui.rendering.block.renderable.block
import com.google.common.collect.HashBiMap
import com.google.gson.JsonObject
@ -22,14 +22,16 @@ import de.bixilon.minosoft.data.text.RGBColor
import de.bixilon.minosoft.gui.rendering.RenderConstants
import de.bixilon.minosoft.gui.rendering.block.models.BlockModel
import de.bixilon.minosoft.gui.rendering.block.models.FaceSize
import de.bixilon.minosoft.gui.rendering.block.renderable.BlockLikeRenderContext
import de.bixilon.minosoft.gui.rendering.block.renderable.WorldEntryRenderer
import de.bixilon.minosoft.gui.rendering.textures.Texture
import de.bixilon.minosoft.gui.rendering.textures.TextureTransparencies
import de.bixilon.minosoft.gui.rendering.util.VecUtil.plus
import de.bixilon.minosoft.gui.rendering.util.VecUtil.rad
import de.bixilon.minosoft.gui.rendering.util.VecUtil.toVec3
import glm_.glm
import glm_.vec3.Vec3
class BlockRenderer(data: JsonObject, parent: BlockModel) : WorldEntryRenderer {
class BlockRenderer(data: JsonObject, model: BlockModel) : WorldEntryRenderer {
private val cullFaces: Array<Directions?> = arrayOfNulls(Directions.VALUES.size)
val textures: MutableMap<String, String> = mutableMapOf()
private val elements: MutableSet<ElementRenderer> = mutableSetOf()
@ -39,19 +41,16 @@ class BlockRenderer(data: JsonObject, parent: BlockModel) : WorldEntryRenderer {
val directionMapping: HashBiMap<Directions, Directions> = HashBiMap.create()
init {
val rotation = glm.radians(data.toVec3())
val rotation = data.toVec3().rad
createDirectionMapping(rotation)
val newElements = ElementRenderer.createElements(data, parent, rotation, directionMapping)
val newElements = ElementRenderer.createElements(data, model, rotation, directionMapping)
this.elements.addAll(newElements.reversed()) // reverse drawing order (for e.g. grass block side overlays
textures.putAll(parent.textures)
textures.putAll(model.textures)
}
private fun createDirectionMapping(rotation: Vec3) {
for (direction in Directions.VALUES) {
try {
directionMapping[direction] = ElementRenderer.getRotatedDirection(rotation, direction)
} catch (_: IllegalArgumentException) {
}
}
}

View File

@ -1,6 +1,6 @@
/*
* Minosoft
* Copyright (C) 2021 Moritz Zwerger, Lukas Eisenhauer
* 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.
*
@ -11,7 +11,7 @@
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.gui.rendering.block.renderable
package de.bixilon.minosoft.gui.rendering.block.renderable.block
import com.google.common.collect.HashBiMap
import com.google.gson.JsonObject
@ -24,6 +24,7 @@ import de.bixilon.minosoft.gui.rendering.block.models.BlockModel
import de.bixilon.minosoft.gui.rendering.block.models.BlockModelElement
import de.bixilon.minosoft.gui.rendering.block.models.BlockModelFace
import de.bixilon.minosoft.gui.rendering.block.models.FaceSize
import de.bixilon.minosoft.gui.rendering.block.renderable.BlockLikeRenderContext
import de.bixilon.minosoft.gui.rendering.textures.Texture
import de.bixilon.minosoft.gui.rendering.textures.TextureTransparencies
import de.bixilon.minosoft.gui.rendering.util.VecUtil.EMPTY
@ -33,35 +34,38 @@ import de.bixilon.minosoft.gui.rendering.util.VecUtil.toVec3
import glm_.vec3.Vec3
class ElementRenderer(
parent: BlockModelElement,
val model: BlockModel,
val element: BlockModelElement,
val rotation: Vec3,
uvLock: Boolean,
rescale: Boolean,
data: JsonObject,
private val directionMapping: HashBiMap<Directions, Directions>,
) {
val faceBorderSize: Array<FaceSize?> = arrayOfNulls(Directions.VALUES.size)
private val faces: MutableMap<Directions, BlockModelFace> = mutableMapOf()
private var transformedPositions: Array<Vec3> = parent.transformedPositions.clone()
private val from = parent.from
private val to = parent.to
private val faces: Map<Directions, BlockModelFace>
private var transformedPositions: Array<Vec3> = element.transformedPositions.clone()
init {
rotatePositionsAxes(transformedPositions, rotation, rescale)
rotatePositionsAxes(transformedPositions, rotation, data["rescale"]?.asBoolean ?: model.rescale)
val faces: MutableMap<Directions, BlockModelFace> = mutableMapOf()
for (direction in Directions.VALUES) {
direction.getFaceBorderSizes(from, to)?.let {
direction.getFaceBorderSizes(element.from, element.to)?.let {
faceBorderSize[direction.ordinal] = it
}
parent.faces[direction]?.let {
element.faces[direction]?.let {
faces[direction] = BlockModelFace(it)
}
}
if (uvLock) {
if (data["uvlock"]?.asBoolean ?: model.uvLock) {
for (direction in Directions.VALUES) {
val axis = Axes.byDirection(direction)
val axis = Axes[direction]
val angle = axis.choose(rotation) * axis.choose(direction.vector)
faces[direction]?.rotate(-angle)
faces[direction] = faces[direction]?.rotate(-angle) ?: continue
}
}
this.faces = faces.toMap()
}
fun render(tintColor: RGBColor?, textureMapping: MutableMap<String, Texture>, direction: Directions, context: BlockLikeRenderContext) {
@ -117,24 +121,24 @@ class ElementRenderer(
0 to 1,
)
fun createElements(state: JsonObject, parent: BlockModel, rotation: Vec3, directionMapping: HashBiMap<Directions, Directions>): MutableList<ElementRenderer> {
val uvLock = state["uvlock"]?.asBoolean ?: false
val rescale = state["rescale"]?.asBoolean ?: false
val parentElements = parent.elements
fun createElements(data: JsonObject, model: BlockModel, rotation: Vec3, directionMapping: HashBiMap<Directions, Directions>): List<ElementRenderer> {
val result: MutableList<ElementRenderer> = mutableListOf()
for (parentElement in parentElements) {
result.add(ElementRenderer(parentElement, rotation, uvLock, rescale, directionMapping))
for (element in model.elements) {
result += ElementRenderer(model, element, rotation, data, directionMapping)
}
return result
return result.toList()
}
fun getRotatedDirection(rotation: Vec3, direction: Directions): Directions {
if (rotation == Vec3.EMPTY) {
return direction
}
var rotatedDirectionVector = direction.vectorf.rotate(-rotation.x, Axes.X)
rotatedDirectionVector = rotatedDirectionVector.rotate(rotation.y, Axes.Y)
return Directions.byDirection(rotatedDirectionVector.rotate(-rotation.z, Axes.Z))
return Directions.byDirection(
direction.vectorf.rotate(-rotation.x, Axes.X)
.rotate(rotation.y, Axes.Y)
.rotate(-rotation.z, Axes.Z)
)
}
fun rotatePositionsAxes(positions: Array<Vec3>, angles: Vec3, rescale: Boolean) {

View File

@ -11,11 +11,13 @@
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.gui.rendering.block.renderable
package de.bixilon.minosoft.gui.rendering.block.renderable.block
import de.bixilon.minosoft.data.direction.Directions
import de.bixilon.minosoft.data.registries.ResourceLocation
import de.bixilon.minosoft.gui.rendering.block.models.FaceSize
import de.bixilon.minosoft.gui.rendering.block.renderable.BlockLikeRenderContext
import de.bixilon.minosoft.gui.rendering.block.renderable.WorldEntryRenderer
import de.bixilon.minosoft.gui.rendering.textures.Texture
@Deprecated(message = "Will be replaced with a normal BlockRenderer and multiple renderers")

View File

@ -1,4 +1,17 @@
package de.bixilon.minosoft.gui.rendering.block.renderable
/*
* 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.renderable.fluid
import de.bixilon.minosoft.data.direction.Directions
import de.bixilon.minosoft.data.registries.ResourceLocation
@ -15,6 +28,9 @@ import de.bixilon.minosoft.gui.rendering.block.mesh.ChunkSectionMeshCollection
import de.bixilon.minosoft.gui.rendering.block.models.BlockModelElement
import de.bixilon.minosoft.gui.rendering.block.models.BlockModelFace
import de.bixilon.minosoft.gui.rendering.block.models.FaceSize
import de.bixilon.minosoft.gui.rendering.block.renderable.BlockLikeRenderContext
import de.bixilon.minosoft.gui.rendering.block.renderable.WorldEntryRenderer
import de.bixilon.minosoft.gui.rendering.block.renderable.block.ElementRenderer
import de.bixilon.minosoft.gui.rendering.textures.Texture
import de.bixilon.minosoft.gui.rendering.util.VecUtil.plus
import de.bixilon.minosoft.util.KUtil.nullCast
@ -49,13 +65,13 @@ class FluidRenderer(
val positions = calculatePositions(heights)
for (direction in Directions.VALUES) {
val face = BlockModelFace(positions, direction)
var face = BlockModelFace(positions, direction)
if (isFlowing || Directions.SIDES.contains(direction)) {
face.scale(0.5)
face = face.scale(0.5)
texture = flowingTexture ?: return
if (!Directions.SIDES.contains(direction)) {
val angle = getRotationAngle(heights)
face.rotate(angle)
face = face.rotate(angle)
}
} else {
texture = stillTexture ?: return

View File

@ -19,10 +19,10 @@ import de.bixilon.minosoft.data.registries.particle.data.BlockParticleData
import de.bixilon.minosoft.data.registries.particle.data.ParticleData
import de.bixilon.minosoft.data.text.RGBColor
import de.bixilon.minosoft.data.text.RGBColor.Companion.asGray
import de.bixilon.minosoft.gui.rendering.block.renderable.BlockRenderer
import de.bixilon.minosoft.gui.rendering.block.renderable.FluidRenderer
import de.bixilon.minosoft.gui.rendering.block.renderable.MultipartRenderer
import de.bixilon.minosoft.gui.rendering.block.renderable.WorldEntryRenderer
import de.bixilon.minosoft.gui.rendering.block.renderable.block.BlockRenderer
import de.bixilon.minosoft.gui.rendering.block.renderable.block.MultipartRenderer
import de.bixilon.minosoft.gui.rendering.block.renderable.fluid.FluidRenderer
import de.bixilon.minosoft.gui.rendering.particle.ParticleFactory
import de.bixilon.minosoft.gui.rendering.particle.types.render.texture.advanced.AdvancedTextureParticle
import de.bixilon.minosoft.gui.rendering.util.VecUtil.blockPosition

View File

@ -470,4 +470,7 @@ object VecUtil {
operator fun AbstractDirection.plus(direction: AbstractDirection): Vec3i {
return this.vector + direction.vector
}
val Vec3.rad: Vec3
get() = glm.radians(this)
}

View File

@ -16,7 +16,7 @@ package de.bixilon.minosoft.gui.rendering.util.mesh
import de.bixilon.minosoft.data.registries.AABB
import de.bixilon.minosoft.data.registries.VoxelShape
import de.bixilon.minosoft.data.text.RGBColor
import de.bixilon.minosoft.gui.rendering.block.renderable.ElementRenderer
import de.bixilon.minosoft.gui.rendering.block.renderable.block.ElementRenderer
import de.bixilon.minosoft.gui.rendering.util.VecUtil.EMPTY
import de.bixilon.minosoft.util.BitByte.isBit
import de.bixilon.minosoft.util.MMath.positiveNegative