mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-15 02:15:34 -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
|
val directionVector: Vec3 = direction
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -22,7 +22,9 @@ import de.bixilon.minosoft.data.text.RGBColor
|
|||||||
import de.bixilon.minosoft.data.world.BlockPosition
|
import de.bixilon.minosoft.data.world.BlockPosition
|
||||||
import de.bixilon.minosoft.gui.rendering.TintColorCalculator
|
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.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.BlockRenderer
|
||||||
|
import de.bixilon.minosoft.gui.rendering.chunk.models.renderable.FluidRenderer
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
|
|
||||||
@ -30,7 +32,7 @@ data class BlockState(
|
|||||||
val owner: Block,
|
val owner: Block,
|
||||||
val properties: Set<BlockProperties> = setOf(),
|
val properties: Set<BlockProperties> = setOf(),
|
||||||
val rotation: BlockRotations = BlockRotations.NONE,
|
val rotation: BlockRotations = BlockRotations.NONE,
|
||||||
val renders: Set<BlockRenderer> = setOf(),
|
val renders: Set<BlockRenderInterface> = setOf(),
|
||||||
val tintColor: RGBColor? = null,
|
val tintColor: RGBColor? = null,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
@ -104,7 +106,7 @@ data class BlockState(
|
|||||||
return String.format("%s%s", owner.resourceLocation, out)
|
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) {
|
if (Minosoft.getConfig().config.game.other.antiMoirePattern) {
|
||||||
// ToDo: Support weight attribute
|
// ToDo: Support weight attribute
|
||||||
return renders.random(Random(position.hashCode()))
|
return renders.random(Random(position.hashCode()))
|
||||||
@ -116,11 +118,16 @@ data class BlockState(
|
|||||||
companion object {
|
companion object {
|
||||||
val ROTATION_PROPERTIES = setOf("facing", "rotation", "orientation", "axis")
|
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 {
|
fun deserialize(owner: Block, data: JsonObject, models: HashBiMap<ResourceLocation, BlockModel>): BlockState {
|
||||||
val (rotation, properties) = data["properties"]?.asJsonObject?.let {
|
val (rotation, properties) = data["properties"]?.asJsonObject?.let {
|
||||||
getProperties(it)
|
getProperties(it)
|
||||||
} ?: Pair(BlockRotations.NONE, mutableSetOf())
|
} ?: Pair(BlockRotations.NONE, mutableSetOf())
|
||||||
val renders: MutableSet<BlockRenderer> = mutableSetOf()
|
val renders: MutableSet<BlockRenderInterface> = mutableSetOf()
|
||||||
|
|
||||||
data["render"]?.let {
|
data["render"]?.let {
|
||||||
when (it) {
|
when (it) {
|
||||||
@ -149,6 +156,13 @@ data class BlockState(
|
|||||||
|
|
||||||
val tintColor: RGBColor? = data["tint_color"]?.asInt?.let { TintColorCalculator.getJsonColor(it) } ?: owner.tintColor
|
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(
|
return BlockState(
|
||||||
owner = owner,
|
owner = owner,
|
||||||
properties = properties.toSet(),
|
properties = properties.toSet(),
|
||||||
@ -192,7 +206,7 @@ data class BlockState(
|
|||||||
return Pair(rotation, properties)
|
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"]}")
|
val model = models[ResourceLocation(data["model"].asString)] ?: error("Can not find block model ${data["model"]}")
|
||||||
renders.add(BlockRenderer(data, model))
|
renders.add(BlockRenderer(data, model))
|
||||||
}
|
}
|
||||||
|
@ -154,7 +154,6 @@ class VersionMapping(var version: Version?) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun loadBlockModels(data: Map<ResourceLocation, JsonObject>) {
|
private fun loadBlockModels(data: Map<ResourceLocation, JsonObject>) {
|
||||||
for ((resourceLocation, model) in data) {
|
for ((resourceLocation, model) in data) {
|
||||||
if (models.containsKey(resourceLocation)) {
|
if (models.containsKey(resourceLocation)) {
|
||||||
|
@ -87,7 +87,7 @@ class WorldRenderer(
|
|||||||
blockInfo.block.tintColor?.let { tintColor = it }
|
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
|
return mesh
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
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.JsonObject
|
import com.google.gson.JsonObject
|
||||||
import de.bixilon.minosoft.data.Directions
|
import de.bixilon.minosoft.data.Directions
|
||||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil
|
import de.bixilon.minosoft.gui.rendering.util.VecUtil
|
||||||
@ -22,7 +23,7 @@ import glm_.vec3.Vec3
|
|||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class BlockModelFace {
|
class BlockModelFace {
|
||||||
val textureName: String
|
val textureName: String?
|
||||||
val cullFace: Directions?
|
val cullFace: Directions?
|
||||||
val tint: Boolean
|
val tint: Boolean
|
||||||
private val positions: MutableList<Vec2>
|
private val positions: MutableList<Vec2>
|
||||||
@ -30,26 +31,6 @@ class BlockModelFace {
|
|||||||
constructor(data: JsonObject, from: Vec3, to: Vec3, direction: Directions) {
|
constructor(data: JsonObject, from: Vec3, to: Vec3, direction: Directions) {
|
||||||
tint = data.has("tintindex")
|
tint = data.has("tintindex")
|
||||||
textureName = data.get("texture").asString.removePrefix("#")
|
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 {
|
cullFace = data["cullface"]?.asString?.let {
|
||||||
return@let if (it == "bottom") {
|
return@let if (it == "bottom") {
|
||||||
Directions.DOWN
|
Directions.DOWN
|
||||||
@ -57,14 +38,33 @@ class BlockModelFace {
|
|||||||
Directions.valueOf(it.toUpperCase())
|
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, textureTopLeft.y)),
|
||||||
uvToFloat(Vec2(textureTopLeft.x, textureBottomRight.y)),
|
uvToFloat(Vec2(textureTopLeft.x, textureBottomRight.y)),
|
||||||
uvToFloat(Vec2(textureBottomRight.x, textureBottomRight.y)),
|
uvToFloat(Vec2(textureBottomRight.x, textureBottomRight.y)),
|
||||||
uvToFloat(Vec2(textureBottomRight.x, textureTopLeft.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) {
|
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?> {
|
fun getTexturePositionArray(direction: Directions): Array<Vec2?> {
|
||||||
val template = textureTemplate[direction.ordinal]
|
val template = textureTemplate[direction.ordinal]
|
||||||
val result = arrayOfNulls<Vec2>(template.size)
|
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.text.RGBColor
|
||||||
import de.bixilon.minosoft.data.world.BlockInfo
|
import de.bixilon.minosoft.data.world.BlockInfo
|
||||||
import de.bixilon.minosoft.data.world.BlockPosition
|
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.data.world.light.LightAccessor
|
||||||
import de.bixilon.minosoft.gui.rendering.chunk.SectionArrayMesh
|
import de.bixilon.minosoft.gui.rendering.chunk.SectionArrayMesh
|
||||||
import de.bixilon.minosoft.gui.rendering.chunk.models.loading.BlockModel
|
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 de.bixilon.minosoft.gui.rendering.textures.TextureTransparencies
|
||||||
import glm_.mat4x4.Mat4
|
import glm_.mat4x4.Mat4
|
||||||
|
|
||||||
class BlockRenderer {
|
class BlockRenderer: BlockRenderInterface {
|
||||||
private val transparentFaces: MutableSet<Directions> = mutableSetOf()
|
|
||||||
private val cullFaces: 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 elements: MutableSet<ElementRenderer> = mutableSetOf()
|
private val elements: MutableSet<ElementRenderer> = mutableSetOf()
|
||||||
private val textureMapping: MutableMap<String, Texture> = mutableMapOf()
|
private val textureMapping: MutableMap<String, Texture> = mutableMapOf()
|
||||||
|
override val fullFaceDirections: MutableSet<Directions> = mutableSetOf()
|
||||||
|
override val transparentFaces: MutableSet<Directions> = mutableSetOf()
|
||||||
|
|
||||||
constructor(data: JsonObject, parent: BlockModel) {
|
constructor(data: JsonObject, parent: BlockModel) {
|
||||||
val newElements = ElementRenderer.createElements(data, parent)
|
val newElements = ElementRenderer.createElements(data, parent)
|
||||||
@ -51,26 +52,15 @@ class BlockRenderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun resolveTextures(indexed: MutableList<Texture>, textureMap: MutableMap<String, Texture>) {
|
||||||
fun resolveTextures(indexed: MutableList<Texture>, textureMap: MutableMap<String, Texture>) {
|
|
||||||
for ((key, textureName) in textures) {
|
for ((key, textureName) in textures) {
|
||||||
if (!textureName.startsWith("#")) {
|
if (!textureName.startsWith("#")) {
|
||||||
var texture: Texture? = null
|
textureMapping[key] = BlockRenderInterface.resolveTexture(indexed, textureMap, textureName = textureName)!!
|
||||||
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!!
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun postInit() {
|
override fun postInit() {
|
||||||
for (direction in Directions.DIRECTIONS) {
|
for (direction in Directions.DIRECTIONS) {
|
||||||
var directionIsCullface: Boolean? = null
|
var directionIsCullface: Boolean? = null
|
||||||
var directionIsNotTransparent: 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())
|
val modelMatrix = Mat4().translate(position.toVec3())
|
||||||
|
|
||||||
for (direction in Directions.DIRECTIONS) {
|
for (direction in Directions.DIRECTIONS) {
|
||||||
|
@ -17,6 +17,8 @@ import com.google.common.collect.HashBiMap
|
|||||||
import com.google.gson.JsonObject
|
import com.google.gson.JsonObject
|
||||||
import de.bixilon.minosoft.data.Axes
|
import de.bixilon.minosoft.data.Axes
|
||||||
import de.bixilon.minosoft.data.Directions
|
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.text.RGBColor
|
||||||
import de.bixilon.minosoft.data.world.BlockPosition
|
import de.bixilon.minosoft.data.world.BlockPosition
|
||||||
import de.bixilon.minosoft.data.world.light.LightAccessor
|
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 realDirection = directionMapping.inverse()[direction]!!
|
||||||
|
|
||||||
val face = faces[realDirection] ?: return // Not our face
|
val face = faces[realDirection] ?: return // Not our face
|
||||||
|
|
||||||
val positionTemplate = BlockModelElement.FACE_POSITION_MAP_TEMPLATE[realDirection.ordinal]
|
val positionTemplate = BlockModelElement.FACE_POSITION_MAP_TEMPLATE[realDirection.ordinal]
|
||||||
|
|
||||||
val texture = textureMapping[face.textureName] ?: TODO()
|
val texture = textureMapping[face.textureName] ?: TODO()
|
||||||
@ -110,8 +111,6 @@ class ElementRenderer(parent: BlockModelElement, val rotation: Vec3, uvLock: Boo
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val EMPTY_VECTOR = Vec3()
|
|
||||||
|
|
||||||
val DRAW_ODER = arrayOf(
|
val DRAW_ODER = arrayOf(
|
||||||
Pair(0, 1),
|
Pair(0, 1),
|
||||||
Pair(3, 2),
|
Pair(3, 2),
|
||||||
@ -151,7 +150,7 @@ class ElementRenderer(parent: BlockModelElement, val rotation: Vec3, uvLock: Boo
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getRotatedDirection(rotation: Vec3, direction: Directions): Directions {
|
fun getRotatedDirection(rotation: Vec3, direction: Directions): Directions {
|
||||||
if (rotation == EMPTY_VECTOR) {
|
if (rotation == VecUtil.EMPTY_VECTOR) {
|
||||||
return direction
|
return direction
|
||||||
}
|
}
|
||||||
var rotatedDirectionVector = VecUtil.rotateVector(direction.directionVector, rotation.x, Axes.X)
|
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) {
|
fun rotatePositionsAxes(positions: Array<Vec3>, angles: Vec3, rescale: Boolean) {
|
||||||
if (angles == EMPTY_VECTOR) {
|
if (angles == VecUtil.EMPTY_VECTOR) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
BlockModelElement.rotatePositions(positions, Axes.X, angles.x, EMPTY_VECTOR, rescale)
|
BlockModelElement.rotatePositions(positions, Axes.X, angles.x, VecUtil.EMPTY_VECTOR, rescale)
|
||||||
BlockModelElement.rotatePositions(positions, Axes.Y, angles.y, EMPTY_VECTOR, rescale)
|
BlockModelElement.rotatePositions(positions, Axes.Y, angles.y, VecUtil.EMPTY_VECTOR, rescale)
|
||||||
BlockModelElement.rotatePositions(positions, Axes.Z, angles.z, 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)
|
val POSITION_1 = Vec3(-0.5f, -0.5f, -0.5f)
|
||||||
private val POSITION_2 = Vec3(+0.5f, -0.5f, -0.5f)
|
val POSITION_2 = Vec3(+0.5f, -0.5f, -0.5f)
|
||||||
private val POSITION_3 = Vec3(-0.5f, -0.5f, +0.5f)
|
val POSITION_3 = Vec3(-0.5f, -0.5f, +0.5f)
|
||||||
private val POSITION_4 = 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_5 = Vec3(-0.5f, +0.5f, -0.5f)
|
||||||
private val POSITION_6 = 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)
|
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.JsonElement
|
||||||
import com.google.gson.JsonObject
|
import com.google.gson.JsonObject
|
||||||
import de.bixilon.minosoft.data.Axes
|
import de.bixilon.minosoft.data.Axes
|
||||||
|
import de.bixilon.minosoft.gui.rendering.chunk.models.loading.BlockModelElement
|
||||||
import glm_.glm
|
import glm_.glm
|
||||||
import glm_.vec2.Vec2
|
import glm_.vec2.Vec2
|
||||||
import glm_.vec3.Vec3
|
import glm_.vec3.Vec3
|
||||||
|
|
||||||
object VecUtil {
|
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 {
|
fun jsonToVec3(json: JsonElement): Vec3 {
|
||||||
when (json) {
|
when (json) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user