[WIP] Falling leaves working

+ more cleanup
+ fix double-tinted leaves
This commit is contained in:
octarine-noise
2021-05-11 15:08:28 +02:00
parent 7168caded1
commit 835bf45f13
18 changed files with 417 additions and 214 deletions

View File

@@ -17,6 +17,8 @@ dependencies {
"minecraft"("net.minecraftforge:forge:${properties["mcVersion"]}-${properties["forgeVersion"]}") "minecraft"("net.minecraftforge:forge:${properties["mcVersion"]}-${properties["forgeVersion"]}")
"api"(fg.deobf("curse.maven:clothconfig-348521:2938583")) "api"(fg.deobf("curse.maven:clothconfig-348521:2938583"))
"implementation"(fg.deobf("curse.maven:biomesoplenty-220318:2988999"))
"implementation"("kottle:Kottle:${properties["kottleVersion"]}") "implementation"("kottle:Kottle:${properties["kottleVersion"]}")
// "implementation"("org.spongepowered:mixin:0.8-SNAPSHOT") // "implementation"("org.spongepowered:mixin:0.8-SNAPSHOT")
} }

View File

@@ -1,8 +1,8 @@
package mods.betterfoliage.mixin; package mods.betterfoliage.mixin;
import mods.betterfoliage.BetterFoliageMod; import mods.betterfoliage.BetterFoliageMod;
import mods.betterfoliage.ModelDefinitionsLoadedEvent;
import mods.betterfoliage.resource.discovery.BakeWrapperManager; import mods.betterfoliage.resource.discovery.BakeWrapperManager;
import mods.betterfoliage.resource.discovery.ModelDefinitionsLoadedEvent;
import net.minecraft.client.renderer.model.*; import net.minecraft.client.renderer.model.*;
import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.profiler.IProfiler; import net.minecraft.profiler.IProfiler;

View File

@@ -4,7 +4,6 @@ import mods.betterfoliage.chunk.ChunkOverlayManager
import mods.betterfoliage.config.BlockConfig import mods.betterfoliage.config.BlockConfig
import mods.betterfoliage.integration.OptifineCustomColors import mods.betterfoliage.integration.OptifineCustomColors
import mods.betterfoliage.integration.ShadersModIntegration import mods.betterfoliage.integration.ShadersModIntegration
import mods.betterfoliage.render.LeafWindTracker
import mods.betterfoliage.render.block.vanilla.StandardDirtDiscovery import mods.betterfoliage.render.block.vanilla.StandardDirtDiscovery
import mods.betterfoliage.render.block.vanilla.StandardDirtKey import mods.betterfoliage.render.block.vanilla.StandardDirtKey
import mods.betterfoliage.render.block.vanilla.StandardDirtModel import mods.betterfoliage.render.block.vanilla.StandardDirtModel
@@ -17,9 +16,11 @@ import mods.betterfoliage.render.block.vanilla.StandardMyceliumModel
import mods.betterfoliage.render.block.vanilla.StandardSandDiscovery import mods.betterfoliage.render.block.vanilla.StandardSandDiscovery
import mods.betterfoliage.render.block.vanilla.StandardSandModel import mods.betterfoliage.render.block.vanilla.StandardSandModel
import mods.betterfoliage.render.lighting.AoSideHelper import mods.betterfoliage.render.lighting.AoSideHelper
import mods.betterfoliage.render.particle.LeafWindTracker
import mods.betterfoliage.resource.discovery.BakeWrapperManager import mods.betterfoliage.resource.discovery.BakeWrapperManager
import mods.betterfoliage.resource.discovery.BlockTypeCache import mods.betterfoliage.resource.discovery.BlockTypeCache
import mods.betterfoliage.resource.generated.GeneratedTexturePack import mods.betterfoliage.resource.generated.GeneratedTexturePack
import mods.betterfoliage.texture.LeafParticleRegistry
import net.minecraft.block.BlockState import net.minecraft.block.BlockState
import net.minecraft.block.Blocks import net.minecraft.block.Blocks
import net.minecraft.client.renderer.RenderType import net.minecraft.client.renderer.RenderType
@@ -39,6 +40,7 @@ object Client {
fun init() { fun init() {
// discoverers // discoverers
BetterFoliageMod.bus.register(BakeWrapperManager) BetterFoliageMod.bus.register(BakeWrapperManager)
BetterFoliageMod.bus.register(LeafParticleRegistry)
listOf( listOf(
StandardLeafDiscovery, StandardLeafDiscovery,
StandardGrassDiscovery, StandardGrassDiscovery,

View File

@@ -6,6 +6,3 @@ import net.minecraft.resources.IResourceManager
import net.minecraft.util.ResourceLocation import net.minecraft.util.ResourceLocation
import net.minecraftforge.eventbus.api.Event import net.minecraftforge.eventbus.api.Event
data class ModelDefinitionsLoadedEvent(
val bakery: ModelBakery
) : Event()

View File

@@ -1,10 +1,16 @@
@file:JvmName("Hooks") @file:JvmName("Hooks")
package mods.betterfoliage package mods.betterfoliage
import mods.betterfoliage.config.Config
import mods.betterfoliage.model.getActualRenderModel
import mods.betterfoliage.render.particle.FallingLeafParticle
import mods.betterfoliage.texture.LeafBlockModel
import net.minecraft.block.Block import net.minecraft.block.Block
import net.minecraft.block.BlockState import net.minecraft.block.BlockState
import net.minecraft.client.Minecraft
import net.minecraft.client.world.ClientWorld import net.minecraft.client.world.ClientWorld
import net.minecraft.util.Direction import net.minecraft.util.Direction
import net.minecraft.util.Direction.DOWN
import net.minecraft.util.math.BlockPos import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.shapes.VoxelShape import net.minecraft.util.math.shapes.VoxelShape
import net.minecraft.world.IBlockReader import net.minecraft.world.IBlockReader
@@ -33,14 +39,17 @@ fun onRandomDisplayTick(block: Block, state: BlockState, world: World, pos: Bloc
// Math.random() < Config.risingSoul.chance) { // Math.random() < Config.risingSoul.chance) {
// EntityRisingSoulFX(world, pos).addIfValid() // EntityRisingSoulFX(world, pos).addIfValid()
// } // }
//
// if (Config.enabled && if (Config.enabled &&
// Config.fallingLeaves.enabled && Config.fallingLeaves.enabled &&
// BlockConfig.leafBlocks.matchesClass(state.block) && random.nextDouble() < Config.fallingLeaves.chance &&
// world.isAirBlock(pos + down1) && world.isAirBlock(pos.offset(DOWN))
// Math.random() < Config.fallingLeaves.chance) { ) {
// EntityFallingLeavesFX(world, pos).addIfValid() (getActualRenderModel(world, pos, state, random) as? LeafBlockModel)?.let { leafModel ->
// } val blockColor = Minecraft.getInstance().blockColors.getColor(state, world, pos, 0)
FallingLeafParticle(world, pos, leafModel.key, blockColor, random).addIfValid()
}
}
} }
fun getVoxelShapeOverride(state: BlockState, reader: IBlockReader, pos: BlockPos, dir: Direction): VoxelShape { fun getVoxelShapeOverride(state: BlockState, reader: IBlockReader, pos: BlockPos, dir: Direction): VoxelShape {

View File

@@ -30,6 +30,7 @@ object Config : DelegatingConfig(BetterFoliageMod.MOD_ID, BetterFoliageMod.MOD_I
val size by double(min=0.75, max=2.5, default=1.4).lang("size") val size by double(min=0.75, max=2.5, default=1.4).lang("size")
val dense by boolean(false) val dense by boolean(false)
val hideInternal by boolean(true) val hideInternal by boolean(true)
val saturationThreshold by double(default=0.1)
} }
object shortGrass : PopulationConfigCategory(){ object shortGrass : PopulationConfigCategory(){

View File

@@ -2,6 +2,8 @@ package mods.betterfoliage.model
import mods.betterfoliage.render.pipeline.RenderCtxBase import mods.betterfoliage.render.pipeline.RenderCtxBase
import mods.betterfoliage.util.HasLogger import mods.betterfoliage.util.HasLogger
import net.minecraft.block.BlockState
import net.minecraft.client.Minecraft
import net.minecraft.client.renderer.model.IBakedModel import net.minecraft.client.renderer.model.IBakedModel
import net.minecraft.client.renderer.model.Material import net.minecraft.client.renderer.model.Material
import net.minecraft.client.renderer.model.ModelBakery import net.minecraft.client.renderer.model.ModelBakery
@@ -9,6 +11,8 @@ import net.minecraft.client.renderer.model.VariantList
import net.minecraft.client.renderer.texture.TextureAtlasSprite import net.minecraft.client.renderer.texture.TextureAtlasSprite
import net.minecraft.util.ResourceLocation import net.minecraft.util.ResourceLocation
import net.minecraft.util.WeightedRandom import net.minecraft.util.WeightedRandom
import net.minecraft.util.math.BlockPos
import net.minecraft.world.ILightReader
import org.apache.logging.log4j.Level.WARN import org.apache.logging.log4j.Level.WARN
import java.util.Random import java.util.Random
import java.util.function.Function import java.util.function.Function
@@ -62,3 +66,12 @@ class SpecialRenderVariantList(
} }
} }
} }
fun getActualRenderModel(world: ILightReader, pos: BlockPos, state: BlockState, random: Random): SpecialRenderModel? {
val model = Minecraft.getInstance().blockRendererDispatcher.blockModelShapes.getModel(state) as? SpecialRenderModel ?: return null
if (model is SpecialRenderVariantList) {
random.setSeed(state.getPositionRandom(pos))
return model.getModel(random).model
}
return model
}

View File

@@ -1,6 +1,5 @@
package mods.betterfoliage.model package mods.betterfoliage.model
import mods.betterfoliage.render.block.vanilla.getColorOverride
import mods.betterfoliage.util.Atlas import mods.betterfoliage.util.Atlas
import mods.betterfoliage.util.Double3 import mods.betterfoliage.util.Double3
import mods.betterfoliage.util.PI2 import mods.betterfoliage.util.PI2
@@ -63,22 +62,17 @@ fun tuftModelSet(shapes: Array<TuftShapeKey>, overrideColor: Color?, spriteGette
fun fullCubeTextured( fun fullCubeTextured(
spriteLocation: ResourceLocation, spriteLocation: ResourceLocation,
overrideColor: Color?, tintIndex: Int,
scrambleUV: Boolean = true scrambleUV: Boolean = true
): List<HalfBakedQuad> { ): List<HalfBakedQuad> {
val sprite = Atlas.BLOCKS[spriteLocation] val sprite = Atlas.BLOCKS[spriteLocation]
return allDirections.map { Quad.faceQuad(it) } return allDirections.map { Quad.faceQuad(it) }
.map { if (!scrambleUV) it else it.rotateUV(randomI(max = 4)) } .map { if (!scrambleUV) it else it.rotateUV(randomI(max = 4)) }
.map { it.sprite(sprite) } .map { it.sprite(sprite) }
.map { it.colorAndIndex(overrideColor) } .map { it.colorIndex(tintIndex) }
.bake(true) .bake(true)
} }
fun fullCubeTinted(spriteLocation: ResourceLocation, threshold: Double, scrambleUV: Boolean = true): List<HalfBakedQuad> {
val overrideColor = Atlas.BLOCKS[spriteLocation].getColorOverride(threshold)
return fullCubeTextured(spriteLocation, overrideColor, scrambleUV)
}
fun crossModelsRaw(num: Int, size: Double, hOffset: Double, vOffset: Double): Array<List<Quad>> { fun crossModelsRaw(num: Int, size: Double, hOffset: Double, vOffset: Double): Array<List<Quad>> {
return Array(num) { idx -> return Array(num) { idx ->
listOf( listOf(
@@ -91,33 +85,22 @@ fun crossModelsRaw(num: Int, size: Double, hOffset: Double, vOffset: Double): Ar
} }
} }
fun crossModelSingle(base: List<Quad>, sprite: TextureAtlasSprite, overrideColor: Color?, scrambleUV: Boolean) = fun crossModelSingle(base: List<Quad>, sprite: TextureAtlasSprite, tintIndex: 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.colorAndIndex(overrideColor) } .map { it.colorIndex(tintIndex) }
.mapIndexed { idx, quad -> quad.sprite(sprite) } .mapIndexed { idx, quad -> quad.sprite(sprite) }
.withOpposites() .withOpposites()
.bake(false) .bake(false)
fun crossModelsTextured( fun crossModelsTextured(
leafBase: Array<List<Quad>>, leafBase: Array<List<Quad>>,
overrideColor: Color?, tintIndex: 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)], overrideColor, scrambleUV) crossModelSingle(leaf, Atlas.BLOCKS[spriteGetter(idx)], tintIndex, scrambleUV)
}.toTypedArray() }.toTypedArray()
fun crossModelsTinted(
leafBase: Array<List<Quad>>,
threshold: Double,
scrambleUV: Boolean = true,
spriteGetter: (Int) -> ResourceLocation
) = leafBase.mapIndexed { idx, leaf ->
val sprite = Atlas.BLOCKS[spriteGetter(idx)]
val overrideColor = sprite.getColorOverride(threshold)
crossModelSingle(leaf, sprite, overrideColor, scrambleUV)
}
fun List<Quad>.withOpposites() = flatMap { listOf(it, it.flipped) } fun List<Quad>.withOpposites() = flatMap { listOf(it, it.flipped) }
fun List<List<Quad>>.buildTufts(applyDiffuseLighting: Boolean = false) = fun List<List<Quad>>.buildTufts(applyDiffuseLighting: Boolean = false) =
map { it.withOpposites().bake(applyDiffuseLighting) }.toTypedArray() map { it.withOpposites().bake(applyDiffuseLighting) }.toTypedArray()

View File

@@ -1,13 +1,25 @@
package mods.betterfoliage.render package mods.betterfoliage.render
import com.mojang.blaze3d.vertex.IVertexBuilder
import mods.betterfoliage.BetterFoliage
import mods.betterfoliage.config.Config import mods.betterfoliage.config.Config
import mods.betterfoliage.render.old.AbstractEntityFX import mods.betterfoliage.render.old.AbstractEntityFX
import mods.betterfoliage.model.HSB import mods.betterfoliage.model.HSB
import mods.betterfoliage.model.getActualRenderModel
import mods.betterfoliage.render.particle.AbstractParticle
import mods.betterfoliage.texture.LeafParticleKey
import mods.betterfoliage.texture.LeafParticleRegistry
import mods.betterfoliage.util.Double3 import mods.betterfoliage.util.Double3
import mods.betterfoliage.util.PI2 import mods.betterfoliage.util.PI2
import mods.betterfoliage.util.get
import mods.betterfoliage.util.minmax import mods.betterfoliage.util.minmax
import mods.betterfoliage.util.randomB
import mods.betterfoliage.util.randomD import mods.betterfoliage.util.randomD
import mods.betterfoliage.util.randomF
import mods.betterfoliage.util.randomI
import net.minecraft.client.Minecraft import net.minecraft.client.Minecraft
import net.minecraft.client.particle.IParticleRenderType
import net.minecraft.client.renderer.ActiveRenderInfo
import net.minecraft.client.renderer.BufferBuilder import net.minecraft.client.renderer.BufferBuilder
import net.minecraft.util.math.BlockPos import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.MathHelper import net.minecraft.util.math.MathHelper
@@ -23,116 +35,3 @@ import kotlin.math.sin
const val rotationFactor = PI2.toFloat() / 64.0f const val rotationFactor = PI2.toFloat() / 64.0f
class EntityFallingLeavesFX(
world: World, pos: BlockPos
) : AbstractEntityFX(
world, pos.x.toDouble() + 0.5, pos.y.toDouble(), pos.z.toDouble() + 0.5
) {
companion object {
@JvmStatic val biomeBrightnessMultiplier = 0.5f
}
var particleRot = rand.nextInt(64)
var rotPositive = true
val isMirrored = (rand.nextInt() and 1) == 1
var wasCollided = false
init {
maxAge = MathHelper.floor(randomD(0.6, 1.0) * Config.fallingLeaves.lifetime * 20.0)
motionY = -Config.fallingLeaves.speed
particleScale = Config.fallingLeaves.size.toFloat() * 0.1f
val state = world.getBlockState(pos)
// val leafInfo = LeafRegistry[state, world, pos]
val blockColor = Minecraft.getInstance().blockColors.getColor(state, world, pos, 0)
// if (leafInfo != null) {
// sprite = leafInfo.particleTextures[rand.nextInt(1024)]
// calculateParticleColor(leafInfo.averageColor, blockColor)
// } else {
// sprite = LeafParticleRegistry["default"][rand.nextInt(1024)]
// setColor(blockColor)
// }
}
override val isValid: Boolean get() = (sprite != null)
override fun update() {
if (rand.nextFloat() > 0.95f) rotPositive = !rotPositive
if (age > maxAge - 20) particleAlpha = 0.05f * (maxAge - age)
if (onGround || wasCollided) {
velocity.setTo(0.0, 0.0, 0.0)
if (!wasCollided) {
age = age.coerceAtLeast(maxAge - 20)
wasCollided = true
}
} else {
velocity.setTo(cos[particleRot], 0.0, sin[particleRot]).mul(Config.fallingLeaves.perturb)
.add(LeafWindTracker.current).add(0.0, -1.0, 0.0).mul(Config.fallingLeaves.speed)
particleRot = (particleRot + (if (rotPositive) 1 else -1)) and 63
particleAngle = rotationFactor * particleRot.toFloat()
}
}
override fun render(worldRenderer: BufferBuilder, partialTickTime: Float) {
// if (Config.fallingLeaves.opacityHack) GL11.glDepthMask(true)
// renderParticleQuad(worldRenderer, partialTickTime, rotation = particleRot, isMirrored = isMirrored)
}
fun calculateParticleColor(textureAvgColor: Int, blockColor: Int) {
val texture = HSB.fromColor(textureAvgColor)
val block = HSB.fromColor(blockColor)
val weightTex = texture.saturation / (texture.saturation + block.saturation)
val weightBlock = 1.0f - weightTex
// avoid circular average for hue for performance reasons
// one of the color components should dominate anyway
val particle = HSB(
weightTex * texture.hue + weightBlock * block.hue,
weightTex * texture.saturation + weightBlock * block.saturation,
weightTex * texture.brightness + weightBlock * block.brightness * biomeBrightnessMultiplier
)
setColor(particle.asColor)
}
}
object LeafWindTracker {
var random = Random()
val target = Double3.zero
val current = Double3.zero
var nextChange: Long = 0
init {
MinecraftForge.EVENT_BUS.register(this)
}
fun changeWind(world: World) {
nextChange = world.worldInfo.gameTime + 120 + random.nextInt(80)
val direction = PI2 * random.nextDouble()
val speed = abs(random.nextGaussian()) * Config.fallingLeaves.windStrength +
(if (!world.isRaining) 0.0 else abs(random.nextGaussian()) * Config.fallingLeaves.stormStrength)
target.setTo(cos(direction) * speed, 0.0, sin(direction) * speed)
}
@SubscribeEvent
fun handleWorldTick(event: TickEvent.ClientTickEvent) {
if (event.phase == TickEvent.Phase.START) Minecraft.getInstance().world?.let { world ->
// change target wind speed
if (world.worldInfo.dayTime >= nextChange) changeWind(world)
// change current wind speed
val changeRate = if (world.isRaining) 0.015 else 0.005
current.add(
(target.x - current.x).minmax(-changeRate, changeRate),
0.0,
(target.z - current.z).minmax(-changeRate, changeRate)
)
}
}
@SubscribeEvent
fun handleWorldLoad(event: WorldEvent.Load) { if (event.world.isRemote) changeWind(event.world.world) }
}

View File

@@ -6,25 +6,25 @@ import mods.betterfoliage.config.BlockConfig
import mods.betterfoliage.config.Config import mods.betterfoliage.config.Config
import mods.betterfoliage.config.ConfigurableBlockMatcher import mods.betterfoliage.config.ConfigurableBlockMatcher
import mods.betterfoliage.config.ModelTextureList import mods.betterfoliage.config.ModelTextureList
import mods.betterfoliage.model.SpecialRenderModel
import mods.betterfoliage.render.lighting.LightingPreferredFace
import mods.betterfoliage.model.Color import mods.betterfoliage.model.Color
import mods.betterfoliage.model.HalfBakedSpecialWrapper import mods.betterfoliage.model.HalfBakedSpecialWrapper
import mods.betterfoliage.model.HalfBakedWrapperKey import mods.betterfoliage.model.HalfBakedWrapperKey
import mods.betterfoliage.model.SpecialRenderModel
import mods.betterfoliage.model.SpriteSetDelegate
import mods.betterfoliage.model.buildTufts
import mods.betterfoliage.model.fullCubeTextured
import mods.betterfoliage.model.tuftModelSet
import mods.betterfoliage.model.tuftShapeSet
import mods.betterfoliage.render.lighting.LightingPreferredFace
import mods.betterfoliage.render.pipeline.RenderCtxBase import mods.betterfoliage.render.pipeline.RenderCtxBase
import mods.betterfoliage.render.pipeline.RenderCtxVanilla import mods.betterfoliage.render.pipeline.RenderCtxVanilla
import mods.betterfoliage.resource.discovery.BakeWrapperManager import mods.betterfoliage.resource.discovery.BakeWrapperManager
import mods.betterfoliage.resource.discovery.ConfigurableModelDiscovery import mods.betterfoliage.resource.discovery.ConfigurableModelDiscovery
import mods.betterfoliage.resource.discovery.ModelBakingKey import mods.betterfoliage.resource.discovery.ModelBakingKey
import mods.betterfoliage.model.SpriteSetDelegate
import mods.betterfoliage.model.buildTufts
import mods.betterfoliage.model.fullCubeTextured
import mods.betterfoliage.model.fullCubeTinted
import mods.betterfoliage.model.tuftModelSet
import mods.betterfoliage.model.tuftShapeSet
import mods.betterfoliage.util.Atlas import mods.betterfoliage.util.Atlas
import mods.betterfoliage.util.LazyInvalidatable import mods.betterfoliage.util.LazyInvalidatable
import mods.betterfoliage.util.LazyMapInvalidatable import mods.betterfoliage.util.LazyMapInvalidatable
import mods.betterfoliage.util.averageColor
import mods.betterfoliage.util.get import mods.betterfoliage.util.get
import mods.betterfoliage.util.isSnow import mods.betterfoliage.util.isSnow
import mods.betterfoliage.util.randomI import mods.betterfoliage.util.randomI
@@ -44,7 +44,7 @@ object StandardGrassDiscovery : ConfigurableModelDiscovery() {
sprites: MutableSet<ResourceLocation>, sprites: MutableSet<ResourceLocation>,
replacements: MutableMap<ResourceLocation, ModelBakingKey> replacements: MutableMap<ResourceLocation, ModelBakingKey>
): Boolean { ): Boolean {
replacements[location] = StandardGrassKey(textureMatch[0]) replacements[location] = StandardGrassKey(textureMatch[0], null)
Client.blockTypes.grass.add(state) Client.blockTypes.grass.add(state)
// RenderTypeLookup.setRenderLayer(state.block, RenderType.getCutout()) // RenderTypeLookup.setRenderLayer(state.block, RenderType.getCutout())
return true return true
@@ -52,11 +52,17 @@ object StandardGrassDiscovery : ConfigurableModelDiscovery() {
} }
data class StandardGrassKey( data class StandardGrassKey(
val grassLocation: ResourceLocation val grassLocation: ResourceLocation,
val overrideColor: Color?
) : HalfBakedWrapperKey() { ) : HalfBakedWrapperKey() {
val tintIndex: Int get() = if (overrideColor == null) 0 else -1
override fun replace(wrapped: SpecialRenderModel): SpecialRenderModel { override fun replace(wrapped: SpecialRenderModel): SpecialRenderModel {
Atlas.BLOCKS[grassLocation].logColorOverride(detailLogger, Config.shortGrass.saturationThreshold) val grassSpriteColor = Atlas.BLOCKS[grassLocation].averageColor.let { hsb ->
return StandardGrassModel(wrapped, this) logColorOverride(BetterFoliageMod.detailLogger(this), Config.shortGrass.saturationThreshold, hsb)
hsb.colorOverride(Config.shortGrass.saturationThreshold)
}
return StandardGrassModel(wrapped, this.copy(overrideColor = grassSpriteColor))
} }
} }
@@ -101,17 +107,16 @@ class StandardGrassModel(
Config.shortGrass.let { tuftShapeSet(it.size, it.heightMin, it.heightMax, it.hOffset) } Config.shortGrass.let { tuftShapeSet(it.size, it.heightMin, it.heightMax, it.hOffset) }
} }
val grassTuftMeshesNormal = LazyMapInvalidatable(BakeWrapperManager) { key: StandardGrassKey -> val grassTuftMeshesNormal = LazyMapInvalidatable(BakeWrapperManager) { key: StandardGrassKey ->
val overrideColor = Atlas.BLOCKS[key.grassLocation].getColorOverride(Config.shortGrass.saturationThreshold) tuftModelSet(grassTuftShapes, key.overrideColor) { idx -> grassTuftSprites[randomI()] }.buildTufts()
tuftModelSet(grassTuftShapes, overrideColor) { idx -> grassTuftSprites[randomI()] }.buildTufts()
} }
val grassTuftMeshesSnowed = LazyMapInvalidatable(BakeWrapperManager) { key: StandardGrassKey -> val grassTuftMeshesSnowed = LazyMapInvalidatable(BakeWrapperManager) { key: StandardGrassKey ->
tuftModelSet(grassTuftShapes, Color.white) { idx -> grassTuftSprites[randomI()] }.buildTufts() tuftModelSet(grassTuftShapes, Color.white) { idx -> grassTuftSprites[randomI()] }.buildTufts()
} }
val grassFullBlockMeshes = LazyMapInvalidatable(BakeWrapperManager) { key: StandardGrassKey -> val grassFullBlockMeshes = LazyMapInvalidatable(BakeWrapperManager) { key: StandardGrassKey ->
Array(64) { fullCubeTinted(key.grassLocation, Config.shortGrass.saturationThreshold) } Array(64) { fullCubeTextured(key.grassLocation, key.tintIndex) }
} }
val snowFullBlockMeshes by LazyInvalidatable(BakeWrapperManager) { val snowFullBlockMeshes by LazyInvalidatable(BakeWrapperManager) {
Array(64) { fullCubeTextured(ResourceLocation("block/snow"), Color.white) } Array(64) { fullCubeTextured(ResourceLocation("block/snow"), -1) }
} }
} }
} }

View File

@@ -6,30 +6,32 @@ import mods.betterfoliage.config.BlockConfig
import mods.betterfoliage.config.Config import mods.betterfoliage.config.Config
import mods.betterfoliage.config.ConfigurableBlockMatcher import mods.betterfoliage.config.ConfigurableBlockMatcher
import mods.betterfoliage.config.ModelTextureList import mods.betterfoliage.config.ModelTextureList
import mods.betterfoliage.model.SpecialRenderModel
import mods.betterfoliage.render.lighting.RoundLeafLighting
import mods.betterfoliage.model.Color import mods.betterfoliage.model.Color
import mods.betterfoliage.model.HSB
import mods.betterfoliage.model.HalfBakedSpecialWrapper import mods.betterfoliage.model.HalfBakedSpecialWrapper
import mods.betterfoliage.model.HalfBakedWrapperKey import mods.betterfoliage.model.HalfBakedWrapperKey
import mods.betterfoliage.model.SpecialRenderModel
import mods.betterfoliage.model.SpriteSetDelegate
import mods.betterfoliage.model.crossModelsRaw
import mods.betterfoliage.model.crossModelsTextured
import mods.betterfoliage.render.lighting.RoundLeafLighting
import mods.betterfoliage.render.pipeline.RenderCtxBase import mods.betterfoliage.render.pipeline.RenderCtxBase
import mods.betterfoliage.render.pipeline.RenderCtxVanilla import mods.betterfoliage.render.pipeline.RenderCtxVanilla
import mods.betterfoliage.resource.discovery.BakeWrapperManager import mods.betterfoliage.resource.discovery.BakeWrapperManager
import mods.betterfoliage.resource.discovery.ConfigurableModelDiscovery import mods.betterfoliage.resource.discovery.ConfigurableModelDiscovery
import mods.betterfoliage.resource.discovery.ModelBakingKey import mods.betterfoliage.resource.discovery.ModelBakingKey
import mods.betterfoliage.resource.generated.GeneratedLeaf import mods.betterfoliage.resource.generated.GeneratedLeaf
import mods.betterfoliage.model.SpriteSetDelegate import mods.betterfoliage.texture.LeafBlockModel
import mods.betterfoliage.model.crossModelsRaw import mods.betterfoliage.texture.LeafParticleKey
import mods.betterfoliage.model.crossModelsTextured
import mods.betterfoliage.model.crossModelsTinted
import mods.betterfoliage.texture.LeafParticleRegistry import mods.betterfoliage.texture.LeafParticleRegistry
import mods.betterfoliage.util.Atlas import mods.betterfoliage.util.Atlas
import mods.betterfoliage.util.LazyMapInvalidatable import mods.betterfoliage.util.LazyMapInvalidatable
import mods.betterfoliage.util.averageColor import mods.betterfoliage.util.averageColor
import mods.betterfoliage.util.isSnow import mods.betterfoliage.util.isSnow
import net.minecraft.block.BlockState import net.minecraft.block.BlockState
import net.minecraft.client.renderer.texture.TextureAtlasSprite
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.DEBUG
import org.apache.logging.log4j.Level.INFO import org.apache.logging.log4j.Level.INFO
import org.apache.logging.log4j.Logger import org.apache.logging.log4j.Logger
@@ -50,13 +52,12 @@ object StandardLeafDiscovery : ConfigurableModelDiscovery() {
.apply { sprites.add(this) } .apply { sprites.add(this) }
detailLogger.log(INFO, " particle $leafType") detailLogger.log(INFO, " particle $leafType")
replacements[location] = StandardLeafKey(generated, leafType) replacements[location] = StandardLeafKey(generated, leafType, null)
return true return true
} }
} }
fun TextureAtlasSprite.logColorOverride(logger: Logger, threshold: Double) { fun logColorOverride(logger: Logger, threshold: Double, hsb: HSB) {
val hsb = averageColor
return if (hsb.saturation >= threshold) { return if (hsb.saturation >= threshold) {
logger.log(INFO, " brightness ${hsb.brightness}") logger.log(INFO, " brightness ${hsb.brightness}")
logger.log(INFO, " saturation ${hsb.saturation} >= ${threshold}, will use texture color") logger.log(INFO, " saturation ${hsb.saturation} >= ${threshold}, will use texture color")
@@ -65,24 +66,30 @@ fun TextureAtlasSprite.logColorOverride(logger: Logger, threshold: Double) {
} }
} }
fun TextureAtlasSprite.getColorOverride(threshold: Double) = averageColor.let { fun HSB.colorOverride(threshold: Double) =
if (it.saturation < threshold) null else it.copy(brightness = (it.brightness * 2.0f).coerceAtMost(0.9f)) if (saturation < threshold) null else copy(brightness = (brightness * 2.0f).coerceAtMost(0.9f)).asColor.let { Color(it) }
}?.asColor?.let { Color(it) }
data class StandardLeafKey( data class StandardLeafKey(
val roundLeafTexture: ResourceLocation, val roundLeafTexture: ResourceLocation,
val leafType: String override val leafType: String,
) : HalfBakedWrapperKey() { override val overrideColor: Color?
) : HalfBakedWrapperKey(), LeafParticleKey {
val tintIndex: Int get() = if (overrideColor == null) 0 else -1
override fun replace(wrapped: SpecialRenderModel): SpecialRenderModel { override fun replace(wrapped: SpecialRenderModel): SpecialRenderModel {
Atlas.BLOCKS[roundLeafTexture].logColorOverride(BetterFoliageMod.detailLogger(this), 0.1) val leafSpriteColor = Atlas.BLOCKS[roundLeafTexture].averageColor.let { hsb ->
return StandardLeafModel(wrapped, this) logColorOverride(BetterFoliageMod.detailLogger(this), Config.leaves.saturationThreshold, hsb)
hsb.colorOverride(Config.leaves.saturationThreshold)
}
detailLogger.log(DEBUG, "roundLeaf=$roundLeafTexture overrideColor=$leafSpriteColor")
return StandardLeafModel(wrapped, this.copy(overrideColor = leafSpriteColor))
} }
} }
class StandardLeafModel( class StandardLeafModel(
model: SpecialRenderModel, model: SpecialRenderModel,
key: StandardLeafKey override val key: StandardLeafKey
) : HalfBakedSpecialWrapper(model) { ) : HalfBakedSpecialWrapper(model), LeafBlockModel {
val leafNormal by leafModelsNormal.delegate(key) val leafNormal by leafModelsNormal.delegate(key)
val leafSnowed by leafModelsSnowed.delegate(key) val leafSnowed by leafModelsSnowed.delegate(key)
@@ -103,10 +110,10 @@ class StandardLeafModel(
Config.leaves.let { crossModelsRaw(64, it.size, it.hOffset, it.vOffset) } Config.leaves.let { crossModelsRaw(64, it.size, it.hOffset, it.vOffset) }
} }
val leafModelsNormal = LazyMapInvalidatable(BakeWrapperManager) { key: StandardLeafKey -> val leafModelsNormal = LazyMapInvalidatable(BakeWrapperManager) { key: StandardLeafKey ->
crossModelsTinted(leafModelsBase[key], Config.shortGrass.saturationThreshold) { key.roundLeafTexture } crossModelsTextured(leafModelsBase[key], key.tintIndex, true) { key.roundLeafTexture }
} }
val leafModelsSnowed = LazyMapInvalidatable(BakeWrapperManager) { key: StandardLeafKey -> val leafModelsSnowed = LazyMapInvalidatable(BakeWrapperManager) { key: StandardLeafKey ->
crossModelsTextured(leafModelsBase[key], Color.white, false) { leafSpritesSnowed[it].name } crossModelsTextured(leafModelsBase[key], -1, false) { leafSpritesSnowed[it].name }
} }
} }
} }

View File

@@ -0,0 +1,101 @@
package mods.betterfoliage.render.particle
import com.mojang.blaze3d.vertex.IVertexBuilder
import mods.betterfoliage.util.Double3
import net.minecraft.client.Minecraft
import net.minecraft.client.particle.SpriteTexturedParticle
import net.minecraft.client.renderer.ActiveRenderInfo
import net.minecraft.client.renderer.Vector3f
import net.minecraft.client.renderer.texture.TextureAtlasSprite
import net.minecraft.util.math.MathHelper
import net.minecraft.world.World
abstract class AbstractParticle(world: World, x: Double, y: Double, z: Double) : SpriteTexturedParticle(world, x, y, z) {
companion object {
// @JvmStatic val sin = Array(64) { idx -> Math.sin(PI2 / 64.0 * idx) }
// @JvmStatic val cos = Array(64) { idx -> Math.cos(PI2 / 64.0 * idx) }
}
val billboardRot = Pair(Double3.zero, Double3.zero)
val currentPos = Double3.zero
val prevPos = Double3.zero
val velocity = Double3.zero
override fun tick() {
super.tick()
currentPos.setTo(posX, posY, posZ)
prevPos.setTo(prevPosX, prevPosY, prevPosZ)
velocity.setTo(motionX, motionY, motionZ)
update()
posX = currentPos.x; posY = currentPos.y; posZ = currentPos.z;
motionX = velocity.x; motionY = velocity.y; motionZ = velocity.z;
}
/** Update particle on world tick. */
abstract fun update()
/** True if the particle is renderable. */
abstract val isValid: Boolean
/** Add the particle to the effect renderer if it is valid. */
fun addIfValid() { if (isValid) Minecraft.getInstance().particles.addEffect(this) }
override fun renderParticle(vertexBuilder: IVertexBuilder, camera: ActiveRenderInfo, tickDelta: Float) {
super.renderParticle(vertexBuilder, camera, tickDelta)
}
/**
* Render a particle quad.
*
* @param[tessellator] the [Tessellator] instance to use
* @param[tickDelta] partial tick time
* @param[currentPos] render position
* @param[prevPos] previous tick position for interpolation
* @param[size] particle size
* @param[currentAngle] viewpoint-dependent particle rotation (64 steps)
* @param[sprite] particle texture
* @param[isMirrored] mirror particle texture along V-axis
* @param[alpha] aplha blending
*/
fun renderParticleQuad(vertexConsumer: IVertexBuilder,
camera: ActiveRenderInfo,
tickDelta: Float,
currentPos: Double3 = this.currentPos,
prevPos: Double3 = this.prevPos,
size: Double = particleScale.toDouble(),
currentAngle: Float = this.particleAngle,
prevAngle: Float = this.prevParticleAngle,
sprite: TextureAtlasSprite = this.sprite,
alpha: Float = this.particleAlpha) {
val center = Double3.lerp(tickDelta.toDouble(), prevPos, currentPos)
val angle = MathHelper.lerp(tickDelta, prevAngle, currentAngle)
val rotation = camera.rotation.copy().apply { multiply(Vector3f.ZP.rotation(angle)) }
val lightmapCoord = getBrightnessForRender(tickDelta)
val coords = arrayOf(
Double3(-1.0, -1.0, 0.0),
Double3(-1.0, 1.0, 0.0),
Double3(1.0, 1.0, 0.0),
Double3(1.0, -1.0, 0.0)
).map { it.rotate(rotation).mul(size).add(center).sub(camera.projectedView.x, camera.projectedView.y, camera.projectedView.z) }
fun renderVertex(vertex: Double3, u: Float, v: Float) = vertexConsumer
.pos(vertex.x, vertex.y, vertex.z).tex(u, v)
.color(particleRed, particleGreen, particleBlue, alpha).lightmap(lightmapCoord)
.endVertex()
renderVertex(coords[0], sprite.maxU, sprite.maxV)
renderVertex(coords[1], sprite.maxU, sprite.minV)
renderVertex(coords[2], sprite.minU, sprite.minV)
renderVertex(coords[3], sprite.minU, sprite.maxV)
}
fun setColor(color: Int) {
particleBlue = (color and 255) / 256.0f
particleGreen = ((color shr 8) and 255) / 256.0f
particleRed = ((color shr 16) and 255) / 256.0f
}
}

View File

@@ -0,0 +1,132 @@
package mods.betterfoliage.render.particle
import mods.betterfoliage.config.Config
import mods.betterfoliage.model.HSB
import mods.betterfoliage.texture.LeafParticleKey
import mods.betterfoliage.texture.LeafParticleRegistry
import mods.betterfoliage.util.Double3
import mods.betterfoliage.util.PI2
import mods.betterfoliage.util.minmax
import mods.betterfoliage.util.randomB
import mods.betterfoliage.util.randomD
import mods.betterfoliage.util.randomF
import mods.betterfoliage.util.randomI
import net.minecraft.client.Minecraft
import net.minecraft.client.particle.IParticleRenderType
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.MathHelper
import net.minecraft.world.World
import net.minecraftforge.common.MinecraftForge
import net.minecraftforge.event.TickEvent
import net.minecraftforge.event.world.WorldEvent
import net.minecraftforge.eventbus.api.SubscribeEvent
import java.util.Random
import kotlin.math.abs
import kotlin.math.cos
import kotlin.math.sin
class FallingLeafParticle(
world: World, pos: BlockPos, leaf: LeafParticleKey, blockColor: Int, random: Random
) : AbstractParticle(
world, pos.x.toDouble() + 0.5, pos.y.toDouble(), pos.z.toDouble() + 0.5
) {
companion object {
@JvmStatic val biomeBrightnessMultiplier = 0.5f
}
var rotationSpeed = random.randomF(min = PI2 / 80.0, max = PI2 / 50.0)
val isMirrored = randomB()
var wasCollided = false
init {
particleAngle = random.randomF(max = PI2)
prevParticleAngle = particleAngle - rotationSpeed
maxAge = MathHelper.floor(randomD(0.6, 1.0) * Config.fallingLeaves.lifetime * 20.0)
motionY = -Config.fallingLeaves.speed
particleScale = Config.fallingLeaves.size.toFloat() * 0.1f
setColor(leaf.overrideColor?.asInt ?: blockColor)
sprite = LeafParticleRegistry[leaf.leafType][randomI(max = 1024)]
}
override val isValid: Boolean get() = (sprite != null)
override fun update() {
if (rand.nextFloat() > 0.95f) rotationSpeed *= -1.0f
if (age > maxAge - 20) particleAlpha = 0.05f * (maxAge - age)
if (onGround || wasCollided) {
velocity.setTo(0.0, 0.0, 0.0)
if (!wasCollided) {
age = age.coerceAtLeast(maxAge - 20)
wasCollided = true
}
} else {
val cosRotation = cos(particleAngle).toDouble(); val sinRotation = sin(particleAngle).toDouble()
velocity.setTo(cosRotation, 0.0, sinRotation).mul(Config.fallingLeaves.perturb)
.add(LeafWindTracker.current).add(0.0, -1.0, 0.0).mul(Config.fallingLeaves.speed)
prevParticleAngle = particleAngle
particleAngle += rotationSpeed
}
}
fun calculateParticleColor(textureAvgColor: Int, blockColor: Int) {
val texture = HSB.fromColor(textureAvgColor)
val block = HSB.fromColor(blockColor)
val weightTex = texture.saturation / (texture.saturation + block.saturation)
val weightBlock = 1.0f - weightTex
// avoid circular average for hue for performance reasons
// one of the color components should dominate anyway
val particle = HSB(
weightTex * texture.hue + weightBlock * block.hue,
weightTex * texture.saturation + weightBlock * block.saturation,
weightTex * texture.brightness + weightBlock * block.brightness * biomeBrightnessMultiplier
)
setColor(particle.asColor)
}
override fun getRenderType(): IParticleRenderType = IParticleRenderType.PARTICLE_SHEET_TRANSLUCENT
}
object LeafWindTracker {
var random = Random()
val target = Double3.zero
val current = Double3.zero
var nextChange: Long = 0
init {
MinecraftForge.EVENT_BUS.register(this)
}
fun changeWind(world: World) {
nextChange = world.worldInfo.gameTime + 120 + random.nextInt(80)
val direction = PI2 * random.nextDouble()
val speed = abs(random.nextGaussian()) * Config.fallingLeaves.windStrength +
(if (!world.isRaining) 0.0 else abs(random.nextGaussian()) * Config.fallingLeaves.stormStrength)
target.setTo(cos(direction) * speed, 0.0, sin(direction) * speed)
}
@SubscribeEvent
fun handleWorldTick(event: TickEvent.ClientTickEvent) {
if (event.phase == TickEvent.Phase.START) Minecraft.getInstance().world?.let { world ->
// change target wind speed
if (world.worldInfo.dayTime >= nextChange) changeWind(world)
// change current wind speed
val changeRate = if (world.isRaining) 0.015 else 0.005
current.add(
(target.x - current.x).minmax(-changeRate, changeRate),
0.0,
(target.z - current.z).minmax(-changeRate, changeRate)
)
}
}
@SubscribeEvent
fun handleWorldLoad(event: WorldEvent.Load) { if (event.world.isRemote) changeWind(event.world.world) }
}

View File

@@ -1,6 +1,5 @@
package mods.betterfoliage.resource.discovery package mods.betterfoliage.resource.discovery
import mods.betterfoliage.ModelDefinitionsLoadedEvent
import mods.betterfoliage.model.SpecialRenderVariantList import mods.betterfoliage.model.SpecialRenderVariantList
import mods.betterfoliage.util.Atlas import mods.betterfoliage.util.Atlas
import mods.betterfoliage.util.HasLogger import mods.betterfoliage.util.HasLogger
@@ -16,12 +15,18 @@ import net.minecraft.client.renderer.texture.TextureAtlasSprite
import net.minecraft.util.ResourceLocation import net.minecraft.util.ResourceLocation
import net.minecraftforge.client.event.ModelBakeEvent import net.minecraftforge.client.event.ModelBakeEvent
import net.minecraftforge.client.event.TextureStitchEvent import net.minecraftforge.client.event.TextureStitchEvent
import net.minecraftforge.eventbus.api.Event
import net.minecraftforge.eventbus.api.EventPriority
import net.minecraftforge.eventbus.api.SubscribeEvent import net.minecraftforge.eventbus.api.SubscribeEvent
import net.minecraftforge.fml.loading.progress.StartupMessageManager import net.minecraftforge.fml.loading.progress.StartupMessageManager
import org.apache.logging.log4j.Level.INFO import org.apache.logging.log4j.Level.INFO
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
import java.util.function.Function import java.util.function.Function
data class ModelDefinitionsLoadedEvent(
val bakery: ModelBakery
) : Event()
interface ModelDiscovery { interface ModelDiscovery {
fun onModelsLoaded( fun onModelsLoaded(
bakery: ModelBakery, bakery: ModelBakery,
@@ -50,7 +55,7 @@ object BakeWrapperManager : Invalidator, HasLogger() {
private val replacements = mutableMapOf<ResourceLocation, ModelBakingKey>() private val replacements = mutableMapOf<ResourceLocation, ModelBakingKey>()
private val sprites = mutableSetOf<ResourceLocation>() private val sprites = mutableSetOf<ResourceLocation>()
@SubscribeEvent @SubscribeEvent(priority = EventPriority.LOWEST)
fun handleModelLoad(event: ModelDefinitionsLoadedEvent) { fun handleModelLoad(event: ModelDefinitionsLoadedEvent) {
modelsValid.invalidate() modelsValid.invalidate()
StartupMessageManager.addModMessage("BetterFoliage: discovering models") StartupMessageManager.addModMessage("BetterFoliage: discovering models")

View File

@@ -1,43 +1,70 @@
package mods.betterfoliage.texture package mods.betterfoliage.texture
import mods.betterfoliage.BetterFoliageMod import mods.betterfoliage.BetterFoliageMod
import mods.betterfoliage.model.Color
import mods.betterfoliage.model.FixedSpriteSet
import mods.betterfoliage.model.SpriteSet
import mods.betterfoliage.resource.discovery.ModelDefinitionsLoadedEvent
import mods.betterfoliage.util.Atlas import mods.betterfoliage.util.Atlas
import mods.betterfoliage.util.HasLogger
import mods.betterfoliage.util.get import mods.betterfoliage.util.get
import mods.betterfoliage.util.getLines import mods.betterfoliage.util.getLines
import mods.betterfoliage.util.resourceManager import mods.betterfoliage.util.resourceManager
import mods.betterfoliage.util.stripStart import mods.betterfoliage.util.stripStart
import net.minecraft.client.renderer.texture.TextureAtlasSprite import net.minecraft.client.renderer.texture.MissingTextureSprite
import net.minecraft.util.ResourceLocation import net.minecraft.util.ResourceLocation
import java.util.concurrent.CompletableFuture import net.minecraftforge.client.event.TextureStitchEvent
import net.minecraftforge.eventbus.api.SubscribeEvent
import org.apache.logging.log4j.Level
object LeafParticleRegistry { interface LeafBlockModel {
val targetAtlas = Atlas.PARTICLES val key: LeafParticleKey
}
interface LeafParticleKey {
val leafType: String
val overrideColor: Color?
}
object LeafParticleRegistry : HasLogger() {
val typeMappings = TextureMatcher() val typeMappings = TextureMatcher()
// val particles = hashMapOf<String, SpriteSet>() val particles = hashMapOf<String, SpriteSet>()
val futures = mutableMapOf<String, List<CompletableFuture<TextureAtlasSprite>>>() operator fun get(type: String) = particles[type] ?: particles["default"]!!
// operator fun get(type: String) = particles[type] ?: particles["default"]!! @SubscribeEvent
fun handleModelLoad(event: ModelDefinitionsLoadedEvent) {
fun discovery() {
typeMappings.loadMappings(ResourceLocation(BetterFoliageMod.MOD_ID, "leaf_texture_mappings.cfg")) typeMappings.loadMappings(ResourceLocation(BetterFoliageMod.MOD_ID, "leaf_texture_mappings.cfg"))
}
@SubscribeEvent
fun handlePreStitch(event: TextureStitchEvent.Pre) {
if (event.map.textureLocation == Atlas.PARTICLES.resourceId) {
(typeMappings.mappings.map { it.type } + "default").distinct().forEach { leafType -> (typeMappings.mappings.map { it.type } + "default").distinct().forEach { leafType ->
val ids = (0 until 16).map { idx -> ResourceLocation(BetterFoliageMod.MOD_ID, "falling_leaf_${leafType}_$idx") } val locations = (0 until 16).map { idx ->
val wids = ids.map { Atlas.PARTICLES.file(it) } ResourceLocation(BetterFoliageMod.MOD_ID, "particle/falling_leaf_${leafType}_$idx")
// futures[leafType] = (0 until 16).map { idx -> ResourceLocation(BetterFoliageMod.MOD_ID, "falling_leaf_${leafType}_$idx") } }.filter { resourceManager.hasResource(Atlas.PARTICLES.file(it)) }
// .filter { manager.hasResource(Atlas.PARTICLES.wrap(it)) }
// .map { atlasFuture.sprite(it) } detailLogger.log(Level.INFO, "Registering sprites for leaf particle type [$leafType], ${locations.size} sprites found")
locations.forEach { event.addSprite(it) }
}
} }
} }
fun cleanup() { @SubscribeEvent
// futures.forEach { leafType, spriteFutures -> fun handlePostStitch(event: TextureStitchEvent.Post) {
// val sprites = spriteFutures.filter { !it.isCompletedExceptionally }.map { it.get() } if (event.map.textureLocation == Atlas.PARTICLES.resourceId) {
// if (sprites.isNotEmpty()) particles[leafType] = FixedSpriteSet(sprites) (typeMappings.mappings.map { it.type } + "default").distinct().forEach { leafType ->
// } val sprites = (0 until 16).map { idx ->
// if (particles["default"] == null) particles["default"] = FixedSpriteSet(listOf(atlasFuture.missing.get()!!)) ResourceLocation(BetterFoliageMod.MOD_ID, "particle/falling_leaf_${leafType}_$idx")
}
.map { event.map.getSprite(it) }
.filter { it !is MissingTextureSprite }
detailLogger.log(Level.INFO, "Leaf particle type [$leafType], ${sprites.size} sprites in atlas")
particles[leafType] = FixedSpriteSet(sprites)
}
}
} }
} }
class TextureMatcher { class TextureMatcher {
@@ -61,7 +88,13 @@ class TextureMatcher {
if (line2.size == 2) { if (line2.size == 2) {
val mapping = line2[0].trim().split(':') val mapping = line2[0].trim().split(':')
if (mapping.size == 1) mappings.add(Mapping(null, mapping[0].trim(), line2[1].trim())) if (mapping.size == 1) mappings.add(Mapping(null, mapping[0].trim(), line2[1].trim()))
else if (mapping.size == 2) mappings.add(Mapping(mapping[0].trim(), mapping[1].trim(), line2[1].trim())) else if (mapping.size == 2) mappings.add(
Mapping(
mapping[0].trim(),
mapping[1].trim(),
line2[1].trim()
)
)
} }
} }
} }

View File

@@ -1,5 +1,6 @@
package mods.betterfoliage.util package mods.betterfoliage.util
import net.minecraft.client.renderer.Quaternion
import net.minecraft.util.Direction import net.minecraft.util.Direction
import net.minecraft.util.Direction.* import net.minecraft.util.Direction.*
import net.minecraft.util.Direction.Axis.* import net.minecraft.util.Direction.Axis.*
@@ -66,6 +67,7 @@ data class Double3(var x: Double, var y: Double, var z: Double) {
val zero: Double3 get() = Double3(0.0, 0.0, 0.0) val zero: Double3 get() = Double3(0.0, 0.0, 0.0)
fun weight(v1: Double3, weight1: Double, v2: Double3, weight2: Double) = fun weight(v1: Double3, weight1: Double, v2: Double3, weight2: Double) =
Double3(v1.x * weight1 + v2.x * weight2, v1.y * weight1 + v2.y * weight2, v1.z * weight1 + v2.z * weight2) Double3(v1.x * weight1 + v2.x * weight2, v1.y * weight1 + v2.y * weight2, v1.z * weight1 + v2.z * weight2)
fun lerp(delta: Double, first: Double3, second: Double3) = first + (second - first) * delta
} }
// immutable operations // immutable operations
@@ -82,6 +84,13 @@ data class Double3(var x: Double, var y: Double, var z: Double) {
rot.rotatedComponent(SOUTH, x, y, z) rot.rotatedComponent(SOUTH, x, y, z)
) )
/** Rotate vector by the given [Quaternion] */
fun rotate(quat: Quaternion) =
quat.copy()
.apply { multiply(Quaternion(x, y, z, 0.0F)) }
.apply { multiply(quat.copy().apply(Quaternion::conjugate)) }
.let { Double3(it.x, it.y, it.z) }
// mutable operations // mutable operations
fun setTo(other: Double3): Double3 { x = other.x; y = other.y; z = other.z; return this } fun setTo(other: Double3): Double3 { x = other.x; y = other.y; z = other.z; return this }
fun setTo(x: Double, y: Double, z: Double): Double3 { this.x = x; this.y = y; this.z = z; return this } fun setTo(x: Double, y: Double, z: Double): Double3 { this.x = x; this.y = y; this.z = z; return this }

View File

@@ -7,7 +7,12 @@ val random = Random(System.nanoTime())
fun randomB() = random.nextBoolean() fun randomB() = random.nextBoolean()
fun randomI(min: Int = 0, max: Int = Int.MAX_VALUE) = min + random.nextInt(max - min) fun randomI(min: Int = 0, max: Int = Int.MAX_VALUE) = min + random.nextInt(max - min)
fun randomD(min: Double = 0.0, max: Double = 1.0) = random.nextDouble() * (max - min) + min fun randomF(min: Float = 0.0f, max: Float = 1.0f) = random.randomF(min, max)
fun randomD(min: Double = 0.0, max: Double = 1.0) = random.randomD(min, max)
fun Random.randomF(min: Float = 0.0f, max: Float = 1.0f) = nextFloat() * (max - min) + min
fun Random.randomF(min: Double = 0.0, max: Double = 1.0) = randomF(min.toFloat(), max.toFloat())
fun Random.randomD(min: Double = 0.0, max: Double = 1.0) = nextDouble() * (max - min) + min
fun semiRandom(x: Int, y: Int, z: Int, seed: Int): Int { fun semiRandom(x: Int, y: Int, z: Int, seed: Int): Int {
var value = (x * x + y * y + z * z + x * y + y * z + z * x + (seed * seed)) var value = (x * x + y * y + z * z + x * y + y * z + z * x + (seed * seed))

View File

@@ -1,4 +1,4 @@
minecraft:block/leaves,all minecraft:block/leaves,all
minecraft:block/cube_all,all minecraft:block/cube_all,all
biomesoplenty:block/leaves_overlay,under biomesoplenty:block/leaves_overlay,leaves