From 835bf45f1342ac4f89816088b52b03a763046a46 Mon Sep 17 00:00:00 2001 From: octarine-noise Date: Tue, 11 May 2021 15:08:28 +0200 Subject: [PATCH] [WIP] Falling leaves working + more cleanup + fix double-tinted leaves --- build.gradle.kts | 2 + .../betterfoliage/mixin/MixinModelBakery.java | 2 +- src/main/kotlin/mods/betterfoliage/Client.kt | 4 +- src/main/kotlin/mods/betterfoliage/Events.kt | 3 - src/main/kotlin/mods/betterfoliage/Hooks.kt | 25 ++-- .../mods/betterfoliage/config/Config.kt | 1 + .../model/SpecialRenderModels.kt | 13 ++ .../mods/betterfoliage/model/TuftMeshes.kt | 29 +--- .../render/EntityFallingLeavesFX.kt | 125 ++--------------- .../render/block/vanilla/Grass.kt | 37 ++--- .../render/block/vanilla/Leaf.kt | 49 ++++--- .../render/particle/AbstractParticle.kt | 101 ++++++++++++++ .../render/particle/FallingLeaves.kt | 132 ++++++++++++++++++ .../resource/discovery/BakingLifecycle.kt | 9 +- .../texture/LeafParticleRegistry.kt | 81 +++++++---- .../mods/betterfoliage/util/Geometry.kt | 9 ++ .../kotlin/mods/betterfoliage/util/Random.kt | 7 +- .../betterfoliage/leaves_models_default.cfg | 2 +- 18 files changed, 417 insertions(+), 214 deletions(-) create mode 100644 src/main/kotlin/mods/betterfoliage/render/particle/AbstractParticle.kt create mode 100644 src/main/kotlin/mods/betterfoliage/render/particle/FallingLeaves.kt diff --git a/build.gradle.kts b/build.gradle.kts index 96e01b4..f9881ef 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -17,6 +17,8 @@ dependencies { "minecraft"("net.minecraftforge:forge:${properties["mcVersion"]}-${properties["forgeVersion"]}") "api"(fg.deobf("curse.maven:clothconfig-348521:2938583")) + + "implementation"(fg.deobf("curse.maven:biomesoplenty-220318:2988999")) "implementation"("kottle:Kottle:${properties["kottleVersion"]}") // "implementation"("org.spongepowered:mixin:0.8-SNAPSHOT") } diff --git a/src/main/java/mods/betterfoliage/mixin/MixinModelBakery.java b/src/main/java/mods/betterfoliage/mixin/MixinModelBakery.java index 855d3cc..590c37c 100644 --- a/src/main/java/mods/betterfoliage/mixin/MixinModelBakery.java +++ b/src/main/java/mods/betterfoliage/mixin/MixinModelBakery.java @@ -1,8 +1,8 @@ package mods.betterfoliage.mixin; import mods.betterfoliage.BetterFoliageMod; -import mods.betterfoliage.ModelDefinitionsLoadedEvent; import mods.betterfoliage.resource.discovery.BakeWrapperManager; +import mods.betterfoliage.resource.discovery.ModelDefinitionsLoadedEvent; import net.minecraft.client.renderer.model.*; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.profiler.IProfiler; diff --git a/src/main/kotlin/mods/betterfoliage/Client.kt b/src/main/kotlin/mods/betterfoliage/Client.kt index ef755d2..77372d3 100644 --- a/src/main/kotlin/mods/betterfoliage/Client.kt +++ b/src/main/kotlin/mods/betterfoliage/Client.kt @@ -4,7 +4,6 @@ import mods.betterfoliage.chunk.ChunkOverlayManager import mods.betterfoliage.config.BlockConfig import mods.betterfoliage.integration.OptifineCustomColors import mods.betterfoliage.integration.ShadersModIntegration -import mods.betterfoliage.render.LeafWindTracker import mods.betterfoliage.render.block.vanilla.StandardDirtDiscovery import mods.betterfoliage.render.block.vanilla.StandardDirtKey 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.StandardSandModel import mods.betterfoliage.render.lighting.AoSideHelper +import mods.betterfoliage.render.particle.LeafWindTracker import mods.betterfoliage.resource.discovery.BakeWrapperManager import mods.betterfoliage.resource.discovery.BlockTypeCache import mods.betterfoliage.resource.generated.GeneratedTexturePack +import mods.betterfoliage.texture.LeafParticleRegistry import net.minecraft.block.BlockState import net.minecraft.block.Blocks import net.minecraft.client.renderer.RenderType @@ -39,6 +40,7 @@ object Client { fun init() { // discoverers BetterFoliageMod.bus.register(BakeWrapperManager) + BetterFoliageMod.bus.register(LeafParticleRegistry) listOf( StandardLeafDiscovery, StandardGrassDiscovery, diff --git a/src/main/kotlin/mods/betterfoliage/Events.kt b/src/main/kotlin/mods/betterfoliage/Events.kt index b638d1f..c27e57b 100644 --- a/src/main/kotlin/mods/betterfoliage/Events.kt +++ b/src/main/kotlin/mods/betterfoliage/Events.kt @@ -6,6 +6,3 @@ import net.minecraft.resources.IResourceManager import net.minecraft.util.ResourceLocation import net.minecraftforge.eventbus.api.Event -data class ModelDefinitionsLoadedEvent( - val bakery: ModelBakery -) : Event() \ No newline at end of file diff --git a/src/main/kotlin/mods/betterfoliage/Hooks.kt b/src/main/kotlin/mods/betterfoliage/Hooks.kt index f984317..76a91ee 100644 --- a/src/main/kotlin/mods/betterfoliage/Hooks.kt +++ b/src/main/kotlin/mods/betterfoliage/Hooks.kt @@ -1,10 +1,16 @@ @file:JvmName("Hooks") 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.BlockState +import net.minecraft.client.Minecraft import net.minecraft.client.world.ClientWorld import net.minecraft.util.Direction +import net.minecraft.util.Direction.DOWN import net.minecraft.util.math.BlockPos import net.minecraft.util.math.shapes.VoxelShape import net.minecraft.world.IBlockReader @@ -33,14 +39,17 @@ fun onRandomDisplayTick(block: Block, state: BlockState, world: World, pos: Bloc // Math.random() < Config.risingSoul.chance) { // EntityRisingSoulFX(world, pos).addIfValid() // } -// -// if (Config.enabled && -// Config.fallingLeaves.enabled && -// BlockConfig.leafBlocks.matchesClass(state.block) && -// world.isAirBlock(pos + down1) && -// Math.random() < Config.fallingLeaves.chance) { -// EntityFallingLeavesFX(world, pos).addIfValid() -// } + + if (Config.enabled && + Config.fallingLeaves.enabled && + random.nextDouble() < Config.fallingLeaves.chance && + world.isAirBlock(pos.offset(DOWN)) + ) { + (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 { diff --git a/src/main/kotlin/mods/betterfoliage/config/Config.kt b/src/main/kotlin/mods/betterfoliage/config/Config.kt index 14f44c8..27f7158 100644 --- a/src/main/kotlin/mods/betterfoliage/config/Config.kt +++ b/src/main/kotlin/mods/betterfoliage/config/Config.kt @@ -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 dense by boolean(false) val hideInternal by boolean(true) + val saturationThreshold by double(default=0.1) } object shortGrass : PopulationConfigCategory(){ diff --git a/src/main/kotlin/mods/betterfoliage/model/SpecialRenderModels.kt b/src/main/kotlin/mods/betterfoliage/model/SpecialRenderModels.kt index 1b0d908..46fbd70 100644 --- a/src/main/kotlin/mods/betterfoliage/model/SpecialRenderModels.kt +++ b/src/main/kotlin/mods/betterfoliage/model/SpecialRenderModels.kt @@ -2,6 +2,8 @@ package mods.betterfoliage.model import mods.betterfoliage.render.pipeline.RenderCtxBase 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.Material 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.util.ResourceLocation import net.minecraft.util.WeightedRandom +import net.minecraft.util.math.BlockPos +import net.minecraft.world.ILightReader import org.apache.logging.log4j.Level.WARN import java.util.Random import java.util.function.Function @@ -61,4 +65,13 @@ class SpecialRenderVariantList( return SpecialRenderVariantList(weightedSpecials, weightedSpecials[0].model) } } +} + +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 } \ No newline at end of file diff --git a/src/main/kotlin/mods/betterfoliage/model/TuftMeshes.kt b/src/main/kotlin/mods/betterfoliage/model/TuftMeshes.kt index c169f9b..6e2c8da 100644 --- a/src/main/kotlin/mods/betterfoliage/model/TuftMeshes.kt +++ b/src/main/kotlin/mods/betterfoliage/model/TuftMeshes.kt @@ -1,6 +1,5 @@ package mods.betterfoliage.model -import mods.betterfoliage.render.block.vanilla.getColorOverride import mods.betterfoliage.util.Atlas import mods.betterfoliage.util.Double3 import mods.betterfoliage.util.PI2 @@ -63,22 +62,17 @@ fun tuftModelSet(shapes: Array, overrideColor: Color?, spriteGette fun fullCubeTextured( spriteLocation: ResourceLocation, - overrideColor: Color?, + tintIndex: Int, scrambleUV: Boolean = true ): List { val sprite = Atlas.BLOCKS[spriteLocation] return allDirections.map { Quad.faceQuad(it) } .map { if (!scrambleUV) it else it.rotateUV(randomI(max = 4)) } .map { it.sprite(sprite) } - .map { it.colorAndIndex(overrideColor) } + .map { it.colorIndex(tintIndex) } .bake(true) } -fun fullCubeTinted(spriteLocation: ResourceLocation, threshold: Double, scrambleUV: Boolean = true): List { - val overrideColor = Atlas.BLOCKS[spriteLocation].getColorOverride(threshold) - return fullCubeTextured(spriteLocation, overrideColor, scrambleUV) -} - fun crossModelsRaw(num: Int, size: Double, hOffset: Double, vOffset: Double): Array> { return Array(num) { idx -> listOf( @@ -91,33 +85,22 @@ fun crossModelsRaw(num: Int, size: Double, hOffset: Double, vOffset: Double): Ar } } -fun crossModelSingle(base: List, sprite: TextureAtlasSprite, overrideColor: Color?, scrambleUV: Boolean) = +fun crossModelSingle(base: List, sprite: TextureAtlasSprite, tintIndex: Int,scrambleUV: Boolean) = 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) } .withOpposites() .bake(false) fun crossModelsTextured( leafBase: Array>, - overrideColor: Color?, + tintIndex: Int, scrambleUV: Boolean, spriteGetter: (Int) -> ResourceLocation ) = leafBase.mapIndexed { idx, leaf -> - crossModelSingle(leaf, Atlas.BLOCKS[spriteGetter(idx)], overrideColor, scrambleUV) + crossModelSingle(leaf, Atlas.BLOCKS[spriteGetter(idx)], tintIndex, scrambleUV) }.toTypedArray() -fun crossModelsTinted( - leafBase: Array>, - 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.withOpposites() = flatMap { listOf(it, it.flipped) } fun List>.buildTufts(applyDiffuseLighting: Boolean = false) = map { it.withOpposites().bake(applyDiffuseLighting) }.toTypedArray() diff --git a/src/main/kotlin/mods/betterfoliage/render/EntityFallingLeavesFX.kt b/src/main/kotlin/mods/betterfoliage/render/EntityFallingLeavesFX.kt index bf1cac6..b67d941 100644 --- a/src/main/kotlin/mods/betterfoliage/render/EntityFallingLeavesFX.kt +++ b/src/main/kotlin/mods/betterfoliage/render/EntityFallingLeavesFX.kt @@ -1,13 +1,25 @@ package mods.betterfoliage.render +import com.mojang.blaze3d.vertex.IVertexBuilder +import mods.betterfoliage.BetterFoliage import mods.betterfoliage.config.Config import mods.betterfoliage.render.old.AbstractEntityFX 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.PI2 +import mods.betterfoliage.util.get 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.client.renderer.ActiveRenderInfo import net.minecraft.client.renderer.BufferBuilder import net.minecraft.util.math.BlockPos import net.minecraft.util.math.MathHelper @@ -23,116 +35,3 @@ import kotlin.math.sin 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) } -} \ 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 53a5974..c53c35d 100644 --- a/src/main/kotlin/mods/betterfoliage/render/block/vanilla/Grass.kt +++ b/src/main/kotlin/mods/betterfoliage/render/block/vanilla/Grass.kt @@ -6,25 +6,25 @@ import mods.betterfoliage.config.BlockConfig import mods.betterfoliage.config.Config import mods.betterfoliage.config.ConfigurableBlockMatcher 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.HalfBakedSpecialWrapper 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.RenderCtxVanilla import mods.betterfoliage.resource.discovery.BakeWrapperManager import mods.betterfoliage.resource.discovery.ConfigurableModelDiscovery 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.LazyInvalidatable import mods.betterfoliage.util.LazyMapInvalidatable +import mods.betterfoliage.util.averageColor import mods.betterfoliage.util.get import mods.betterfoliage.util.isSnow import mods.betterfoliage.util.randomI @@ -44,7 +44,7 @@ object StandardGrassDiscovery : ConfigurableModelDiscovery() { sprites: MutableSet, replacements: MutableMap ): Boolean { - replacements[location] = StandardGrassKey(textureMatch[0]) + replacements[location] = StandardGrassKey(textureMatch[0], null) Client.blockTypes.grass.add(state) // RenderTypeLookup.setRenderLayer(state.block, RenderType.getCutout()) return true @@ -52,11 +52,17 @@ object StandardGrassDiscovery : ConfigurableModelDiscovery() { } data class StandardGrassKey( - val grassLocation: ResourceLocation + val grassLocation: ResourceLocation, + val overrideColor: Color? ) : HalfBakedWrapperKey() { + val tintIndex: Int get() = if (overrideColor == null) 0 else -1 + override fun replace(wrapped: SpecialRenderModel): SpecialRenderModel { - Atlas.BLOCKS[grassLocation].logColorOverride(detailLogger, Config.shortGrass.saturationThreshold) - return StandardGrassModel(wrapped, this) + val grassSpriteColor = Atlas.BLOCKS[grassLocation].averageColor.let { hsb -> + 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) } } val grassTuftMeshesNormal = LazyMapInvalidatable(BakeWrapperManager) { key: StandardGrassKey -> - val overrideColor = Atlas.BLOCKS[key.grassLocation].getColorOverride(Config.shortGrass.saturationThreshold) - tuftModelSet(grassTuftShapes, overrideColor) { idx -> grassTuftSprites[randomI()] }.buildTufts() + tuftModelSet(grassTuftShapes, key.overrideColor) { idx -> grassTuftSprites[randomI()] }.buildTufts() } val grassTuftMeshesSnowed = LazyMapInvalidatable(BakeWrapperManager) { key: StandardGrassKey -> tuftModelSet(grassTuftShapes, Color.white) { idx -> grassTuftSprites[randomI()] }.buildTufts() } 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) { - Array(64) { fullCubeTextured(ResourceLocation("block/snow"), Color.white) } + Array(64) { fullCubeTextured(ResourceLocation("block/snow"), -1) } } } } \ No newline at end of file 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 47649c2..ae6368d 100644 --- a/src/main/kotlin/mods/betterfoliage/render/block/vanilla/Leaf.kt +++ b/src/main/kotlin/mods/betterfoliage/render/block/vanilla/Leaf.kt @@ -6,30 +6,32 @@ import mods.betterfoliage.config.BlockConfig import mods.betterfoliage.config.Config import mods.betterfoliage.config.ConfigurableBlockMatcher 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.HSB import mods.betterfoliage.model.HalfBakedSpecialWrapper 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.RenderCtxVanilla import mods.betterfoliage.resource.discovery.BakeWrapperManager import mods.betterfoliage.resource.discovery.ConfigurableModelDiscovery import mods.betterfoliage.resource.discovery.ModelBakingKey import mods.betterfoliage.resource.generated.GeneratedLeaf -import mods.betterfoliage.model.SpriteSetDelegate -import mods.betterfoliage.model.crossModelsRaw -import mods.betterfoliage.model.crossModelsTextured -import mods.betterfoliage.model.crossModelsTinted +import mods.betterfoliage.texture.LeafBlockModel +import mods.betterfoliage.texture.LeafParticleKey import mods.betterfoliage.texture.LeafParticleRegistry import mods.betterfoliage.util.Atlas import mods.betterfoliage.util.LazyMapInvalidatable import mods.betterfoliage.util.averageColor import mods.betterfoliage.util.isSnow import net.minecraft.block.BlockState -import net.minecraft.client.renderer.texture.TextureAtlasSprite import net.minecraft.util.Direction.UP import net.minecraft.util.ResourceLocation +import org.apache.logging.log4j.Level.DEBUG import org.apache.logging.log4j.Level.INFO import org.apache.logging.log4j.Logger @@ -50,13 +52,12 @@ object StandardLeafDiscovery : ConfigurableModelDiscovery() { .apply { sprites.add(this) } detailLogger.log(INFO, " particle $leafType") - replacements[location] = StandardLeafKey(generated, leafType) + replacements[location] = StandardLeafKey(generated, leafType, null) return true } } -fun TextureAtlasSprite.logColorOverride(logger: Logger, threshold: Double) { - val hsb = averageColor +fun logColorOverride(logger: Logger, threshold: Double, hsb: HSB) { return if (hsb.saturation >= threshold) { logger.log(INFO, " brightness ${hsb.brightness}") 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 { - if (it.saturation < threshold) null else it.copy(brightness = (it.brightness * 2.0f).coerceAtMost(0.9f)) -}?.asColor?.let { Color(it) } +fun HSB.colorOverride(threshold: Double) = + if (saturation < threshold) null else copy(brightness = (brightness * 2.0f).coerceAtMost(0.9f)).asColor.let { Color(it) } data class StandardLeafKey( val roundLeafTexture: ResourceLocation, - val leafType: String -) : HalfBakedWrapperKey() { + override val leafType: String, + override val overrideColor: Color? +) : HalfBakedWrapperKey(), LeafParticleKey { + val tintIndex: Int get() = if (overrideColor == null) 0 else -1 + override fun replace(wrapped: SpecialRenderModel): SpecialRenderModel { - Atlas.BLOCKS[roundLeafTexture].logColorOverride(BetterFoliageMod.detailLogger(this), 0.1) - return StandardLeafModel(wrapped, this) + val leafSpriteColor = Atlas.BLOCKS[roundLeafTexture].averageColor.let { hsb -> + 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( model: SpecialRenderModel, - key: StandardLeafKey -) : HalfBakedSpecialWrapper(model) { + override val key: StandardLeafKey +) : HalfBakedSpecialWrapper(model), LeafBlockModel { val leafNormal by leafModelsNormal.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) } } 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 -> - crossModelsTextured(leafModelsBase[key], Color.white, false) { leafSpritesSnowed[it].name } + crossModelsTextured(leafModelsBase[key], -1, false) { leafSpritesSnowed[it].name } } } } \ No newline at end of file diff --git a/src/main/kotlin/mods/betterfoliage/render/particle/AbstractParticle.kt b/src/main/kotlin/mods/betterfoliage/render/particle/AbstractParticle.kt new file mode 100644 index 0000000..d06be4c --- /dev/null +++ b/src/main/kotlin/mods/betterfoliage/render/particle/AbstractParticle.kt @@ -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 + } +} + diff --git a/src/main/kotlin/mods/betterfoliage/render/particle/FallingLeaves.kt b/src/main/kotlin/mods/betterfoliage/render/particle/FallingLeaves.kt new file mode 100644 index 0000000..7e4ba54 --- /dev/null +++ b/src/main/kotlin/mods/betterfoliage/render/particle/FallingLeaves.kt @@ -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) } +} \ No newline at end of file diff --git a/src/main/kotlin/mods/betterfoliage/resource/discovery/BakingLifecycle.kt b/src/main/kotlin/mods/betterfoliage/resource/discovery/BakingLifecycle.kt index 32e2c29..5f91d3d 100644 --- a/src/main/kotlin/mods/betterfoliage/resource/discovery/BakingLifecycle.kt +++ b/src/main/kotlin/mods/betterfoliage/resource/discovery/BakingLifecycle.kt @@ -1,6 +1,5 @@ package mods.betterfoliage.resource.discovery -import mods.betterfoliage.ModelDefinitionsLoadedEvent import mods.betterfoliage.model.SpecialRenderVariantList import mods.betterfoliage.util.Atlas import mods.betterfoliage.util.HasLogger @@ -16,12 +15,18 @@ import net.minecraft.client.renderer.texture.TextureAtlasSprite import net.minecraft.util.ResourceLocation import net.minecraftforge.client.event.ModelBakeEvent 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.fml.loading.progress.StartupMessageManager import org.apache.logging.log4j.Level.INFO import java.lang.ref.WeakReference import java.util.function.Function +data class ModelDefinitionsLoadedEvent( + val bakery: ModelBakery +) : Event() + interface ModelDiscovery { fun onModelsLoaded( bakery: ModelBakery, @@ -50,7 +55,7 @@ object BakeWrapperManager : Invalidator, HasLogger() { private val replacements = mutableMapOf() private val sprites = mutableSetOf() - @SubscribeEvent + @SubscribeEvent(priority = EventPriority.LOWEST) fun handleModelLoad(event: ModelDefinitionsLoadedEvent) { modelsValid.invalidate() StartupMessageManager.addModMessage("BetterFoliage: discovering models") diff --git a/src/main/kotlin/mods/betterfoliage/texture/LeafParticleRegistry.kt b/src/main/kotlin/mods/betterfoliage/texture/LeafParticleRegistry.kt index 3521fb7..4b0ebe3 100644 --- a/src/main/kotlin/mods/betterfoliage/texture/LeafParticleRegistry.kt +++ b/src/main/kotlin/mods/betterfoliage/texture/LeafParticleRegistry.kt @@ -1,43 +1,70 @@ package mods.betterfoliage.texture 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.HasLogger import mods.betterfoliage.util.get import mods.betterfoliage.util.getLines import mods.betterfoliage.util.resourceManager 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 java.util.concurrent.CompletableFuture +import net.minecraftforge.client.event.TextureStitchEvent +import net.minecraftforge.eventbus.api.SubscribeEvent +import org.apache.logging.log4j.Level -object LeafParticleRegistry { - val targetAtlas = Atlas.PARTICLES +interface LeafBlockModel { + val key: LeafParticleKey +} + +interface LeafParticleKey { + val leafType: String + val overrideColor: Color? +} + +object LeafParticleRegistry : HasLogger() { val typeMappings = TextureMatcher() -// val particles = hashMapOf() + val particles = hashMapOf() - val futures = mutableMapOf>>() + operator fun get(type: String) = particles[type] ?: particles["default"]!! -// operator fun get(type: String) = particles[type] ?: particles["default"]!! - - fun discovery() { + @SubscribeEvent + fun handleModelLoad(event: ModelDefinitionsLoadedEvent) { typeMappings.loadMappings(ResourceLocation(BetterFoliageMod.MOD_ID, "leaf_texture_mappings.cfg")) - (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 wids = ids.map { Atlas.PARTICLES.file(it) } -// futures[leafType] = (0 until 16).map { idx -> ResourceLocation(BetterFoliageMod.MOD_ID, "falling_leaf_${leafType}_$idx") } -// .filter { manager.hasResource(Atlas.PARTICLES.wrap(it)) } -// .map { atlasFuture.sprite(it) } + } + + @SubscribeEvent + fun handlePreStitch(event: TextureStitchEvent.Pre) { + if (event.map.textureLocation == Atlas.PARTICLES.resourceId) { + (typeMappings.mappings.map { it.type } + "default").distinct().forEach { leafType -> + val locations = (0 until 16).map { idx -> + ResourceLocation(BetterFoliageMod.MOD_ID, "particle/falling_leaf_${leafType}_$idx") + }.filter { resourceManager.hasResource(Atlas.PARTICLES.file(it)) } + + detailLogger.log(Level.INFO, "Registering sprites for leaf particle type [$leafType], ${locations.size} sprites found") + locations.forEach { event.addSprite(it) } + } } } - fun cleanup() { -// futures.forEach { leafType, spriteFutures -> -// val sprites = spriteFutures.filter { !it.isCompletedExceptionally }.map { it.get() } -// if (sprites.isNotEmpty()) particles[leafType] = FixedSpriteSet(sprites) -// } -// if (particles["default"] == null) particles["default"] = FixedSpriteSet(listOf(atlasFuture.missing.get()!!)) + @SubscribeEvent + fun handlePostStitch(event: TextureStitchEvent.Post) { + if (event.map.textureLocation == Atlas.PARTICLES.resourceId) { + (typeMappings.mappings.map { it.type } + "default").distinct().forEach { leafType -> + val sprites = (0 until 16).map { idx -> + 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 { @@ -45,7 +72,7 @@ class TextureMatcher { data class Mapping(val domain: String?, val path: String, val type: String) { fun matches(iconLocation: ResourceLocation): Boolean { return (domain == null || domain == iconLocation.namespace) && - iconLocation.path.stripStart("blocks/").contains(path, ignoreCase = true) + iconLocation.path.stripStart("blocks/").contains(path, ignoreCase = true) } } @@ -61,7 +88,13 @@ class TextureMatcher { if (line2.size == 2) { val mapping = line2[0].trim().split(':') 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() + ) + ) } } } diff --git a/src/main/kotlin/mods/betterfoliage/util/Geometry.kt b/src/main/kotlin/mods/betterfoliage/util/Geometry.kt index 67f9738..ff53b5e 100644 --- a/src/main/kotlin/mods/betterfoliage/util/Geometry.kt +++ b/src/main/kotlin/mods/betterfoliage/util/Geometry.kt @@ -1,5 +1,6 @@ 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.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) 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) + fun lerp(delta: Double, first: Double3, second: Double3) = first + (second - first) * delta } // immutable operations @@ -82,6 +84,13 @@ data class Double3(var x: Double, var y: Double, var z: Double) { 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 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 } diff --git a/src/main/kotlin/mods/betterfoliage/util/Random.kt b/src/main/kotlin/mods/betterfoliage/util/Random.kt index 86fee95..d590756 100644 --- a/src/main/kotlin/mods/betterfoliage/util/Random.kt +++ b/src/main/kotlin/mods/betterfoliage/util/Random.kt @@ -7,7 +7,12 @@ val random = Random(System.nanoTime()) fun randomB() = random.nextBoolean() 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 { var value = (x * x + y * y + z * z + x * y + y * z + z * x + (seed * seed)) diff --git a/src/main/resources/assets/betterfoliage/leaves_models_default.cfg b/src/main/resources/assets/betterfoliage/leaves_models_default.cfg index 1cf5abb..c6110b8 100644 --- a/src/main/resources/assets/betterfoliage/leaves_models_default.cfg +++ b/src/main/resources/assets/betterfoliage/leaves_models_default.cfg @@ -1,4 +1,4 @@ minecraft:block/leaves,all minecraft:block/cube_all,all -biomesoplenty:block/leaves_overlay,under +biomesoplenty:block/leaves_overlay,leaves