- Material managers should not be inside WorldContext
 - InstancedRenderDispatcher now stores the material managers
 - Delete crumbling material manager on renderer reload
 - CrumblingRenderer gets its own class
 - CrumblingRenderer is less jank overall
 - Defer InstancedRenderRegistry deprecated function removal until 0.3
This commit is contained in:
Jozufozu 2021-07-12 16:42:43 -07:00
parent f0822a5cd4
commit 5d47cc6136
10 changed files with 155 additions and 118 deletions

View file

@ -17,7 +17,6 @@ import java.util.function.Predicate;
import java.util.stream.Stream;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import org.lwjgl.system.MemoryUtil;
@ -47,7 +46,6 @@ import net.minecraftforge.resource.IResourceType;
import net.minecraftforge.resource.ISelectiveResourceReloadListener;
import net.minecraftforge.resource.VanillaResourceType;
@ParametersAreNonnullByDefault
public class ShaderSources implements ISelectiveResourceReloadListener {
public static final String SHADER_DIR = "flywheel/shaders/";
public static final String PROGRAM_DIR = "flywheel/programs/";

View file

@ -0,0 +1,130 @@
package com.jozufozu.flywheel.backend.instancing;
import static org.lwjgl.opengl.GL11.GL_TEXTURE_2D;
import static org.lwjgl.opengl.GL11.glBindTexture;
import static org.lwjgl.opengl.GL13.GL_TEXTURE0;
import static org.lwjgl.opengl.GL13.GL_TEXTURE4;
import static org.lwjgl.opengl.GL13.glActiveTexture;
import java.util.ArrayList;
import java.util.List;
import java.util.SortedSet;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.core.Contexts;
import com.jozufozu.flywheel.core.crumbling.CrumblingInstanceManager;
import com.jozufozu.flywheel.core.crumbling.CrumblingMaterialManager;
import com.jozufozu.flywheel.core.crumbling.CrumblingProgram;
import com.jozufozu.flywheel.event.ReloadRenderersEvent;
import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.ActiveRenderInfo;
import net.minecraft.client.renderer.DestroyBlockProgress;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.model.ModelBakery;
import net.minecraft.client.renderer.texture.Texture;
import net.minecraft.client.renderer.texture.TextureManager;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.LazyValue;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.vector.Matrix4f;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
/**
* Responsible for rendering the block breaking overlay for instanced tiles.
*/
@OnlyIn(Dist.CLIENT)
@Mod.EventBusSubscriber(Dist.CLIENT)
public class CrumblingRenderer {
private static final LazyValue<MaterialManager<CrumblingProgram>> materialManager = new LazyValue<>(() -> new CrumblingMaterialManager(Contexts.CRUMBLING));
private static final LazyValue<InstanceManager<TileEntity>> manager = new LazyValue<>(() -> new CrumblingInstanceManager(materialManager.getValue()));
private static final RenderType crumblingLayer = ModelBakery.BLOCK_DESTRUCTION_RENDER_LAYERS.get(0);
public static void renderBreaking(ClientWorld world, Matrix4f viewProjection, double cameraX, double cameraY, double cameraZ) {
if (!Backend.getInstance()
.canUseInstancing(world)) return;
Int2ObjectMap<List<TileEntity>> activeStages = getActiveStageTiles(world);
if (activeStages.isEmpty()) return;
InstanceManager<TileEntity> renderer = manager.getValue();
TextureManager textureManager = Minecraft.getInstance().textureManager;
ActiveRenderInfo info = Minecraft.getInstance().gameRenderer.getActiveRenderInfo();
MaterialManager<CrumblingProgram> materials = materialManager.getValue();
crumblingLayer.startDrawing();
for (Int2ObjectMap.Entry<List<TileEntity>> stage : activeStages.int2ObjectEntrySet()) {
int i = stage.getIntKey();
Texture breaking = textureManager.getTexture(ModelBakery.BLOCK_DESTRUCTION_STAGE_TEXTURES.get(i));
// something about when we call this means that the textures are not ready for use on the first frame they should appear
if (breaking != null) {
stage.getValue().forEach(renderer::add);
renderer.beginFrame(info);
glActiveTexture(GL_TEXTURE4);
glBindTexture(GL_TEXTURE_2D, breaking.getGlTextureId());
materials.render(RenderType.getCutoutMipped(), viewProjection, cameraX, cameraY, cameraZ);
renderer.invalidate();
}
}
crumblingLayer.endDrawing();
glActiveTexture(GL_TEXTURE0);
Texture breaking = textureManager.getTexture(ModelBakery.BLOCK_DESTRUCTION_STAGE_TEXTURES.get(0));
if (breaking != null) glBindTexture(GL_TEXTURE_2D, breaking.getGlTextureId());
}
/**
* Associate each breaking stage with a list of all tile entities at that stage.
*/
private static Int2ObjectMap<List<TileEntity>> getActiveStageTiles(ClientWorld world) {
Long2ObjectMap<SortedSet<DestroyBlockProgress>> breakingProgressions = Minecraft.getInstance().worldRenderer.blockBreakingProgressions;
Int2ObjectMap<List<TileEntity>> breakingEntities = new Int2ObjectArrayMap<>();
for (Long2ObjectMap.Entry<SortedSet<DestroyBlockProgress>> entry : breakingProgressions.long2ObjectEntrySet()) {
BlockPos breakingPos = BlockPos.fromLong(entry.getLongKey());
SortedSet<DestroyBlockProgress> progresses = entry.getValue();
if (progresses != null && !progresses.isEmpty()) {
int blockDamage = progresses.last()
.getPartialBlockDamage();
TileEntity tileEntity = world.getTileEntity(breakingPos);
if (tileEntity != null) {
List<TileEntity> tileEntities = breakingEntities.computeIfAbsent(blockDamage, $ -> new ArrayList<>());
tileEntities.add(tileEntity);
}
}
}
return breakingEntities;
}
@SubscribeEvent
public static void onReloadRenderers(ReloadRenderersEvent event) {
ClientWorld world = event.getWorld();
if (Backend.getInstance()
.canUseInstancing() && world != null) {
materialManager.getValue().delete();
}
}
}

View file

@ -1,44 +1,22 @@
package com.jozufozu.flywheel.backend.instancing;
import static org.lwjgl.opengl.GL11.GL_TEXTURE_2D;
import static org.lwjgl.opengl.GL11.glBindTexture;
import static org.lwjgl.opengl.GL13.GL_TEXTURE0;
import static org.lwjgl.opengl.GL13.GL_TEXTURE4;
import static org.lwjgl.opengl.GL13.glActiveTexture;
import java.util.BitSet;
import java.util.SortedSet;
import java.util.Vector;
import javax.annotation.Nonnull;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.instancing.entity.EntityInstanceManager;
import com.jozufozu.flywheel.backend.instancing.tile.TileInstanceManager;
import com.jozufozu.flywheel.core.Contexts;
import com.jozufozu.flywheel.core.crumbling.CrumblingInstanceManager;
import com.jozufozu.flywheel.core.shader.WorldProgram;
import com.jozufozu.flywheel.event.BeginFrameEvent;
import com.jozufozu.flywheel.event.ReloadRenderersEvent;
import com.jozufozu.flywheel.event.RenderLayerEvent;
import com.jozufozu.flywheel.util.AnimationTickHolder;
import com.jozufozu.flywheel.util.WorldAttached;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.ActiveRenderInfo;
import net.minecraft.client.renderer.DestroyBlockProgress;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.WorldRenderer;
import net.minecraft.client.renderer.model.ModelBakery;
import net.minecraft.client.renderer.texture.Texture;
import net.minecraft.client.renderer.texture.TextureManager;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.entity.Entity;
import net.minecraft.inventory.container.PlayerContainer;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.LazyValue;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.vector.Matrix4f;
import net.minecraft.world.IWorld;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@ -50,16 +28,10 @@ import net.minecraftforge.fml.common.Mod;
@Mod.EventBusSubscriber(Dist.CLIENT)
public class InstancedRenderDispatcher {
private static final WorldAttached<InstanceManager<Entity>> entityInstanceManager = new WorldAttached<>(world -> new EntityInstanceManager(Contexts.WORLD.getMaterialManager(world)));
private static final WorldAttached<InstanceManager<TileEntity>> tileInstanceManager = new WorldAttached<>(world -> new TileInstanceManager(Contexts.WORLD.getMaterialManager(world)));
private static final WorldAttached<MaterialManager<WorldProgram>> materialManagers = new WorldAttached<>($ -> new MaterialManager<>(Contexts.WORLD));
private static final LazyValue<Vector<CrumblingInstanceManager>> blockBreaking = new LazyValue<>(() -> {
Vector<CrumblingInstanceManager> renderers = new Vector<>(10);
for (int i = 0; i < 10; i++) {
renderers.add(new CrumblingInstanceManager());
}
return renderers;
});
private static final WorldAttached<InstanceManager<Entity>> entityInstanceManager = new WorldAttached<>(world -> new EntityInstanceManager(materialManagers.get(world)));
private static final WorldAttached<InstanceManager<TileEntity>> tileInstanceManager = new WorldAttached<>(world -> new TileInstanceManager(materialManagers.get(world)));
@Nonnull
public static InstanceManager<TileEntity> getTiles(IWorld world) {
@ -99,7 +71,7 @@ public class InstancedRenderDispatcher {
@SubscribeEvent
public static void onBeginFrame(BeginFrameEvent event) {
Contexts.WORLD.getMaterialManager(event.getWorld())
materialManagers.get(event.getWorld())
.checkAndShiftOrigin(event.getInfo());
getTiles(event.getWorld()).beginFrame(event.getInfo());
@ -114,7 +86,7 @@ public class InstancedRenderDispatcher {
event.type.startDrawing();
Contexts.WORLD.getMaterialManager(world)
materialManagers.get(world)
.render(event.type, event.viewProjection, event.camX, event.camY, event.camZ);
event.type.endDrawing();
@ -129,64 +101,8 @@ public class InstancedRenderDispatcher {
}
}
private static final RenderType crumblingLayer = ModelBakery.BLOCK_DESTRUCTION_RENDER_LAYERS.get(0);
public static void renderBreaking(ClientWorld world, Matrix4f viewProjection, double cameraX, double cameraY, double cameraZ) {
if (!Backend.getInstance()
.canUseInstancing(world)) return;
WorldRenderer worldRenderer = Minecraft.getInstance().worldRenderer;
Long2ObjectMap<SortedSet<DestroyBlockProgress>> breakingProgressions = worldRenderer.blockBreakingProgressions;
if (breakingProgressions.isEmpty()) return;
Vector<CrumblingInstanceManager> renderers = blockBreaking.getValue();
BitSet bitSet = new BitSet(10);
for (Long2ObjectMap.Entry<SortedSet<DestroyBlockProgress>> entry : breakingProgressions.long2ObjectEntrySet()) {
BlockPos breakingPos = BlockPos.fromLong(entry.getLongKey());
SortedSet<DestroyBlockProgress> progresses = entry.getValue();
if (progresses != null && !progresses.isEmpty()) {
int blockDamage = progresses.last()
.getPartialBlockDamage();
bitSet.set(blockDamage);
renderers.get(blockDamage)
.add(world.getTileEntity(breakingPos));
}
}
TextureManager textureManager = Minecraft.getInstance().textureManager;
ActiveRenderInfo info = Minecraft.getInstance().gameRenderer.getActiveRenderInfo();
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textureManager.getTexture(PlayerContainer.BLOCK_ATLAS_TEXTURE)
.getGlTextureId());
crumblingLayer.startDrawing();
bitSet.stream()
.forEach(i -> {
Texture breaking = textureManager.getTexture(ModelBakery.BLOCK_DESTRUCTION_STAGE_TEXTURES.get(i));
CrumblingInstanceManager renderer = renderers.get(i);
renderer.beginFrame(info);
if (breaking != null) {
glActiveTexture(GL_TEXTURE4);
glBindTexture(GL_TEXTURE_2D, breaking.getGlTextureId());
renderer.materialManager.render(RenderType.getCutoutMipped(), viewProjection, cameraX, cameraY, cameraZ);
}
renderer.invalidate();
});
crumblingLayer.endDrawing();
glActiveTexture(GL_TEXTURE0);
Texture breaking = textureManager.getTexture(ModelBakery.BLOCK_DESTRUCTION_STAGE_TEXTURES.get(0));
if (breaking != null) glBindTexture(GL_TEXTURE_2D, breaking.getGlTextureId());
}
public static void loadAllInWorld(ClientWorld world) {
Contexts.WORLD.getMaterialManager(world)
materialManagers.get(world)
.delete();
InstanceManager<TileEntity> tiles = tileInstanceManager.replace(world);

View file

@ -57,7 +57,7 @@ public class InstancedRenderRegistry {
}
/**
* @deprecated will be removed in 0.2.0, use {@link #tile}
* @deprecated will be removed in 0.3.0, use {@link #tile}
*/
@Deprecated
public <T extends TileEntity> void register(TileEntityType<? extends T> type, ITileInstanceFactory<? super T> rendererFactory) {
@ -66,7 +66,7 @@ public class InstancedRenderRegistry {
}
/**
* @deprecated will be removed in 0.2.0, use {@link #entity}
* @deprecated will be removed in 0.3.0, use {@link #entity}
*/
@Deprecated
public <T extends Entity> void register(EntityType<? extends T> type, IEntityInstanceFactory<? super T> rendererFactory) {

View file

@ -12,7 +12,6 @@ import com.jozufozu.flywheel.backend.ResourceUtil;
import com.jozufozu.flywheel.backend.ShaderContext;
import com.jozufozu.flywheel.backend.ShaderSources;
import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
import com.jozufozu.flywheel.backend.instancing.MaterialManager;
import com.jozufozu.flywheel.backend.instancing.MaterialSpec;
import com.jozufozu.flywheel.backend.loading.InstancedArraysTemplate;
import com.jozufozu.flywheel.backend.loading.Program;
@ -23,10 +22,8 @@ import com.jozufozu.flywheel.backend.loading.ShaderTransformer;
import com.jozufozu.flywheel.core.shader.ExtensibleGlProgram;
import com.jozufozu.flywheel.core.shader.StateSensitiveMultiProgram;
import com.jozufozu.flywheel.core.shader.WorldProgram;
import com.jozufozu.flywheel.util.WorldAttached;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.IWorld;
public class WorldContext<P extends WorldProgram> extends ShaderContext<P> {
@ -37,8 +34,6 @@ public class WorldContext<P extends WorldProgram> extends ShaderContext<P> {
protected Supplier<Stream<ResourceLocation>> specStream;
protected TemplateFactory templateFactory;
private final WorldAttached<MaterialManager<P>> worldAttachedMMs = new WorldAttached<>($ -> new MaterialManager<>(this));
private final Map<ShaderType, ResourceLocation> builtins = new EnumMap<>(ShaderType.class);
private final Map<ShaderType, String> builtinSources = new EnumMap<>(ShaderType.class);
@ -69,10 +64,6 @@ public class WorldContext<P extends WorldProgram> extends ShaderContext<P> {
return this;
}
public MaterialManager<P> getMaterialManager(IWorld world) {
return worldAttachedMMs.get(world);
}
public WorldContext<P> withSpecStream(Supplier<Stream<ResourceLocation>> specStream) {
this.specStream = specStream;
return this;
@ -122,13 +113,6 @@ public class WorldContext<P extends WorldProgram> extends ShaderContext<P> {
});
}
@Override
public void delete() {
super.delete();
worldAttachedMMs.empty(MaterialManager::delete);
}
@Override
protected Shader getSource(ShaderType type, ResourceLocation name) {
Shader source = super.getSource(type, name);

View file

@ -1,12 +1,14 @@
package com.jozufozu.flywheel.core.crumbling;
import com.jozufozu.flywheel.backend.instancing.MaterialManager;
import com.jozufozu.flywheel.backend.instancing.tile.TileInstanceManager;
import net.minecraft.util.math.BlockPos;
public class CrumblingInstanceManager extends TileInstanceManager {
public CrumblingInstanceManager() {
super(new CrumblingMaterialManager());
public CrumblingInstanceManager(MaterialManager<?> materialManager) {
super(materialManager);
}
@Override

View file

@ -10,7 +10,7 @@ import java.util.Map;
import com.jozufozu.flywheel.backend.instancing.MaterialManager;
import com.jozufozu.flywheel.backend.instancing.MaterialRenderer;
import com.jozufozu.flywheel.core.Contexts;
import com.jozufozu.flywheel.core.WorldContext;
import com.jozufozu.flywheel.core.atlas.AtlasInfo;
import com.jozufozu.flywheel.core.atlas.SheetData;
import com.jozufozu.flywheel.core.shader.IProgramCallback;
@ -24,8 +24,8 @@ import net.minecraft.util.math.vector.Matrix4f;
public class CrumblingMaterialManager extends MaterialManager<CrumblingProgram> {
public CrumblingMaterialManager() {
super(Contexts.CRUMBLING);
public CrumblingMaterialManager(WorldContext<CrumblingProgram> context) {
super(context);
}
/**

View file

@ -0,0 +1,6 @@
@ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault
package com.jozufozu.flywheel.core;
import javax.annotation.ParametersAreNonnullByDefault;
import mcp.MethodsReturnNonnullByDefault;

View file

@ -9,6 +9,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.OptifineHandler;
import com.jozufozu.flywheel.backend.instancing.CrumblingRenderer;
import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher;
import com.jozufozu.flywheel.event.BeginFrameEvent;
import com.jozufozu.flywheel.event.ReloadRenderersEvent;
@ -81,7 +82,7 @@ public class RenderHooksMixin {
.getProjectionMatrix());
Vector3d cameraPos = info.getProjectedView();
InstancedRenderDispatcher.renderBreaking(world, viewProjection, cameraPos.x, cameraPos.y, cameraPos.z);
CrumblingRenderer.renderBreaking(world, viewProjection, cameraPos.x, cameraPos.y, cameraPos.z);
if (!OptifineHandler.usingShaders()) GL20.glUseProgram(0);
}

View file

@ -12,7 +12,7 @@ import net.minecraft.world.IWorld;
public class WorldAttached<T> {
Map<IWorld, T> attached;
private final Map<IWorld, T> attached;
private final Function<IWorld, T> factory;
public WorldAttached(Function<IWorld, T> factory) {