mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-14 09:56:37 -04:00
rendering: add support for liquids
This commit is contained in:
parent
aea488e7ab
commit
7bfc18ebdb
@ -31,6 +31,14 @@ enum class Directions(direction: Vec3) {
|
||||
}
|
||||
}
|
||||
|
||||
fun sidesNextTo(direction: Directions): Set<Directions> {
|
||||
return when (direction) {
|
||||
NORTH, SOUTH -> setOf(EAST, WEST)
|
||||
EAST, WEST -> setOf(NORTH, SOUTH)
|
||||
else -> emptySet()
|
||||
}
|
||||
}
|
||||
|
||||
val directionVector: Vec3 = direction
|
||||
|
||||
companion object {
|
||||
|
@ -22,7 +22,9 @@ import de.bixilon.minosoft.data.text.RGBColor
|
||||
import de.bixilon.minosoft.data.world.BlockPosition
|
||||
import de.bixilon.minosoft.gui.rendering.TintColorCalculator
|
||||
import de.bixilon.minosoft.gui.rendering.chunk.models.loading.BlockModel
|
||||
import de.bixilon.minosoft.gui.rendering.chunk.models.renderable.BlockRenderInterface
|
||||
import de.bixilon.minosoft.gui.rendering.chunk.models.renderable.BlockRenderer
|
||||
import de.bixilon.minosoft.gui.rendering.chunk.models.renderable.FluidRenderer
|
||||
import java.util.*
|
||||
import kotlin.random.Random
|
||||
|
||||
@ -30,7 +32,7 @@ data class BlockState(
|
||||
val owner: Block,
|
||||
val properties: Set<BlockProperties> = setOf(),
|
||||
val rotation: BlockRotations = BlockRotations.NONE,
|
||||
val renders: Set<BlockRenderer> = setOf(),
|
||||
val renders: Set<BlockRenderInterface> = setOf(),
|
||||
val tintColor: RGBColor? = null,
|
||||
) {
|
||||
|
||||
@ -104,7 +106,7 @@ data class BlockState(
|
||||
return String.format("%s%s", owner.resourceLocation, out)
|
||||
}
|
||||
|
||||
fun getBlockRenderer(position: BlockPosition): BlockRenderer {
|
||||
fun getBlockRenderer(position: BlockPosition): BlockRenderInterface {
|
||||
if (Minosoft.getConfig().config.game.other.antiMoirePattern) {
|
||||
// ToDo: Support weight attribute
|
||||
return renders.random(Random(position.hashCode()))
|
||||
@ -116,11 +118,16 @@ data class BlockState(
|
||||
companion object {
|
||||
val ROTATION_PROPERTIES = setOf("facing", "rotation", "orientation", "axis")
|
||||
|
||||
val SPECIAL_RENDERERS = mutableMapOf(
|
||||
Pair("water", FluidRenderer("block/water_still", "block/water_flow", "water")),
|
||||
Pair("lava", FluidRenderer("block/lava_still", "block/lava_flow", "lava")),
|
||||
)
|
||||
|
||||
fun deserialize(owner: Block, data: JsonObject, models: HashBiMap<ResourceLocation, BlockModel>): BlockState {
|
||||
val (rotation, properties) = data["properties"]?.asJsonObject?.let {
|
||||
getProperties(it)
|
||||
} ?: Pair(BlockRotations.NONE, mutableSetOf())
|
||||
val renders: MutableSet<BlockRenderer> = mutableSetOf()
|
||||
val renders: MutableSet<BlockRenderInterface> = mutableSetOf()
|
||||
|
||||
data["render"]?.let {
|
||||
when (it) {
|
||||
@ -149,6 +156,13 @@ data class BlockState(
|
||||
|
||||
val tintColor: RGBColor? = data["tint_color"]?.asInt?.let { TintColorCalculator.getJsonColor(it) } ?: owner.tintColor
|
||||
|
||||
for ((regex, renderer) in SPECIAL_RENDERERS) {
|
||||
if (owner.resourceLocation.full.contains(regex)) {
|
||||
renders.clear()
|
||||
renders.add(renderer)
|
||||
}
|
||||
}
|
||||
|
||||
return BlockState(
|
||||
owner = owner,
|
||||
properties = properties.toSet(),
|
||||
@ -192,7 +206,7 @@ data class BlockState(
|
||||
return Pair(rotation, properties)
|
||||
}
|
||||
|
||||
private fun addBlockModel(data: JsonObject, renders: MutableSet<BlockRenderer>, models: HashBiMap<ResourceLocation, BlockModel>) {
|
||||
private fun addBlockModel(data: JsonObject, renders: MutableSet<BlockRenderInterface>, models: HashBiMap<ResourceLocation, BlockModel>) {
|
||||
val model = models[ResourceLocation(data["model"].asString)] ?: error("Can not find block model ${data["model"]}")
|
||||
renders.add(BlockRenderer(data, model))
|
||||
}
|
||||
|
@ -154,7 +154,6 @@ class VersionMapping(var version: Version?) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun loadBlockModels(data: Map<ResourceLocation, JsonObject>) {
|
||||
for ((resourceLocation, model) in data) {
|
||||
if (models.containsKey(resourceLocation)) {
|
||||
|
@ -87,7 +87,7 @@ class WorldRenderer(
|
||||
blockInfo.block.tintColor?.let { tintColor = it }
|
||||
}
|
||||
|
||||
blockInfo.block.getBlockRenderer(blockPosition).render(blockInfo, world.worldLightAccessor, tintColor, blockPosition, mesh, neighborBlocks)
|
||||
blockInfo.block.getBlockRenderer(blockPosition).render(blockInfo, world.worldLightAccessor, tintColor, blockPosition, mesh, neighborBlocks, world)
|
||||
}
|
||||
}
|
||||
return mesh
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
package de.bixilon.minosoft.gui.rendering.chunk.models.loading
|
||||
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonObject
|
||||
import de.bixilon.minosoft.data.Directions
|
||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil
|
||||
@ -22,7 +23,7 @@ import glm_.vec3.Vec3
|
||||
import java.util.*
|
||||
|
||||
class BlockModelFace {
|
||||
val textureName: String
|
||||
val textureName: String?
|
||||
val cullFace: Directions?
|
||||
val tint: Boolean
|
||||
private val positions: MutableList<Vec2>
|
||||
@ -30,26 +31,6 @@ class BlockModelFace {
|
||||
constructor(data: JsonObject, from: Vec3, to: Vec3, direction: Directions) {
|
||||
tint = data.has("tintindex")
|
||||
textureName = data.get("texture").asString.removePrefix("#")
|
||||
var textureTopLeft = Vec2(0, 16)
|
||||
var textureBottomRight = Vec2(16, 0)
|
||||
when (direction) {
|
||||
Directions.EAST, Directions.WEST -> run {
|
||||
textureTopLeft = Vec2(from.z.toInt(), to.y.toInt())
|
||||
textureBottomRight = Vec2(to.z.toInt(), from.y.toInt())
|
||||
}
|
||||
Directions.UP, Directions.DOWN -> {
|
||||
textureTopLeft = Vec2(from.x.toInt(), to.z.toInt())
|
||||
textureBottomRight = Vec2(to.x.toInt(), from.z.toInt())
|
||||
}
|
||||
Directions.NORTH, Directions.SOUTH -> {
|
||||
textureTopLeft = Vec2(from.x.toInt(), to.y.toInt())
|
||||
textureBottomRight = Vec2(to.x.toInt(), from.y.toInt())
|
||||
}
|
||||
}
|
||||
data["uv"]?.asJsonArray?.let {
|
||||
textureTopLeft = Vec2(it[0].asFloat, it[3].asFloat)
|
||||
textureBottomRight = Vec2(it[2].asFloat, it[1].asFloat)
|
||||
}
|
||||
cullFace = data["cullface"]?.asString?.let {
|
||||
return@let if (it == "bottom") {
|
||||
Directions.DOWN
|
||||
@ -57,14 +38,33 @@ class BlockModelFace {
|
||||
Directions.valueOf(it.toUpperCase())
|
||||
}
|
||||
}
|
||||
positions = mutableListOf(
|
||||
positions = calculateTexturePositions(data, from, to, direction)
|
||||
val rotation = data["rotation"]?.asInt?.div(90) ?: 0
|
||||
Collections.rotate(positions, rotation)
|
||||
}
|
||||
|
||||
private fun calculateTexturePositions(data: JsonObject?, from: Vec3, to: Vec3, direction: Directions): MutableList<Vec2> {
|
||||
val (textureTopLeft: Vec2, textureBottomRight: Vec2) = data?.get("uv")?.asJsonArray?.let {
|
||||
readUV(it)
|
||||
} ?: getTexturePositionsFromRegion(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)),
|
||||
)
|
||||
val rotation = data["rotation"]?.asInt?.div(90) ?: 0
|
||||
Collections.rotate(positions, rotation)
|
||||
}
|
||||
|
||||
private fun readUV(data: JsonArray): Pair<Vec2, Vec2> {
|
||||
return Pair(Vec2(data[0].asFloat, data[3].asFloat), Vec2(data[2].asFloat, data[1].asFloat))
|
||||
}
|
||||
|
||||
private fun getTexturePositionsFromRegion(from: Vec3, to: Vec3, direction: Directions): Pair<Vec2, Vec2> {
|
||||
return when (direction) {
|
||||
Directions.EAST, Directions.WEST -> Pair(Vec2(from.z.toInt(), to.y.toInt()), Vec2(to.z.toInt(), from.y.toInt()))
|
||||
Directions.UP, Directions.DOWN -> Pair(Vec2(from.x.toInt(), to.z.toInt()), Vec2(to.x.toInt(), from.z.toInt()))
|
||||
Directions.NORTH, Directions.SOUTH -> Pair(Vec2(from.x.toInt(), to.y.toInt()), Vec2(to.x.toInt(), from.y.toInt()))
|
||||
}
|
||||
}
|
||||
|
||||
constructor(parent: BlockModelFace) {
|
||||
@ -77,6 +77,20 @@ class BlockModelFace {
|
||||
}
|
||||
}
|
||||
|
||||
constructor() {
|
||||
textureName = null
|
||||
cullFace = null
|
||||
tint = false
|
||||
positions = calculateTexturePositions(null, VecUtil.EMPTY_VECTOR, VecUtil.BLOCK_SIZE_VECTOR, Directions.EAST)
|
||||
}
|
||||
|
||||
constructor(from: Vec3, to: Vec3, direction: Directions) {
|
||||
textureName = null
|
||||
cullFace = null
|
||||
tint = false
|
||||
positions = calculateTexturePositions(null, from, to, direction)
|
||||
}
|
||||
|
||||
fun getTexturePositionArray(direction: Directions): Array<Vec2?> {
|
||||
val template = textureTemplate[direction.ordinal]
|
||||
val result = arrayOfNulls<Vec2>(template.size)
|
||||
|
@ -0,0 +1,37 @@
|
||||
package de.bixilon.minosoft.gui.rendering.chunk.models.renderable
|
||||
|
||||
import de.bixilon.minosoft.data.Directions
|
||||
import de.bixilon.minosoft.data.text.RGBColor
|
||||
import de.bixilon.minosoft.data.world.BlockInfo
|
||||
import de.bixilon.minosoft.data.world.BlockPosition
|
||||
import de.bixilon.minosoft.data.world.World
|
||||
import de.bixilon.minosoft.data.world.light.LightAccessor
|
||||
import de.bixilon.minosoft.gui.rendering.chunk.SectionArrayMesh
|
||||
import de.bixilon.minosoft.gui.rendering.textures.Texture
|
||||
|
||||
interface BlockRenderInterface {
|
||||
val fullFaceDirections: MutableSet<Directions>
|
||||
val transparentFaces: MutableSet<Directions>
|
||||
|
||||
fun render(blockInfo: BlockInfo, lightAccessor: LightAccessor, tintColor: RGBColor?, position: BlockPosition, mesh: SectionArrayMesh, neighbourBlocks: Array<BlockInfo?>, world: World)
|
||||
|
||||
fun resolveTextures(indexed: MutableList<Texture>, textureMap: MutableMap<String, Texture>)
|
||||
|
||||
fun postInit() {}
|
||||
|
||||
companion object {
|
||||
fun resolveTexture(indexed: MutableList<Texture>, textureMap: MutableMap<String, Texture>, textureName: String): Texture? {
|
||||
var texture: Texture? = null
|
||||
val index: Int? = textureMap[textureName]?.let {
|
||||
texture = it
|
||||
indexed.indexOf(it)
|
||||
}
|
||||
if (index == null) {
|
||||
texture = Texture(Texture.getResourceTextureIdentifier(textureName = textureName))
|
||||
textureMap[textureName] = texture!!
|
||||
indexed.add(texture!!)
|
||||
}
|
||||
return texture
|
||||
}
|
||||
}
|
||||
}
|
@ -20,6 +20,7 @@ import de.bixilon.minosoft.data.mappings.ResourceLocation
|
||||
import de.bixilon.minosoft.data.text.RGBColor
|
||||
import de.bixilon.minosoft.data.world.BlockInfo
|
||||
import de.bixilon.minosoft.data.world.BlockPosition
|
||||
import de.bixilon.minosoft.data.world.World
|
||||
import de.bixilon.minosoft.data.world.light.LightAccessor
|
||||
import de.bixilon.minosoft.gui.rendering.chunk.SectionArrayMesh
|
||||
import de.bixilon.minosoft.gui.rendering.chunk.models.loading.BlockModel
|
||||
@ -27,13 +28,13 @@ import de.bixilon.minosoft.gui.rendering.textures.Texture
|
||||
import de.bixilon.minosoft.gui.rendering.textures.TextureTransparencies
|
||||
import glm_.mat4x4.Mat4
|
||||
|
||||
class BlockRenderer {
|
||||
private val transparentFaces: MutableSet<Directions> = mutableSetOf()
|
||||
class BlockRenderer: BlockRenderInterface {
|
||||
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 textureMapping: MutableMap<String, Texture> = mutableMapOf()
|
||||
override val fullFaceDirections: MutableSet<Directions> = mutableSetOf()
|
||||
override val transparentFaces: MutableSet<Directions> = mutableSetOf()
|
||||
|
||||
constructor(data: JsonObject, parent: BlockModel) {
|
||||
val newElements = ElementRenderer.createElements(data, parent)
|
||||
@ -51,26 +52,15 @@ class BlockRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun resolveTextures(indexed: MutableList<Texture>, textureMap: MutableMap<String, Texture>) {
|
||||
override fun resolveTextures(indexed: MutableList<Texture>, textureMap: MutableMap<String, Texture>) {
|
||||
for ((key, textureName) in textures) {
|
||||
if (!textureName.startsWith("#")) {
|
||||
var texture: Texture? = null
|
||||
val index: Int? = textureMap[textureName]?.let {
|
||||
texture = it
|
||||
indexed.indexOf(it)
|
||||
}
|
||||
if (index == null) {
|
||||
texture = Texture(Texture.getResourceTextureIdentifier(textureName = textureName))
|
||||
textureMap[textureName] = texture!!
|
||||
indexed.add(texture!!)
|
||||
}
|
||||
textureMapping[key] = texture!!
|
||||
textureMapping[key] = BlockRenderInterface.resolveTexture(indexed, textureMap, textureName = textureName)!!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun postInit() {
|
||||
override fun postInit() {
|
||||
for (direction in Directions.DIRECTIONS) {
|
||||
var directionIsCullface: Boolean? = null
|
||||
var directionIsNotTransparent: Boolean? = null
|
||||
@ -103,7 +93,7 @@ class BlockRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
fun render(blockInfo: BlockInfo, lightAccessor: LightAccessor, tintColor: RGBColor?, position: BlockPosition, mesh: SectionArrayMesh, neighbourBlocks: Array<BlockInfo?>) {
|
||||
override fun render(blockInfo: BlockInfo, lightAccessor: LightAccessor, tintColor: RGBColor?, position: BlockPosition, mesh: SectionArrayMesh, neighbourBlocks: Array<BlockInfo?>, world: World) {
|
||||
val modelMatrix = Mat4().translate(position.toVec3())
|
||||
|
||||
for (direction in Directions.DIRECTIONS) {
|
||||
|
@ -17,6 +17,8 @@ import com.google.common.collect.HashBiMap
|
||||
import com.google.gson.JsonObject
|
||||
import de.bixilon.minosoft.data.Axes
|
||||
import de.bixilon.minosoft.data.Directions
|
||||
import de.bixilon.minosoft.data.mappings.ResourceLocation
|
||||
import de.bixilon.minosoft.data.mappings.versions.VersionMapping
|
||||
import de.bixilon.minosoft.data.text.RGBColor
|
||||
import de.bixilon.minosoft.data.world.BlockPosition
|
||||
import de.bixilon.minosoft.data.world.light.LightAccessor
|
||||
@ -67,7 +69,6 @@ class ElementRenderer(parent: BlockModelElement, val rotation: Vec3, uvLock: Boo
|
||||
val realDirection = directionMapping.inverse()[direction]!!
|
||||
|
||||
val face = faces[realDirection] ?: return // Not our face
|
||||
|
||||
val positionTemplate = BlockModelElement.FACE_POSITION_MAP_TEMPLATE[realDirection.ordinal]
|
||||
|
||||
val texture = textureMapping[face.textureName] ?: TODO()
|
||||
@ -110,8 +111,6 @@ class ElementRenderer(parent: BlockModelElement, val rotation: Vec3, uvLock: Boo
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val EMPTY_VECTOR = Vec3()
|
||||
|
||||
val DRAW_ODER = arrayOf(
|
||||
Pair(0, 1),
|
||||
Pair(3, 2),
|
||||
@ -151,7 +150,7 @@ class ElementRenderer(parent: BlockModelElement, val rotation: Vec3, uvLock: Boo
|
||||
}
|
||||
|
||||
fun getRotatedDirection(rotation: Vec3, direction: Directions): Directions {
|
||||
if (rotation == EMPTY_VECTOR) {
|
||||
if (rotation == VecUtil.EMPTY_VECTOR) {
|
||||
return direction
|
||||
}
|
||||
var rotatedDirectionVector = VecUtil.rotateVector(direction.directionVector, rotation.x, Axes.X)
|
||||
@ -160,18 +159,18 @@ class ElementRenderer(parent: BlockModelElement, val rotation: Vec3, uvLock: Boo
|
||||
}
|
||||
|
||||
fun rotatePositionsAxes(positions: Array<Vec3>, angles: Vec3, rescale: Boolean) {
|
||||
if (angles == EMPTY_VECTOR) {
|
||||
if (angles == VecUtil.EMPTY_VECTOR) {
|
||||
return
|
||||
}
|
||||
BlockModelElement.rotatePositions(positions, Axes.X, angles.x, EMPTY_VECTOR, rescale)
|
||||
BlockModelElement.rotatePositions(positions, Axes.Y, angles.y, EMPTY_VECTOR, rescale)
|
||||
BlockModelElement.rotatePositions(positions, Axes.Z, angles.z, EMPTY_VECTOR, rescale)
|
||||
BlockModelElement.rotatePositions(positions, Axes.X, angles.x, VecUtil.EMPTY_VECTOR, rescale)
|
||||
BlockModelElement.rotatePositions(positions, Axes.Y, angles.y, VecUtil.EMPTY_VECTOR, rescale)
|
||||
BlockModelElement.rotatePositions(positions, Axes.Z, angles.z, VecUtil.EMPTY_VECTOR, rescale)
|
||||
}
|
||||
|
||||
private val POSITION_1 = Vec3(-0.5f, -0.5f, -0.5f)
|
||||
private val POSITION_2 = Vec3(+0.5f, -0.5f, -0.5f)
|
||||
private val POSITION_3 = Vec3(-0.5f, -0.5f, +0.5f)
|
||||
private val POSITION_4 = Vec3(+0.5f, -0.5f, +0.5f)
|
||||
val POSITION_1 = Vec3(-0.5f, -0.5f, -0.5f)
|
||||
val POSITION_2 = Vec3(+0.5f, -0.5f, -0.5f)
|
||||
val POSITION_3 = Vec3(-0.5f, -0.5f, +0.5f)
|
||||
val POSITION_4 = Vec3(+0.5f, -0.5f, +0.5f)
|
||||
private val POSITION_5 = Vec3(-0.5f, +0.5f, -0.5f)
|
||||
private val POSITION_6 = Vec3(+0.5f, +0.5f, +0.5f)
|
||||
private val POSITION_7 = Vec3(-0.5f, +0.5f, +0.5f)
|
||||
|
@ -0,0 +1,220 @@
|
||||
package de.bixilon.minosoft.gui.rendering.chunk.models.renderable
|
||||
|
||||
import de.bixilon.minosoft.data.Directions
|
||||
import de.bixilon.minosoft.data.mappings.blocks.BlockProperties
|
||||
import de.bixilon.minosoft.data.text.RGBColor
|
||||
import de.bixilon.minosoft.data.world.BlockInfo
|
||||
import de.bixilon.minosoft.data.world.BlockPosition
|
||||
import de.bixilon.minosoft.data.world.World
|
||||
import de.bixilon.minosoft.data.world.light.LightAccessor
|
||||
import de.bixilon.minosoft.gui.rendering.chunk.SectionArrayMesh
|
||||
import de.bixilon.minosoft.gui.rendering.chunk.models.loading.BlockModelElement
|
||||
import de.bixilon.minosoft.gui.rendering.chunk.models.loading.BlockModelFace
|
||||
import de.bixilon.minosoft.gui.rendering.textures.Texture
|
||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil
|
||||
import glm_.glm
|
||||
import glm_.mat4x4.Mat4
|
||||
import glm_.toInt
|
||||
import glm_.vec2.Vec2
|
||||
import glm_.vec3.Vec3
|
||||
import glm_.vec4.Vec4
|
||||
|
||||
class FluidRenderer(private val stillTextureName: String, private val flowingTextureName: String, val regex: String): BlockRenderInterface {
|
||||
override val fullFaceDirections: MutableSet<Directions> = mutableSetOf()
|
||||
override val transparentFaces: MutableSet<Directions> = Directions.DIRECTIONS.toMutableSet()
|
||||
private var still: Texture? = null
|
||||
private var flowing: Texture? = null
|
||||
|
||||
override fun render(blockInfo: BlockInfo, lightAccessor: LightAccessor, tintColor: RGBColor?, position: BlockPosition, mesh: SectionArrayMesh, neighbourBlocks: Array<BlockInfo?>, world: World) {
|
||||
val modelMatrix = Mat4().translate(position.toVec3())
|
||||
val lightLevel = lightAccessor.getLightLevel(position)
|
||||
val heights = calculateHeights(neighbourBlocks, blockInfo, world, position)
|
||||
val (texture, angle) = if (isLiquidFlowing(heights)) {
|
||||
Pair(flowing, getRotationAngle(heights))
|
||||
} else {
|
||||
Pair(still, 0f)
|
||||
}
|
||||
val positions = calculatePositions(heights)
|
||||
for (direction in Directions.DIRECTIONS) {
|
||||
if (isBlockSameFluid(neighbourBlocks[direction.ordinal]) || neighbourBlocks[direction.ordinal]?.block?.getBlockRenderer(position + direction)?.fullFaceDirections?.contains(direction.inverse()) == true && direction != Directions.UP) {
|
||||
continue
|
||||
}
|
||||
val face = BlockModelFace(VecUtil.EMPTY_VECTOR, Vec3(VecUtil.BLOCK_SIZE_VECTOR.x, positions[7].y * 8, VecUtil.BLOCK_SIZE_VECTOR.z), direction)
|
||||
face.rotate(angle)
|
||||
val positionTemplate = BlockModelElement.FACE_POSITION_MAP_TEMPLATE[direction.ordinal]
|
||||
val drawPositions = arrayOf(positions[positionTemplate[0]], positions[positionTemplate[1]], positions[positionTemplate[2]], positions[positionTemplate[3]])
|
||||
createQuad(drawPositions, face.getTexturePositionArray(direction), texture!!, modelMatrix, mesh, tintColor, lightLevel)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getRotationAngle(heights: FloatArray): Float {
|
||||
val maxHeight = heights.maxOrNull()
|
||||
for (direction in Directions.SIDES) {
|
||||
val positions = getPositionsForDirection(direction)
|
||||
val currentHeights = mutableListOf<Float>()
|
||||
for (position in positions) {
|
||||
currentHeights.add(heights[position])
|
||||
}
|
||||
val allCurrentHeightsAreEqual = currentHeights.toSet().size == 1
|
||||
if (allCurrentHeightsAreEqual) {
|
||||
if (maxHeight == currentHeights[0]) {
|
||||
return getRotationAngle(direction)
|
||||
}
|
||||
}
|
||||
}
|
||||
val minHeight = heights.minOrNull()
|
||||
val position = heights.indexOfFirst { it == minHeight }
|
||||
val directions = HEIGHT_POSITIONS_REVERSED[position]
|
||||
var angle = 0f
|
||||
for (direction in directions!!) {
|
||||
angle += getRotationAngle(direction)
|
||||
}
|
||||
return angle / directions.size
|
||||
}
|
||||
|
||||
private fun getRotationAngle(direction: Directions): Float {
|
||||
return when (direction) {
|
||||
Directions.SOUTH -> glm.PI.toFloat()
|
||||
Directions.NORTH -> 0f
|
||||
Directions.WEST -> glm.PI.toFloat() * 0.5f
|
||||
Directions.EAST -> glm.PI.toFloat() * 1.5f
|
||||
else -> error("Unexpected value: $direction")
|
||||
}
|
||||
}
|
||||
|
||||
private fun isLiquidFlowing(heights: FloatArray): Boolean {
|
||||
return heights.toSet().size != 1 // liquid is flowing, if not all of the heights are the same
|
||||
}
|
||||
|
||||
private fun createQuad(drawPositions: Array<Vec3>, texturePositions: Array<Vec2?>, texture: Texture, modelMatrix: Mat4, mesh: SectionArrayMesh, tintColor: RGBColor?, lightLevel: Int) {
|
||||
for (vertex in ElementRenderer.DRAW_ODER) {
|
||||
val input = Vec4(drawPositions[vertex.first], 1.0f)
|
||||
val output = modelMatrix * input
|
||||
mesh.addVertex(
|
||||
position = output.toVec3(),
|
||||
textureCoordinates = texturePositions[vertex.second]!!,
|
||||
texture = texture,
|
||||
tintColor = tintColor,
|
||||
lightLevel = lightLevel,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun calculatePositions(heights: FloatArray): List<Vec3> {
|
||||
val positions = mutableListOf<Vec3>()
|
||||
positions.addAll(DEFAULT_POSITIONS)
|
||||
for ((i, defaultPosition) in DEFAULT_POSITIONS.withIndex()) {
|
||||
val position = Vec3(defaultPosition)
|
||||
position.y += heights[i]
|
||||
positions.add(position)
|
||||
}
|
||||
return positions
|
||||
}
|
||||
|
||||
private fun calculateHeights(neighbourBlocks: Array<BlockInfo?>, blockInfo: BlockInfo, world: World, position: BlockPosition): FloatArray {
|
||||
val height = getLevel(blockInfo)
|
||||
val heights = floatArrayOf(height, height, height, height)
|
||||
for (direction in Directions.SIDES) {
|
||||
val positions = getPositionsForDirection(direction)
|
||||
handleUpperBlocks(world, position, direction, positions, heights)
|
||||
handleDirectNeighbours(neighbourBlocks, direction, world, position, positions, heights)
|
||||
}
|
||||
return heights
|
||||
}
|
||||
|
||||
private fun handleDirectNeighbours(neighbourBlocks: Array<BlockInfo?>, direction: Directions, world: World, position: BlockPosition, positions: MutableSet<Int>, heights: FloatArray) {
|
||||
if (isBlockSameFluid(neighbourBlocks[direction.ordinal])) {
|
||||
val neighbourLevel = getLevel(neighbourBlocks[direction.ordinal]!!)
|
||||
for (heightPosition in positions) {
|
||||
heights[heightPosition] = glm.max(heights[heightPosition], neighbourLevel)
|
||||
}
|
||||
}
|
||||
for (altDirection in direction.sidesNextTo(direction)) {
|
||||
val bothDirections = setOf(direction, altDirection)
|
||||
if (isBlockSameFluid(world.getBlockInfo(position + direction + altDirection))) {
|
||||
val neighbourLevel = getLevel(world.getBlockInfo(position + direction + altDirection)!!)
|
||||
for (heightPosition in HEIGHT_POSITIONS) {
|
||||
if (heightPosition.key.containsAll(bothDirections)) {
|
||||
heights[heightPosition.value] = glm.max(heights[heightPosition.value], neighbourLevel)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleUpperBlocks(world: World, position: BlockPosition, direction: Directions, positions: MutableSet<Int>, heights: FloatArray) {
|
||||
if (isBlockSameFluid(world.getBlockInfo(position + Directions.UP + direction))) {
|
||||
for (heightPosition in positions) {
|
||||
heights[heightPosition] = 1.0f
|
||||
}
|
||||
}
|
||||
for (altDirection in direction.sidesNextTo(direction)) {
|
||||
val bothDirections = setOf(direction, altDirection)
|
||||
if (isBlockSameFluid(world.getBlockInfo(position + Directions.UP + direction + altDirection))) {
|
||||
for (heightPosition in HEIGHT_POSITIONS) {
|
||||
if (heightPosition.key.containsAll(bothDirections)) {
|
||||
heights[heightPosition.value] = 1.0f
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getPositionsForDirection(direction: Directions): MutableSet<Int> {
|
||||
val positions = mutableSetOf<Int>()
|
||||
for (heightPosition in HEIGHT_POSITIONS) {
|
||||
if (heightPosition.key.contains(direction)) {
|
||||
positions.add(heightPosition.value)
|
||||
}
|
||||
}
|
||||
return positions
|
||||
}
|
||||
|
||||
private fun getLevel(blockInfo: BlockInfo): Float {
|
||||
for (property in blockInfo.block.properties) {
|
||||
if (property.group == "level") {
|
||||
return (8 - property.value!!.toInt) * (1f / 8f) - 0.125f
|
||||
}
|
||||
}
|
||||
return 0.8125f
|
||||
}
|
||||
|
||||
private fun isBlockSameFluid(blockInfo: BlockInfo?): Boolean {
|
||||
if (blockInfo == null) {
|
||||
return false
|
||||
}
|
||||
if (blockInfo.block.owner.resourceLocation.full!!.contains(regex)) {
|
||||
return true
|
||||
}
|
||||
if (blockInfo.block.properties.contains(BlockProperties.GENERAL_WATERLOGGED_YES)) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun resolveTextures(indexed: MutableList<Texture>, textureMap: MutableMap<String, Texture>) {
|
||||
if (still != null) {
|
||||
return
|
||||
}
|
||||
still = BlockRenderInterface.resolveTexture(indexed, textureMap, stillTextureName)
|
||||
flowing = BlockRenderInterface.resolveTexture(indexed, textureMap, flowingTextureName)
|
||||
}
|
||||
|
||||
companion object {
|
||||
val DEFAULT_POSITIONS = arrayOf(
|
||||
ElementRenderer.POSITION_1,
|
||||
ElementRenderer.POSITION_2,
|
||||
ElementRenderer.POSITION_3,
|
||||
ElementRenderer.POSITION_4
|
||||
)
|
||||
|
||||
val HEIGHT_POSITIONS = mapOf(
|
||||
Pair(setOf(Directions.NORTH, Directions.WEST), 0),
|
||||
Pair(setOf(Directions.NORTH, Directions.EAST), 1),
|
||||
Pair(setOf(Directions.SOUTH, Directions.WEST), 2),
|
||||
Pair(setOf(Directions.SOUTH, Directions.EAST), 3),
|
||||
)
|
||||
|
||||
val HEIGHT_POSITIONS_REVERSED = HEIGHT_POSITIONS.entries.associate{(k,v)-> v to k}
|
||||
}
|
||||
}
|
@ -17,11 +17,15 @@ import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonElement
|
||||
import com.google.gson.JsonObject
|
||||
import de.bixilon.minosoft.data.Axes
|
||||
import de.bixilon.minosoft.gui.rendering.chunk.models.loading.BlockModelElement
|
||||
import glm_.glm
|
||||
import glm_.vec2.Vec2
|
||||
import glm_.vec3.Vec3
|
||||
|
||||
object VecUtil {
|
||||
val EMPTY_VECTOR = Vec3()
|
||||
|
||||
val BLOCK_SIZE_VECTOR = Vec3(BlockModelElement.BLOCK_RESOLUTION, BlockModelElement.BLOCK_RESOLUTION, BlockModelElement.BLOCK_RESOLUTION)
|
||||
|
||||
fun jsonToVec3(json: JsonElement): Vec3 {
|
||||
when (json) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user