rendering: performance and cde quality improvements

This commit is contained in:
Lukas 2021-02-20 20:21:37 +01:00
parent 74e5482096
commit 5312e0d436
9 changed files with 260 additions and 204 deletions

View File

@ -1,6 +1,6 @@
/*
* 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.
*
@ -15,7 +15,6 @@ package de.bixilon.minosoft.data.mappings.blocks
import de.bixilon.minosoft.Minosoft
import de.bixilon.minosoft.data.mappings.ModIdentifier
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 java.util.*
import kotlin.random.Random
@ -23,7 +22,6 @@ import kotlin.random.Random
data class Block(val identifier: ModIdentifier) {
var rotation: BlockRotations = BlockRotations.NONE
var properties: Set<BlockProperties> = setOf()
val blockModels: MutableList<BlockModel> = mutableListOf()
val blockRenderers: MutableList<BlockRenderer> = mutableListOf()
constructor(identifier: ModIdentifier, properties: Set<BlockProperties>, rotation: BlockRotations) : this(identifier) {

View File

@ -56,7 +56,7 @@ class VersionMapping(var version: Version?) {
private val dimensionIdMap = HashBiMap.create<Int, Dimension>()
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 entityMetaIndexMap = HashMap<EntityMetaDataFields, Int>(180)

View File

@ -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);
}
}

View File

@ -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
}
}
}
}

View File

@ -14,17 +14,13 @@
package de.bixilon.minosoft.gui.rendering.chunk.models.loading
import com.google.gson.JsonObject
import de.bixilon.minosoft.data.Directions
import de.bixilon.minosoft.gui.rendering.textures.Texture
import glm_.glm
import glm_.vec3.Vec3
open class BlockModel(val parent: BlockModel? = null, json: JsonObject) {
val textures: MutableMap<String, String> = parent?.textures?.toMutableMap() ?: mutableMapOf()
private val textureMapping: MutableMap<String, Texture> = mutableMapOf()
var elements: MutableList<BlockModelElement> = parent?.elements?.toMutableList() ?: mutableListOf()
val fullFaceDirections: MutableSet<Directions> = parent?.fullFaceDirections?.toMutableSet() ?: mutableSetOf()
private var rotation: Vec3
var rotation: Vec3
private var uvLock = false // ToDo
private var rescale = false // ToDo
@ -41,11 +37,9 @@ open class BlockModel(val parent: BlockModel? = null, json: JsonObject) {
}
json["elements"]?.let { it ->
elements.clear()
fullFaceDirections.clear()
for (element in it.asJsonArray) {
val blockModelElement = BlockModelElement(element.asJsonObject)
elements.add(blockModelElement)
fullFaceDirections.addAll(blockModelElement.fullFaceDirections)
}
}
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))
}
private fun getTextureByType(type: String): String {
var currentValue: String = type
while (currentValue.startsWith("#")) {
@ -82,23 +75,4 @@ open class BlockModel(val parent: BlockModel? = null, json: JsonObject) {
}
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
}
}

View File

@ -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
import com.google.gson.JsonArray
@ -9,13 +22,11 @@ import glm_.vec3.Vec3
open class BlockModelElement(data: JsonObject) {
val faces: MutableMap<Directions, BlockModelFace> = mutableMapOf()
val fullFaceDirections: MutableSet<Directions> = mutableSetOf()
var fullFace = false
var positions: Array<Vec3>
init {
var from = Vec3(0, 0, 0)
var to = Vec3(16, 16, 16)
var to = Vec3(BLOCK_RESOLUTION, BLOCK_RESOLUTION, BLOCK_RESOLUTION)
data["from"]?.let {
val array = it.asJsonArray
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(to),
)
var rotate = Vec3()
data["rotation"]?.let {
val rotation = it.asJsonObject
val axis = Axes.valueOf(rotation["axis"].asString.toUpperCase())
val angle = glm.radians(rotation["angle"].asDouble)
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 {
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)
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()) {
@ -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 {
fun jsonArrayToVec3(array: JsonArray) : Vec3 {
fun jsonArrayToVec3(array: JsonArray): Vec3 {
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(
intArrayOf(0, 2, 3, 1),
@ -85,50 +77,40 @@ open class BlockModelElement(data: JsonObject) {
intArrayOf(5, 1, 3, 7)
)
private val POSITION_1 = Vec3(0, 0, 0)
private val POSITION_2 = Vec3(BLOCK_RESOLUTION, 0, 0)
private val POSITION_3 = Vec3(0, 0, BLOCK_RESOLUTION)
private val POSITION_4 = Vec3(BLOCK_RESOLUTION, 0, BLOCK_RESOLUTION)
private val POSITION_5 = Vec3(0, BLOCK_RESOLUTION, 0)
private val POSITION_6 = Vec3(BLOCK_RESOLUTION, BLOCK_RESOLUTION, 0)
private val POSITION_7 = Vec3(0, BLOCK_RESOLUTION, BLOCK_RESOLUTION)
private val POSITION_8 = Vec3(BLOCK_RESOLUTION, BLOCK_RESOLUTION, BLOCK_RESOLUTION)
private val POSITION_1 = Vec3(-0.5f, -0.5f, -0.5f) // Vec3(0, 0, 0)
private val POSITION_2 = Vec3(+0.5f, -0.5f, -0.5f) // Vec3(BLOCK_RESOLUTION, 0, 0)
private val POSITION_3 = Vec3(-0.5f, -0.5f, +0.5f) // Vec3(0, 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_6 = Vec3(+0.5f, +0.5f, +0.5f) // 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_8 = Vec3(+0.5f, +0.5f, +0.5f) // Vec3(BLOCK_RESOLUTION, BLOCK_RESOLUTION, BLOCK_RESOLUTION)
val fullTestPositions = mapOf(
Pair(Directions.EAST, setOf(POSITION_1, POSITION_3, POSITION_5, POSITION_7)),
Pair(Directions.WEST, setOf(POSITION_2, POSITION_4, POSITION_6, POSITION_8)),
Pair(Directions.DOWN, setOf(POSITION_1, POSITION_2, POSITION_3, POSITION_4)),
Pair(Directions.UP, setOf(POSITION_5, POSITION_6, POSITION_7, POSITION_8)),
Pair(Directions.SOUTH, setOf(POSITION_1, POSITION_2, POSITION_5, POSITION_6)),
Pair(Directions.NORTH, setOf(POSITION_3, POSITION_4, POSITION_7, POSITION_8)),
Directions.EAST to setOf(POSITION_1, POSITION_3, POSITION_5, POSITION_7),
Directions.WEST to setOf(POSITION_2, POSITION_4, POSITION_6, POSITION_8),
Directions.DOWN to setOf(POSITION_1, POSITION_2, POSITION_3, POSITION_4),
Directions.UP to setOf(POSITION_5, POSITION_6, POSITION_7, POSITION_8),
Directions.SOUTH to setOf(POSITION_1, POSITION_2, POSITION_5, POSITION_6),
Directions.NORTH to setOf(POSITION_3, POSITION_4, POSITION_7, POSITION_8),
)
fun getRotatedDirection(rotation: Vec3, direction: Directions): Directions {
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 rotateVector(original: Vec3, angle: Double, axis: Axes): Vec3 {
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 when (axis) {
Axes.X -> run {
Axes.X -> {
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))
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))
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 positionToFloat(uv: Float): Float {
return (uv - 8f) / 16f
return (uv - 8f) / BLOCK_RESOLUTION
}
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
}

View File

@ -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
import com.google.gson.JsonObject
@ -16,16 +29,16 @@ class BlockModelFace(data: JsonObject, from: Vec3, to: Vec3, direction: Directio
var textureEnd = Vec2(16, 16)
when (direction) {
Directions.EAST, Directions.WEST -> run {
textureStart = Vec2(from.z.toInt(), 16 - from.y.toInt());
textureEnd = Vec2(to.z.toInt(), 16 - to.y.toInt());
textureStart = Vec2(from.z.toInt(), BlockModelElement.BLOCK_RESOLUTION - from.y.toInt())
textureEnd = Vec2(to.z.toInt(), BlockModelElement.BLOCK_RESOLUTION - to.y.toInt())
}
Directions.UP, Directions.DOWN -> {
textureStart = Vec2(from.x.toInt(), 16 - from.z.toInt());
textureEnd = Vec2(to.x.toInt(), 16 - to.z.toInt());
textureStart = Vec2(from.x.toInt(), BlockModelElement.BLOCK_RESOLUTION - from.z.toInt())
textureEnd = Vec2(to.x.toInt(), BlockModelElement.BLOCK_RESOLUTION - to.z.toInt())
}
Directions.NORTH, Directions.SOUTH -> {
textureStart = Vec2(from.x.toInt(), 16 - from.y.toInt());
textureEnd = Vec2(to.x.toInt(), 16 - to.y.toInt());
textureStart = Vec2(from.x.toInt(), BlockModelElement.BLOCK_RESOLUTION - from.y.toInt())
textureEnd = Vec2(to.x.toInt(), BlockModelElement.BLOCK_RESOLUTION - to.y.toInt())
}
}
data["uv"]?.asJsonArray?.let {
@ -66,7 +79,7 @@ class BlockModelFace(data: JsonObject, from: Vec3, to: Vec3, direction: Directio
companion object {
private fun uvToFloat(uv: Float): Float {
return (uv) / 16f
return (uv) / BlockModelElement.BLOCK_RESOLUTION
}
fun uvToFloat(vec2: Vec2): Vec2 {
@ -74,12 +87,12 @@ class BlockModelFace(data: JsonObject, from: Vec3, to: Vec3, direction: Directio
}
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, ),
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),
)
}
}

View File

@ -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
import com.google.gson.JsonObject
@ -9,24 +22,26 @@ import de.bixilon.minosoft.gui.rendering.textures.Texture
import glm_.mat4x4.Mat4
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()
private val fullFaceDirections: MutableSet<Directions> = mutableSetOf()
private val elements: MutableSet<ElementRenderer> = mutableSetOf()
private val rotation: Vec3 = Vec3()
private val textureMapping: MutableMap<String, Texture> = mutableMapOf()
constructor(entry: JsonObject, mapping: VersionMapping) : this() {
constructor(entry: JsonObject, mapping: VersionMapping) {
loadElements(entry, mapping)
}
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/", ""))]
textures.putAll(parent!!.textures)
}
constructor(models: List<JsonObject>, mapping: VersionMapping) : this() {
constructor(models: List<JsonObject>, mapping: VersionMapping) {
for (state in models) {
loadElements(state, mapping)
}
@ -49,35 +64,42 @@ class BlockRenderer() {
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?>) {
val modelMatrix = Mat4().translate(Vec3(position.x, position.y, position.z))
.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
val modelMatrix = Mat4().translate(position)
for (direction in Directions.DIRECTIONS) {
for (element in elements) {
val blockFullFace = fullFaceDirections.contains(direction)
val cullFace = cullFaces.contains(direction)
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) {
if (model.fullFaceDirections.contains(direction.inverse())) {
if (model.fullFaceDirections.contains(testDirection) && ! model.transparentFaces.contains(testDirection)) {
neighbourBlockFullFace = true
break
}
}
}
if (blockFullFace && neighbourBlockFullFace) {
if (neighbourBlockFullFace && cullFace) {
continue
}
if (!blockFullFace && neighbourBlockFullFace) {
continue
}
element.render(textureMapping, modelMatrix, direction, rotation, data)
element.render(textureMapping, modelMatrix, direction, data)
}
}
}

View File

@ -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
import com.google.gson.JsonObject
import de.bixilon.minosoft.data.Axes
import de.bixilon.minosoft.data.Directions
import de.bixilon.minosoft.data.mappings.ModIdentifier
import de.bixilon.minosoft.data.mappings.versions.VersionMapping
@ -15,17 +29,25 @@ import glm_.vec3.Vec3
import glm_.vec4.Vec4
class ElementRenderer(element: BlockModelElement, rotation: Vec3, uvlock: Boolean) {
private val fullFaceDirections: MutableSet<Directions> = mutableSetOf()
private val faces: MutableMap<Directions, BlockModelFace> = element.faces
private var positions: Array<Vec3> = element.positions.clone()
private val directionMapping: MutableMap<Directions, Directions> = mutableMapOf()
init {
BlockModelElement.rotatePositionsAxes(positions, rotation)
rotatePositionsAxes(positions, rotation)
// 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>) {
val realDirection = BlockModelElement.getRotatedDirection(rotation, direction)
fun render(textureMapping: MutableMap<String, Texture>, modelMatrix: Mat4, direction: Directions, data: MutableList<Float>) {
val realDirection = directionMapping[direction]!! // BlockModelElement.getRotatedDirection(rotation, direction)
val positionTemplate = BlockModelElement.FACE_POSITION_MAP_TEMPLATE[realDirection.ordinal]
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?>) {
addToData(drawPositions[0], texturePositions[1]!!)
addToData(drawPositions[3], texturePositions[2]!!)
addToData(drawPositions[2], texturePositions[3]!!)
addToData(drawPositions[2], texturePositions[3]!!)
addToData(drawPositions[1], texturePositions[0]!!)
addToData(drawPositions[0], texturePositions[1]!!)
for (vertex in drawOrder) {
addToData(drawPositions[vertex.first], texturePositions[vertex.second]!!)
}
}
val texturePositions = face.getTexturePositionArray(realDirection)
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 {
fun createElements(state: JsonObject, mapping: VersionMapping): MutableList<ElementRenderer> {
val rotation = glm.radians(vec3InJsonObject(state))
@ -81,5 +111,47 @@ class ElementRenderer(element: BlockModelElement, rotation: Vec3, uvlock: Boolea
private fun vec3InJsonObject(json: JsonObject): Vec3 {
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())
}
}
}