[WIP] Falling leaves working
+ more cleanup + fix double-tinted leaves
This commit is contained in:
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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()
|
||||
@@ -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 {
|
||||
|
||||
@@ -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(){
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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<TuftShapeKey>, overrideColor: Color?, spriteGette
|
||||
|
||||
fun fullCubeTextured(
|
||||
spriteLocation: ResourceLocation,
|
||||
overrideColor: Color?,
|
||||
tintIndex: Int,
|
||||
scrambleUV: Boolean = true
|
||||
): List<HalfBakedQuad> {
|
||||
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<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>> {
|
||||
return Array(num) { idx ->
|
||||
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 }
|
||||
.map { it.colorAndIndex(overrideColor) }
|
||||
.map { it.colorIndex(tintIndex) }
|
||||
.mapIndexed { idx, quad -> quad.sprite(sprite) }
|
||||
.withOpposites()
|
||||
.bake(false)
|
||||
|
||||
fun crossModelsTextured(
|
||||
leafBase: Array<List<Quad>>,
|
||||
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<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<List<Quad>>.buildTufts(applyDiffuseLighting: Boolean = false) =
|
||||
map { it.withOpposites().bake(applyDiffuseLighting) }.toTypedArray()
|
||||
|
||||
@@ -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) }
|
||||
}
|
||||
@@ -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<ResourceLocation>,
|
||||
replacements: MutableMap<ResourceLocation, ModelBakingKey>
|
||||
): 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) }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) }
|
||||
}
|
||||
@@ -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<ResourceLocation, ModelBakingKey>()
|
||||
private val sprites = mutableSetOf<ResourceLocation>()
|
||||
|
||||
@SubscribeEvent
|
||||
@SubscribeEvent(priority = EventPriority.LOWEST)
|
||||
fun handleModelLoad(event: ModelDefinitionsLoadedEvent) {
|
||||
modelsValid.invalidate()
|
||||
StartupMessageManager.addModMessage("BetterFoliage: discovering models")
|
||||
|
||||
@@ -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<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"]!!
|
||||
|
||||
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()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 }
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
minecraft:block/leaves,all
|
||||
minecraft:block/cube_all,all
|
||||
|
||||
biomesoplenty:block/leaves_overlay,under
|
||||
biomesoplenty:block/leaves_overlay,leaves
|
||||
|
||||
Reference in New Issue
Block a user