flower random offset, bump pixlyzer

This commit is contained in:
Bixilon 2021-05-13 17:50:36 +02:00
parent 88bbb2c15d
commit c3c4981ece
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
14 changed files with 176 additions and 59 deletions

View File

@ -17,4 +17,5 @@ import com.squareup.moshi.Json
data class OtherGameConfig(
@Json(name = "anti_moire_pattern") var antiMoirePattern: Boolean = true,
@Json(name = "flower_random_offset") var flowerRandomOffset: Boolean = true,
)

View File

@ -27,6 +27,7 @@ open class Block(
val explosionResistance: Float = 0.0f,
val hasDynamicShape: Boolean = false,
val tintColor: RGBColor? = null,
val randomOffsetType: RandomOffsetTypes? = null,
private val itemId: Int = 0,
val tint: ResourceLocation? = null,
val renderOverride: MutableList<BlockLikeRenderer>? = null,
@ -52,6 +53,13 @@ open class Block(
var renderOverride: MutableList<BlockLikeRenderer>? = null
val explosionResistance = data["explosion_resistance"]?.asFloat ?: 0.0f
val hasDynamicShape = data["has_dynamic_shape"]?.asBoolean ?: false
val tintColor = data["tint_color"]?.asInt?.let { TintColorCalculator.getJsonColor(it) }
val randomOffsetType = data["offset_type"]?.asString?.let { RandomOffsetTypes[it] }
val itemId = data["item"]?.asInt ?: 0
val tint = data["tint"]?.asString?.let { ResourceLocation(it) }
val block = when (data["class"].asString) {
"FluidBlock" -> {
val stillFluid = mappings.fluidRegistry.get(data["still_fluid"].asInt)
@ -60,22 +68,26 @@ open class Block(
FluidBlock(
resourceLocation = resourceLocation, explosionResistance = data["explosion_resistance"]?.asFloat ?: 0.0f,
hasDynamicShape = data["has_dynamic_shape"]?.asBoolean ?: false,
tintColor = data["tint_color"]?.asInt?.let { TintColorCalculator.getJsonColor(it) },
itemId = data["item"]?.asInt ?: 0,
tint = data["tint"]?.asString?.let { ResourceLocation(it) },
resourceLocation = resourceLocation,
explosionResistance = explosionResistance,
hasDynamicShape = hasDynamicShape,
tintColor = tintColor,
randomOffsetType = randomOffsetType,
itemId = itemId,
tint = tint,
renderOverride = renderOverride,
stillFluid = stillFluid,
flowingFluid = flowingFluid,
)
}
else -> Block(
resourceLocation = resourceLocation, explosionResistance = data["explosion_resistance"]?.asFloat ?: 0.0f,
hasDynamicShape = data["has_dynamic_shape"]?.asBoolean ?: false,
tintColor = data["tint_color"]?.asInt?.let { TintColorCalculator.getJsonColor(it) },
itemId = data["item"]?.asInt ?: 0,
tint = data["tint"]?.asString?.let { ResourceLocation(it) },
resourceLocation = resourceLocation,
explosionResistance = explosionResistance,
hasDynamicShape = hasDynamicShape,
tintColor = tintColor,
randomOffsetType = randomOffsetType,
itemId = itemId,
tint = tint,
renderOverride = renderOverride,
)
}

View File

@ -24,12 +24,13 @@ class FluidBlock(
explosionResistance: Float = 0.0f,
hasDynamicShape: Boolean = false,
tintColor: RGBColor? = null,
randomOffsetType: RandomOffsetTypes? = null,
itemId: Int = 0,
tint: ResourceLocation? = null,
val stillFluid: Fluid,
val flowingFluid: Fluid,
renderOverride: MutableList<BlockLikeRenderer> = mutableListOf(),
) : Block(resourceLocation, explosionResistance, hasDynamicShape, tintColor, itemId, tint, renderOverride) {
) : Block(resourceLocation, explosionResistance, hasDynamicShape, tintColor, randomOffsetType, itemId, tint, renderOverride) {
val fluidRenderer: FluidRenderer = FluidRenderer(this, stillFluid, flowingFluid)
init {

View File

@ -0,0 +1,28 @@
/*
* Minosoft
* Copyright (C) 2021 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.data.mappings.blocks
import de.bixilon.minosoft.util.KUtil
import de.bixilon.minosoft.util.enum.ValuesEnum
enum class RandomOffsetTypes {
XZ,
XYZ,
;
companion object : ValuesEnum<RandomOffsetTypes> {
override val VALUES: Array<RandomOffsetTypes> = values()
override val NAME_MAP: Map<String, RandomOffsetTypes> = KUtil.getEnumValues(VALUES)
}
}

View File

@ -27,11 +27,13 @@ import de.bixilon.minosoft.data.world.ChunkSection.Companion.indexPosition
import de.bixilon.minosoft.data.world.World
import de.bixilon.minosoft.gui.input.camera.Frustum
import de.bixilon.minosoft.gui.rendering.*
import de.bixilon.minosoft.gui.rendering.chunk.models.renderable.BlockLikeRenderContext
import de.bixilon.minosoft.gui.rendering.modding.events.FrustumChangeEvent
import de.bixilon.minosoft.gui.rendering.modding.events.RenderingStateChangeEvent
import de.bixilon.minosoft.gui.rendering.shader.Shader
import de.bixilon.minosoft.gui.rendering.textures.Texture
import de.bixilon.minosoft.gui.rendering.util.VecUtil.chunkPosition
import de.bixilon.minosoft.gui.rendering.util.VecUtil.getWorldOffset
import de.bixilon.minosoft.gui.rendering.util.VecUtil.of
import de.bixilon.minosoft.gui.rendering.util.VecUtil.plus
import de.bixilon.minosoft.gui.rendering.util.VecUtil.sectionHeight
@ -80,9 +82,9 @@ class WorldRenderer(
}
val blockPosition = Vec3i.of(chunkPosition, sectionHeight, index.indexPosition)
val neighborBlocks: Array<BlockState?> = arrayOfNulls(Directions.VALUES.size)
val neighbourBlocks: Array<BlockState?> = arrayOfNulls(Directions.VALUES.size)
for (direction in Directions.VALUES) {
neighborBlocks[direction.ordinal] = world.getBlockState(blockPosition + direction)
neighbourBlocks[direction.ordinal] = world.getBlockState(blockPosition + direction)
}
// if (!blockState.block.resourceLocation.full.contains("white_stained_glass_pane")) {
@ -90,11 +92,22 @@ class WorldRenderer(
// }
val context = BlockLikeRenderContext(
blockState = blockState,
lightAccessor = world.worldLightAccessor,
renderWindow = renderWindow,
blockPosition = blockPosition,
meshCollection = meshCollection,
neighbourBlocks = neighbourBlocks,
world = world,
offset = blockPosition.getWorldOffset(blockState.block),
)
if (blockState.properties[BlockProperties.WATERLOGGED] == true) {
waterBlock?.fluidRenderer?.render(waterBlock.defaultState, world.worldLightAccessor, renderWindow, blockPosition, meshCollection, neighborBlocks, world)
waterBlock?.fluidRenderer?.render(context.copy(blockState = waterBlock.defaultState))
}
blockState.getBlockRenderer(blockPosition).render(blockState, world.worldLightAccessor, renderWindow, blockPosition, meshCollection, neighborBlocks, world)
blockState.getBlockRenderer(blockPosition).render(context)
}
}

View File

@ -0,0 +1,33 @@
/*
* Minosoft
* Copyright (C) 2021 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.gui.rendering.chunk.models.renderable
import de.bixilon.minosoft.data.mappings.blocks.BlockState
import de.bixilon.minosoft.data.world.World
import de.bixilon.minosoft.data.world.light.LightAccessor
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.chunk.ChunkMeshCollection
import glm_.vec3.Vec3
import glm_.vec3.Vec3i
data class BlockLikeRenderContext(
val blockState: BlockState,
val lightAccessor: LightAccessor,
val renderWindow: RenderWindow,
val blockPosition: Vec3i,
val meshCollection: ChunkMeshCollection,
val neighbourBlocks: Array<BlockState?>,
val world: World,
val offset: Vec3,
)

View File

@ -1,19 +1,13 @@
package de.bixilon.minosoft.gui.rendering.chunk.models.renderable
import de.bixilon.minosoft.data.mappings.blocks.BlockState
import de.bixilon.minosoft.data.world.World
import de.bixilon.minosoft.data.world.light.LightAccessor
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.chunk.ChunkMeshCollection
import de.bixilon.minosoft.gui.rendering.chunk.models.FaceSize
import de.bixilon.minosoft.gui.rendering.textures.Texture
import glm_.vec3.Vec3i
interface BlockLikeRenderer {
val faceBorderSizes: Array<Array<FaceSize>?> // direction indexed
val transparentFaces: BooleanArray
fun render(blockState: BlockState, lightAccessor: LightAccessor, renderWindow: RenderWindow, blockPosition: Vec3i, meshCollection: ChunkMeshCollection, neighbourBlocks: Array<BlockState?>, world: World)
fun render(context: BlockLikeRenderContext)
fun resolveTextures(indexed: MutableList<Texture>, textureMap: MutableMap<String, Texture>)

View File

@ -17,13 +17,8 @@ import com.google.common.collect.HashBiMap
import com.google.gson.JsonObject
import de.bixilon.minosoft.data.Directions
import de.bixilon.minosoft.data.mappings.biomes.Biome
import de.bixilon.minosoft.data.mappings.blocks.BlockState
import de.bixilon.minosoft.data.text.RGBColor
import de.bixilon.minosoft.data.world.World
import de.bixilon.minosoft.data.world.light.LightAccessor
import de.bixilon.minosoft.gui.rendering.RenderConstants
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.chunk.ChunkMeshCollection
import de.bixilon.minosoft.gui.rendering.chunk.models.FaceSize
import de.bixilon.minosoft.gui.rendering.chunk.models.loading.BlockModel
import de.bixilon.minosoft.gui.rendering.textures.Texture
@ -32,7 +27,6 @@ import de.bixilon.minosoft.gui.rendering.util.VecUtil.plus
import de.bixilon.minosoft.gui.rendering.util.VecUtil.toVec3
import glm_.glm
import glm_.vec3.Vec3
import glm_.vec3.Vec3i
class BlockRenderer(data: JsonObject, parent: BlockModel) : BlockLikeRenderer {
private val cullFaces: Array<Directions?> = arrayOfNulls(Directions.VALUES.size)
@ -102,7 +96,7 @@ class BlockRenderer(data: JsonObject, parent: BlockModel) : BlockLikeRenderer {
}
}
override fun render(blockState: BlockState, lightAccessor: LightAccessor, renderWindow: RenderWindow, blockPosition: Vec3i, meshCollection: ChunkMeshCollection, neighbourBlocks: Array<BlockState?>, world: World) {
override fun render(context: BlockLikeRenderContext) {
if (!RenderConstants.RENDER_BLOCKS) {
return
}
@ -114,8 +108,8 @@ class BlockRenderer(data: JsonObject, parent: BlockModel) : BlockLikeRenderer {
val invertedDirection = direction.inverted
var isNeighbourTransparent = false
var neighbourFaceSize: Array<FaceSize>? = null
val neighbourBlock = neighbourBlocks[direction.ordinal]
neighbourBlock?.getBlockRenderer(blockPosition + direction)?.let {
val neighbourBlock = context.neighbourBlocks[direction.ordinal]
neighbourBlock?.getBlockRenderer(context.blockPosition + direction)?.let {
val itDirection = if (it is BlockRenderer) {
it.directionMapping[invertedDirection] ?: invertedDirection
} else {
@ -147,7 +141,7 @@ class BlockRenderer(data: JsonObject, parent: BlockModel) : BlockLikeRenderer {
// force draw transparent faces
if (isNeighbourTransparent && !transparentFaces[direction.ordinal]) {
drawElementFace = true
} else if (isNeighbourTransparent && transparentFaces[direction.ordinal] && neighbourBlock != blockState) {
} else if (isNeighbourTransparent && transparentFaces[direction.ordinal] && neighbourBlock != context.blockState) {
drawElementFace = true
}
}
@ -157,10 +151,10 @@ class BlockRenderer(data: JsonObject, parent: BlockModel) : BlockLikeRenderer {
}
if (biome == null) {
biome = world.getBiome(blockPosition)
tintColor = renderWindow.tintColorCalculator.getAverageTint(biome, blockState, blockPosition)
biome = context.world.getBiome(context.blockPosition)
tintColor = context.renderWindow.tintColorCalculator.getAverageTint(biome, context.blockState, context.blockPosition)
}
element.render(tintColor, blockPosition, lightAccessor, textureMapping, direction, meshCollection)
element.render(tintColor, textureMapping, direction, context)
}
}
}

View File

@ -18,7 +18,6 @@ import com.google.gson.JsonObject
import de.bixilon.minosoft.data.Axes
import de.bixilon.minosoft.data.Directions
import de.bixilon.minosoft.data.text.RGBColor
import de.bixilon.minosoft.data.world.light.LightAccessor
import de.bixilon.minosoft.gui.rendering.chunk.ChunkMeshCollection
import de.bixilon.minosoft.gui.rendering.chunk.SectionArrayMesh
import de.bixilon.minosoft.gui.rendering.chunk.models.FaceSize
@ -31,7 +30,6 @@ import de.bixilon.minosoft.gui.rendering.util.VecUtil
import de.bixilon.minosoft.gui.rendering.util.VecUtil.plus
import de.bixilon.minosoft.gui.rendering.util.VecUtil.rotate
import glm_.vec3.Vec3
import glm_.vec3.Vec3i
class ElementRenderer(
parent: BlockModelElement,
@ -65,7 +63,7 @@ class ElementRenderer(
}
}
fun render(tintColor: RGBColor?, blockPosition: Vec3i, lightAccessor: LightAccessor, textureMapping: MutableMap<String, Texture>, direction: Directions, meshCollection: ChunkMeshCollection) {
fun render(tintColor: RGBColor?, textureMapping: MutableMap<String, Texture>, direction: Directions, context: BlockLikeRenderContext) {
val realDirection = directionMapping.inverse()[direction]!!
val face = faces[realDirection] ?: return // Not our face
@ -73,16 +71,16 @@ class ElementRenderer(
val texture = textureMapping[face.textureName] ?: TODO("Unknown texture used ${face.textureName}") // ToDo: can be replaced with RenderConstants.DEBUG_TEXTURE_ID?
val lightLevel = lightAccessor.getLightLevel(blockPosition + face.cullFace?.let { directionMapping[it] }) // ToDo: rotate cullface
val lightLevel = context.lightAccessor.getLightLevel(context.blockPosition + face.cullFace?.let { directionMapping[it] }) // ToDo: rotate cullface
val drawPositions = arrayOf(transformedPositions[positionTemplate[0]], transformedPositions[positionTemplate[1]], transformedPositions[positionTemplate[2]], transformedPositions[positionTemplate[3]])
val mesh = getMesh(meshCollection, texture.transparency)
val mesh = getMesh(context.meshCollection, texture.transparency)
val texturePositions = face.getTexturePositionArray(realDirection)
for (vertex in DRAW_ODER) {
val input = drawPositions[vertex.first]
val output = blockPosition plus input + DRAW_OFFSET
val output = context.blockPosition plus context.offset + input + DRAW_OFFSET
mesh.addVertex(
position = output,
textureCoordinates = texturePositions[vertex.second]!!,

View File

@ -8,9 +8,7 @@ import de.bixilon.minosoft.data.mappings.blocks.properties.BlockProperties
import de.bixilon.minosoft.data.mappings.fluid.Fluid
import de.bixilon.minosoft.data.text.RGBColor
import de.bixilon.minosoft.data.world.World
import de.bixilon.minosoft.data.world.light.LightAccessor
import de.bixilon.minosoft.gui.rendering.RenderConstants
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.chunk.ChunkMeshCollection
import de.bixilon.minosoft.gui.rendering.chunk.models.FaceSize
import de.bixilon.minosoft.gui.rendering.chunk.models.loading.BlockModelElement
@ -32,12 +30,12 @@ class FluidRenderer(
private lateinit var stillTexture: Texture
private lateinit var flowingTexture: Texture
override fun render(blockState: BlockState, lightAccessor: LightAccessor, renderWindow: RenderWindow, blockPosition: Vec3i, meshCollection: ChunkMeshCollection, neighbourBlocks: Array<BlockState?>, world: World) {
override fun render(context: BlockLikeRenderContext) {
if (!RenderConstants.RENDER_FLUIDS) {
return
}
val lightLevel = lightAccessor.getLightLevel(blockPosition)
val heights = calculateHeights(neighbourBlocks, blockState, world, blockPosition)
val lightLevel = context.lightAccessor.getLightLevel(context.blockPosition)
val heights = calculateHeights(context.neighbourBlocks, context.blockState, context.world, context.blockPosition)
val isFlowing = isLiquidFlowing(heights)
var texture: Texture
@ -58,18 +56,19 @@ class FluidRenderer(
} else {
texture = stillTexture
}
if (isBlockSameFluid(neighbourBlocks[direction.ordinal]) || neighbourBlocks[direction.ordinal]?.getBlockRenderer(blockPosition + direction)?.faceBorderSizes?.let { it[direction.inverted.ordinal] != null } == true && direction != Directions.UP) {
val neighbourBlocks = context.neighbourBlocks
if (isBlockSameFluid(neighbourBlocks[direction.ordinal]) || neighbourBlocks[direction.ordinal]?.getBlockRenderer(context.blockPosition + direction)?.faceBorderSizes?.let { it[direction.inverted.ordinal] != null } == true && direction != Directions.UP) {
continue
}
val positionTemplate = BlockModelElement.FACE_POSITION_MAP_TEMPLATE[direction.ordinal]
val drawPositions = arrayOf(positions[positionTemplate[0]], positions[positionTemplate[1]], positions[positionTemplate[2]], positions[positionTemplate[3]])
if (biome == null) {
biome = world.getBiome(blockPosition)
tintColor = renderWindow.tintColorCalculator.getAverageTint(biome, blockState, blockPosition)
biome = context.world.getBiome(context.blockPosition)
tintColor = context.renderWindow.tintColorCalculator.getAverageTint(biome, context.blockState, context.blockPosition)
}
createQuad(drawPositions, face.getTexturePositionArray(direction), texture, blockPosition, meshCollection, tintColor, lightLevel)
createQuad(drawPositions, face.getTexturePositionArray(direction), texture, context.blockPosition, context.meshCollection, tintColor, lightLevel)
}
}

View File

@ -14,14 +14,8 @@
package de.bixilon.minosoft.gui.rendering.chunk.models.renderable
import de.bixilon.minosoft.data.Directions
import de.bixilon.minosoft.data.mappings.blocks.BlockState
import de.bixilon.minosoft.data.world.World
import de.bixilon.minosoft.data.world.light.LightAccessor
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.chunk.ChunkMeshCollection
import de.bixilon.minosoft.gui.rendering.chunk.models.FaceSize
import de.bixilon.minosoft.gui.rendering.textures.Texture
import glm_.vec3.Vec3i
class MultipartRenderer(
val models: List<BlockLikeRenderer>,
@ -45,9 +39,9 @@ class MultipartRenderer(
this.faceBorderSizes = faceBorderSizes.toTypedArray()
}
override fun render(blockState: BlockState, lightAccessor: LightAccessor, renderWindow: RenderWindow, blockPosition: Vec3i, meshCollection: ChunkMeshCollection, neighbourBlocks: Array<BlockState?>, world: World) {
override fun render(context: BlockLikeRenderContext) {
for (model in models) {
model.render(blockState, lightAccessor, renderWindow, blockPosition, meshCollection, neighbourBlocks, world)
model.render(context)
}
}

View File

@ -16,10 +16,14 @@ package de.bixilon.minosoft.gui.rendering.util
import com.google.gson.JsonArray
import com.google.gson.JsonElement
import com.google.gson.JsonObject
import de.bixilon.minosoft.Minosoft
import de.bixilon.minosoft.data.Axes
import de.bixilon.minosoft.data.Directions
import de.bixilon.minosoft.data.mappings.blocks.Block
import de.bixilon.minosoft.data.mappings.blocks.RandomOffsetTypes
import de.bixilon.minosoft.gui.rendering.chunk.models.loading.BlockModelElement
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
import glm_.func.common.clamp
import glm_.func.cos
import glm_.func.sin
import glm_.vec2.Vec2
@ -172,4 +176,40 @@ object VecUtil {
infix operator fun Vec2i.plus(direction: Directions): Vec2i {
return this + direction.directionVector
}
fun Vec3i.getWorldOffset(block: Block): Vec3 {
if (block.randomOffsetType == null || !Minosoft.config.config.game.other.flowerRandomOffset) {
return EMPTY_VEC3
}
val positionHash = generatePositionHash(x, 0, z)
val maxModelOffset = 0.25f // use block.model.max_model_offset
fun horizontal(axisHash: Long): Float {
return (((axisHash and 0xF) / 15.0f) - 0.5f) / 2.0f
}
return Vec3(
x = horizontal(positionHash),
y = if (block.randomOffsetType === RandomOffsetTypes.XYZ) {
(((positionHash shr 4 and 0xF) / 15.0f) - 1.0f) / 5.0f
} else {
0.0f
},
z = horizontal(positionHash shr 8)).clamp(-maxModelOffset, maxModelOffset)
}
private fun Vec3.clamp(min: Float, max: Float): Vec3 {
return Vec3(
x = x.clamp(min, max),
y = y.clamp(min, max),
z = z.clamp(min, max),
)
}
private fun generatePositionHash(x: Int, y: Int, z: Int): Long {
var hash = (x * 3129871L) xor z.toLong() * 116129781L xor y.toLong()
hash = hash * hash * 42317861L + hash * 11L
return hash shr 16
}
}

View File

@ -51,6 +51,16 @@ object MMath {
return value
}
fun clamp(value: Double, min: Double, max: Double): Double {
if (value < min) {
return min
}
if (value > max) {
return max
}
return value
}
fun divideUp(value: Int, divider: Int): Int {
return (value + divider - 1) / divider
}

File diff suppressed because one or more lines are too long