diff --git a/src/main/kotlin/mods/betterfoliage/model/Quads.kt b/src/main/kotlin/mods/betterfoliage/model/Quads.kt index 4658385..041395e 100644 --- a/src/main/kotlin/mods/betterfoliage/model/Quads.kt +++ b/src/main/kotlin/mods/betterfoliage/model/Quads.kt @@ -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 asHSB get() = HSB.fromColor(this) + operator fun times(f: Float) = Color( alpha, (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) 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 asColor: Color get() = Color(asInt) diff --git a/src/main/kotlin/mods/betterfoliage/model/TuftMeshes.kt b/src/main/kotlin/mods/betterfoliage/model/TuftMeshes.kt index 65780c1..f36db3d 100644 --- a/src/main/kotlin/mods/betterfoliage/model/TuftMeshes.kt +++ b/src/main/kotlin/mods/betterfoliage/model/TuftMeshes.kt @@ -84,20 +84,20 @@ fun crossModelsRaw(num: Int, size: Double, hOffset: Double, vOffset: Double): Li } } -fun crossModelSingle(base: List, sprite: TextureAtlasSprite, tintIndex: Int,scrambleUV: Boolean) = +fun crossModelSingle(base: List, sprite: TextureAtlasSprite, color: Color, tint: Int, scrambleUV: Boolean) = 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) } .withOpposites() .bake(false) fun crossModelsTextured( leafBase: Iterable>, - tintIndex: Int, + color: Color, tint: Int, scrambleUV: Boolean, spriteGetter: (Int) -> ResourceLocation ) = leafBase.mapIndexed { idx, leaf -> - crossModelSingle(leaf, Atlas.BLOCKS[spriteGetter(idx)], tintIndex, scrambleUV) + crossModelSingle(leaf, Atlas.BLOCKS[spriteGetter(idx)], color, tint, scrambleUV) }.toTypedArray() fun Iterable.withOpposites() = flatMap { listOf(it, it.flipped) } diff --git a/src/main/kotlin/mods/betterfoliage/render/block/vanilla/Cactus.kt b/src/main/kotlin/mods/betterfoliage/render/block/vanilla/Cactus.kt index 68f575d..d609f1e 100644 --- a/src/main/kotlin/mods/betterfoliage/render/block/vanilla/Cactus.kt +++ b/src/main/kotlin/mods/betterfoliage/render/block/vanilla/Cactus.kt @@ -87,7 +87,7 @@ class StandardCactusModel( crossModelsRaw(64, config.size, 0.0, 0.0) .transform { rotateZ(randomD(-config.sizeVariation, config.sizeVariation)) } } - crossModelsTextured(models, -1, true) { cactusCrossSprite } + crossModelsTextured(models, Color.white, -1, true) { cactusCrossSprite } } } } \ No newline at end of file diff --git a/src/main/kotlin/mods/betterfoliage/render/block/vanilla/Grass.kt b/src/main/kotlin/mods/betterfoliage/render/block/vanilla/Grass.kt index a07723f..09315cd 100644 --- a/src/main/kotlin/mods/betterfoliage/render/block/vanilla/Grass.kt +++ b/src/main/kotlin/mods/betterfoliage/render/block/vanilla/Grass.kt @@ -28,19 +28,24 @@ import mods.betterfoliage.util.averageHSB import mods.betterfoliage.util.idxOrNull import mods.betterfoliage.util.lazy 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 net.minecraft.client.renderer.RenderType import net.minecraft.util.Direction.DOWN import net.minecraft.util.Direction.UP import net.minecraft.util.ResourceLocation +import org.apache.logging.log4j.Level.INFO import java.util.Random object StandardGrassDiscovery : ParametrizedModelDiscovery() { override fun processModel(ctx: ModelDiscoveryContext, params: Map) { val texture = params.location("texture") ?: return 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)) BetterFoliage.blockTypes.grass.add(ctx.blockState) ctx.blockState.block.extendLayers() diff --git a/src/main/kotlin/mods/betterfoliage/render/block/vanilla/Leaf.kt b/src/main/kotlin/mods/betterfoliage/render/block/vanilla/Leaf.kt index f1ba234..90c6086 100644 --- a/src/main/kotlin/mods/betterfoliage/render/block/vanilla/Leaf.kt +++ b/src/main/kotlin/mods/betterfoliage/render/block/vanilla/Leaf.kt @@ -22,8 +22,12 @@ import mods.betterfoliage.resource.discovery.ModelDiscoveryContext import mods.betterfoliage.resource.discovery.ParametrizedModelDiscovery import mods.betterfoliage.resource.generated.GeneratedLeafSprite import mods.betterfoliage.util.Atlas +import mods.betterfoliage.util.averageHSB +import mods.betterfoliage.util.lazy 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.util.Direction.UP import net.minecraft.util.ResourceLocation @@ -31,14 +35,19 @@ import org.apache.logging.log4j.Level.INFO object StandardLeafDiscovery : ParametrizedModelDiscovery() { override fun processModel(ctx: ModelDiscoveryContext, params: Map) { - val leafSprite = params.location("texture-leaf") ?: return - val leafType = LeafParticleRegistry.typeMappings.getType(leafSprite) ?: "default" - val generated = GeneratedLeafSprite(leafSprite, leafType) + val texture = params.location("texture") ?: return + val tint = params.int("tint") ?: -1 + 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) .apply { ctx.sprites.add(this) } detailLogger.log(INFO, " particle $leafType") - ctx.addReplacement(StandardLeafKey(generated, leafType, null)) + ctx.addReplacement(StandardLeafKey(generated, leafType, tint, color)) BetterFoliage.blockTypes.leaf.add(ctx.blockState) } } @@ -46,10 +55,9 @@ object StandardLeafDiscovery : ParametrizedModelDiscovery() { data class StandardLeafKey( val roundLeafTexture: ResourceLocation, override val leafType: String, - override val overrideColor: Color? + override val tintIndex: Int, + override val avgColor: Color ) : HalfBakedWrapperKey(), LeafParticleKey { - val tintIndex: Int get() = if (overrideColor == null) 0 else -1 - override fun bake(ctx: ModelBakingContext, wrapped: SpecialRenderModel): SpecialRenderModel { return StandardLeafModel(wrapped, this) } @@ -78,14 +86,16 @@ class StandardLeafModel( val leafSpritesSnowed by SpriteSetDelegate(Atlas.BLOCKS) { 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) } } 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 -> - crossModelsTextured(leafModelsBase[key], -1, false) { leafSpritesSnowed[it].name } + crossModelsTextured(leafModelsBase, Color.white, -1, false) { leafSpritesSnowed[it].name } } } } \ No newline at end of file diff --git a/src/main/kotlin/mods/betterfoliage/render/block/vanilla/Mycelium.kt b/src/main/kotlin/mods/betterfoliage/render/block/vanilla/Mycelium.kt index 6bdf67a..8e0cf83 100644 --- a/src/main/kotlin/mods/betterfoliage/render/block/vanilla/Mycelium.kt +++ b/src/main/kotlin/mods/betterfoliage/render/block/vanilla/Mycelium.kt @@ -25,7 +25,7 @@ import mods.betterfoliage.util.averageHSB import mods.betterfoliage.util.idxOrNull import mods.betterfoliage.util.lazy import mods.betterfoliage.util.lazyMap -import mods.betterfoliage.util.lighten +import mods.betterfoliage.util.brighten import mods.betterfoliage.util.randomI import net.minecraft.client.renderer.RenderType import net.minecraft.util.Direction @@ -36,7 +36,7 @@ object StandardMyceliumDiscovery : ParametrizedModelDiscovery() { override fun processModel(ctx: ModelDiscoveryContext, params: Map) { val texture = params.location("texture") ?: return 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.blockState.block.extendLayers() } diff --git a/src/main/kotlin/mods/betterfoliage/render/particle/AbstractParticle.kt b/src/main/kotlin/mods/betterfoliage/render/particle/AbstractParticle.kt index f95d516..4ba728e 100644 --- a/src/main/kotlin/mods/betterfoliage/render/particle/AbstractParticle.kt +++ b/src/main/kotlin/mods/betterfoliage/render/particle/AbstractParticle.kt @@ -1,6 +1,8 @@ package mods.betterfoliage.render.particle import com.mojang.blaze3d.vertex.IVertexBuilder +import mods.betterfoliage.model.Color +import mods.betterfoliage.model.HSB import mods.betterfoliage.util.Double3 import net.minecraft.client.Minecraft 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) } - fun setColor(color: Int) { - bCol = (color and 255) / 256.0f - gCol = ((color shr 8) and 255) / 256.0f - rCol = ((color shr 16) and 255) / 256.0f + fun setColor(color: Color) { + rCol = color.red / 256.0f + gCol = color.green / 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) } diff --git a/src/main/kotlin/mods/betterfoliage/render/particle/FallingLeaves.kt b/src/main/kotlin/mods/betterfoliage/render/particle/FallingLeaves.kt index e1d8a89..90c35e7 100644 --- a/src/main/kotlin/mods/betterfoliage/render/particle/FallingLeaves.kt +++ b/src/main/kotlin/mods/betterfoliage/render/particle/FallingLeaves.kt @@ -1,6 +1,7 @@ package mods.betterfoliage.render.particle import mods.betterfoliage.config.Config +import mods.betterfoliage.model.Color import mods.betterfoliage.util.Double3 import mods.betterfoliage.util.PI2 import mods.betterfoliage.util.minmax @@ -44,7 +45,7 @@ class FallingLeafParticle( yd = -Config.fallingLeaves.speed 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)] } diff --git a/src/main/kotlin/mods/betterfoliage/render/particle/LeafParticleRegistry.kt b/src/main/kotlin/mods/betterfoliage/render/particle/LeafParticleRegistry.kt index 0a766eb..0db5bed 100644 --- a/src/main/kotlin/mods/betterfoliage/render/particle/LeafParticleRegistry.kt +++ b/src/main/kotlin/mods/betterfoliage/render/particle/LeafParticleRegistry.kt @@ -23,7 +23,8 @@ interface LeafBlockModel { interface LeafParticleKey { val leafType: String - val overrideColor: Color? + val tintIndex: Int + val avgColor: Color } object LeafParticleRegistry : HasLogger(), VeryEarlyReloadListener { diff --git a/src/main/kotlin/mods/betterfoliage/util/Misc.kt b/src/main/kotlin/mods/betterfoliage/util/Misc.kt index a0a8af7..078d341 100644 --- a/src/main/kotlin/mods/betterfoliage/util/Misc.kt +++ b/src/main/kotlin/mods/betterfoliage/util/Misc.kt @@ -2,6 +2,7 @@ package mods.betterfoliage.util import mods.betterfoliage.BetterFoliageMod +import mods.betterfoliage.model.HSB import net.minecraft.block.BlockState import net.minecraft.client.Minecraft import net.minecraft.util.ResourceLocation @@ -65,6 +66,11 @@ abstract class HasLogger { 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) /** * Check if the Chunk containing the given [BlockPos] is loaded. diff --git a/src/main/kotlin/mods/betterfoliage/util/Sprites.kt b/src/main/kotlin/mods/betterfoliage/util/Sprites.kt index 77b73d3..1251e56 100644 --- a/src/main/kotlin/mods/betterfoliage/util/Sprites.kt +++ b/src/main/kotlin/mods/betterfoliage/util/Sprites.kt @@ -16,6 +16,8 @@ import java.io.IOException import javax.imageio.ImageIO import kotlin.math.atan2 import kotlin.math.cos +import kotlin.math.max +import kotlin.math.min import kotlin.math.sin 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()) } -fun HSB.lighten(multiplier: Float = 2.0f, ceiling: Float = 0.9f) = - copy(brightness = (brightness * multiplier).coerceAtMost(ceiling)).asColor +fun HSB.brighten(multiplier: Float = 1.5f, floor: Float = 0.1f, ceiling: Float = 0.9f) = + 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 */ fun blendRGB(rgb1: Int, rgb2: Int, weight1: Int, weight2: Int): Int { diff --git a/src/main/resources/assets/betterfoliage/config/betterfoliage/vanilla.rules b/src/main/resources/assets/betterfoliage/config/betterfoliage/vanilla.rules index 8965e41..d95a17a 100644 --- a/src/main/resources/assets/betterfoliage/config/betterfoliage/vanilla.rules +++ b/src/main/resources/assets/betterfoliage/config/betterfoliage/vanilla.rules @@ -3,8 +3,8 @@ match block.class.extends(classOf("minecraft:oak_leaves")) setParam("type", "lea match isParam("type", "leaf") model.extends("minecraft:block/leaves", "minecraft:block/cube_all") -setParam("texture-leaf", model.texture("all")) -setParam("tint-leaf", model.tint("all")) +setParam("texture", model.texture("all")) +setParam("tint", model.tint("all")) end // Podzol