[WIP] algae, reeds, mycelium, coral working

+ lots of cleanup, reorganizing
This commit is contained in:
octarine-noise
2021-05-07 19:08:00 +02:00
parent f44d2a7a50
commit 7168caded1
29 changed files with 501 additions and 332 deletions

View File

@@ -2,7 +2,7 @@ package mods.betterfoliage.mixin;
import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.matrix.MatrixStack;
import com.mojang.blaze3d.vertex.IVertexBuilder; import com.mojang.blaze3d.vertex.IVertexBuilder;
import mods.betterfoliage.render.ISpecialRenderModel; import mods.betterfoliage.model.SpecialRenderModel;
import mods.betterfoliage.render.pipeline.RenderCtxVanilla; import mods.betterfoliage.render.pipeline.RenderCtxVanilla;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.client.renderer.BlockModelRenderer; import net.minecraft.client.renderer.BlockModelRenderer;
@@ -25,16 +25,16 @@ public class MixinBlockModelRenderer {
@Redirect(method = renderModel, at = @At(value = "INVOKE", target = renderModelSmooth), remap = false) @Redirect(method = renderModel, at = @At(value = "INVOKE", target = renderModelSmooth), remap = false)
public boolean onRenderModelSmooth(BlockModelRenderer renderer, ILightReader world, IBakedModel model, BlockState state, BlockPos pos, MatrixStack matrixStack, IVertexBuilder buffer, boolean checkSides, Random random, long rand, int combinedOverlay, IModelData modelData) { public boolean onRenderModelSmooth(BlockModelRenderer renderer, ILightReader world, IBakedModel model, BlockState state, BlockPos pos, MatrixStack matrixStack, IVertexBuilder buffer, boolean checkSides, Random random, long rand, int combinedOverlay, IModelData modelData) {
if (model instanceof ISpecialRenderModel) if (model instanceof SpecialRenderModel)
return RenderCtxVanilla.render(renderer, world, (ISpecialRenderModel) model, state, pos, matrixStack, buffer, checkSides, random, rand, combinedOverlay, modelData, true); return RenderCtxVanilla.render(renderer, world, (SpecialRenderModel) model, state, pos, matrixStack, buffer, checkSides, random, rand, combinedOverlay, modelData, true);
else else
return renderer.renderModelSmooth(world, model, state, pos, matrixStack, buffer, checkSides, random, rand, combinedOverlay, modelData); return renderer.renderModelSmooth(world, model, state, pos, matrixStack, buffer, checkSides, random, rand, combinedOverlay, modelData);
} }
@Redirect(method = renderModel, at = @At(value = "INVOKE", target = renderModelFlat), remap = false) @Redirect(method = renderModel, at = @At(value = "INVOKE", target = renderModelFlat), remap = false)
public boolean onRenderModelFlat(BlockModelRenderer renderer, ILightReader world, IBakedModel model, BlockState state, BlockPos pos, MatrixStack matrixStack, IVertexBuilder buffer, boolean checkSides, Random random, long rand, int combinedOverlay, IModelData modelData) { public boolean onRenderModelFlat(BlockModelRenderer renderer, ILightReader world, IBakedModel model, BlockState state, BlockPos pos, MatrixStack matrixStack, IVertexBuilder buffer, boolean checkSides, Random random, long rand, int combinedOverlay, IModelData modelData) {
if (model instanceof ISpecialRenderModel) if (model instanceof SpecialRenderModel)
return RenderCtxVanilla.render(renderer, world, (ISpecialRenderModel) model, state, pos, matrixStack, buffer, checkSides, random, rand, combinedOverlay, modelData, false); return RenderCtxVanilla.render(renderer, world, (SpecialRenderModel) model, state, pos, matrixStack, buffer, checkSides, random, rand, combinedOverlay, modelData, false);
else else
return renderer.renderModelSmooth(world, model, state, pos, matrixStack, buffer, checkSides, random, rand, combinedOverlay, modelData); return renderer.renderModelSmooth(world, model, state, pos, matrixStack, buffer, checkSides, random, rand, combinedOverlay, modelData);
} }

View File

@@ -2,7 +2,7 @@ package mods.betterfoliage.mixin;
import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.matrix.MatrixStack;
import mods.betterfoliage.render.pipeline.RenderCtxForge; import mods.betterfoliage.render.pipeline.RenderCtxForge;
import mods.betterfoliage.render.ISpecialRenderModel; import mods.betterfoliage.model.SpecialRenderModel;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.client.renderer.model.IBakedModel; import net.minecraft.client.renderer.model.IBakedModel;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
@@ -36,8 +36,8 @@ public class MixinForgeBlockModelRenderer {
long seed, long seed,
IModelData modelData IModelData modelData
) { ) {
if (model instanceof ISpecialRenderModel) if (model instanceof SpecialRenderModel)
return RenderCtxForge.render(lighter, world, (ISpecialRenderModel) model, state, pos, matrixStack, checkSides, rand, seed, modelData); return RenderCtxForge.render(lighter, world, (SpecialRenderModel) model, state, pos, matrixStack, checkSides, rand, seed, modelData);
else else
return ForgeBlockModelRenderer.render(lighter, world, model, state, pos, matrixStack, checkSides, rand, seed, modelData); return ForgeBlockModelRenderer.render(lighter, world, model, state, pos, matrixStack, checkSides, rand, seed, modelData);
} }

View File

@@ -60,7 +60,6 @@ abstract public class MixinForgeCustomVertexLighting implements ForgeVertexLight
@Inject(method = resetBlockInfo, at = @At("RETURN"), remap = false) @Inject(method = resetBlockInfo, at = @At("RETURN"), remap = false)
void onReset(CallbackInfo ci) { void onReset(CallbackInfo ci) {
// just in case
vertexLighter = this; vertexLighter = this;
} }
} }

View File

@@ -33,7 +33,7 @@ object BetterFoliageMod {
init { init {
ModLoadingContext.get().registerConfig(ModConfig.Type.CLIENT, Config.build()) ModLoadingContext.get().registerConfig(ModConfig.Type.CLIENT, Config.build())
Minecraft.getInstance().resourcePackList.addPackFinder(Client.asyncPack.finder) Minecraft.getInstance().resourcePackList.addPackFinder(Client.generatedPack.finder)
bus.register(BlockConfig) bus.register(BlockConfig)
Client.init() Client.init()
} }

View File

@@ -7,10 +7,15 @@ import mods.betterfoliage.integration.ShadersModIntegration
import mods.betterfoliage.render.LeafWindTracker 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.StandardGrassDiscovery import mods.betterfoliage.render.block.vanilla.StandardGrassDiscovery
import mods.betterfoliage.render.block.vanilla.StandardGrassModel import mods.betterfoliage.render.block.vanilla.StandardGrassModel
import mods.betterfoliage.render.block.vanilla.StandardLeafDiscovery import mods.betterfoliage.render.block.vanilla.StandardLeafDiscovery
import mods.betterfoliage.render.block.vanilla.StandardLeafModel import mods.betterfoliage.render.block.vanilla.StandardLeafModel
import mods.betterfoliage.render.block.vanilla.StandardMyceliumDiscovery
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.lighting.AoSideHelper
import mods.betterfoliage.resource.discovery.BakeWrapperManager import mods.betterfoliage.resource.discovery.BakeWrapperManager
import mods.betterfoliage.resource.discovery.BlockTypeCache import mods.betterfoliage.resource.discovery.BlockTypeCache
@@ -26,7 +31,7 @@ import net.minecraftforge.common.ForgeConfig
* except for the call hooks. * except for the call hooks.
*/ */
object Client { object Client {
val asyncPack = GeneratedTexturePack("bf_gen", "Better Foliage generated assets") val generatedPack = GeneratedTexturePack("bf_gen", "Better Foliage generated assets")
var blockTypes = BlockTypeCache() var blockTypes = BlockTypeCache()
val suppressRenderErrors = mutableSetOf<BlockState>() val suppressRenderErrors = mutableSetOf<BlockState>()
@@ -37,7 +42,9 @@ object Client {
listOf( listOf(
StandardLeafDiscovery, StandardLeafDiscovery,
StandardGrassDiscovery, StandardGrassDiscovery,
StandardDirtDiscovery StandardDirtDiscovery,
StandardMyceliumDiscovery,
StandardSandDiscovery
).forEach { ).forEach {
BakeWrapperManager.discoverers.add(it) BakeWrapperManager.discoverers.add(it)
} }
@@ -52,7 +59,10 @@ object Client {
val modelSingletons = listOf( val modelSingletons = listOf(
StandardLeafModel.Companion, StandardLeafModel.Companion,
StandardGrassModel.Companion StandardGrassModel.Companion,
StandardDirtModel.Companion,
StandardMyceliumModel.Companion,
StandardSandModel.Companion
) )
// init mod integrations // init mod integrations

View File

@@ -7,6 +7,7 @@ import mods.betterfoliage.util.plus
import mods.betterfoliage.util.semiRandom import mods.betterfoliage.util.semiRandom
import net.minecraft.block.Block import net.minecraft.block.Block
import net.minecraft.block.BlockState import net.minecraft.block.BlockState
import net.minecraft.client.renderer.chunk.ChunkRenderCache
import net.minecraft.util.Direction import net.minecraft.util.Direction
import net.minecraft.util.math.BlockPos import net.minecraft.util.math.BlockPos
import net.minecraft.world.ILightReader import net.minecraft.world.ILightReader
@@ -29,7 +30,9 @@ interface BlockCtx {
fun state(dir: Direction) = world.getBlockState(pos + dir.offset) fun state(dir: Direction) = world.getBlockState(pos + dir.offset)
fun state(offset: Int3) = world.getBlockState(pos + offset) fun state(offset: Int3) = world.getBlockState(pos + offset)
val biome: Biome? get() = (world as? IWorldReader)?.getBiome(pos) val biome: Biome? get() =
(world as? IWorldReader)?.getBiome(pos) ?:
(world as? ChunkRenderCache)?.world?.getBiome(pos)
val isNormalCube: Boolean get() = state.isNormalCube(world, pos) val isNormalCube: Boolean get() = state.isNormalCube(world, pos)

View File

@@ -1,8 +1,7 @@
package mods.betterfoliage.render.old package mods.betterfoliage.model
import mods.betterfoliage.render.ISpecialRenderModel
import mods.betterfoliage.render.pipeline.RenderCtxBase import mods.betterfoliage.render.pipeline.RenderCtxBase
import mods.betterfoliage.resource.discovery.ModelBakeKey import mods.betterfoliage.resource.discovery.ModelBakingKey
import mods.betterfoliage.util.Double3 import mods.betterfoliage.util.Double3
import mods.betterfoliage.util.HasLogger import mods.betterfoliage.util.HasLogger
import mods.betterfoliage.util.directionsAndNull import mods.betterfoliage.util.directionsAndNull
@@ -21,13 +20,19 @@ import net.minecraftforge.client.model.pipeline.BakedQuadBuilder
import java.util.Random import java.util.Random
import java.util.function.Function import java.util.function.Function
/**
* Hybrid baked quad implementation, carrying both baked and unbaked information.
* Used to do advanced vertex lighting without unbaking vertex data at lighting time.
*/
data class HalfBakedQuad( data class HalfBakedQuad(
val raw: Quad, val raw: Quad,
val baked: BakedQuad val baked: BakedQuad
) )
open class HalfBakedSimpleModelWrapper(baseModel: SimpleBakedModel): IBakedModel by baseModel, ISpecialRenderModel { /**
*
*/
open class HalfBakedSimpleModelWrapper(baseModel: SimpleBakedModel): IBakedModel by baseModel, SpecialRenderModel {
val baseQuads = baseModel.unbakeQuads() val baseQuads = baseModel.unbakeQuads()
override fun render(ctx: RenderCtxBase, noDecorations: Boolean) { override fun render(ctx: RenderCtxBase, noDecorations: Boolean) {
@@ -35,21 +40,21 @@ open class HalfBakedSimpleModelWrapper(baseModel: SimpleBakedModel): IBakedModel
} }
} }
open class HalfBakedSpecialWrapper(val baseModel: ISpecialRenderModel): IBakedModel by baseModel, ISpecialRenderModel { open class HalfBakedSpecialWrapper(val baseModel: SpecialRenderModel): IBakedModel by baseModel, SpecialRenderModel {
override fun render(ctx: RenderCtxBase, noDecorations: Boolean) { override fun render(ctx: RenderCtxBase, noDecorations: Boolean) {
baseModel.render(ctx, noDecorations) baseModel.render(ctx, noDecorations)
} }
} }
abstract class HalfBakedWrapKey : ModelBakeKey, HasLogger() { abstract class HalfBakedWrapperKey : ModelBakingKey, HasLogger() {
override fun replace( override fun bake(
location: ResourceLocation, location: ResourceLocation,
unbaked: IUnbakedModel, unbaked: IUnbakedModel,
transform: IModelTransform, transform: IModelTransform,
bakery: ModelBakery, bakery: ModelBakery,
spriteGetter: Function<Material, TextureAtlasSprite> spriteGetter: Function<Material, TextureAtlasSprite>
): IBakedModel? { ): IBakedModel? {
val baseModel = super.replace(location, unbaked, transform, bakery, spriteGetter) val baseModel = super.bake(location, unbaked, transform, bakery, spriteGetter)
val halfBaked = when(baseModel) { val halfBaked = when(baseModel) {
is SimpleBakedModel -> HalfBakedSimpleModelWrapper(baseModel) is SimpleBakedModel -> HalfBakedSimpleModelWrapper(baseModel)
else -> null else -> null
@@ -57,7 +62,8 @@ abstract class HalfBakedWrapKey : ModelBakeKey, HasLogger() {
return if (halfBaked == null) baseModel else replace(halfBaked) return if (halfBaked == null) baseModel else replace(halfBaked)
} }
abstract fun replace(wrapped: ISpecialRenderModel): ISpecialRenderModel
abstract fun replace(wrapped: SpecialRenderModel): SpecialRenderModel
} }
fun List<Quad>.bake(applyDiffuseLighting: Boolean) = map { quad -> fun List<Quad>.bake(applyDiffuseLighting: Boolean) = map { quad ->

View File

@@ -1,26 +1,16 @@
package mods.betterfoliage.render.old package mods.betterfoliage.model
import mods.betterfoliage.util.Double3 import mods.betterfoliage.util.Double3
import mods.betterfoliage.util.Rotation import mods.betterfoliage.util.Rotation
import mods.betterfoliage.util.allDirections
import mods.betterfoliage.util.boxFaces import mods.betterfoliage.util.boxFaces
import mods.betterfoliage.util.get import mods.betterfoliage.util.get
import mods.betterfoliage.util.minmax import mods.betterfoliage.util.minmax
import mods.betterfoliage.util.nearestAngle import mods.betterfoliage.util.nearestAngle
import mods.betterfoliage.util.replace
import mods.betterfoliage.util.rotate import mods.betterfoliage.util.rotate
import mods.betterfoliage.util.times import mods.betterfoliage.util.times
import mods.betterfoliage.util.toImmutableList
import mods.betterfoliage.util.vec import mods.betterfoliage.util.vec
import net.minecraft.client.renderer.model.BakedQuad
import net.minecraft.client.renderer.texture.TextureAtlasSprite import net.minecraft.client.renderer.texture.TextureAtlasSprite
import net.minecraft.client.renderer.vertex.DefaultVertexFormats
import net.minecraft.client.renderer.vertex.VertexFormat
import net.minecraft.client.renderer.vertex.VertexFormatElement
import net.minecraft.client.renderer.vertex.VertexFormatElement.Type
import net.minecraft.client.renderer.vertex.VertexFormatElement.Usage
import net.minecraft.util.Direction import net.minecraft.util.Direction
import net.minecraftforge.client.model.pipeline.BakedQuadBuilder
import java.lang.Math.max import java.lang.Math.max
import java.lang.Math.min import java.lang.Math.min
import java.util.Random import java.util.Random

View File

@@ -0,0 +1,64 @@
package mods.betterfoliage.model
import mods.betterfoliage.render.pipeline.RenderCtxBase
import mods.betterfoliage.util.HasLogger
import net.minecraft.client.renderer.model.IBakedModel
import net.minecraft.client.renderer.model.Material
import net.minecraft.client.renderer.model.ModelBakery
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 org.apache.logging.log4j.Level.WARN
import java.util.Random
import java.util.function.Function
/**
* Model that makes use of advanced rendering features.
*/
interface SpecialRenderModel : IBakedModel {
fun render(ctx: RenderCtxBase, noDecorations: Boolean = false)
}
class SpecialRenderVariantList(
val models: List<WeightedModel>, baseModel: SpecialRenderModel
): IBakedModel by baseModel, SpecialRenderModel {
class WeightedModel(val model: SpecialRenderModel, weight: Int) : WeightedRandom.Item(weight)
val totalWeight = models.sumBy { it.itemWeight }
fun getModel(random: Random) = WeightedRandom.getRandomItem(models, random.nextInt(totalWeight))
override fun render(ctx: RenderCtxBase, noDecorations: Boolean) {
getModel(ctx.random).model.render(ctx, noDecorations)
}
companion object : HasLogger() {
/**
* If any of the variants in this [VariantList] bake to [SpecialRenderModel], give back a
* [SpecialRenderVariantList] so that variants can take advantage of extra features.
* Otherwise, give back null.
*/
fun bakeIfSpecial(
location: ResourceLocation,
variantModel: VariantList,
bakery: ModelBakery,
spriteGetter: Function<Material, TextureAtlasSprite>
): SpecialRenderVariantList? {
val bakedModels = variantModel.variantList.map {
it to bakery.getBakedModel(it.modelLocation, it, spriteGetter)
}.filter { it.second != null }
if (bakedModels.all { it.second !is SpecialRenderModel }) return null
val weightedSpecials = bakedModels.mapNotNull { (variant, model) ->
when (model) {
is SpecialRenderModel -> WeightedModel(model, variant.weight)
else -> null
}
}
if (bakedModels.size > weightedSpecials.size) {
detailLogger.log(WARN, "Dropped ${bakedModels.size - weightedSpecials.size} variants from model $location")
}
return SpecialRenderVariantList(weightedSpecials, weightedSpecials[0].model)
}
}
}

View File

@@ -1,4 +1,4 @@
package mods.betterfoliage.resource.model package mods.betterfoliage.model
import mods.betterfoliage.BetterFoliageMod import mods.betterfoliage.BetterFoliageMod
import mods.betterfoliage.util.Atlas import mods.betterfoliage.util.Atlas

View File

@@ -1,22 +1,16 @@
package mods.betterfoliage.resource.model package mods.betterfoliage.model
import mods.betterfoliage.render.block.vanilla.getColorOverride import mods.betterfoliage.render.block.vanilla.getColorOverride
import mods.betterfoliage.render.old.Color
import mods.betterfoliage.render.old.HalfBakedQuad
import mods.betterfoliage.render.old.Quad
import mods.betterfoliage.render.old.bake
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
import mods.betterfoliage.util.allDirections import mods.betterfoliage.util.allDirections
import mods.betterfoliage.util.averageColor
import mods.betterfoliage.util.random import mods.betterfoliage.util.random
import mods.betterfoliage.util.randomB import mods.betterfoliage.util.randomB
import mods.betterfoliage.util.randomD import mods.betterfoliage.util.randomD
import mods.betterfoliage.util.randomI import mods.betterfoliage.util.randomI
import mods.betterfoliage.util.rot import mods.betterfoliage.util.rot
import mods.betterfoliage.util.vec import mods.betterfoliage.util.vec
import net.minecraft.client.renderer.model.BakedQuad
import net.minecraft.client.renderer.texture.TextureAtlasSprite 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
@@ -127,3 +121,5 @@ fun crossModelsTinted(
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()
fun List<List<Quad>>.transform(trans: Quad.(Int)-> Quad) = mapIndexed { idx, qList -> qList.map { it.trans(idx) } }

View File

@@ -2,7 +2,7 @@ package mods.betterfoliage.render
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.render.old.HSB import mods.betterfoliage.model.HSB
import mods.betterfoliage.util.Double3 import mods.betterfoliage.util.Double3
import mods.betterfoliage.util.PI2 import mods.betterfoliage.util.PI2
import mods.betterfoliage.util.minmax import mods.betterfoliage.util.minmax

View File

@@ -1,48 +0,0 @@
package mods.betterfoliage.render
import mods.betterfoliage.render.pipeline.RenderCtxBase
import net.minecraft.client.renderer.model.IBakedModel
import net.minecraft.client.renderer.model.Material
import net.minecraft.client.renderer.model.ModelBakery
import net.minecraft.client.renderer.model.VariantList
import net.minecraft.client.renderer.texture.TextureAtlasSprite
import net.minecraft.util.WeightedRandom
import java.util.Random
import java.util.function.Function
interface ISpecialRenderModel : IBakedModel {
fun render(ctx: RenderCtxBase, noDecorations: Boolean = false)
}
open class SpecialRenderWrapper(val baseModel: IBakedModel) : IBakedModel by baseModel, ISpecialRenderModel {
override fun render(ctx: RenderCtxBase, noDecorations: Boolean) {
ctx.renderFallback(baseModel)
}
}
/**
* If any of the variants in this [VariantList] bake to [ISpecialRenderModel], give back a
* [SpecialRenderVariantList] so that variants can take advantage of extra features.
* Otherwise, give back null.
*/
fun VariantList.bakeSpecial(bakery: ModelBakery, spriteGetter: Function<Material, TextureAtlasSprite>): SpecialRenderVariantList? {
val bakedModels = variantList.map { bakery.getBakedModel(it.modelLocation, it, spriteGetter) }
if (bakedModels.all { it !is ISpecialRenderModel }) return null
val weightedItems = (variantList zip bakedModels)
.filter { it.second != null }
.map { (variant, model) ->
val modelWrapped = (model!! as? ISpecialRenderModel) ?: SpecialRenderWrapper(model)
SpecialRenderVariantList.WeightedModel(modelWrapped, variant.weight)
}
return SpecialRenderVariantList(weightedItems, weightedItems[0].model)
}
open class SpecialRenderVariantList(
val models: List<WeightedModel>, baseModel: ISpecialRenderModel
): IBakedModel by baseModel, ISpecialRenderModel {
class WeightedModel(val model: ISpecialRenderModel, weight: Int) : WeightedRandom.Item(weight)
val totalWeight = models.sumBy { it.itemWeight }
fun getModel(random: Random) = WeightedRandom.getRandomItem(models, random.nextInt(totalWeight))
override fun render(ctx: RenderCtxBase, noDecorations: Boolean) = getModel(ctx.random).model.render(ctx, noDecorations)
}

View File

@@ -1,57 +1,77 @@
package mods.betterfoliage.render.block.vanilla package mods.betterfoliage.render.block.vanilla
import mods.betterfoliage.BetterFoliageMod
import mods.betterfoliage.Client import mods.betterfoliage.Client
import mods.betterfoliage.config.Config import mods.betterfoliage.config.Config
import mods.betterfoliage.render.ISpecialRenderModel import mods.betterfoliage.model.Color
import mods.betterfoliage.render.old.HalfBakedSpecialWrapper import mods.betterfoliage.model.HalfBakedSpecialWrapper
import mods.betterfoliage.render.old.HalfBakedWrapKey import mods.betterfoliage.model.HalfBakedWrapperKey
import mods.betterfoliage.model.SpecialRenderModel
import mods.betterfoliage.model.SpriteSetDelegate
import mods.betterfoliage.model.buildTufts
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.resource.discovery.ModelBakeKey import mods.betterfoliage.render.pipeline.RenderCtxVanilla
import mods.betterfoliage.resource.discovery.ModelReplacer import mods.betterfoliage.resource.discovery.AbstractModelDiscovery
import mods.betterfoliage.resource.discovery.BakeWrapperManager
import mods.betterfoliage.resource.discovery.ModelBakingKey
import mods.betterfoliage.resource.generated.CenteredSprite
import mods.betterfoliage.util.Atlas
import mods.betterfoliage.util.Int3
import mods.betterfoliage.util.LazyInvalidatable
import mods.betterfoliage.util.get
import mods.betterfoliage.util.offset import mods.betterfoliage.util.offset
import mods.betterfoliage.util.randomI
import net.minecraft.block.BlockState import net.minecraft.block.BlockState
import net.minecraft.block.Blocks import net.minecraft.block.Blocks
import net.minecraft.block.material.Material
import net.minecraft.client.renderer.RenderType import net.minecraft.client.renderer.RenderType
import net.minecraft.client.renderer.RenderTypeLookup import net.minecraft.client.renderer.RenderTypeLookup
import net.minecraft.client.renderer.model.BlockModel import net.minecraft.client.renderer.model.BlockModel
import net.minecraft.client.renderer.model.ModelBakery import net.minecraft.client.renderer.model.ModelBakery
import net.minecraft.util.Direction.UP import net.minecraft.util.Direction.UP
import net.minecraft.util.ResourceLocation import net.minecraft.util.ResourceLocation
import net.minecraft.world.biome.Biome
object StandardDirtDiscovery : ModelReplacer() { object StandardDirtDiscovery : AbstractModelDiscovery() {
val dirtBlocks = listOf(Blocks.DIRT, Blocks.COARSE_DIRT, Blocks.PODZOL) val DIRT_BLOCKS = listOf(Blocks.DIRT, Blocks.COARSE_DIRT, Blocks.PODZOL)
override fun processModel( override fun processModel(
bakery: ModelBakery, bakery: ModelBakery,
state: BlockState, state: BlockState,
location: ResourceLocation, location: ResourceLocation,
sprites: MutableSet<ResourceLocation>, sprites: MutableSet<ResourceLocation>,
replacements: MutableMap<ResourceLocation, ModelBakeKey> replacements: MutableMap<ResourceLocation, ModelBakingKey>
): Boolean { ): Boolean {
val model = bakery.getUnbakedModel(location) val model = bakery.getUnbakedModel(location)
if (model is BlockModel && state.block in dirtBlocks) { if (model is BlockModel && state.block in DIRT_BLOCKS) {
Client.blockTypes.dirt.add(state) Client.blockTypes.dirt.add(state)
replacements[location] = StandardDirtKey replacements[location] = StandardDirtKey
RenderTypeLookup.setRenderLayer(state.block, RenderType.getCutout()) // RenderTypeLookup.setRenderLayer(state.block, RenderType.getCutout())
RenderTypeLookup.setRenderLayer(state.block, RenderType.getCutoutMipped())
return true return true
} }
return super.processModel(bakery, state, location, sprites, replacements) return super.processModel(bakery, state, location, sprites, replacements)
} }
} }
object StandardDirtKey : HalfBakedWrapKey() { object StandardDirtKey : HalfBakedWrapperKey() {
override fun replace(wrapped: ISpecialRenderModel) = StandardDirtModel(wrapped) override fun replace(wrapped: SpecialRenderModel) = StandardDirtModel(wrapped)
} }
class StandardDirtModel( class StandardDirtModel(
wrapped: ISpecialRenderModel wrapped: SpecialRenderModel
) : HalfBakedSpecialWrapper(wrapped) { ) : HalfBakedSpecialWrapper(wrapped) {
val vanillaTuftLighting = LightingPreferredFace(UP)
override fun render(ctx: RenderCtxBase, noDecorations: Boolean) { override fun render(ctx: RenderCtxBase, noDecorations: Boolean) {
if (!Config.enabled || noDecorations) return super.render(ctx, false) if (!Config.enabled || noDecorations) return super.render(ctx, noDecorations)
val stateUp = ctx.offset(UP).state val stateUp = ctx.offset(UP).state
val isConnectedGrass = Config.connectedGrass.enabled && stateUp in Client.blockTypes.grass val isConnectedGrass = Config.connectedGrass.enabled && stateUp in Client.blockTypes.grass
if (isConnectedGrass) { if (isConnectedGrass) {
(ctx.blockModelShapes.getModel(stateUp) as? ISpecialRenderModel)?.let { grassModel -> (ctx.blockModelShapes.getModel(stateUp) as? SpecialRenderModel)?.let { grassModel ->
ctx.renderMasquerade(UP.offset) { ctx.renderMasquerade(UP.offset) {
grassModel.render(ctx, true) grassModel.render(ctx, true)
} }
@@ -61,5 +81,39 @@ class StandardDirtModel(
} }
super.render(ctx, false) super.render(ctx, false)
val isWater = stateUp.material == Material.WATER
val isDeepWater = isWater && ctx.offset(Int3(2 to UP)).state.material == Material.WATER
val isShallowWater = isWater && ctx.offset(Int3(2 to UP)).state.isAir
val isSaltWater = isWater && ctx.biome?.category in SALTWATER_BIOMES
if (Config.algae.enabled(ctx.random) && isDeepWater) {
(ctx as? RenderCtxVanilla)?.vertexLighter = vanillaTuftLighting
ctx.render(algaeModels[ctx.random])
} else if (Config.reed.enabled(ctx.random) && isShallowWater && !isSaltWater) {
(ctx as? RenderCtxVanilla)?.vertexLighter = vanillaTuftLighting
ctx.render(reedModels[ctx.random])
}
}
companion object {
val SALTWATER_BIOMES = listOf(Biome.Category.BEACH, Biome.Category.OCEAN)
val algaeSprites by SpriteSetDelegate(Atlas.BLOCKS) { idx ->
ResourceLocation(BetterFoliageMod.MOD_ID, "blocks/better_algae_$idx")
}
val reedSprites by SpriteSetDelegate(
Atlas.BLOCKS,
idFunc = { idx -> ResourceLocation(BetterFoliageMod.MOD_ID, "blocks/better_reed_$idx") },
idRegister = { id -> CenteredSprite(id, aspectHeight = 2).register(Client.generatedPack) }
)
val algaeModels by LazyInvalidatable(BakeWrapperManager) {
val shapes = Config.algae.let { tuftShapeSet(it.size, it.heightMin, it.heightMax, it.hOffset) }
tuftModelSet(shapes, Color.white) { algaeSprites[randomI()] }.buildTufts()
}
val reedModels by LazyInvalidatable(BakeWrapperManager) {
val shapes = Config.reed.let { tuftShapeSet(2.0, it.heightMin, it.heightMax, it.hOffset) }
tuftModelSet(shapes, Color.white) { reedSprites[randomI()] }.buildTufts()
}
} }
} }

View File

@@ -6,22 +6,22 @@ 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.render.ISpecialRenderModel import mods.betterfoliage.model.SpecialRenderModel
import mods.betterfoliage.render.lighting.LightingPreferredFace import mods.betterfoliage.render.lighting.LightingPreferredFace
import mods.betterfoliage.render.old.Color import mods.betterfoliage.model.Color
import mods.betterfoliage.render.old.HalfBakedSpecialWrapper import mods.betterfoliage.model.HalfBakedSpecialWrapper
import mods.betterfoliage.render.old.HalfBakedWrapKey import mods.betterfoliage.model.HalfBakedWrapperKey
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.ConfigurableModelReplacer import mods.betterfoliage.resource.discovery.ConfigurableModelDiscovery
import mods.betterfoliage.resource.discovery.ModelBakeKey import mods.betterfoliage.resource.discovery.ModelBakingKey
import mods.betterfoliage.resource.model.SpriteSetDelegate import mods.betterfoliage.model.SpriteSetDelegate
import mods.betterfoliage.resource.model.buildTufts import mods.betterfoliage.model.buildTufts
import mods.betterfoliage.resource.model.fullCubeTextured import mods.betterfoliage.model.fullCubeTextured
import mods.betterfoliage.resource.model.fullCubeTinted import mods.betterfoliage.model.fullCubeTinted
import mods.betterfoliage.resource.model.tuftModelSet import mods.betterfoliage.model.tuftModelSet
import mods.betterfoliage.resource.model.tuftShapeSet 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
@@ -29,14 +29,11 @@ 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
import net.minecraft.block.BlockState import net.minecraft.block.BlockState
import net.minecraft.block.Blocks
import net.minecraft.client.renderer.RenderType
import net.minecraft.client.renderer.RenderTypeLookup
import net.minecraft.util.Direction.DOWN import net.minecraft.util.Direction.DOWN
import net.minecraft.util.Direction.UP import net.minecraft.util.Direction.UP
import net.minecraft.util.ResourceLocation import net.minecraft.util.ResourceLocation
object StandardGrassDiscovery : ConfigurableModelReplacer() { object StandardGrassDiscovery : ConfigurableModelDiscovery() {
override val matchClasses: ConfigurableBlockMatcher get() = BlockConfig.grassBlocks override val matchClasses: ConfigurableBlockMatcher get() = BlockConfig.grassBlocks
override val modelTextures: List<ModelTextureList> get() = BlockConfig.grassModels.modelList override val modelTextures: List<ModelTextureList> get() = BlockConfig.grassModels.modelList
@@ -45,36 +42,33 @@ object StandardGrassDiscovery : ConfigurableModelReplacer() {
location: ResourceLocation, location: ResourceLocation,
textureMatch: List<ResourceLocation>, textureMatch: List<ResourceLocation>,
sprites: MutableSet<ResourceLocation>, sprites: MutableSet<ResourceLocation>,
replacements: MutableMap<ResourceLocation, ModelBakeKey> replacements: MutableMap<ResourceLocation, ModelBakingKey>
): Boolean { ): Boolean {
replacements[location] = StandardGrassKey(textureMatch[0]) replacements[location] = StandardGrassKey(textureMatch[0])
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
} }
} }
data class StandardGrassKey( data class StandardGrassKey(
val grassLocation: ResourceLocation val grassLocation: ResourceLocation
) : HalfBakedWrapKey() { ) : HalfBakedWrapperKey() {
override fun replace(wrapped: ISpecialRenderModel): ISpecialRenderModel { override fun replace(wrapped: SpecialRenderModel): SpecialRenderModel {
Atlas.BLOCKS[grassLocation].logColorOverride(detailLogger, Config.shortGrass.saturationThreshold) Atlas.BLOCKS[grassLocation].logColorOverride(detailLogger, Config.shortGrass.saturationThreshold)
return StandardGrassModel(wrapped, this) return StandardGrassModel(wrapped, this)
} }
} }
class StandardGrassModel( class StandardGrassModel(
wrapped: ISpecialRenderModel, wrapped: SpecialRenderModel,
key: StandardGrassKey key: StandardGrassKey
) : HalfBakedSpecialWrapper(wrapped) { ) : HalfBakedSpecialWrapper(wrapped) {
val tuftNormal by grassTuftMeshesNormal.delegate(key) val tuftNormal by grassTuftMeshesNormal.delegate(key)
val tuftSnowed by grassTuftMeshesSnowed.delegate(key) val tuftSnowed by grassTuftMeshesSnowed.delegate(key)
val fullBlock by grassFullBlockMeshes.delegate(key) val fullBlock by grassFullBlockMeshes.delegate(key)
val tuftLighting = LightingPreferredFace(UP)
val upNormal = arrayOf(0.0f, 1.0f, 0.0f, 0.0f).toFloatArray()
val vanillaTuftLighting = LightingPreferredFace(UP)
override fun render(ctx: RenderCtxBase, noDecorations: Boolean) { override fun render(ctx: RenderCtxBase, noDecorations: Boolean) {
if (!Config.enabled || noDecorations) return super.render(ctx, noDecorations) if (!Config.enabled || noDecorations) return super.render(ctx, noDecorations)
@@ -94,7 +88,7 @@ class StandardGrassModel(
} }
if (Config.shortGrass.enabled(ctx.random) && !ctx.isNeighborSolid(UP)) { if (Config.shortGrass.enabled(ctx.random) && !ctx.isNeighborSolid(UP)) {
(ctx as? RenderCtxVanilla)?.let { it.vertexLighter = vanillaTuftLighting } (ctx as? RenderCtxVanilla)?.let { it.vertexLighter = tuftLighting }
ctx.render(if (isSnowed) tuftSnowed[ctx.random] else tuftNormal[ctx.random]) ctx.render(if (isSnowed) tuftSnowed[ctx.random] else tuftNormal[ctx.random])
} }
} }

View File

@@ -6,21 +6,21 @@ 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.render.ISpecialRenderModel import mods.betterfoliage.model.SpecialRenderModel
import mods.betterfoliage.render.lighting.RoundLeafLighting import mods.betterfoliage.render.lighting.RoundLeafLighting
import mods.betterfoliage.render.old.Color import mods.betterfoliage.model.Color
import mods.betterfoliage.render.old.HalfBakedSpecialWrapper import mods.betterfoliage.model.HalfBakedSpecialWrapper
import mods.betterfoliage.render.old.HalfBakedWrapKey import mods.betterfoliage.model.HalfBakedWrapperKey
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.ConfigurableModelReplacer import mods.betterfoliage.resource.discovery.ConfigurableModelDiscovery
import mods.betterfoliage.resource.discovery.ModelBakeKey import mods.betterfoliage.resource.discovery.ModelBakingKey
import mods.betterfoliage.resource.generated.GeneratedLeaf import mods.betterfoliage.resource.generated.GeneratedLeaf
import mods.betterfoliage.resource.model.SpriteSetDelegate import mods.betterfoliage.model.SpriteSetDelegate
import mods.betterfoliage.resource.model.crossModelsRaw import mods.betterfoliage.model.crossModelsRaw
import mods.betterfoliage.resource.model.crossModelsTextured import mods.betterfoliage.model.crossModelsTextured
import mods.betterfoliage.resource.model.crossModelsTinted 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
@@ -33,7 +33,7 @@ import net.minecraft.util.ResourceLocation
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
object StandardLeafDiscovery : ConfigurableModelReplacer() { object StandardLeafDiscovery : ConfigurableModelDiscovery() {
override val matchClasses: ConfigurableBlockMatcher get() = BlockConfig.leafBlocks override val matchClasses: ConfigurableBlockMatcher get() = BlockConfig.leafBlocks
override val modelTextures: List<ModelTextureList> get() = BlockConfig.leafModels.modelList override val modelTextures: List<ModelTextureList> get() = BlockConfig.leafModels.modelList
@@ -42,11 +42,11 @@ object StandardLeafDiscovery : ConfigurableModelReplacer() {
location: ResourceLocation, location: ResourceLocation,
textureMatch: List<ResourceLocation>, textureMatch: List<ResourceLocation>,
sprites: MutableSet<ResourceLocation>, sprites: MutableSet<ResourceLocation>,
replacements: MutableMap<ResourceLocation, ModelBakeKey> replacements: MutableMap<ResourceLocation, ModelBakingKey>
): Boolean { ): Boolean {
val leafType = LeafParticleRegistry.typeMappings.getType(textureMatch[0]) ?: "default" val leafType = LeafParticleRegistry.typeMappings.getType(textureMatch[0]) ?: "default"
val generated = GeneratedLeaf(textureMatch[0], leafType) val generated = GeneratedLeaf(textureMatch[0], leafType)
.register(Client.asyncPack) .register(Client.generatedPack)
.apply { sprites.add(this) } .apply { sprites.add(this) }
detailLogger.log(INFO, " particle $leafType") detailLogger.log(INFO, " particle $leafType")
@@ -72,15 +72,15 @@ fun TextureAtlasSprite.getColorOverride(threshold: Double) = averageColor.let {
data class StandardLeafKey( data class StandardLeafKey(
val roundLeafTexture: ResourceLocation, val roundLeafTexture: ResourceLocation,
val leafType: String val leafType: String
) : HalfBakedWrapKey() { ) : HalfBakedWrapperKey() {
override fun replace(wrapped: ISpecialRenderModel): ISpecialRenderModel { override fun replace(wrapped: SpecialRenderModel): SpecialRenderModel {
Atlas.BLOCKS[roundLeafTexture].logColorOverride(BetterFoliageMod.detailLogger(this), 0.1) Atlas.BLOCKS[roundLeafTexture].logColorOverride(BetterFoliageMod.detailLogger(this), 0.1)
return StandardLeafModel(wrapped, this) return StandardLeafModel(wrapped, this)
} }
} }
class StandardLeafModel( class StandardLeafModel(
model: ISpecialRenderModel, model: SpecialRenderModel,
key: StandardLeafKey key: StandardLeafKey
) : HalfBakedSpecialWrapper(model) { ) : HalfBakedSpecialWrapper(model) {
val leafNormal by leafModelsNormal.delegate(key) val leafNormal by leafModelsNormal.delegate(key)

View File

@@ -0,0 +1,83 @@
package mods.betterfoliage.render.block.vanilla
import mods.betterfoliage.BetterFoliageMod
import mods.betterfoliage.config.Config
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.tuftModelSet
import mods.betterfoliage.model.tuftShapeSet
import mods.betterfoliage.render.lighting.LightingPreferredFace
import mods.betterfoliage.render.pipeline.RenderCtxBase
import mods.betterfoliage.resource.discovery.AbstractModelDiscovery
import mods.betterfoliage.resource.discovery.BakeWrapperManager
import mods.betterfoliage.resource.discovery.ModelBakingKey
import mods.betterfoliage.util.Atlas
import mods.betterfoliage.util.LazyInvalidatable
import mods.betterfoliage.util.get
import mods.betterfoliage.util.randomI
import net.minecraft.block.BlockState
import net.minecraft.block.Blocks
import net.minecraft.client.renderer.RenderType
import net.minecraft.client.renderer.RenderTypeLookup
import net.minecraft.client.renderer.model.BlockModel
import net.minecraft.client.renderer.model.ModelBakery
import net.minecraft.util.Direction
import net.minecraft.util.ResourceLocation
object StandardMyceliumDiscovery : AbstractModelDiscovery() {
val MYCELIUM_BLOCKS = listOf(Blocks.MYCELIUM)
override fun processModel(
bakery: ModelBakery,
state: BlockState,
location: ResourceLocation,
sprites: MutableSet<ResourceLocation>,
replacements: MutableMap<ResourceLocation, ModelBakingKey>
): Boolean {
val model = bakery.getUnbakedModel(location)
if (model is BlockModel && state.block in MYCELIUM_BLOCKS) {
replacements[location] = StandardMyceliumKey
RenderTypeLookup.setRenderLayer(state.block, RenderType.getCutout())
return true
}
return super.processModel(bakery, state, location, sprites, replacements)
}
}
object StandardMyceliumKey : HalfBakedWrapperKey() {
override fun replace(wrapped: SpecialRenderModel) = StandardMyceliumModel(wrapped)
}
class StandardMyceliumModel(
wrapped: SpecialRenderModel
) : HalfBakedSpecialWrapper(wrapped) {
val tuftLighting = LightingPreferredFace(Direction.UP)
override fun render(ctx: RenderCtxBase, noDecorations: Boolean) {
super.render(ctx, noDecorations)
if (Config.shortGrass.enabled &&
Config.shortGrass.myceliumEnabled &&
Config.shortGrass.enabled(ctx.random) &&
ctx.state(Direction.UP).isAir(ctx.world, ctx.pos)
) {
ctx.vertexLighter = tuftLighting
ctx.render(myceliumTuftModels[ctx.random])
}
}
companion object {
val myceliumTuftSprites by SpriteSetDelegate(Atlas.BLOCKS) { idx ->
ResourceLocation(BetterFoliageMod.MOD_ID, "blocks/better_mycel_$idx")
}
val myceliumTuftModels by LazyInvalidatable(BakeWrapperManager) {
val shapes = Config.shortGrass.let { tuftShapeSet(it.size, it.heightMin, it.heightMax, it.hOffset) }
tuftModelSet(shapes, Color.white) { idx -> myceliumTuftSprites[randomI()] }.buildTufts()
}
}
}

View File

@@ -1,7 +1,7 @@
package mods.betterfoliage.render.block.vanilla package mods.betterfoliage.render.block.vanilla
import mods.betterfoliage.render.column.ColumnBlockKey import mods.betterfoliage.render.column.ColumnBlockKey
import mods.betterfoliage.resource.discovery.ModelBakeKey import mods.betterfoliage.resource.discovery.ModelBakingKey
import net.minecraft.util.Direction import net.minecraft.util.Direction
import net.minecraft.util.ResourceLocation import net.minecraft.util.ResourceLocation
@@ -9,5 +9,5 @@ data class RoundLogKey(
override val axis: Direction.Axis?, override val axis: Direction.Axis?,
val barkSprite: ResourceLocation, val barkSprite: ResourceLocation,
val endSprite: ResourceLocation val endSprite: ResourceLocation
) : ColumnBlockKey, ModelBakeKey { ) : ColumnBlockKey, ModelBakingKey {
} }

View File

@@ -0,0 +1,118 @@
package mods.betterfoliage.render.block.vanilla
import mods.betterfoliage.BetterFoliageMod
import mods.betterfoliage.Client
import mods.betterfoliage.config.Config
import mods.betterfoliage.model.Color
import mods.betterfoliage.model.HalfBakedSpecialWrapper
import mods.betterfoliage.model.HalfBakedWrapperKey
import mods.betterfoliage.model.Quad
import mods.betterfoliage.model.SpecialRenderModel
import mods.betterfoliage.model.SpriteSetDelegate
import mods.betterfoliage.model.bake
import mods.betterfoliage.model.buildTufts
import mods.betterfoliage.model.transform
import mods.betterfoliage.model.tuftModelSet
import mods.betterfoliage.model.tuftShapeSet
import mods.betterfoliage.render.block.vanilla.StandardDirtModel.Companion.SALTWATER_BIOMES
import mods.betterfoliage.render.lighting.LightingPreferredFace
import mods.betterfoliage.render.pipeline.RenderCtxBase
import mods.betterfoliage.resource.discovery.AbstractModelDiscovery
import mods.betterfoliage.resource.discovery.BakeWrapperManager
import mods.betterfoliage.resource.discovery.ModelBakingKey
import mods.betterfoliage.util.Atlas
import mods.betterfoliage.util.LazyInvalidatable
import mods.betterfoliage.util.Rotation
import mods.betterfoliage.util.allDirections
import mods.betterfoliage.util.get
import mods.betterfoliage.util.mapArray
import mods.betterfoliage.util.randomB
import mods.betterfoliage.util.randomD
import mods.betterfoliage.util.randomI
import net.minecraft.block.BlockState
import net.minecraft.block.Blocks
import net.minecraft.block.material.Material
import net.minecraft.client.renderer.RenderType
import net.minecraft.client.renderer.RenderTypeLookup
import net.minecraft.client.renderer.model.BlockModel
import net.minecraft.client.renderer.model.ModelBakery
import net.minecraft.util.Direction
import net.minecraft.util.Direction.UP
import net.minecraft.util.ResourceLocation
object StandardSandDiscovery : AbstractModelDiscovery() {
val SAND_BLOCKS = listOf(Blocks.SAND, Blocks.RED_SAND)
override fun processModel(
bakery: ModelBakery,
state: BlockState,
location: ResourceLocation,
sprites: MutableSet<ResourceLocation>,
replacements: MutableMap<ResourceLocation, ModelBakingKey>
): Boolean {
val model = bakery.getUnbakedModel(location)
if (model is BlockModel && state.block in SAND_BLOCKS) {
Client.blockTypes.dirt.add(state)
replacements[location] = StandardSandKey
RenderTypeLookup.setRenderLayer(state.block, RenderType.getCutoutMipped())
return true
}
return super.processModel(bakery, state, location, sprites, replacements)
}
}
object StandardSandKey : HalfBakedWrapperKey() {
override fun replace(wrapped: SpecialRenderModel) = StandardSandModel(wrapped)
}
class StandardSandModel(
wrapped: SpecialRenderModel
) : HalfBakedSpecialWrapper(wrapped) {
val coralLighting = Direction.values().mapArray { LightingPreferredFace(it) }
override fun render(ctx: RenderCtxBase, noDecorations: Boolean) {
super.render(ctx, noDecorations)
if (noDecorations || !Config.enabled || !Config.coral.enabled(ctx.random)) return
if (ctx.biome?.category !in SALTWATER_BIOMES) return
allDirections.filter { ctx.random.nextInt(64) < Config.coral.chance }.forEach { face ->
val isWater = ctx.state(face).material == Material.WATER
val isDeepWater = isWater && ctx.offset(face).state(UP).material == Material.WATER
if (isDeepWater) {
ctx.vertexLighter = coralLighting[face]
ctx.render(coralCrustModels[face][ctx.random])
ctx.render(coralTuftModels[face][ctx.random])
}
}
}
companion object {
val coralTuftSprites by SpriteSetDelegate(Atlas.BLOCKS) { idx ->
ResourceLocation(BetterFoliageMod.MOD_ID, "blocks/better_coral_$idx")
}
val coralCrustSprites by SpriteSetDelegate(Atlas.BLOCKS) { idx ->
ResourceLocation(BetterFoliageMod.MOD_ID, "blocks/better_crust_$idx")
}
val coralTuftModels by LazyInvalidatable(BakeWrapperManager) {
val shapes = Config.coral.let { tuftShapeSet(it.size, 1.0, 1.0, it.hOffset) }
allDirections.mapArray { face ->
tuftModelSet(shapes, Color.white) { coralTuftSprites[randomI()] }
.transform { rotate(Rotation.fromUp[face]) }
.buildTufts()
}
}
val coralCrustModels by LazyInvalidatable(BakeWrapperManager) {
allDirections.map { face ->
Array(64) { idx ->
listOf(
Quad.horizontalRectangle(x1 = -0.5, x2 = 0.5, z1 = -0.5, z2 = 0.5, y = 0.0)
.scale(Config.coral.crustSize)
.move(0.5 + randomD(0.01, Config.coral.vOffset) to UP)
.rotate(Rotation.fromUp[face])
.mirrorUV(randomB(), randomB()).rotateUV(randomI(max = 4))
.sprite(coralCrustSprites[idx]).colorAndIndex(null)
).bake(applyDiffuseLighting = false)
}
}.toTypedArray()
}
}
}

View File

@@ -8,26 +8,3 @@ interface ForgeVertexLighter {
fun updateVertexLightmap(normal: FloatArray, lightmap: FloatArray, x: Float, y: Float, z: Float) fun updateVertexLightmap(normal: FloatArray, lightmap: FloatArray, x: Float, y: Float, z: Float)
fun updateVertexColor(normal: FloatArray, color: FloatArray, x: Float, y: Float, z: Float, tint: Float, multiplier: Int) fun updateVertexColor(normal: FloatArray, color: FloatArray, x: Float, y: Float, z: Float, tint: Float, multiplier: Int)
} }
fun ForgeVertexLighter.grass() = object: ForgeVertexLighter {
override fun updateVertexLightmap(normal: FloatArray, lightmap: FloatArray, x: Float, y: Float, z: Float) {
this@grass.updateVertexLightmap(normal, lightmap, x * 0.5f, 1.0f, z * 0.5f)
}
override fun updateVertexColor(normal: FloatArray, color: FloatArray, x: Float, y: Float, z: Float, tint: Float, multiplier: Int) {
this@grass.updateVertexColor(normal, color, x * 0.5f, 1.0f, z * 0.5f, tint, multiplier
)
}
}
fun ForgeVertexLighter.grassSimple() = object: ForgeVertexLighter {
val normalUp = floatArrayOf(0.0f, 1.0f, 0.0f, 0.0f)
override fun updateVertexLightmap(normal: FloatArray, lightmap: FloatArray, x: Float, y: Float, z: Float) {
this@grassSimple.updateVertexLightmap(normalUp, lightmap, 0.0f, 1.0f, 0.0f)
}
override fun updateVertexColor(normal: FloatArray, color: FloatArray, x: Float, y: Float, z: Float, tint: Float, multiplier: Int) {
this@grassSimple.updateVertexColor(normalUp, color, 0.0f, 1.0f, 0.0f, tint, multiplier
)
}
}

View File

@@ -1,6 +1,6 @@
package mods.betterfoliage.render.lighting package mods.betterfoliage.render.lighting
import mods.betterfoliage.render.old.HalfBakedQuad import mods.betterfoliage.model.HalfBakedQuad
import mods.betterfoliage.util.Double3 import mods.betterfoliage.util.Double3
import mods.betterfoliage.util.EPSILON import mods.betterfoliage.util.EPSILON
import mods.betterfoliage.util.minBy import mods.betterfoliage.util.minBy

View File

@@ -1,45 +0,0 @@
package mods.betterfoliage.render.old
import net.minecraft.util.math.BlockPos
import net.minecraft.world.IBlockReader
import net.minecraft.world.ILightReader
/**
* Delegating [IBlockAccess] that fakes a _modified_ location to return values from a _target_ location.
* All other locations are handled normally.
*
* @param[original] the [IBlockAccess] that is delegated to
*/
@Suppress("NOTHING_TO_INLINE", "NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS", "HasPlatformType")
open class OffsetBlockReader(open val original: IBlockReader, val modded: BlockPos, val target: BlockPos) : IBlockReader {
inline fun actualPos(pos: BlockPos) = if (pos != null && pos.x == modded.x && pos.y == modded.y && pos.z == modded.z) target else pos
override fun getBlockState(pos: BlockPos) = original.getBlockState(actualPos(pos))
override fun getTileEntity(pos: BlockPos) = original.getTileEntity(actualPos(pos))
override fun getFluidState(pos: BlockPos) = original.getFluidState(actualPos(pos))
}
@Suppress("NOTHING_TO_INLINE", "NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS", "HasPlatformType")
class OffsetEnvBlockReader(val original: ILightReader, val modded: BlockPos, val target: BlockPos) : ILightReader by original {
inline fun actualPos(pos: BlockPos) = if (pos.x == modded.x && pos.y == modded.y && pos.z == modded.z) target else pos
override fun getBlockState(pos: BlockPos) = original.getBlockState(actualPos(pos))
override fun getTileEntity(pos: BlockPos) = original.getTileEntity(actualPos(pos))
override fun getFluidState(pos: BlockPos) = original.getFluidState(actualPos(pos))
}
/**
* Temporarily replaces the [IBlockReader] used by this [BlockContext] and the corresponding [ExtendedRenderBlocks]
* to use an [OffsetEnvBlockReader] while executing this lambda.
*
* @param[modded] the _modified_ location
* @param[target] the _target_ location
* @param[func] the lambda to execute
*/
//inline fun <reified T> BlockContext.withOffset(modded: Int3, target: Int3, func: () -> T): T {
// val original = reader!!
// reader = OffsetEnvBlockReader(original, pos + modded, pos + target)
// val result = func()
// reader = original
// return result
//}

View File

@@ -3,17 +3,27 @@ package mods.betterfoliage.render.pipeline
import com.mojang.blaze3d.matrix.MatrixStack import com.mojang.blaze3d.matrix.MatrixStack
import mods.betterfoliage.chunk.BasicBlockCtx import mods.betterfoliage.chunk.BasicBlockCtx
import mods.betterfoliage.chunk.BlockCtx import mods.betterfoliage.chunk.BlockCtx
import mods.betterfoliage.render.old.HalfBakedQuad import mods.betterfoliage.model.SpecialRenderModel
import mods.betterfoliage.render.lighting.VanillaFullBlockLighting
import mods.betterfoliage.render.lighting.VanillaQuadLighting
import mods.betterfoliage.render.lighting.VanillaVertexLighter
import mods.betterfoliage.model.HalfBakedQuad
import mods.betterfoliage.util.Int3 import mods.betterfoliage.util.Int3
import mods.betterfoliage.util.plus
import net.minecraft.block.Block import net.minecraft.block.Block
import net.minecraft.client.Minecraft import net.minecraft.client.Minecraft
import net.minecraft.client.renderer.model.IBakedModel
import net.minecraft.util.Direction import net.minecraft.util.Direction
import net.minecraft.util.math.BlockPos import net.minecraft.util.math.BlockPos
import net.minecraft.world.ILightReader import net.minecraft.world.ILightReader
import net.minecraftforge.client.model.data.IModelData import net.minecraftforge.client.model.data.IModelData
import java.util.Random import java.util.Random
/**
* Rendering context for drawing [SpecialRenderModel] models.
*
* This class (and others in its constellation) basically form a replacement, highly customizable,
* push-based partial rendering pipeline for [SpecialRenderModel] instances.
*/
abstract class RenderCtxBase( abstract class RenderCtxBase(
world: ILightReader, world: ILightReader,
pos: BlockPos, pos: BlockPos,
@@ -23,12 +33,17 @@ abstract class RenderCtxBase(
val modelData: IModelData val modelData: IModelData
) : BlockCtx by BasicBlockCtx(world, pos) { ) : BlockCtx by BasicBlockCtx(world, pos) {
abstract fun renderQuad(quad: HalfBakedQuad)
var hasRendered = false var hasRendered = false
val blockModelShapes = Minecraft.getInstance().blockRendererDispatcher.blockModelShapes val blockModelShapes = Minecraft.getInstance().blockRendererDispatcher.blockModelShapes
inline fun Direction?.shouldRender() = this == null || !checkSides || Block.shouldSideBeRendered(state, world, pos, this) var vertexLighter: VanillaVertexLighter = VanillaFullBlockLighting
protected val lightingData = RenderCtxBase.lightingData.get().apply {
calc.reset(this@RenderCtxBase)
blockColors = Minecraft.getInstance().blockColors
}
protected abstract fun renderQuad(quad: HalfBakedQuad) inline fun Direction?.shouldRender() = this == null || !checkSides || Block.shouldSideBeRendered(state, world, pos, this)
abstract fun renderFallback(model: IBakedModel)
fun render(quads: Iterable<HalfBakedQuad>) { fun render(quads: Iterable<HalfBakedQuad>) {
quads.forEach { quad -> quads.forEach { quad ->
@@ -39,5 +54,13 @@ abstract class RenderCtxBase(
} }
} }
abstract fun renderMasquerade(offset: Int3, func: ()->Unit) fun renderMasquerade(offset: Int3, func: () -> Unit) {
lightingData.calc.blockPos += offset
func()
lightingData.calc.blockPos = pos
}
companion object {
val lightingData = ThreadLocal.withInitial { VanillaQuadLighting() }
}
} }

View File

@@ -1,16 +1,12 @@
package mods.betterfoliage.render.pipeline package mods.betterfoliage.render.pipeline
import com.mojang.blaze3d.matrix.MatrixStack import com.mojang.blaze3d.matrix.MatrixStack
import mods.betterfoliage.render.ISpecialRenderModel import mods.betterfoliage.model.SpecialRenderModel
import mods.betterfoliage.render.lighting.ForgeVertexLighter import mods.betterfoliage.render.lighting.ForgeVertexLighter
import mods.betterfoliage.render.lighting.ForgeVertexLighterAccess import mods.betterfoliage.render.lighting.ForgeVertexLighterAccess
import mods.betterfoliage.render.old.HalfBakedQuad import mods.betterfoliage.model.HalfBakedQuad
import mods.betterfoliage.util.Int3
import mods.betterfoliage.util.directionsAndNull
import mods.betterfoliage.util.get
import mods.octarinecore.VertexLighterFlat_blockInfo
import net.minecraft.block.BlockState import net.minecraft.block.BlockState
import net.minecraft.client.renderer.model.IBakedModel import net.minecraft.client.renderer.LightTexture
import net.minecraft.util.math.BlockPos import net.minecraft.util.math.BlockPos
import net.minecraft.world.ILightReader import net.minecraft.world.ILightReader
import net.minecraftforge.client.model.data.IModelData import net.minecraftforge.client.model.data.IModelData
@@ -25,28 +21,28 @@ class RenderCtxForge(
checkSides: Boolean, checkSides: Boolean,
random: Random, random: Random,
modelData: IModelData modelData: IModelData
): RenderCtxBase(world, pos, matrixStack, checkSides, random, modelData), ForgeVertexLighterAccess { ): RenderCtxBase(world, pos, matrixStack, checkSides, random, modelData), ForgeVertexLighter {
val blockInfo = lighter[VertexLighterFlat_blockInfo] override fun renderQuad(quad: HalfBakedQuad) {
override var vertexLighter: ForgeVertexLighter // set Forge lighter AO calculator to us
get() = (lighter as ForgeVertexLighterAccess).vertexLighter vertexLighter.updateLightmapAndColor(quad, lightingData)
set(value) { (lighter as ForgeVertexLighterAccess).vertexLighter = value } quad.baked.pipe(lighter)
override fun renderQuad(quad: HalfBakedQuad) { quad.baked.pipe(lighter) }
override fun renderFallback(model: IBakedModel) {
directionsAndNull.forEach { face ->
model.getQuads(state, null, random, modelData).forEach { quad ->
if (quad.face.shouldRender()) {
quad.pipe(lighter)
hasRendered = true
}
} }
// somewhat ugly hack to pipe lighting values into the Forge pipeline
var vIdx = 0
override fun updateVertexLightmap(normal: FloatArray, lightmap: FloatArray, x: Float, y: Float, z: Float) {
lightingData.packedLight[vIdx].let { packedLight ->
lightmap[0] = LightTexture.getLightBlock(packedLight) / 0xF.toFloat()
lightmap[1] = LightTexture.getLightSky(packedLight) / 0xF.toFloat()
} }
} }
override fun renderMasquerade(offset: Int3, func: () -> Unit) { override fun updateVertexColor(normal: FloatArray, color: FloatArray, x: Float, y: Float, z: Float, tint: Float, multiplier: Int) {
TODO("Not yet implemented") color[0] = lightingData.tint[0] * lightingData.colorMultiplier[vIdx]
color[1] = lightingData.tint[1] * lightingData.colorMultiplier[vIdx]
color[2] = lightingData.tint[2] * lightingData.colorMultiplier[vIdx]
vIdx++
} }
companion object { companion object {
@@ -54,7 +50,7 @@ class RenderCtxForge(
fun render( fun render(
lighter: VertexLighterFlat, lighter: VertexLighterFlat,
world: ILightReader, world: ILightReader,
model: ISpecialRenderModel, model: SpecialRenderModel,
state: BlockState, state: BlockState,
pos: BlockPos, pos: BlockPos,
matrixStack: MatrixStack, matrixStack: MatrixStack,
@@ -68,6 +64,7 @@ class RenderCtxForge(
rand.setSeed(seed) rand.setSeed(seed)
lighter.updateBlockInfo() lighter.updateBlockInfo()
return RenderCtxForge(world, pos, lighter, matrixStack, checkSides, rand, modelData).let { return RenderCtxForge(world, pos, lighter, matrixStack, checkSides, rand, modelData).let {
(lighter as ForgeVertexLighterAccess).vertexLighter = it
model.render(it, false) model.render(it, false)
lighter.resetBlockInfo() lighter.resetBlockInfo()
it.hasRendered it.hasRendered

View File

@@ -2,17 +2,10 @@ package mods.betterfoliage.render.pipeline
import com.mojang.blaze3d.matrix.MatrixStack import com.mojang.blaze3d.matrix.MatrixStack
import com.mojang.blaze3d.vertex.IVertexBuilder import com.mojang.blaze3d.vertex.IVertexBuilder
import mods.betterfoliage.render.ISpecialRenderModel import mods.betterfoliage.model.SpecialRenderModel
import mods.betterfoliage.render.lighting.VanillaFullBlockLighting import mods.betterfoliage.model.HalfBakedQuad
import mods.betterfoliage.render.lighting.VanillaVertexLighter
import mods.betterfoliage.render.lighting.VanillaQuadLighting
import mods.betterfoliage.render.old.HalfBakedQuad
import mods.betterfoliage.util.Int3
import mods.betterfoliage.util.ThreadLocalDelegate
import mods.betterfoliage.util.plus
import net.minecraft.block.BlockState import net.minecraft.block.BlockState
import net.minecraft.client.renderer.BlockModelRenderer import net.minecraft.client.renderer.BlockModelRenderer
import net.minecraft.client.renderer.model.IBakedModel
import net.minecraft.util.math.BlockPos import net.minecraft.util.math.BlockPos
import net.minecraft.world.ILightReader import net.minecraft.world.ILightReader
import net.minecraftforge.client.model.data.IModelData import net.minecraftforge.client.model.data.IModelData
@@ -32,38 +25,22 @@ class RenderCtxVanilla(
val useAO: Boolean val useAO: Boolean
): RenderCtxBase(world, pos, matrixStack, checkSides, random, modelData) { ): RenderCtxBase(world, pos, matrixStack, checkSides, random, modelData) {
private val blockColors = renderer.blockColors
var vertexLighter: VanillaVertexLighter = VanillaFullBlockLighting
override fun renderQuad(quad: HalfBakedQuad) { override fun renderQuad(quad: HalfBakedQuad) {
lightingData.let { lighting -> vertexLighter.updateLightmapAndColor(quad, lightingData)
vertexLighter.updateLightmapAndColor(quad, lighting)
buffer.addQuad( buffer.addQuad(
matrixStack.last, quad.baked, matrixStack.last, quad.baked,
lighting.colorMultiplier, lightingData.colorMultiplier,
lighting.tint[0], lighting.tint[1], lighting.tint[2], lightingData.tint[0], lightingData.tint[1], lightingData.tint[2],
lighting.packedLight, combinedOverlay, true lightingData.packedLight, combinedOverlay, true
) )
} }
}
override fun renderFallback(model: IBakedModel) {
if (useAO) renderer.renderModelSmooth(world, model, state, pos, matrixStack, buffer, checkSides, random, seed, combinedOverlay, modelData)
else renderer.renderModelFlat(world, model, state, pos, matrixStack, buffer, checkSides, random, seed, combinedOverlay, modelData)
}
override fun renderMasquerade(offset: Int3, func: () -> Unit) {
lightingData.calc.blockPos += offset
func()
lightingData.calc.blockPos = pos
}
companion object { companion object {
@JvmStatic @JvmStatic
fun render( fun render(
renderer: BlockModelRenderer, renderer: BlockModelRenderer,
world: ILightReader, world: ILightReader,
model: ISpecialRenderModel, model: SpecialRenderModel,
state: BlockState, state: BlockState,
pos: BlockPos, pos: BlockPos,
matrixStack: MatrixStack, matrixStack: MatrixStack,
@@ -78,13 +55,12 @@ class RenderCtxVanilla(
random.setSeed(rand) random.setSeed(rand)
val ctx = RenderCtxVanilla(renderer, world, pos, buffer, combinedOverlay, matrixStack, checkSides, random, rand, modelData, smooth) val ctx = RenderCtxVanilla(renderer, world, pos, buffer, combinedOverlay, matrixStack, checkSides, random, rand, modelData, smooth)
lightingData.apply { lightingData.apply {
calc.reset(ctx)
blockColors = renderer.blockColors
} }
model.render(ctx, false) model.render(ctx, false)
return ctx.hasRendered return ctx.hasRendered
} }
val lightingData by ThreadLocalDelegate { VanillaQuadLighting() }
} }
} }

View File

@@ -1,12 +1,11 @@
package mods.betterfoliage.resource.discovery package mods.betterfoliage.resource.discovery
import mods.betterfoliage.ModelDefinitionsLoadedEvent import mods.betterfoliage.ModelDefinitionsLoadedEvent
import mods.betterfoliage.render.bakeSpecial 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
import mods.betterfoliage.util.Invalidator import mods.betterfoliage.util.Invalidator
import mods.betterfoliage.util.SimpleInvalidator import mods.betterfoliage.util.SimpleInvalidator
import mods.betterfoliage.util.asBlockMaterial
import net.minecraft.client.renderer.model.IBakedModel import net.minecraft.client.renderer.model.IBakedModel
import net.minecraft.client.renderer.model.IModelTransform import net.minecraft.client.renderer.model.IModelTransform
import net.minecraft.client.renderer.model.IUnbakedModel import net.minecraft.client.renderer.model.IUnbakedModel
@@ -17,11 +16,9 @@ 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.common.ForgeConfig
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 org.apache.logging.log4j.LogManager
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
import java.util.function.Function import java.util.function.Function
@@ -29,13 +26,12 @@ interface ModelDiscovery {
fun onModelsLoaded( fun onModelsLoaded(
bakery: ModelBakery, bakery: ModelBakery,
sprites: MutableSet<ResourceLocation>, sprites: MutableSet<ResourceLocation>,
replacements: MutableMap<ResourceLocation, ModelBakeKey> replacements: MutableMap<ResourceLocation, ModelBakingKey>
) )
} }
@FunctionalInterface interface ModelBakingKey {
interface ModelBakeKey { fun bake(
fun replace(
location: ResourceLocation, location: ResourceLocation,
unbaked: IUnbakedModel, unbaked: IUnbakedModel,
transform: IModelTransform, transform: IModelTransform,
@@ -44,28 +40,6 @@ interface ModelBakeKey {
): IBakedModel? = unbaked.bakeModel(bakery, spriteGetter, transform, location) ): IBakedModel? = unbaked.bakeModel(bakery, spriteGetter, transform, location)
} }
interface ModelWrapperKey : ModelBakeKey {
override fun replace(
location: ResourceLocation,
unbaked: IUnbakedModel,
transform: IModelTransform,
bakery: ModelBakery,
spriteGetter: Function<Material, TextureAtlasSprite>
): IBakedModel? {
val baked = super.replace(location, unbaked, transform, bakery, spriteGetter) ?: return null
val sprites = { res: ResourceLocation -> spriteGetter.apply(res.asBlockMaterial) }
return replace(location, baked, sprites)
}
fun replace(
location: ResourceLocation,
wrapped: IBakedModel,
sprites: (ResourceLocation) -> TextureAtlasSprite
) = replace(wrapped)
fun replace(wrapped: IBakedModel) = wrapped
}
object BakeWrapperManager : Invalidator, HasLogger() { object BakeWrapperManager : Invalidator, HasLogger() {
val discoverers = mutableListOf<ModelDiscovery>() val discoverers = mutableListOf<ModelDiscovery>()
override val callbacks = mutableListOf<WeakReference<()->Unit>>() override val callbacks = mutableListOf<WeakReference<()->Unit>>()
@@ -73,7 +47,7 @@ object BakeWrapperManager : Invalidator, HasLogger() {
val modelsValid = SimpleInvalidator() val modelsValid = SimpleInvalidator()
val spritesValid = SimpleInvalidator() val spritesValid = SimpleInvalidator()
private val replacements = mutableMapOf<ResourceLocation, ModelBakeKey>() private val replacements = mutableMapOf<ResourceLocation, ModelBakingKey>()
private val sprites = mutableSetOf<ResourceLocation>() private val sprites = mutableSetOf<ResourceLocation>()
@SubscribeEvent @SubscribeEvent
@@ -82,7 +56,7 @@ object BakeWrapperManager : Invalidator, HasLogger() {
StartupMessageManager.addModMessage("BetterFoliage: discovering models") StartupMessageManager.addModMessage("BetterFoliage: discovering models")
logger.log(INFO, "starting model discovery (${discoverers.size} listeners)") logger.log(INFO, "starting model discovery (${discoverers.size} listeners)")
discoverers.forEach { listener -> discoverers.forEach { listener ->
val replacementsLocal = mutableMapOf<ResourceLocation, ModelBakeKey>() val replacementsLocal = mutableMapOf<ResourceLocation, ModelBakingKey>()
listener.onModelsLoaded(event.bakery, sprites, replacementsLocal) listener.onModelsLoaded(event.bakery, sprites, replacementsLocal)
replacements.putAll(replacementsLocal) replacements.putAll(replacementsLocal)
} }
@@ -113,10 +87,10 @@ object BakeWrapperManager : Invalidator, HasLogger() {
// bake replacement if available // bake replacement if available
replacements[location]?.let { replacement -> replacements[location]?.let { replacement ->
detailLogger.log(INFO, "Baking replacement for [${unbaked::class.java.simpleName}] $location -> $replacement") detailLogger.log(INFO, "Baking replacement for [${unbaked::class.java.simpleName}] $location -> $replacement")
return replacement.replace(location, unbaked, transform, bakery, spriteGetter) return replacement.bake(location, unbaked, transform, bakery, spriteGetter)
} }
// container model support // container model support
if (unbaked is VariantList) unbaked.bakeSpecial(bakery, spriteGetter)?.let { if (unbaked is VariantList) SpecialRenderVariantList.bakeIfSpecial(location, unbaked, bakery, spriteGetter)?.let {
detailLogger.log(INFO, "Wrapping container [${unbaked::class.java.simpleName}] $location") detailLogger.log(INFO, "Wrapping container [${unbaked::class.java.simpleName}] $location")
return it return it
} }

View File

@@ -11,7 +11,7 @@ class BlockTypeCache {
val dirt = mutableSetOf<BlockState>() val dirt = mutableSetOf<BlockState>()
companion object : ModelDiscovery { companion object : ModelDiscovery {
override fun onModelsLoaded(bakery: ModelBakery, sprites: MutableSet<ResourceLocation>, replacements: MutableMap<ResourceLocation, ModelBakeKey> override fun onModelsLoaded(bakery: ModelBakery, sprites: MutableSet<ResourceLocation>, replacements: MutableMap<ResourceLocation, ModelBakingKey>
) { ) {
Client.blockTypes = BlockTypeCache() Client.blockTypes = BlockTypeCache()
} }

View File

@@ -15,11 +15,11 @@ import net.minecraft.util.ResourceLocation
import net.minecraftforge.registries.ForgeRegistries import net.minecraftforge.registries.ForgeRegistries
import org.apache.logging.log4j.Level import org.apache.logging.log4j.Level
abstract class ModelReplacer : HasLogger(), ModelDiscovery { abstract class AbstractModelDiscovery : HasLogger(), ModelDiscovery {
override fun onModelsLoaded( override fun onModelsLoaded(
bakery: ModelBakery, bakery: ModelBakery,
sprites: MutableSet<ResourceLocation>, sprites: MutableSet<ResourceLocation>,
replacements: MutableMap<ResourceLocation, ModelBakeKey> replacements: MutableMap<ResourceLocation, ModelBakingKey>
) { ) {
ForgeRegistries.BLOCKS ForgeRegistries.BLOCKS
.flatMap { block -> block.stateContainer.validStates } .flatMap { block -> block.stateContainer.validStates }
@@ -38,7 +38,7 @@ abstract class ModelReplacer : HasLogger(), ModelDiscovery {
state: BlockState, state: BlockState,
location: ResourceLocation, location: ResourceLocation,
sprites: MutableSet<ResourceLocation>, sprites: MutableSet<ResourceLocation>,
replacements: MutableMap<ResourceLocation, ModelBakeKey> replacements: MutableMap<ResourceLocation, ModelBakingKey>
): Boolean { ): Boolean {
// built-in support for container models // built-in support for container models
return when (val model = bakery.getUnbakedModel(location)) { return when (val model = bakery.getUnbakedModel(location)) {
@@ -59,9 +59,7 @@ abstract class ModelReplacer : HasLogger(), ModelDiscovery {
} }
} }
abstract class ConfigurableModelDiscovery : AbstractModelDiscovery() {
abstract class ConfigurableModelReplacer : ModelReplacer() {
abstract val matchClasses: IBlockMatcher abstract val matchClasses: IBlockMatcher
abstract val modelTextures: List<ModelTextureList> abstract val modelTextures: List<ModelTextureList>
@@ -70,7 +68,7 @@ abstract class ConfigurableModelReplacer : ModelReplacer() {
location: ResourceLocation, location: ResourceLocation,
textureMatch: List<ResourceLocation>, textureMatch: List<ResourceLocation>,
sprites: MutableSet<ResourceLocation>, sprites: MutableSet<ResourceLocation>,
replacements: MutableMap<ResourceLocation, ModelBakeKey> replacements: MutableMap<ResourceLocation, ModelBakingKey>
): Boolean ): Boolean
override fun processModel( override fun processModel(
@@ -78,7 +76,7 @@ abstract class ConfigurableModelReplacer : ModelReplacer() {
state: BlockState, state: BlockState,
location: ResourceLocation, location: ResourceLocation,
sprites: MutableSet<ResourceLocation>, sprites: MutableSet<ResourceLocation>,
replacements: MutableMap<ResourceLocation, ModelBakeKey> replacements: MutableMap<ResourceLocation, ModelBakingKey>
): Boolean { ): Boolean {
val model = bakery.getUnbakedModel(location) val model = bakery.getUnbakedModel(location)
if (model is BlockModel) { if (model is BlockModel) {

View File

@@ -1,6 +1,6 @@
package mods.betterfoliage.util package mods.betterfoliage.util
import mods.betterfoliage.render.old.HSB import mods.betterfoliage.model.HSB
import net.minecraft.client.Minecraft import net.minecraft.client.Minecraft
import net.minecraft.client.renderer.model.Material import net.minecraft.client.renderer.model.Material
import net.minecraft.client.renderer.texture.AtlasTexture import net.minecraft.client.renderer.texture.AtlasTexture