fix leaf block & leaf particle colors

This commit is contained in:
octarine-noise
2021-07-26 14:52:16 +02:00
parent 4c08354d74
commit b4824b77ae
12 changed files with 71 additions and 30 deletions

View File

@@ -70,6 +70,8 @@ data class Color(val alpha: Int, val red: Int, val green: Int, val blue: Int) {
) )
val asInt get() = (alpha shl 24) or (red shl 16) or (green shl 8) or blue val asInt get() = (alpha shl 24) or (red shl 16) or (green shl 8) or blue
val asHSB get() = HSB.fromColor(this)
operator fun times(f: Float) = Color( operator fun times(f: Float) = Color(
alpha, alpha,
(f * red.toFloat()).toInt().coerceIn(0 until 256), (f * red.toFloat()).toInt().coerceIn(0 until 256),
@@ -93,6 +95,10 @@ data class HSB(var hue: Float, var saturation: Float, var brightness: Float) {
val hsbVals = java.awt.Color.RGBtoHSB((color shr 16) and 255, (color shr 8) and 255, color and 255, null) val hsbVals = java.awt.Color.RGBtoHSB((color shr 16) and 255, (color shr 8) and 255, color and 255, null)
return HSB(hsbVals[0], hsbVals[1], hsbVals[2]) return HSB(hsbVals[0], hsbVals[1], hsbVals[2])
} }
fun fromColor(color: Color): HSB {
val hsbVals = java.awt.Color.RGBtoHSB(color.red, color.green, color.blue, null)
return HSB(hsbVals[0], hsbVals[1], hsbVals[2])
}
} }
val asInt: Int get() = java.awt.Color.HSBtoRGB(hue, saturation, brightness) val asInt: Int get() = java.awt.Color.HSBtoRGB(hue, saturation, brightness)
val asColor: Color get() = Color(asInt) val asColor: Color get() = Color(asInt)

View File

@@ -84,20 +84,20 @@ fun crossModelsRaw(num: Int, size: Double, hOffset: Double, vOffset: Double): Li
} }
} }
fun crossModelSingle(base: List<Quad>, sprite: TextureAtlasSprite, tintIndex: Int,scrambleUV: Boolean) = fun crossModelSingle(base: List<Quad>, sprite: TextureAtlasSprite, color: Color, tint: Int, scrambleUV: Boolean) =
base.map { if (scrambleUV) it.scrambleUV(random, canFlipU = true, canFlipV = true, canRotate = true) else it } base.map { if (scrambleUV) it.scrambleUV(random, canFlipU = true, canFlipV = true, canRotate = true) else it }
.map { it.colorIndex(tintIndex) } .map { it.color(color).colorIndex(tint) }
.mapIndexed { idx, quad -> quad.sprite(sprite) } .mapIndexed { idx, quad -> quad.sprite(sprite) }
.withOpposites() .withOpposites()
.bake(false) .bake(false)
fun crossModelsTextured( fun crossModelsTextured(
leafBase: Iterable<List<Quad>>, leafBase: Iterable<List<Quad>>,
tintIndex: Int, color: Color, tint: Int,
scrambleUV: Boolean, scrambleUV: Boolean,
spriteGetter: (Int) -> ResourceLocation spriteGetter: (Int) -> ResourceLocation
) = leafBase.mapIndexed { idx, leaf -> ) = leafBase.mapIndexed { idx, leaf ->
crossModelSingle(leaf, Atlas.BLOCKS[spriteGetter(idx)], tintIndex, scrambleUV) crossModelSingle(leaf, Atlas.BLOCKS[spriteGetter(idx)], color, tint, scrambleUV)
}.toTypedArray() }.toTypedArray()
fun Iterable<Quad>.withOpposites() = flatMap { listOf(it, it.flipped) } fun Iterable<Quad>.withOpposites() = flatMap { listOf(it, it.flipped) }

View File

@@ -87,7 +87,7 @@ class StandardCactusModel(
crossModelsRaw(64, config.size, 0.0, 0.0) crossModelsRaw(64, config.size, 0.0, 0.0)
.transform { rotateZ(randomD(-config.sizeVariation, config.sizeVariation)) } .transform { rotateZ(randomD(-config.sizeVariation, config.sizeVariation)) }
} }
crossModelsTextured(models, -1, true) { cactusCrossSprite } crossModelsTextured(models, Color.white, -1, true) { cactusCrossSprite }
} }
} }
} }

View File

@@ -28,19 +28,24 @@ import mods.betterfoliage.util.averageHSB
import mods.betterfoliage.util.idxOrNull import mods.betterfoliage.util.idxOrNull
import mods.betterfoliage.util.lazy import mods.betterfoliage.util.lazy
import mods.betterfoliage.util.lazyMap import mods.betterfoliage.util.lazyMap
import mods.betterfoliage.util.lighten import mods.betterfoliage.util.brighten
import mods.betterfoliage.util.logTextureColor
import mods.betterfoliage.util.randomI import mods.betterfoliage.util.randomI
import net.minecraft.client.renderer.RenderType import net.minecraft.client.renderer.RenderType
import net.minecraft.util.Direction.DOWN import net.minecraft.util.Direction.DOWN
import net.minecraft.util.Direction.UP import net.minecraft.util.Direction.UP
import net.minecraft.util.ResourceLocation import net.minecraft.util.ResourceLocation
import org.apache.logging.log4j.Level.INFO
import java.util.Random import java.util.Random
object StandardGrassDiscovery : ParametrizedModelDiscovery() { object StandardGrassDiscovery : ParametrizedModelDiscovery() {
override fun processModel(ctx: ModelDiscoveryContext, params: Map<String, String>) { override fun processModel(ctx: ModelDiscoveryContext, params: Map<String, String>) {
val texture = params.location("texture") ?: return val texture = params.location("texture") ?: return
val tint = params.int("tint") ?: -1 val tint = params.int("tint") ?: -1
val color = Atlas.BLOCKS.file(texture).averageHSB.lighten() val color = Atlas.BLOCKS.file(texture).averageHSB.let {
detailLogger.logTextureColor(INFO, "grass texture \"$texture\"", it)
it.brighten().asColor
}
ctx.addReplacement(StandardGrassKey(texture, tint, color)) ctx.addReplacement(StandardGrassKey(texture, tint, color))
BetterFoliage.blockTypes.grass.add(ctx.blockState) BetterFoliage.blockTypes.grass.add(ctx.blockState)
ctx.blockState.block.extendLayers() ctx.blockState.block.extendLayers()

View File

@@ -22,8 +22,12 @@ import mods.betterfoliage.resource.discovery.ModelDiscoveryContext
import mods.betterfoliage.resource.discovery.ParametrizedModelDiscovery import mods.betterfoliage.resource.discovery.ParametrizedModelDiscovery
import mods.betterfoliage.resource.generated.GeneratedLeafSprite import mods.betterfoliage.resource.generated.GeneratedLeafSprite
import mods.betterfoliage.util.Atlas import mods.betterfoliage.util.Atlas
import mods.betterfoliage.util.averageHSB
import mods.betterfoliage.util.lazy
import mods.betterfoliage.util.lazyMap import mods.betterfoliage.util.lazyMap
import mods.betterfoliage.util.logColorOverride import mods.betterfoliage.util.brighten
import mods.betterfoliage.util.logTextureColor
import mods.betterfoliage.util.saturate
import net.minecraft.client.renderer.RenderType import net.minecraft.client.renderer.RenderType
import net.minecraft.util.Direction.UP import net.minecraft.util.Direction.UP
import net.minecraft.util.ResourceLocation import net.minecraft.util.ResourceLocation
@@ -31,14 +35,19 @@ import org.apache.logging.log4j.Level.INFO
object StandardLeafDiscovery : ParametrizedModelDiscovery() { object StandardLeafDiscovery : ParametrizedModelDiscovery() {
override fun processModel(ctx: ModelDiscoveryContext, params: Map<String, String>) { override fun processModel(ctx: ModelDiscoveryContext, params: Map<String, String>) {
val leafSprite = params.location("texture-leaf") ?: return val texture = params.location("texture") ?: return
val leafType = LeafParticleRegistry.typeMappings.getType(leafSprite) ?: "default" val tint = params.int("tint") ?: -1
val generated = GeneratedLeafSprite(leafSprite, leafType) val color = Atlas.BLOCKS.file(texture).averageHSB.let {
detailLogger.logTextureColor(INFO, "leaf texture \"$texture\"", it)
it.brighten().asColor
}
val leafType = LeafParticleRegistry.typeMappings.getType(texture) ?: "default"
val generated = GeneratedLeafSprite(texture, leafType)
.register(BetterFoliage.generatedPack) .register(BetterFoliage.generatedPack)
.apply { ctx.sprites.add(this) } .apply { ctx.sprites.add(this) }
detailLogger.log(INFO, " particle $leafType") detailLogger.log(INFO, " particle $leafType")
ctx.addReplacement(StandardLeafKey(generated, leafType, null)) ctx.addReplacement(StandardLeafKey(generated, leafType, tint, color))
BetterFoliage.blockTypes.leaf.add(ctx.blockState) BetterFoliage.blockTypes.leaf.add(ctx.blockState)
} }
} }
@@ -46,10 +55,9 @@ object StandardLeafDiscovery : ParametrizedModelDiscovery() {
data class StandardLeafKey( data class StandardLeafKey(
val roundLeafTexture: ResourceLocation, val roundLeafTexture: ResourceLocation,
override val leafType: String, override val leafType: String,
override val overrideColor: Color? override val tintIndex: Int,
override val avgColor: Color
) : HalfBakedWrapperKey(), LeafParticleKey { ) : HalfBakedWrapperKey(), LeafParticleKey {
val tintIndex: Int get() = if (overrideColor == null) 0 else -1
override fun bake(ctx: ModelBakingContext, wrapped: SpecialRenderModel): SpecialRenderModel { override fun bake(ctx: ModelBakingContext, wrapped: SpecialRenderModel): SpecialRenderModel {
return StandardLeafModel(wrapped, this) return StandardLeafModel(wrapped, this)
} }
@@ -78,14 +86,16 @@ class StandardLeafModel(
val leafSpritesSnowed by SpriteSetDelegate(Atlas.BLOCKS) { idx -> val leafSpritesSnowed by SpriteSetDelegate(Atlas.BLOCKS) { idx ->
ResourceLocation(BetterFoliageMod.MOD_ID, "blocks/better_leaves_snowed_$idx") ResourceLocation(BetterFoliageMod.MOD_ID, "blocks/better_leaves_snowed_$idx")
} }
val leafModelsBase = BetterFoliage.modelManager.lazyMap { key: StandardLeafKey -> val leafModelsBase by BetterFoliage.modelManager.lazy {
Config.leaves.let { crossModelsRaw(64, it.size, it.hOffset, it.vOffset) } Config.leaves.let { crossModelsRaw(64, it.size, it.hOffset, it.vOffset) }
} }
val leafModelsNormal = BetterFoliage.modelManager.lazyMap { key: StandardLeafKey -> val leafModelsNormal = BetterFoliage.modelManager.lazyMap { key: StandardLeafKey ->
crossModelsTextured(leafModelsBase[key], key.tintIndex, true) { key.roundLeafTexture } // generated leaf textures naturally carry the color of their source textures
// no need to color the quad a second time
crossModelsTextured(leafModelsBase, Color.white, key.tintIndex, true) { key.roundLeafTexture }
} }
val leafModelsSnowed = BetterFoliage.modelManager.lazyMap { key: StandardLeafKey -> val leafModelsSnowed = BetterFoliage.modelManager.lazyMap { key: StandardLeafKey ->
crossModelsTextured(leafModelsBase[key], -1, false) { leafSpritesSnowed[it].name } crossModelsTextured(leafModelsBase, Color.white, -1, false) { leafSpritesSnowed[it].name }
} }
} }
} }

View File

@@ -25,7 +25,7 @@ import mods.betterfoliage.util.averageHSB
import mods.betterfoliage.util.idxOrNull import mods.betterfoliage.util.idxOrNull
import mods.betterfoliage.util.lazy import mods.betterfoliage.util.lazy
import mods.betterfoliage.util.lazyMap import mods.betterfoliage.util.lazyMap
import mods.betterfoliage.util.lighten import mods.betterfoliage.util.brighten
import mods.betterfoliage.util.randomI import mods.betterfoliage.util.randomI
import net.minecraft.client.renderer.RenderType import net.minecraft.client.renderer.RenderType
import net.minecraft.util.Direction import net.minecraft.util.Direction
@@ -36,7 +36,7 @@ object StandardMyceliumDiscovery : ParametrizedModelDiscovery() {
override fun processModel(ctx: ModelDiscoveryContext, params: Map<String, String>) { override fun processModel(ctx: ModelDiscoveryContext, params: Map<String, String>) {
val texture = params.location("texture") ?: return val texture = params.location("texture") ?: return
val tint = params.int("tint") ?: -1 val tint = params.int("tint") ?: -1
val color = Atlas.BLOCKS.file(texture).averageHSB.lighten(multiplier = 1.5f) val color = Atlas.BLOCKS.file(texture).averageHSB.brighten(multiplier = 1.5f).asColor
ctx.addReplacement(StandardMyceliumKey(texture, tint, color)) ctx.addReplacement(StandardMyceliumKey(texture, tint, color))
ctx.blockState.block.extendLayers() ctx.blockState.block.extendLayers()
} }

View File

@@ -1,6 +1,8 @@
package mods.betterfoliage.render.particle package mods.betterfoliage.render.particle
import com.mojang.blaze3d.vertex.IVertexBuilder import com.mojang.blaze3d.vertex.IVertexBuilder
import mods.betterfoliage.model.Color
import mods.betterfoliage.model.HSB
import mods.betterfoliage.util.Double3 import mods.betterfoliage.util.Double3
import net.minecraft.client.Minecraft import net.minecraft.client.Minecraft
import net.minecraft.client.particle.SpriteTexturedParticle import net.minecraft.client.particle.SpriteTexturedParticle
@@ -92,10 +94,16 @@ abstract class AbstractParticle(world: ClientWorld, x: Double, y: Double, z: Dou
renderVertex(coords[3], sprite.u0, sprite.v1) renderVertex(coords[3], sprite.u0, sprite.v1)
} }
fun setColor(color: Int) { fun setColor(color: Color) {
bCol = (color and 255) / 256.0f rCol = color.red / 256.0f
gCol = ((color shr 8) and 255) / 256.0f gCol = color.green / 256.0f
rCol = ((color shr 16) and 255) / 256.0f bCol = color.blue / 256.0f
} }
/**
* Set particle color to the "stronger" of the given colors, determined by higher color saturation
*/
fun setColor(color1: Color, color2: Color) =
setColor(if (color1.asHSB.saturation > color2.asHSB.saturation) color1 else color2)
} }

View File

@@ -1,6 +1,7 @@
package mods.betterfoliage.render.particle package mods.betterfoliage.render.particle
import mods.betterfoliage.config.Config import mods.betterfoliage.config.Config
import mods.betterfoliage.model.Color
import mods.betterfoliage.util.Double3 import mods.betterfoliage.util.Double3
import mods.betterfoliage.util.PI2 import mods.betterfoliage.util.PI2
import mods.betterfoliage.util.minmax import mods.betterfoliage.util.minmax
@@ -44,7 +45,7 @@ class FallingLeafParticle(
yd = -Config.fallingLeaves.speed yd = -Config.fallingLeaves.speed
quadSize = Config.fallingLeaves.size.toFloat() * 0.1f quadSize = Config.fallingLeaves.size.toFloat() * 0.1f
setColor(leaf.overrideColor?.asInt ?: blockColor) if (leaf.tintIndex == -1) setColor(leaf.avgColor) else setColor(leaf.avgColor, Color(blockColor))
sprite = LeafParticleRegistry[leaf.leafType][randomI(max = 1024)] sprite = LeafParticleRegistry[leaf.leafType][randomI(max = 1024)]
} }

View File

@@ -23,7 +23,8 @@ interface LeafBlockModel {
interface LeafParticleKey { interface LeafParticleKey {
val leafType: String val leafType: String
val overrideColor: Color? val tintIndex: Int
val avgColor: Color
} }
object LeafParticleRegistry : HasLogger(), VeryEarlyReloadListener { object LeafParticleRegistry : HasLogger(), VeryEarlyReloadListener {

View File

@@ -2,6 +2,7 @@
package mods.betterfoliage.util package mods.betterfoliage.util
import mods.betterfoliage.BetterFoliageMod import mods.betterfoliage.BetterFoliageMod
import mods.betterfoliage.model.HSB
import net.minecraft.block.BlockState import net.minecraft.block.BlockState
import net.minecraft.client.Minecraft import net.minecraft.client.Minecraft
import net.minecraft.util.ResourceLocation import net.minecraft.util.ResourceLocation
@@ -65,6 +66,11 @@ abstract class HasLogger {
val detailLogger = BetterFoliageMod.detailLogger(this) val detailLogger = BetterFoliageMod.detailLogger(this)
} }
fun Logger.logTextureColor(level: Level, description: String, avgColor: HSB) {
val rgb = avgColor.asColor
log(level, "$description average color RGB[${rgb.red},${rgb.green},${rgb.blue}], HSB[${avgColor.hue},${avgColor.saturation},${avgColor.brightness}]")
}
fun getBlockModel(state: BlockState) = Minecraft.getInstance().blockRenderer.blockModelShaper.getBlockModel(state) fun getBlockModel(state: BlockState) = Minecraft.getInstance().blockRenderer.blockModelShaper.getBlockModel(state)
/** /**
* Check if the Chunk containing the given [BlockPos] is loaded. * Check if the Chunk containing the given [BlockPos] is loaded.

View File

@@ -16,6 +16,8 @@ import java.io.IOException
import javax.imageio.ImageIO import javax.imageio.ImageIO
import kotlin.math.atan2 import kotlin.math.atan2
import kotlin.math.cos import kotlin.math.cos
import kotlin.math.max
import kotlin.math.min
import kotlin.math.sin import kotlin.math.sin
enum class Atlas(val resourceId: ResourceLocation) { enum class Atlas(val resourceId: ResourceLocation) {
@@ -107,8 +109,10 @@ val ResourceLocation.averageHSB: HSB get() = resourceManager.loadSprite(this).le
return HSB(avgHue, sumSaturation / numOpaque.toFloat(), sumBrightness / numOpaque.toFloat()) return HSB(avgHue, sumSaturation / numOpaque.toFloat(), sumBrightness / numOpaque.toFloat())
} }
fun HSB.lighten(multiplier: Float = 2.0f, ceiling: Float = 0.9f) = fun HSB.brighten(multiplier: Float = 1.5f, floor: Float = 0.1f, ceiling: Float = 0.9f) =
copy(brightness = (brightness * multiplier).coerceAtMost(ceiling)).asColor copy(brightness = (brightness * multiplier).coerceAtMost(max(ceiling, brightness)).coerceAtLeast(min(floor, brightness)))
fun HSB.saturate(multiplier: Float = 1.5f, floor: Float = 0.1f, ceiling: Float = 0.9f) =
copy(saturation = (saturation * multiplier).coerceAtMost(max(ceiling, saturation)).coerceAtLeast(min(floor, saturation)))
/** Weighted blend of 2 packed RGB colors */ /** Weighted blend of 2 packed RGB colors */
fun blendRGB(rgb1: Int, rgb2: Int, weight1: Int, weight2: Int): Int { fun blendRGB(rgb1: Int, rgb2: Int, weight1: Int, weight2: Int): Int {

View File

@@ -3,8 +3,8 @@ match block.class.extends(classOf("minecraft:oak_leaves")) setParam("type", "lea
match isParam("type", "leaf") match isParam("type", "leaf")
model.extends("minecraft:block/leaves", "minecraft:block/cube_all") model.extends("minecraft:block/leaves", "minecraft:block/cube_all")
setParam("texture-leaf", model.texture("all")) setParam("texture", model.texture("all"))
setParam("tint-leaf", model.tint("all")) setParam("tint", model.tint("all"))
end end
// Podzol // Podzol