mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-18 11:54:59 -04:00
rendering: performance and cde quality improvements
This commit is contained in:
parent
74e5482096
commit
5312e0d436
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Minosoft
|
* Minosoft
|
||||||
* Copyright (C) 2020 Moritz Zwerger
|
* Copyright (C) 2020 Moritz Zwerger, Lukas Eisenhauer
|
||||||
*
|
*
|
||||||
* 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 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.
|
||||||
*
|
*
|
||||||
@ -15,7 +15,6 @@ package de.bixilon.minosoft.data.mappings.blocks
|
|||||||
import de.bixilon.minosoft.Minosoft
|
import de.bixilon.minosoft.Minosoft
|
||||||
import de.bixilon.minosoft.data.mappings.ModIdentifier
|
import de.bixilon.minosoft.data.mappings.ModIdentifier
|
||||||
import de.bixilon.minosoft.data.world.BlockPosition
|
import de.bixilon.minosoft.data.world.BlockPosition
|
||||||
import de.bixilon.minosoft.gui.rendering.chunk.models.loading.BlockModel
|
|
||||||
import de.bixilon.minosoft.gui.rendering.chunk.models.renderable.BlockRenderer
|
import de.bixilon.minosoft.gui.rendering.chunk.models.renderable.BlockRenderer
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
@ -23,7 +22,6 @@ import kotlin.random.Random
|
|||||||
data class Block(val identifier: ModIdentifier) {
|
data class Block(val identifier: ModIdentifier) {
|
||||||
var rotation: BlockRotations = BlockRotations.NONE
|
var rotation: BlockRotations = BlockRotations.NONE
|
||||||
var properties: Set<BlockProperties> = setOf()
|
var properties: Set<BlockProperties> = setOf()
|
||||||
val blockModels: MutableList<BlockModel> = mutableListOf()
|
|
||||||
val blockRenderers: MutableList<BlockRenderer> = mutableListOf()
|
val blockRenderers: MutableList<BlockRenderer> = mutableListOf()
|
||||||
|
|
||||||
constructor(identifier: ModIdentifier, properties: Set<BlockProperties>, rotation: BlockRotations) : this(identifier) {
|
constructor(identifier: ModIdentifier, properties: Set<BlockProperties>, rotation: BlockRotations) : this(identifier) {
|
||||||
|
@ -56,7 +56,7 @@ class VersionMapping(var version: Version?) {
|
|||||||
private val dimensionIdMap = HashBiMap.create<Int, Dimension>()
|
private val dimensionIdMap = HashBiMap.create<Int, Dimension>()
|
||||||
var dimensionIdentifierMap: HashBiMap<ModIdentifier, Dimension> = HashBiMap.create()
|
var dimensionIdentifierMap: HashBiMap<ModIdentifier, Dimension> = HashBiMap.create()
|
||||||
|
|
||||||
val blockIdMap = HashBiMap.create<Int, Block>(20000)
|
val blockIdMap: HashBiMap<Int, Block> = HashBiMap.create(20000)
|
||||||
|
|
||||||
private val entityInformationMap = HashBiMap.create<Class<out Entity>, EntityInformation>(120)
|
private val entityInformationMap = HashBiMap.create<Class<out Entity>, EntityInformation>(120)
|
||||||
private val entityMetaIndexMap = HashMap<EntityMetaDataFields, Int>(180)
|
private val entityMetaIndexMap = HashMap<EntityMetaDataFields, Int>(180)
|
||||||
|
@ -1,45 +0,0 @@
|
|||||||
package de.bixilon.minosoft.gui.rendering.chunk.models.loading;
|
|
||||||
|
|
||||||
import com.google.gson.JsonElement;
|
|
||||||
import com.google.gson.JsonObject;
|
|
||||||
import de.bixilon.minosoft.data.mappings.blocks.Block;
|
|
||||||
import de.bixilon.minosoft.data.mappings.blocks.BlockProperties;
|
|
||||||
import de.bixilon.minosoft.data.mappings.blocks.BlockRotations;
|
|
||||||
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class BlockCondition {
|
|
||||||
public static final BlockCondition TRUE_CONDITION = new BlockCondition() {
|
|
||||||
@Override
|
|
||||||
public boolean contains(Block block) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private HashSet<BlockProperties> properties;
|
|
||||||
private BlockRotations rotation;
|
|
||||||
|
|
||||||
public BlockCondition(JsonObject json) {
|
|
||||||
properties = new HashSet<>();
|
|
||||||
rotation = BlockRotations.NONE;
|
|
||||||
for (Map.Entry<String, JsonElement> entry : json.entrySet()) {
|
|
||||||
String value = entry.getValue().getAsString();
|
|
||||||
if (BlockProperties.PROPERTIES_MAPPING.containsKey(entry.getKey())) {
|
|
||||||
properties.add(BlockProperties.PROPERTIES_MAPPING.get(entry.getKey()).get(value));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
rotation = BlockRotations.ROTATION_MAPPING.get(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public BlockCondition() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean contains(Block block) {
|
|
||||||
if (rotation != BlockRotations.NONE && rotation != block.getRotation()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return block.getProperties().containsAll(properties);
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* Minosoft
|
||||||
|
* Copyright (C) 2021 Moritz Zwerger, Lukas Eisenhauer
|
||||||
|
*
|
||||||
|
* 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.chunk.models.loading
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject
|
||||||
|
import de.bixilon.minosoft.data.mappings.blocks.Block
|
||||||
|
import de.bixilon.minosoft.data.mappings.blocks.BlockProperties
|
||||||
|
import de.bixilon.minosoft.data.mappings.blocks.BlockRotations
|
||||||
|
|
||||||
|
open class BlockCondition {
|
||||||
|
private var properties: MutableSet<BlockProperties> = mutableSetOf()
|
||||||
|
private var rotation: BlockRotations = BlockRotations.NONE
|
||||||
|
|
||||||
|
constructor(json: JsonObject) {
|
||||||
|
for ((key, value) in json.entrySet()) {
|
||||||
|
val value = value.asString
|
||||||
|
kotlin.run {
|
||||||
|
BlockRotations.ROTATION_MAPPING[value]?.let {
|
||||||
|
rotation = it
|
||||||
|
return@run
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockProperties.PROPERTIES_MAPPING[key]?.get(value)?.let {
|
||||||
|
properties.add(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor()
|
||||||
|
|
||||||
|
open operator fun contains(block: Block): Boolean {
|
||||||
|
return if (rotation != BlockRotations.NONE && rotation != block.rotation) {
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
block.properties.containsAll(properties)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val TRUE_CONDITION: BlockCondition = object : BlockCondition() {
|
||||||
|
override fun contains(block: Block): Boolean {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -14,17 +14,13 @@
|
|||||||
package de.bixilon.minosoft.gui.rendering.chunk.models.loading
|
package de.bixilon.minosoft.gui.rendering.chunk.models.loading
|
||||||
|
|
||||||
import com.google.gson.JsonObject
|
import com.google.gson.JsonObject
|
||||||
import de.bixilon.minosoft.data.Directions
|
|
||||||
import de.bixilon.minosoft.gui.rendering.textures.Texture
|
|
||||||
import glm_.glm
|
import glm_.glm
|
||||||
import glm_.vec3.Vec3
|
import glm_.vec3.Vec3
|
||||||
|
|
||||||
open class BlockModel(val parent: BlockModel? = null, json: JsonObject) {
|
open class BlockModel(val parent: BlockModel? = null, json: JsonObject) {
|
||||||
val textures: MutableMap<String, String> = parent?.textures?.toMutableMap() ?: mutableMapOf()
|
val textures: MutableMap<String, String> = parent?.textures?.toMutableMap() ?: mutableMapOf()
|
||||||
private val textureMapping: MutableMap<String, Texture> = mutableMapOf()
|
|
||||||
var elements: MutableList<BlockModelElement> = parent?.elements?.toMutableList() ?: mutableListOf()
|
var elements: MutableList<BlockModelElement> = parent?.elements?.toMutableList() ?: mutableListOf()
|
||||||
val fullFaceDirections: MutableSet<Directions> = parent?.fullFaceDirections?.toMutableSet() ?: mutableSetOf()
|
var rotation: Vec3
|
||||||
private var rotation: Vec3
|
|
||||||
private var uvLock = false // ToDo
|
private var uvLock = false // ToDo
|
||||||
private var rescale = false // ToDo
|
private var rescale = false // ToDo
|
||||||
|
|
||||||
@ -41,11 +37,9 @@ open class BlockModel(val parent: BlockModel? = null, json: JsonObject) {
|
|||||||
}
|
}
|
||||||
json["elements"]?.let { it ->
|
json["elements"]?.let { it ->
|
||||||
elements.clear()
|
elements.clear()
|
||||||
fullFaceDirections.clear()
|
|
||||||
for (element in it.asJsonArray) {
|
for (element in it.asJsonArray) {
|
||||||
val blockModelElement = BlockModelElement(element.asJsonObject)
|
val blockModelElement = BlockModelElement(element.asJsonObject)
|
||||||
elements.add(blockModelElement)
|
elements.add(blockModelElement)
|
||||||
fullFaceDirections.addAll(blockModelElement.fullFaceDirections)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var rotateX = parent?.rotation?.x ?: 0f
|
var rotateX = parent?.rotation?.x ?: 0f
|
||||||
@ -69,7 +63,6 @@ open class BlockModel(val parent: BlockModel? = null, json: JsonObject) {
|
|||||||
rotation = glm.radians(Vec3(rotateX, rotateY, rotateZ))
|
rotation = glm.radians(Vec3(rotateX, rotateY, rotateZ))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun getTextureByType(type: String): String {
|
private fun getTextureByType(type: String): String {
|
||||||
var currentValue: String = type
|
var currentValue: String = type
|
||||||
while (currentValue.startsWith("#")) {
|
while (currentValue.startsWith("#")) {
|
||||||
@ -82,23 +75,4 @@ open class BlockModel(val parent: BlockModel? = null, json: JsonObject) {
|
|||||||
}
|
}
|
||||||
return currentValue
|
return currentValue
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isCullFace(direction: Directions): Boolean {
|
|
||||||
for (element in elements) {
|
|
||||||
if (element.isCullFace(direction)) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
fun isTransparent(direction: Directions): Boolean {
|
|
||||||
for (element in elements) {
|
|
||||||
if (textureMapping[element.getTexture(direction)]?.isTransparent == true) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,16 @@
|
|||||||
|
/*
|
||||||
|
* Minosoft
|
||||||
|
* Copyright (C) 2021 Moritz Zwerger, Lukas Eisenhauer
|
||||||
|
*
|
||||||
|
* 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.chunk.models.loading
|
package de.bixilon.minosoft.gui.rendering.chunk.models.loading
|
||||||
|
|
||||||
import com.google.gson.JsonArray
|
import com.google.gson.JsonArray
|
||||||
@ -9,13 +22,11 @@ import glm_.vec3.Vec3
|
|||||||
|
|
||||||
open class BlockModelElement(data: JsonObject) {
|
open class BlockModelElement(data: JsonObject) {
|
||||||
val faces: MutableMap<Directions, BlockModelFace> = mutableMapOf()
|
val faces: MutableMap<Directions, BlockModelFace> = mutableMapOf()
|
||||||
val fullFaceDirections: MutableSet<Directions> = mutableSetOf()
|
|
||||||
var fullFace = false
|
|
||||||
var positions: Array<Vec3>
|
var positions: Array<Vec3>
|
||||||
|
|
||||||
init {
|
init {
|
||||||
var from = Vec3(0, 0, 0)
|
var from = Vec3(0, 0, 0)
|
||||||
var to = Vec3(16, 16, 16)
|
var to = Vec3(BLOCK_RESOLUTION, BLOCK_RESOLUTION, BLOCK_RESOLUTION)
|
||||||
data["from"]?.let {
|
data["from"]?.let {
|
||||||
val array = it.asJsonArray
|
val array = it.asJsonArray
|
||||||
from = Vec3(array[0].asFloat, array[1].asFloat, array[2].asFloat)
|
from = Vec3(array[0].asFloat, array[1].asFloat, array[2].asFloat)
|
||||||
@ -34,27 +45,16 @@ open class BlockModelElement(data: JsonObject) {
|
|||||||
Vec3(from.x, to.y, to.z),
|
Vec3(from.x, to.y, to.z),
|
||||||
Vec3(to),
|
Vec3(to),
|
||||||
)
|
)
|
||||||
var rotate = Vec3()
|
|
||||||
data["rotation"]?.let {
|
data["rotation"]?.let {
|
||||||
val rotation = it.asJsonObject
|
val rotation = it.asJsonObject
|
||||||
val axis = Axes.valueOf(rotation["axis"].asString.toUpperCase())
|
val axis = Axes.valueOf(rotation["axis"].asString.toUpperCase())
|
||||||
val angle = glm.radians(rotation["angle"].asDouble)
|
val angle = glm.radians(rotation["angle"].asDouble)
|
||||||
rotatePositions(positions, axis, angle, jsonArrayToVec3(rotation["origin"].asJsonArray))
|
rotatePositions(positions, axis, angle, jsonArrayToVec3(rotation["origin"].asJsonArray))
|
||||||
rotate = when (axis) {
|
|
||||||
Axes.X -> run { return@run Vec3(angle, 0, 0) }
|
|
||||||
Axes.Y -> run { return@run Vec3(0, angle, 0) }
|
|
||||||
Axes.Z -> run { return@run Vec3(0, 0, angle) }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
data["faces"]?.let {
|
data["faces"]?.let {
|
||||||
for ((directionName, json) in it.asJsonObject.entrySet()) {
|
for ((directionName, json) in it.asJsonObject.entrySet()) {
|
||||||
var direction = Directions.valueOf(directionName.toUpperCase())
|
val direction = Directions.valueOf(directionName.toUpperCase())
|
||||||
faces[direction] = BlockModelFace(json.asJsonObject, from, to, direction)
|
faces[direction] = BlockModelFace(json.asJsonObject, from, to, direction)
|
||||||
direction = getRotatedDirection(rotate, direction)
|
|
||||||
fullFace = positions.containsAll(fullTestPositions[direction]) // TODO: check if texture is transparent ==> && ! texture.isTransparent
|
|
||||||
if (fullFace) {
|
|
||||||
fullFaceDirections.add(direction)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for ((i, position) in positions.withIndex()) {
|
for ((i, position) in positions.withIndex()) {
|
||||||
@ -62,19 +62,11 @@ open class BlockModelElement(data: JsonObject) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isCullFace(direction: Directions): Boolean {
|
|
||||||
return faces[direction]?.cullFace == direction
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getTexture(direction: Directions): String? {
|
|
||||||
return faces[direction]?.textureName
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun jsonArrayToVec3(array: JsonArray) : Vec3 {
|
fun jsonArrayToVec3(array: JsonArray): Vec3 {
|
||||||
return Vec3(array[0].asFloat, array[1].asFloat, array[2].asFloat)
|
return Vec3(array[0].asFloat, array[1].asFloat, array[2].asFloat)
|
||||||
}
|
}
|
||||||
private const val BLOCK_RESOLUTION = 16
|
const val BLOCK_RESOLUTION = 16f
|
||||||
|
|
||||||
val FACE_POSITION_MAP_TEMPLATE = arrayOf(
|
val FACE_POSITION_MAP_TEMPLATE = arrayOf(
|
||||||
intArrayOf(0, 2, 3, 1),
|
intArrayOf(0, 2, 3, 1),
|
||||||
@ -85,50 +77,40 @@ open class BlockModelElement(data: JsonObject) {
|
|||||||
intArrayOf(5, 1, 3, 7)
|
intArrayOf(5, 1, 3, 7)
|
||||||
)
|
)
|
||||||
|
|
||||||
private val POSITION_1 = Vec3(0, 0, 0)
|
private val POSITION_1 = Vec3(-0.5f, -0.5f, -0.5f) // Vec3(0, 0, 0)
|
||||||
private val POSITION_2 = Vec3(BLOCK_RESOLUTION, 0, 0)
|
private val POSITION_2 = Vec3(+0.5f, -0.5f, -0.5f) // Vec3(BLOCK_RESOLUTION, 0, 0)
|
||||||
private val POSITION_3 = Vec3(0, 0, BLOCK_RESOLUTION)
|
private val POSITION_3 = Vec3(-0.5f, -0.5f, +0.5f) // Vec3(0, 0, BLOCK_RESOLUTION)
|
||||||
private val POSITION_4 = Vec3(BLOCK_RESOLUTION, 0, BLOCK_RESOLUTION)
|
private val POSITION_4 = Vec3(+0.5f, -0.5f, +0.5f) // Vec3(BLOCK_RESOLUTION, 0, BLOCK_RESOLUTION)
|
||||||
|
private val POSITION_5 = Vec3(-0.5f, +0.5f, -0.5f) // Vec3(0, BLOCK_RESOLUTION, 0)
|
||||||
private val POSITION_5 = Vec3(0, BLOCK_RESOLUTION, 0)
|
private val POSITION_6 = Vec3(+0.5f, +0.5f, +0.5f) // Vec3(BLOCK_RESOLUTION, BLOCK_RESOLUTION, 0)
|
||||||
private val POSITION_6 = Vec3(BLOCK_RESOLUTION, BLOCK_RESOLUTION, 0)
|
private val POSITION_7 = Vec3(-0.5f, +0.5f, +0.5f) // Vec3(0, BLOCK_RESOLUTION, BLOCK_RESOLUTION)
|
||||||
private val POSITION_7 = Vec3(0, BLOCK_RESOLUTION, BLOCK_RESOLUTION)
|
private val POSITION_8 = Vec3(+0.5f, +0.5f, +0.5f) // Vec3(BLOCK_RESOLUTION, BLOCK_RESOLUTION, BLOCK_RESOLUTION)
|
||||||
private val POSITION_8 = Vec3(BLOCK_RESOLUTION, BLOCK_RESOLUTION, BLOCK_RESOLUTION)
|
|
||||||
|
|
||||||
val fullTestPositions = mapOf(
|
val fullTestPositions = mapOf(
|
||||||
Pair(Directions.EAST, setOf(POSITION_1, POSITION_3, POSITION_5, POSITION_7)),
|
Directions.EAST to setOf(POSITION_1, POSITION_3, POSITION_5, POSITION_7),
|
||||||
Pair(Directions.WEST, setOf(POSITION_2, POSITION_4, POSITION_6, POSITION_8)),
|
Directions.WEST to setOf(POSITION_2, POSITION_4, POSITION_6, POSITION_8),
|
||||||
Pair(Directions.DOWN, setOf(POSITION_1, POSITION_2, POSITION_3, POSITION_4)),
|
Directions.DOWN to setOf(POSITION_1, POSITION_2, POSITION_3, POSITION_4),
|
||||||
Pair(Directions.UP, setOf(POSITION_5, POSITION_6, POSITION_7, POSITION_8)),
|
Directions.UP to setOf(POSITION_5, POSITION_6, POSITION_7, POSITION_8),
|
||||||
Pair(Directions.SOUTH, setOf(POSITION_1, POSITION_2, POSITION_5, POSITION_6)),
|
Directions.SOUTH to setOf(POSITION_1, POSITION_2, POSITION_5, POSITION_6),
|
||||||
Pair(Directions.NORTH, setOf(POSITION_3, POSITION_4, POSITION_7, POSITION_8)),
|
Directions.NORTH to setOf(POSITION_3, POSITION_4, POSITION_7, POSITION_8),
|
||||||
)
|
)
|
||||||
|
|
||||||
fun getRotatedDirection(rotation: Vec3, direction: Directions): Directions {
|
fun rotateVector(original: Vec3, angle: Double, axis: Axes): Vec3 {
|
||||||
if (rotation == Vec3(0, 0, 0)) {
|
|
||||||
return direction
|
|
||||||
}
|
|
||||||
var rotatedDirectionVector = rotateVector(direction.directionVector, rotation.z.toDouble(), Axes.Z)
|
|
||||||
rotatedDirectionVector = rotateVector(rotatedDirectionVector, rotation.y.toDouble(), Axes.Y)
|
|
||||||
return Directions.byDirection(rotateVector(rotatedDirectionVector, rotation.x.toDouble(), Axes.X))
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun rotateVector(original: Vec3, angle: Double, axis: Axes): Vec3 {
|
|
||||||
fun getRotatedValues(x: Float, y: Float, sin: Double, cos: Double): Pair<Float, Float> {
|
fun getRotatedValues(x: Float, y: Float, sin: Double, cos: Double): Pair<Float, Float> {
|
||||||
return Pair((x * cos - y * sin).toFloat(), (x * sin + y * cos).toFloat())
|
return Pair((x * cos - y * sin).toFloat(), (x * sin + y * cos).toFloat())
|
||||||
}
|
}
|
||||||
return when (axis) {
|
return when (axis) {
|
||||||
Axes.X -> run {
|
Axes.X -> {
|
||||||
val rotatedValues = getRotatedValues(original.y, original.z, glm.sin(angle), glm.cos(angle))
|
val rotatedValues = getRotatedValues(original.y, original.z, glm.sin(angle), glm.cos(angle))
|
||||||
return@run Vec3(original.x, rotatedValues.first, rotatedValues.second)
|
Vec3(original.x, rotatedValues.first, rotatedValues.second)
|
||||||
}
|
}
|
||||||
Axes.Y -> run {
|
Axes.Y -> {
|
||||||
val rotatedValues = getRotatedValues(original.x, original.z, glm.sin(angle), glm.cos(angle))
|
val rotatedValues = getRotatedValues(original.x, original.z, glm.sin(angle), glm.cos(angle))
|
||||||
return@run Vec3(rotatedValues.first, original.y, rotatedValues.second)
|
Vec3(rotatedValues.first, original.y, rotatedValues.second)
|
||||||
}
|
}
|
||||||
Axes.Z -> run {
|
Axes.Z -> {
|
||||||
val rotatedValues = getRotatedValues(original.x, original.y, glm.sin(angle), glm.cos(angle))
|
val rotatedValues = getRotatedValues(original.x, original.y, glm.sin(angle), glm.cos(angle))
|
||||||
return@run Vec3(rotatedValues.first, rotatedValues.second, original.z)
|
Vec3(rotatedValues.first, rotatedValues.second, original.z)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -145,29 +127,11 @@ open class BlockModelElement(data: JsonObject) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun rotatePositionsAxes(positions: Array<Vec3>, angles: Vec3) {
|
|
||||||
rotatePositions(positions, Axes.Z, angles.z.toDouble(), Vec3())
|
|
||||||
rotatePositions(positions, Axes.Y, angles.y.toDouble(), Vec3())
|
|
||||||
rotatePositions(positions, Axes.X, angles.x.toDouble(), Vec3())
|
|
||||||
}
|
|
||||||
|
|
||||||
fun transformPosition(position: Vec3): Vec3 {
|
fun transformPosition(position: Vec3): Vec3 {
|
||||||
fun positionToFloat(uv: Float): Float {
|
fun positionToFloat(uv: Float): Float {
|
||||||
return (uv - 8f) / 16f
|
return (uv - 8f) / BLOCK_RESOLUTION
|
||||||
}
|
}
|
||||||
return Vec3(positionToFloat(position.x), positionToFloat(position.y), positionToFloat(position.z))
|
return Vec3(positionToFloat(position.x), positionToFloat(position.y), positionToFloat(position.z))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun <T> Array<T>.containsAll(set: Set<T>?): Boolean {
|
|
||||||
if (set != null) {
|
|
||||||
for (value in set) {
|
|
||||||
if (! this.contains(value)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
@ -1,3 +1,16 @@
|
|||||||
|
/*
|
||||||
|
* Minosoft
|
||||||
|
* Copyright (C) 2021 Moritz Zwerger, Lukas Eisenhauer
|
||||||
|
*
|
||||||
|
* 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.chunk.models.loading
|
package de.bixilon.minosoft.gui.rendering.chunk.models.loading
|
||||||
|
|
||||||
import com.google.gson.JsonObject
|
import com.google.gson.JsonObject
|
||||||
@ -16,16 +29,16 @@ class BlockModelFace(data: JsonObject, from: Vec3, to: Vec3, direction: Directio
|
|||||||
var textureEnd = Vec2(16, 16)
|
var textureEnd = Vec2(16, 16)
|
||||||
when (direction) {
|
when (direction) {
|
||||||
Directions.EAST, Directions.WEST -> run {
|
Directions.EAST, Directions.WEST -> run {
|
||||||
textureStart = Vec2(from.z.toInt(), 16 - from.y.toInt());
|
textureStart = Vec2(from.z.toInt(), BlockModelElement.BLOCK_RESOLUTION - from.y.toInt())
|
||||||
textureEnd = Vec2(to.z.toInt(), 16 - to.y.toInt());
|
textureEnd = Vec2(to.z.toInt(), BlockModelElement.BLOCK_RESOLUTION - to.y.toInt())
|
||||||
}
|
}
|
||||||
Directions.UP, Directions.DOWN -> {
|
Directions.UP, Directions.DOWN -> {
|
||||||
textureStart = Vec2(from.x.toInt(), 16 - from.z.toInt());
|
textureStart = Vec2(from.x.toInt(), BlockModelElement.BLOCK_RESOLUTION - from.z.toInt())
|
||||||
textureEnd = Vec2(to.x.toInt(), 16 - to.z.toInt());
|
textureEnd = Vec2(to.x.toInt(), BlockModelElement.BLOCK_RESOLUTION - to.z.toInt())
|
||||||
}
|
}
|
||||||
Directions.NORTH, Directions.SOUTH -> {
|
Directions.NORTH, Directions.SOUTH -> {
|
||||||
textureStart = Vec2(from.x.toInt(), 16 - from.y.toInt());
|
textureStart = Vec2(from.x.toInt(), BlockModelElement.BLOCK_RESOLUTION - from.y.toInt())
|
||||||
textureEnd = Vec2(to.x.toInt(), 16 - to.y.toInt());
|
textureEnd = Vec2(to.x.toInt(), BlockModelElement.BLOCK_RESOLUTION - to.y.toInt())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
data["uv"]?.asJsonArray?.let {
|
data["uv"]?.asJsonArray?.let {
|
||||||
@ -66,7 +79,7 @@ class BlockModelFace(data: JsonObject, from: Vec3, to: Vec3, direction: Directio
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private fun uvToFloat(uv: Float): Float {
|
private fun uvToFloat(uv: Float): Float {
|
||||||
return (uv) / 16f
|
return (uv) / BlockModelElement.BLOCK_RESOLUTION
|
||||||
}
|
}
|
||||||
|
|
||||||
fun uvToFloat(vec2: Vec2): Vec2 {
|
fun uvToFloat(vec2: Vec2): Vec2 {
|
||||||
@ -74,12 +87,12 @@ class BlockModelFace(data: JsonObject, from: Vec3, to: Vec3, direction: Directio
|
|||||||
}
|
}
|
||||||
|
|
||||||
val textureTemplate = arrayOf(
|
val textureTemplate = arrayOf(
|
||||||
arrayOf(0, 1, 2, 3, ),
|
arrayOf(0, 1, 2, 3),
|
||||||
arrayOf(0, 1, 2, 3, ),
|
arrayOf(0, 1, 2, 3),
|
||||||
arrayOf(3, 2, 1, 0, ),
|
arrayOf(3, 2, 1, 0),
|
||||||
arrayOf(0, 1, 2, 3, ),
|
arrayOf(0, 1, 2, 3),
|
||||||
arrayOf(2, 3, 0, 1, ),
|
arrayOf(2, 3, 0, 1),
|
||||||
arrayOf(1, 0, 3, 2, ),
|
arrayOf(1, 0, 3, 2),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,16 @@
|
|||||||
|
/*
|
||||||
|
* Minosoft
|
||||||
|
* Copyright (C) 2021 Moritz Zwerger, Lukas Eisenhauer
|
||||||
|
*
|
||||||
|
* 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.chunk.models.renderable
|
package de.bixilon.minosoft.gui.rendering.chunk.models.renderable
|
||||||
|
|
||||||
import com.google.gson.JsonObject
|
import com.google.gson.JsonObject
|
||||||
@ -9,24 +22,26 @@ import de.bixilon.minosoft.gui.rendering.textures.Texture
|
|||||||
import glm_.mat4x4.Mat4
|
import glm_.mat4x4.Mat4
|
||||||
import glm_.vec3.Vec3
|
import glm_.vec3.Vec3
|
||||||
|
|
||||||
class BlockRenderer() {
|
class BlockRenderer {
|
||||||
|
private val transparentFaces: MutableSet<Directions> = mutableSetOf()
|
||||||
|
private val cullFaces: MutableSet<Directions> = mutableSetOf()
|
||||||
val textures: MutableMap<String, String> = mutableMapOf()
|
val textures: MutableMap<String, String> = mutableMapOf()
|
||||||
private val fullFaceDirections: MutableSet<Directions> = mutableSetOf()
|
private val fullFaceDirections: MutableSet<Directions> = mutableSetOf()
|
||||||
private val elements: MutableSet<ElementRenderer> = mutableSetOf()
|
private val elements: MutableSet<ElementRenderer> = mutableSetOf()
|
||||||
private val rotation: Vec3 = Vec3()
|
|
||||||
private val textureMapping: MutableMap<String, Texture> = mutableMapOf()
|
private val textureMapping: MutableMap<String, Texture> = mutableMapOf()
|
||||||
|
|
||||||
constructor(entry: JsonObject, mapping: VersionMapping) : this() {
|
constructor(entry: JsonObject, mapping: VersionMapping) {
|
||||||
loadElements(entry, mapping)
|
loadElements(entry, mapping)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadElements(entry: JsonObject, mapping: VersionMapping) {
|
private fun loadElements(entry: JsonObject, mapping: VersionMapping) {
|
||||||
this.elements.addAll(ElementRenderer.createElements(entry, mapping))
|
val newElements = ElementRenderer.createElements(entry, mapping)
|
||||||
|
this.elements.addAll(newElements)
|
||||||
val parent = mapping.blockModels[ModIdentifier(entry["model"].asString.replace("block/", ""))]
|
val parent = mapping.blockModels[ModIdentifier(entry["model"].asString.replace("block/", ""))]
|
||||||
textures.putAll(parent!!.textures)
|
textures.putAll(parent!!.textures)
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(models: List<JsonObject>, mapping: VersionMapping) : this() {
|
constructor(models: List<JsonObject>, mapping: VersionMapping) {
|
||||||
for (state in models) {
|
for (state in models) {
|
||||||
loadElements(state, mapping)
|
loadElements(state, mapping)
|
||||||
}
|
}
|
||||||
@ -49,35 +64,42 @@ class BlockRenderer() {
|
|||||||
textureMapping[key] = texture!!
|
textureMapping[key] = texture!!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (direction in Directions.DIRECTIONS) {
|
||||||
|
for (element in elements) {
|
||||||
|
if (element.isCullFace(direction)) {
|
||||||
|
cullFaces.add(direction)
|
||||||
|
}
|
||||||
|
if (textureMapping[element.getTexture(direction)]?.isTransparent == true) { // THIS IS BROKEN!
|
||||||
|
transparentFaces.add(direction)
|
||||||
|
}
|
||||||
|
if (element.isFullTowards(direction)) {
|
||||||
|
fullFaceDirections.add(direction)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun render(position: Vec3, data: MutableList<Float>, neighbourBlocks: Array<Block?>) {
|
fun render(position: Vec3, data: MutableList<Float>, neighbourBlocks: Array<Block?>) {
|
||||||
val modelMatrix = Mat4().translate(Vec3(position.x, position.y, position.z))
|
val modelMatrix = Mat4().translate(position)
|
||||||
.rotate(rotation.z, Vec3(0, 0, -1))
|
|
||||||
.rotate(rotation.y, Vec3(0, -1, 0))
|
|
||||||
.rotate(rotation.x, Vec3(1, 0, 0 ))
|
|
||||||
// ToDo: this should be made easier/more efficient
|
|
||||||
|
|
||||||
for (direction in Directions.DIRECTIONS) {
|
for (direction in Directions.DIRECTIONS) {
|
||||||
for (element in elements) {
|
for (element in elements) {
|
||||||
val blockFullFace = fullFaceDirections.contains(direction)
|
val cullFace = cullFaces.contains(direction)
|
||||||
|
|
||||||
var neighbourBlockFullFace = false
|
var neighbourBlockFullFace = false
|
||||||
neighbourBlocks[direction.ordinal]?.blockModels?.let { // ToDo: Improve this
|
neighbourBlocks[direction.ordinal]?.blockRenderers?.let { // ToDo: Improve this
|
||||||
|
val testDirection = direction.inverse()
|
||||||
for (model in it) {
|
for (model in it) {
|
||||||
if (model.fullFaceDirections.contains(direction.inverse())) {
|
if (model.fullFaceDirections.contains(testDirection) && ! model.transparentFaces.contains(testDirection)) {
|
||||||
neighbourBlockFullFace = true
|
neighbourBlockFullFace = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (blockFullFace && neighbourBlockFullFace) {
|
if (neighbourBlockFullFace && cullFace) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if (!blockFullFace && neighbourBlockFullFace) {
|
element.render(textureMapping, modelMatrix, direction, data)
|
||||||
continue
|
|
||||||
}
|
|
||||||
element.render(textureMapping, modelMatrix, direction, rotation, data)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* Minosoft
|
||||||
|
* Copyright (C) 2021 Moritz Zwerger, Lukas Eisenhauer
|
||||||
|
*
|
||||||
|
* 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.chunk.models.renderable
|
package de.bixilon.minosoft.gui.rendering.chunk.models.renderable
|
||||||
|
|
||||||
import com.google.gson.JsonObject
|
import com.google.gson.JsonObject
|
||||||
|
import de.bixilon.minosoft.data.Axes
|
||||||
import de.bixilon.minosoft.data.Directions
|
import de.bixilon.minosoft.data.Directions
|
||||||
import de.bixilon.minosoft.data.mappings.ModIdentifier
|
import de.bixilon.minosoft.data.mappings.ModIdentifier
|
||||||
import de.bixilon.minosoft.data.mappings.versions.VersionMapping
|
import de.bixilon.minosoft.data.mappings.versions.VersionMapping
|
||||||
@ -15,17 +29,25 @@ import glm_.vec3.Vec3
|
|||||||
import glm_.vec4.Vec4
|
import glm_.vec4.Vec4
|
||||||
|
|
||||||
class ElementRenderer(element: BlockModelElement, rotation: Vec3, uvlock: Boolean) {
|
class ElementRenderer(element: BlockModelElement, rotation: Vec3, uvlock: Boolean) {
|
||||||
|
private val fullFaceDirections: MutableSet<Directions> = mutableSetOf()
|
||||||
private val faces: MutableMap<Directions, BlockModelFace> = element.faces
|
private val faces: MutableMap<Directions, BlockModelFace> = element.faces
|
||||||
private var positions: Array<Vec3> = element.positions.clone()
|
private var positions: Array<Vec3> = element.positions.clone()
|
||||||
|
private val directionMapping: MutableMap<Directions, Directions> = mutableMapOf()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
BlockModelElement.rotatePositionsAxes(positions, rotation)
|
rotatePositionsAxes(positions, rotation)
|
||||||
// TODO : uvlock
|
// TODO : uvlock
|
||||||
|
for (direction in Directions.DIRECTIONS) {
|
||||||
|
if (positions.containsAllVectors(BlockModelElement.fullTestPositions[direction], 0.0001f)) { // TODO: check if texture is transparent ==> && ! texture.isTransparent
|
||||||
|
fullFaceDirections.add(direction)
|
||||||
|
}
|
||||||
|
directionMapping[direction] = getRotatedDirection(rotation, direction)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun render(textureMapping: MutableMap<String, Texture>, modelMatrix: Mat4, direction: Directions, rotation: Vec3, data: MutableList<Float>) {
|
fun render(textureMapping: MutableMap<String, Texture>, modelMatrix: Mat4, direction: Directions, data: MutableList<Float>) {
|
||||||
val realDirection = BlockModelElement.getRotatedDirection(rotation, direction)
|
val realDirection = directionMapping[direction]!! // BlockModelElement.getRotatedDirection(rotation, direction)
|
||||||
val positionTemplate = BlockModelElement.FACE_POSITION_MAP_TEMPLATE[realDirection.ordinal]
|
val positionTemplate = BlockModelElement.FACE_POSITION_MAP_TEMPLATE[realDirection.ordinal]
|
||||||
|
|
||||||
val face = faces[realDirection] ?: return // Not our face
|
val face = faces[realDirection] ?: return // Not our face
|
||||||
@ -53,19 +75,27 @@ class ElementRenderer(element: BlockModelElement, rotation: Vec3, uvlock: Boolea
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun createQuad(drawPositions: Array<Vec3>, texturePositions: Array<Vec2?>) {
|
fun createQuad(drawPositions: Array<Vec3>, texturePositions: Array<Vec2?>) {
|
||||||
addToData(drawPositions[0], texturePositions[1]!!)
|
for (vertex in drawOrder) {
|
||||||
addToData(drawPositions[3], texturePositions[2]!!)
|
addToData(drawPositions[vertex.first], texturePositions[vertex.second]!!)
|
||||||
addToData(drawPositions[2], texturePositions[3]!!)
|
}
|
||||||
addToData(drawPositions[2], texturePositions[3]!!)
|
|
||||||
addToData(drawPositions[1], texturePositions[0]!!)
|
|
||||||
addToData(drawPositions[0], texturePositions[1]!!)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
val texturePositions = face.getTexturePositionArray(realDirection)
|
val texturePositions = face.getTexturePositionArray(realDirection)
|
||||||
createQuad(drawPositions, texturePositions)
|
createQuad(drawPositions, texturePositions)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getTexture(direction: Directions): String? {
|
||||||
|
return faces[direction]?.textureName
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isCullFace(direction: Directions): Boolean {
|
||||||
|
return faces[direction]?.cullFace == direction
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isFullTowards(direction: Directions): Boolean {
|
||||||
|
return fullFaceDirections.contains(direction)
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun createElements(state: JsonObject, mapping: VersionMapping): MutableList<ElementRenderer> {
|
fun createElements(state: JsonObject, mapping: VersionMapping): MutableList<ElementRenderer> {
|
||||||
val rotation = glm.radians(vec3InJsonObject(state))
|
val rotation = glm.radians(vec3InJsonObject(state))
|
||||||
@ -81,5 +111,47 @@ class ElementRenderer(element: BlockModelElement, rotation: Vec3, uvlock: Boolea
|
|||||||
private fun vec3InJsonObject(json: JsonObject): Vec3 {
|
private fun vec3InJsonObject(json: JsonObject): Vec3 {
|
||||||
return Vec3(json["x"]?.asFloat?: 0, json["y"]?.asFloat?: 0, json["z"]?.asFloat?: 0)
|
return Vec3(json["x"]?.asFloat?: 0, json["y"]?.asFloat?: 0, json["z"]?.asFloat?: 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val drawOrder = arrayOf(
|
||||||
|
Pair(0, 1),
|
||||||
|
Pair(3, 2),
|
||||||
|
Pair(2, 3),
|
||||||
|
Pair(2, 3),
|
||||||
|
Pair(1, 0),
|
||||||
|
Pair(0, 1),
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun Array<Vec3>.containsAllVectors(set: Set<Vec3>?, margin: Float): Boolean {
|
||||||
|
for (position in set!!) {
|
||||||
|
var isIn = false
|
||||||
|
for (testposition in this) {
|
||||||
|
if ((position - testposition).length() < margin) {
|
||||||
|
isIn = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (! isIn) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getRotatedDirection(rotation: Vec3, direction: Directions): Directions {
|
||||||
|
if (rotation == Vec3(0, 0, 0)) {
|
||||||
|
return direction
|
||||||
|
}
|
||||||
|
var rotatedDirectionVector = BlockModelElement.rotateVector(direction.directionVector, rotation.z.toDouble(), Axes.Z)
|
||||||
|
rotatedDirectionVector = BlockModelElement.rotateVector(rotatedDirectionVector, rotation.y.toDouble(), Axes.Y)
|
||||||
|
return Directions.byDirection(BlockModelElement.rotateVector(rotatedDirectionVector, rotation.x.toDouble(), Axes.X))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun rotatePositionsAxes(positions: Array<Vec3>, angles: Vec3) {
|
||||||
|
if (angles == Vec3()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
BlockModelElement.rotatePositions(positions, Axes.X, angles.x.toDouble(), Vec3())
|
||||||
|
BlockModelElement.rotatePositions(positions, Axes.Y, angles.y.toDouble(), Vec3())
|
||||||
|
BlockModelElement.rotatePositions(positions, Axes.Z, angles.z.toDouble(), Vec3())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user