Aggressively cache RenderMaterials

This commit is contained in:
quat1024 2023-07-02 06:26:19 -04:00
parent ed42e4da9f
commit 97de0d1b9c
5 changed files with 73 additions and 53 deletions

View File

@ -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) -> {

View File

@ -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();

View File

@ -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<Random> 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<Random> 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()];

View File

@ -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;
}
}
}

View File

@ -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<SpriteIdentifier, Sprite> 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<BlockState, TemplateAppearance> appearanceCache = new ConcurrentHashMap<>();
//Immutable contents:
private final EnumMap<BlendMode, RenderMaterial> 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;
}
}
}