From 97de0d1b9c17a295c6e1ca109388b53c23bd7bf0 Mon Sep 17 00:00:00 2001 From: quat1024 Date: Sun, 2 Jul 2023 06:26:19 -0400 Subject: [PATCH] Aggressively cache RenderMaterials --- .../cottonmc/templates/TemplatesClient.java | 9 +++ .../templates/model/SlopeBaseMesh.java | 4 +- .../model/SlopeQuadTransformFactory.java | 29 ++------- .../templates/model/TemplateAppearance.java | 24 ++------ .../model/TemplateAppearanceManager.java | 60 ++++++++++++++++--- 5 files changed, 73 insertions(+), 53 deletions(-) diff --git a/src/main/java/io/github/cottonmc/templates/TemplatesClient.java b/src/main/java/io/github/cottonmc/templates/TemplatesClient.java index ca60a71..c6e68db 100644 --- a/src/main/java/io/github/cottonmc/templates/TemplatesClient.java +++ b/src/main/java/io/github/cottonmc/templates/TemplatesClient.java @@ -5,6 +5,8 @@ import io.github.cottonmc.templates.model.TemplateModelVariantProvider; import net.fabricmc.api.ClientModInitializer; import net.fabricmc.fabric.api.blockrenderlayer.v1.BlockRenderLayerMap; import net.fabricmc.fabric.api.client.model.ModelLoadingRegistry; +import net.fabricmc.fabric.api.renderer.v1.Renderer; +import net.fabricmc.fabric.api.renderer.v1.RendererAccess; import net.fabricmc.fabric.api.resource.ResourceManagerHelper; import net.fabricmc.fabric.api.resource.SimpleSynchronousResourceReloadListener; import net.minecraft.client.MinecraftClient; @@ -13,10 +15,17 @@ import net.minecraft.resource.ResourceManager; import net.minecraft.resource.ResourceType; import net.minecraft.util.Identifier; import net.minecraft.util.math.ChunkSectionPos; +import org.jetbrains.annotations.NotNull; + +import java.util.Objects; public class TemplatesClient implements ClientModInitializer { public static TemplateModelVariantProvider provider = new TemplateModelVariantProvider(); + public static @NotNull Renderer getFabricRenderer() { + return Objects.requireNonNull(RendererAccess.INSTANCE.getRenderer(), "A Fabric Rendering API implementation is required to use Templates!"); + } + @Override public void onInitializeClient() { Templates.chunkRerenderProxy = (world, pos) -> { diff --git a/src/main/java/io/github/cottonmc/templates/model/SlopeBaseMesh.java b/src/main/java/io/github/cottonmc/templates/model/SlopeBaseMesh.java index 9a90332..89693ba 100644 --- a/src/main/java/io/github/cottonmc/templates/model/SlopeBaseMesh.java +++ b/src/main/java/io/github/cottonmc/templates/model/SlopeBaseMesh.java @@ -1,5 +1,6 @@ package io.github.cottonmc.templates.model; +import io.github.cottonmc.templates.TemplatesClient; import net.fabricmc.fabric.api.renderer.v1.Renderer; import net.fabricmc.fabric.api.renderer.v1.RendererAccess; import net.fabricmc.fabric.api.renderer.v1.mesh.Mesh; @@ -18,8 +19,7 @@ public class SlopeBaseMesh { public static final int TAG_BOTTOM = Direction.DOWN.ordinal(); public static Mesh make() { - Renderer renderer = RendererAccess.INSTANCE.getRenderer(); - if(renderer == null) throw new IllegalStateException("RenderAccess.INSTANCE not populated - no Fabric Renderer API?"); + Renderer renderer = TemplatesClient.getFabricRenderer(); MeshBuilder builder = renderer.meshBuilder(); QuadEmitter qu = builder.getEmitter(); diff --git a/src/main/java/io/github/cottonmc/templates/model/SlopeQuadTransformFactory.java b/src/main/java/io/github/cottonmc/templates/model/SlopeQuadTransformFactory.java index 69377ce..91b84ff 100644 --- a/src/main/java/io/github/cottonmc/templates/model/SlopeQuadTransformFactory.java +++ b/src/main/java/io/github/cottonmc/templates/model/SlopeQuadTransformFactory.java @@ -1,19 +1,13 @@ package io.github.cottonmc.templates.model; import net.fabricmc.fabric.api.client.rendering.v1.ColorProviderRegistry; -import net.fabricmc.fabric.api.renderer.v1.Renderer; -import net.fabricmc.fabric.api.renderer.v1.RendererAccess; -import net.fabricmc.fabric.api.renderer.v1.material.BlendMode; -import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial; import net.fabricmc.fabric.api.renderer.v1.mesh.MutableQuadView; import net.fabricmc.fabric.api.renderer.v1.render.RenderContext; import net.fabricmc.fabric.api.rendering.data.v1.RenderAttachedBlockView; -import net.fabricmc.fabric.api.util.TriState; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.client.color.block.BlockColorProvider; -import net.minecraft.client.render.RenderLayers; import net.minecraft.client.texture.Sprite; import net.minecraft.item.ItemStack; import net.minecraft.util.math.BlockPos; @@ -22,17 +16,15 @@ import net.minecraft.util.math.random.Random; import net.minecraft.world.BlockRenderView; import org.jetbrains.annotations.NotNull; -import java.util.Objects; import java.util.function.Supplier; +@SuppressWarnings("ClassCanBeRecord") public class SlopeQuadTransformFactory implements TemplateQuadTransformFactory { public SlopeQuadTransformFactory(TemplateAppearanceManager tam) { this.tam = tam; - this.r = Objects.requireNonNull(RendererAccess.INSTANCE.getRenderer(), "A Fabric Rendering API implementation is required"); } private final TemplateAppearanceManager tam; - private final Renderer r; @Override public @NotNull RenderContext.QuadTransform blockTransformer(BlockRenderView blockView, BlockState state, BlockPos pos, Supplier randomSupplier) { @@ -41,40 +33,31 @@ public class SlopeQuadTransformFactory implements TemplateQuadTransformFactory { Block block = template.getBlock(); TemplateAppearance appearance; - RenderMaterial material; - int globalTint; + int globalTint = 0xFFFFFF; if(block == Blocks.AIR) { appearance = tam.getDefaultAppearance(); - material = r.materialFinder().clear().blendMode(BlendMode.CUTOUT).find(); - globalTint = 0xFFFFFF; } else { appearance = tam.getAppearance(template); - material = r.materialFinder().clear() - .disableDiffuse(false) - .ambientOcclusion(TriState.FALSE) - .blendMode(BlendMode.fromRenderLayer(RenderLayers.getBlockLayer(template))) - .find(); BlockColorProvider tint = ColorProviderRegistry.BLOCK.get(block); if(tint != null) globalTint = 0xFF000000 | tint.getColor(template, blockView, pos, 1); - else globalTint = 0xFFFFFF; } - return new Transformer(appearance, material, globalTint); + return new Transformer(appearance, globalTint); } @Override public @NotNull RenderContext.QuadTransform itemTransformer(ItemStack stack, Supplier randomSupplier) { - return new Transformer(tam.getDefaultAppearance(), r.materialFinder().clear().find(), 0xFFFFFF); + return new Transformer(tam.getDefaultAppearance(), 0xFFFFFF); } - public static record Transformer(TemplateAppearance appearance, RenderMaterial material, int color) implements RenderContext.QuadTransform { + public static record Transformer(TemplateAppearance appearance, int color) implements RenderContext.QuadTransform { private static final Direction[] DIRECTIONS = Direction.values(); @Override public boolean transform(MutableQuadView quad) { - quad.material(material); + quad.material(appearance.getRenderMaterial()); //The quad tag numbers were selected so this magic trick works: Direction dir = DIRECTIONS[quad.tag()]; diff --git a/src/main/java/io/github/cottonmc/templates/model/TemplateAppearance.java b/src/main/java/io/github/cottonmc/templates/model/TemplateAppearance.java index 47e725f..dc78121 100644 --- a/src/main/java/io/github/cottonmc/templates/model/TemplateAppearance.java +++ b/src/main/java/io/github/cottonmc/templates/model/TemplateAppearance.java @@ -1,5 +1,6 @@ package io.github.cottonmc.templates.model; +import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial; import net.minecraft.client.texture.Sprite; import net.minecraft.util.math.Direction; import org.jetbrains.annotations.NotNull; @@ -8,27 +9,10 @@ import java.util.Objects; public interface TemplateAppearance { @NotNull Sprite getParticleSprite(); //TODO: plug this in + + @NotNull RenderMaterial getRenderMaterial(); @NotNull Sprite getSprite(Direction dir); boolean hasColor(Direction dir); - record SingleSprite(@NotNull Sprite defaultSprite) implements TemplateAppearance { - public SingleSprite(Sprite defaultSprite) { - this.defaultSprite = Objects.requireNonNull(defaultSprite); - } - - @Override - public @NotNull Sprite getParticleSprite() { - return defaultSprite; - } - - @Override - public @NotNull Sprite getSprite(Direction dir) { - return defaultSprite; - } - - @Override - public boolean hasColor(Direction dir) { - return false; - } - } + } diff --git a/src/main/java/io/github/cottonmc/templates/model/TemplateAppearanceManager.java b/src/main/java/io/github/cottonmc/templates/model/TemplateAppearanceManager.java index da47708..ff01967 100644 --- a/src/main/java/io/github/cottonmc/templates/model/TemplateAppearanceManager.java +++ b/src/main/java/io/github/cottonmc/templates/model/TemplateAppearanceManager.java @@ -1,10 +1,15 @@ package io.github.cottonmc.templates.model; +import io.github.cottonmc.templates.TemplatesClient; +import net.fabricmc.fabric.api.renderer.v1.material.BlendMode; +import net.fabricmc.fabric.api.renderer.v1.material.MaterialFinder; +import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial; +import net.fabricmc.fabric.api.util.TriState; import net.minecraft.block.BlockState; import net.minecraft.client.MinecraftClient; +import net.minecraft.client.render.RenderLayers; import net.minecraft.client.render.model.BakedModel; import net.minecraft.client.render.model.BakedQuad; -import net.minecraft.client.texture.MissingSprite; import net.minecraft.client.texture.Sprite; import net.minecraft.client.util.SpriteIdentifier; import net.minecraft.screen.PlayerScreenHandler; @@ -13,22 +18,34 @@ import net.minecraft.util.math.Direction; import net.minecraft.util.math.random.Random; import org.jetbrains.annotations.NotNull; +import java.util.EnumMap; import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; public class TemplateAppearanceManager { public TemplateAppearanceManager(Function spriteLookup) { - Sprite defaultSprite = spriteLookup.apply(DEFAULT_SPRITE_ID); - if(defaultSprite == null) throw new IllegalStateException("Couldn't locate " + DEFAULT_SPRITE_ID + " !"); - defaultAppearance = new TemplateAppearance.SingleSprite(defaultSprite); + SpriteIdentifier defaultSpriteId = new SpriteIdentifier(PlayerScreenHandler.BLOCK_ATLAS_TEXTURE, new Identifier("minecraft:block/scaffolding_top")); + Sprite defaultSprite = spriteLookup.apply(defaultSpriteId); + if(defaultSprite == null) throw new IllegalStateException("Couldn't locate " + defaultSpriteId + " !"); + + MaterialFinder finder = TemplatesClient.getFabricRenderer().materialFinder(); + + for(BlendMode blend : BlendMode.values()) { + blockMaterials.put(blend, finder.clear().disableDiffuse(false).ambientOcclusion(TriState.FALSE).blendMode(blend).find()); + } + + this.defaultAppearance = new SingleSpriteAppearance(defaultSprite, blockMaterials.get(BlendMode.CUTOUT)); } - private static final SpriteIdentifier DEFAULT_SPRITE_ID = new SpriteIdentifier(PlayerScreenHandler.BLOCK_ATLAS_TEXTURE, new Identifier("minecraft:block/scaffolding_top")); private final TemplateAppearance defaultAppearance; + //Mutable, append-only cache: private final ConcurrentHashMap appearanceCache = new ConcurrentHashMap<>(); + //Immutable contents: + private final EnumMap blockMaterials = new EnumMap<>(BlendMode.class); + public TemplateAppearance getDefaultAppearance() { return defaultAppearance; } @@ -63,20 +80,25 @@ public class TemplateAppearanceManager { //Just for space-usage purposes, we store the particle in sprites[6] instead of using another field. sprites[6] = model.getParticleSprite(); - //Fill out any missing values in the sprites array + //Fill out any missing values in the sprites array. Failure to pick textures shouldn't lead to NPEs later on. for(int i = 0; i < sprites.length; i++) { if(sprites[i] == null) sprites[i] = defaultAppearance.getParticleSprite(); } - return new ComputedApperance(sprites, hasColorMask); + return new ComputedApperance(sprites, hasColorMask, blockMaterials.get(BlendMode.fromRenderLayer(RenderLayers.getBlockLayer(state)))); } - private static record ComputedApperance(@NotNull Sprite[] sprites, byte hasColorMask) implements TemplateAppearance { + private static record ComputedApperance(@NotNull Sprite[] sprites, byte hasColorMask, RenderMaterial mat) implements TemplateAppearance { @Override public @NotNull Sprite getParticleSprite() { return sprites[6]; } + @Override + public @NotNull RenderMaterial getRenderMaterial() { + return mat; + } + @Override public @NotNull Sprite getSprite(Direction dir) { return sprites[dir.ordinal()]; @@ -87,4 +109,26 @@ public class TemplateAppearanceManager { return (hasColorMask & (1 << dir.ordinal())) != 0; } } + + private static record SingleSpriteAppearance(@NotNull Sprite defaultSprite, RenderMaterial mat) implements TemplateAppearance { + @Override + public @NotNull Sprite getParticleSprite() { + return defaultSprite; + } + + @Override + public @NotNull RenderMaterial getRenderMaterial() { + return mat; + } + + @Override + public @NotNull Sprite getSprite(Direction dir) { + return defaultSprite; + } + + @Override + public boolean hasColor(Direction dir) { + return false; + } + } }