[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.vertex.IVertexBuilder;
import mods.betterfoliage.render.ISpecialRenderModel;
import mods.betterfoliage.model.SpecialRenderModel;
import mods.betterfoliage.render.pipeline.RenderCtxVanilla;
import net.minecraft.block.BlockState;
import net.minecraft.client.renderer.BlockModelRenderer;
@@ -25,16 +25,16 @@ public class MixinBlockModelRenderer {
@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) {
if (model instanceof ISpecialRenderModel)
return RenderCtxVanilla.render(renderer, world, (ISpecialRenderModel) model, state, pos, matrixStack, buffer, checkSides, random, rand, combinedOverlay, modelData, true);
if (model instanceof SpecialRenderModel)
return RenderCtxVanilla.render(renderer, world, (SpecialRenderModel) model, state, pos, matrixStack, buffer, checkSides, random, rand, combinedOverlay, modelData, true);
else
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)
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)
return RenderCtxVanilla.render(renderer, world, (ISpecialRenderModel) model, state, pos, matrixStack, buffer, checkSides, random, rand, combinedOverlay, modelData, false);
if (model instanceof SpecialRenderModel)
return RenderCtxVanilla.render(renderer, world, (SpecialRenderModel) model, state, pos, matrixStack, buffer, checkSides, random, rand, combinedOverlay, modelData, false);
else
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 mods.betterfoliage.render.pipeline.RenderCtxForge;
import mods.betterfoliage.render.ISpecialRenderModel;
import mods.betterfoliage.model.SpecialRenderModel;
import net.minecraft.block.BlockState;
import net.minecraft.client.renderer.model.IBakedModel;
import net.minecraft.util.math.BlockPos;
@@ -36,8 +36,8 @@ public class MixinForgeBlockModelRenderer {
long seed,
IModelData modelData
) {
if (model instanceof ISpecialRenderModel)
return RenderCtxForge.render(lighter, world, (ISpecialRenderModel) model, state, pos, matrixStack, checkSides, rand, seed, modelData);
if (model instanceof SpecialRenderModel)
return RenderCtxForge.render(lighter, world, (SpecialRenderModel) model, state, pos, matrixStack, checkSides, rand, seed, modelData);
else
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)
void onReset(CallbackInfo ci) {
// just in case
vertexLighter = this;
}
}

View File

@@ -33,7 +33,7 @@ object BetterFoliageMod {
init {
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)
Client.init()
}

View File

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

View File

@@ -7,6 +7,7 @@ import mods.betterfoliage.util.plus
import mods.betterfoliage.util.semiRandom
import net.minecraft.block.Block
import net.minecraft.block.BlockState
import net.minecraft.client.renderer.chunk.ChunkRenderCache
import net.minecraft.util.Direction
import net.minecraft.util.math.BlockPos
import net.minecraft.world.ILightReader
@@ -29,7 +30,9 @@ interface BlockCtx {
fun state(dir: Direction) = world.getBlockState(pos + dir.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)

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.resource.discovery.ModelBakeKey
import mods.betterfoliage.resource.discovery.ModelBakingKey
import mods.betterfoliage.util.Double3
import mods.betterfoliage.util.HasLogger
import mods.betterfoliage.util.directionsAndNull
@@ -21,13 +20,19 @@ import net.minecraftforge.client.model.pipeline.BakedQuadBuilder
import java.util.Random
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(
val raw: Quad,
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()
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) {
baseModel.render(ctx, noDecorations)
}
}
abstract class HalfBakedWrapKey : ModelBakeKey, HasLogger() {
override fun replace(
abstract class HalfBakedWrapperKey : ModelBakingKey, HasLogger() {
override fun bake(
location: ResourceLocation,
unbaked: IUnbakedModel,
transform: IModelTransform,
bakery: ModelBakery,
spriteGetter: Function<Material, TextureAtlasSprite>
): IBakedModel? {
val baseModel = super.replace(location, unbaked, transform, bakery, spriteGetter)
val baseModel = super.bake(location, unbaked, transform, bakery, spriteGetter)
val halfBaked = when(baseModel) {
is SimpleBakedModel -> HalfBakedSimpleModelWrapper(baseModel)
else -> null
@@ -57,7 +62,8 @@ abstract class HalfBakedWrapKey : ModelBakeKey, HasLogger() {
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 ->

View File

@@ -1,26 +1,16 @@
package mods.betterfoliage.render.old
package mods.betterfoliage.model
import mods.betterfoliage.util.Double3
import mods.betterfoliage.util.Rotation
import mods.betterfoliage.util.allDirections
import mods.betterfoliage.util.boxFaces
import mods.betterfoliage.util.get
import mods.betterfoliage.util.minmax
import mods.betterfoliage.util.nearestAngle
import mods.betterfoliage.util.replace
import mods.betterfoliage.util.rotate
import mods.betterfoliage.util.times
import mods.betterfoliage.util.toImmutableList
import mods.betterfoliage.util.vec
import net.minecraft.client.renderer.model.BakedQuad
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.minecraftforge.client.model.pipeline.BakedQuadBuilder
import java.lang.Math.max
import java.lang.Math.min
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.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.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.Double3
import mods.betterfoliage.util.PI2
import mods.betterfoliage.util.allDirections
import mods.betterfoliage.util.averageColor
import mods.betterfoliage.util.random
import mods.betterfoliage.util.randomB
import mods.betterfoliage.util.randomD
import mods.betterfoliage.util.randomI
import mods.betterfoliage.util.rot
import mods.betterfoliage.util.vec
import net.minecraft.client.renderer.model.BakedQuad
import net.minecraft.client.renderer.texture.TextureAtlasSprite
import net.minecraft.util.Direction.UP
import net.minecraft.util.ResourceLocation
@@ -126,4 +120,6 @@ fun crossModelsTinted(
fun List<Quad>.withOpposites() = flatMap { listOf(it, it.flipped) }
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.render.old.AbstractEntityFX
import mods.betterfoliage.render.old.HSB
import mods.betterfoliage.model.HSB
import mods.betterfoliage.util.Double3
import mods.betterfoliage.util.PI2
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
import mods.betterfoliage.BetterFoliageMod
import mods.betterfoliage.Client
import mods.betterfoliage.config.Config
import mods.betterfoliage.render.ISpecialRenderModel
import mods.betterfoliage.render.old.HalfBakedSpecialWrapper
import mods.betterfoliage.render.old.HalfBakedWrapKey
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.ModelBakeKey
import mods.betterfoliage.resource.discovery.ModelReplacer
import mods.betterfoliage.render.pipeline.RenderCtxVanilla
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.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.UP
import net.minecraft.util.ResourceLocation
import net.minecraft.world.biome.Biome
object StandardDirtDiscovery : ModelReplacer() {
val dirtBlocks = listOf(Blocks.DIRT, Blocks.COARSE_DIRT, Blocks.PODZOL)
object StandardDirtDiscovery : AbstractModelDiscovery() {
val DIRT_BLOCKS = listOf(Blocks.DIRT, Blocks.COARSE_DIRT, Blocks.PODZOL)
override fun processModel(
bakery: ModelBakery,
state: BlockState,
location: ResourceLocation,
sprites: MutableSet<ResourceLocation>,
replacements: MutableMap<ResourceLocation, ModelBakeKey>
replacements: MutableMap<ResourceLocation, ModelBakingKey>
): Boolean {
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)
replacements[location] = StandardDirtKey
RenderTypeLookup.setRenderLayer(state.block, RenderType.getCutout())
// RenderTypeLookup.setRenderLayer(state.block, RenderType.getCutout())
RenderTypeLookup.setRenderLayer(state.block, RenderType.getCutoutMipped())
return true
}
return super.processModel(bakery, state, location, sprites, replacements)
}
}
object StandardDirtKey : HalfBakedWrapKey() {
override fun replace(wrapped: ISpecialRenderModel) = StandardDirtModel(wrapped)
object StandardDirtKey : HalfBakedWrapperKey() {
override fun replace(wrapped: SpecialRenderModel) = StandardDirtModel(wrapped)
}
class StandardDirtModel(
wrapped: ISpecialRenderModel
wrapped: SpecialRenderModel
) : HalfBakedSpecialWrapper(wrapped) {
val vanillaTuftLighting = LightingPreferredFace(UP)
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 isConnectedGrass = Config.connectedGrass.enabled && stateUp in Client.blockTypes.grass
if (isConnectedGrass) {
(ctx.blockModelShapes.getModel(stateUp) as? ISpecialRenderModel)?.let { grassModel ->
(ctx.blockModelShapes.getModel(stateUp) as? SpecialRenderModel)?.let { grassModel ->
ctx.renderMasquerade(UP.offset) {
grassModel.render(ctx, true)
}
@@ -61,5 +81,39 @@ class StandardDirtModel(
}
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.ConfigurableBlockMatcher
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.old.Color
import mods.betterfoliage.render.old.HalfBakedSpecialWrapper
import mods.betterfoliage.render.old.HalfBakedWrapKey
import mods.betterfoliage.model.Color
import mods.betterfoliage.model.HalfBakedSpecialWrapper
import mods.betterfoliage.model.HalfBakedWrapperKey
import mods.betterfoliage.render.pipeline.RenderCtxBase
import mods.betterfoliage.render.pipeline.RenderCtxVanilla
import mods.betterfoliage.resource.discovery.BakeWrapperManager
import mods.betterfoliage.resource.discovery.ConfigurableModelReplacer
import mods.betterfoliage.resource.discovery.ModelBakeKey
import mods.betterfoliage.resource.model.SpriteSetDelegate
import mods.betterfoliage.resource.model.buildTufts
import mods.betterfoliage.resource.model.fullCubeTextured
import mods.betterfoliage.resource.model.fullCubeTinted
import mods.betterfoliage.resource.model.tuftModelSet
import mods.betterfoliage.resource.model.tuftShapeSet
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
@@ -29,14 +29,11 @@ import mods.betterfoliage.util.get
import mods.betterfoliage.util.isSnow
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.util.Direction.DOWN
import net.minecraft.util.Direction.UP
import net.minecraft.util.ResourceLocation
object StandardGrassDiscovery : ConfigurableModelReplacer() {
object StandardGrassDiscovery : ConfigurableModelDiscovery() {
override val matchClasses: ConfigurableBlockMatcher get() = BlockConfig.grassBlocks
override val modelTextures: List<ModelTextureList> get() = BlockConfig.grassModels.modelList
@@ -45,36 +42,33 @@ object StandardGrassDiscovery : ConfigurableModelReplacer() {
location: ResourceLocation,
textureMatch: List<ResourceLocation>,
sprites: MutableSet<ResourceLocation>,
replacements: MutableMap<ResourceLocation, ModelBakeKey>
replacements: MutableMap<ResourceLocation, ModelBakingKey>
): Boolean {
replacements[location] = StandardGrassKey(textureMatch[0])
Client.blockTypes.grass.add(state)
RenderTypeLookup.setRenderLayer(state.block, RenderType.getCutout())
// RenderTypeLookup.setRenderLayer(state.block, RenderType.getCutout())
return true
}
}
data class StandardGrassKey(
val grassLocation: ResourceLocation
) : HalfBakedWrapKey() {
override fun replace(wrapped: ISpecialRenderModel): ISpecialRenderModel {
) : HalfBakedWrapperKey() {
override fun replace(wrapped: SpecialRenderModel): SpecialRenderModel {
Atlas.BLOCKS[grassLocation].logColorOverride(detailLogger, Config.shortGrass.saturationThreshold)
return StandardGrassModel(wrapped, this)
}
}
class StandardGrassModel(
wrapped: ISpecialRenderModel,
wrapped: SpecialRenderModel,
key: StandardGrassKey
) : HalfBakedSpecialWrapper(wrapped) {
val tuftNormal by grassTuftMeshesNormal.delegate(key)
val tuftSnowed by grassTuftMeshesSnowed.delegate(key)
val fullBlock by grassFullBlockMeshes.delegate(key)
val upNormal = arrayOf(0.0f, 1.0f, 0.0f, 0.0f).toFloatArray()
val vanillaTuftLighting = LightingPreferredFace(UP)
val tuftLighting = LightingPreferredFace(UP)
override fun render(ctx: RenderCtxBase, noDecorations: Boolean) {
if (!Config.enabled || noDecorations) return super.render(ctx, noDecorations)
@@ -94,7 +88,7 @@ class StandardGrassModel(
}
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])
}
}

View File

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

@@ -7,27 +7,4 @@ interface ForgeVertexLighterAccess {
interface ForgeVertexLighter {
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 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
import mods.betterfoliage.render.old.HalfBakedQuad
import mods.betterfoliage.model.HalfBakedQuad
import mods.betterfoliage.util.Double3
import mods.betterfoliage.util.EPSILON
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 mods.betterfoliage.chunk.BasicBlockCtx
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.plus
import net.minecraft.block.Block
import net.minecraft.client.Minecraft
import net.minecraft.client.renderer.model.IBakedModel
import net.minecraft.util.Direction
import net.minecraft.util.math.BlockPos
import net.minecraft.world.ILightReader
import net.minecraftforge.client.model.data.IModelData
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(
world: ILightReader,
pos: BlockPos,
@@ -23,12 +33,17 @@ abstract class RenderCtxBase(
val modelData: IModelData
) : BlockCtx by BasicBlockCtx(world, pos) {
abstract fun renderQuad(quad: HalfBakedQuad)
var hasRendered = false
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)
abstract fun renderFallback(model: IBakedModel)
inline fun Direction?.shouldRender() = this == null || !checkSides || Block.shouldSideBeRendered(state, world, pos, this)
fun render(quads: Iterable<HalfBakedQuad>) {
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
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.ForgeVertexLighterAccess
import mods.betterfoliage.render.old.HalfBakedQuad
import mods.betterfoliage.util.Int3
import mods.betterfoliage.util.directionsAndNull
import mods.betterfoliage.util.get
import mods.octarinecore.VertexLighterFlat_blockInfo
import mods.betterfoliage.model.HalfBakedQuad
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.world.ILightReader
import net.minecraftforge.client.model.data.IModelData
@@ -25,28 +21,28 @@ class RenderCtxForge(
checkSides: Boolean,
random: Random,
modelData: IModelData
): RenderCtxBase(world, pos, matrixStack, checkSides, random, modelData), ForgeVertexLighterAccess {
): RenderCtxBase(world, pos, matrixStack, checkSides, random, modelData), ForgeVertexLighter {
val blockInfo = lighter[VertexLighterFlat_blockInfo]
override var vertexLighter: ForgeVertexLighter
get() = (lighter as ForgeVertexLighterAccess).vertexLighter
set(value) { (lighter as ForgeVertexLighterAccess).vertexLighter = value }
override fun renderQuad(quad: HalfBakedQuad) {
// set Forge lighter AO calculator to us
vertexLighter.updateLightmapAndColor(quad, lightingData)
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) {
TODO("Not yet implemented")
override fun updateVertexColor(normal: FloatArray, color: FloatArray, x: Float, y: Float, z: Float, tint: Float, multiplier: Int) {
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 {
@@ -54,7 +50,7 @@ class RenderCtxForge(
fun render(
lighter: VertexLighterFlat,
world: ILightReader,
model: ISpecialRenderModel,
model: SpecialRenderModel,
state: BlockState,
pos: BlockPos,
matrixStack: MatrixStack,
@@ -68,6 +64,7 @@ class RenderCtxForge(
rand.setSeed(seed)
lighter.updateBlockInfo()
return RenderCtxForge(world, pos, lighter, matrixStack, checkSides, rand, modelData).let {
(lighter as ForgeVertexLighterAccess).vertexLighter = it
model.render(it, false)
lighter.resetBlockInfo()
it.hasRendered

View File

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

View File

@@ -1,12 +1,11 @@
package mods.betterfoliage.resource.discovery
import mods.betterfoliage.ModelDefinitionsLoadedEvent
import mods.betterfoliage.render.bakeSpecial
import mods.betterfoliage.model.SpecialRenderVariantList
import mods.betterfoliage.util.Atlas
import mods.betterfoliage.util.HasLogger
import mods.betterfoliage.util.Invalidator
import mods.betterfoliage.util.SimpleInvalidator
import mods.betterfoliage.util.asBlockMaterial
import net.minecraft.client.renderer.model.IBakedModel
import net.minecraft.client.renderer.model.IModelTransform
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.minecraftforge.client.event.ModelBakeEvent
import net.minecraftforge.client.event.TextureStitchEvent
import net.minecraftforge.common.ForgeConfig
import net.minecraftforge.eventbus.api.SubscribeEvent
import net.minecraftforge.fml.loading.progress.StartupMessageManager
import org.apache.logging.log4j.Level.INFO
import org.apache.logging.log4j.LogManager
import java.lang.ref.WeakReference
import java.util.function.Function
@@ -29,13 +26,12 @@ interface ModelDiscovery {
fun onModelsLoaded(
bakery: ModelBakery,
sprites: MutableSet<ResourceLocation>,
replacements: MutableMap<ResourceLocation, ModelBakeKey>
replacements: MutableMap<ResourceLocation, ModelBakingKey>
)
}
@FunctionalInterface
interface ModelBakeKey {
fun replace(
interface ModelBakingKey {
fun bake(
location: ResourceLocation,
unbaked: IUnbakedModel,
transform: IModelTransform,
@@ -44,28 +40,6 @@ interface ModelBakeKey {
): 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() {
val discoverers = mutableListOf<ModelDiscovery>()
override val callbacks = mutableListOf<WeakReference<()->Unit>>()
@@ -73,7 +47,7 @@ object BakeWrapperManager : Invalidator, HasLogger() {
val modelsValid = SimpleInvalidator()
val spritesValid = SimpleInvalidator()
private val replacements = mutableMapOf<ResourceLocation, ModelBakeKey>()
private val replacements = mutableMapOf<ResourceLocation, ModelBakingKey>()
private val sprites = mutableSetOf<ResourceLocation>()
@SubscribeEvent
@@ -82,7 +56,7 @@ object BakeWrapperManager : Invalidator, HasLogger() {
StartupMessageManager.addModMessage("BetterFoliage: discovering models")
logger.log(INFO, "starting model discovery (${discoverers.size} listeners)")
discoverers.forEach { listener ->
val replacementsLocal = mutableMapOf<ResourceLocation, ModelBakeKey>()
val replacementsLocal = mutableMapOf<ResourceLocation, ModelBakingKey>()
listener.onModelsLoaded(event.bakery, sprites, replacementsLocal)
replacements.putAll(replacementsLocal)
}
@@ -113,10 +87,10 @@ object BakeWrapperManager : Invalidator, HasLogger() {
// bake replacement if available
replacements[location]?.let { 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
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")
return it
}

View File

@@ -11,7 +11,7 @@ class BlockTypeCache {
val dirt = mutableSetOf<BlockState>()
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()
}

View File

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

View File

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