From 7c202ed4910fe06ac57d1eb2ca9f1863c2bdf407 Mon Sep 17 00:00:00 2001 From: Jozufozu Date: Wed, 28 Jul 2021 19:25:25 -0700 Subject: [PATCH] DRY contraption rendering - Different subclasses for flywheel rendering and sbb rendering - Select which to use on renderer reload, gather context, and when create buffers are invalidated --- .../com/simibubi/create/CreateClient.java | 4 +- .../render/ContraptionMatrices.java | 14 +- .../render/ContraptionRenderDispatcher.java | 19 +- .../render/ContraptionRenderInfo.java | 26 +- .../render/ContraptionRenderManager.java | 87 +++++++ .../render/FlwContraptionManager.java | 99 ++++++++ .../render/RenderedContraption.java | 36 +-- .../render/SBBContraptionManager.java | 51 ++++ .../render/WorldContraptions.java | 234 ------------------ 9 files changed, 295 insertions(+), 275 deletions(-) create mode 100644 src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionRenderManager.java create mode 100644 src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/FlwContraptionManager.java create mode 100644 src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/SBBContraptionManager.java delete mode 100644 src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/WorldContraptions.java diff --git a/src/main/java/com/simibubi/create/CreateClient.java b/src/main/java/com/simibubi/create/CreateClient.java index bfcf01b1b..29500e2c7 100644 --- a/src/main/java/com/simibubi/create/CreateClient.java +++ b/src/main/java/com/simibubi/create/CreateClient.java @@ -86,7 +86,7 @@ public class CreateClient { modEventBus.addListener(ClientEvents::loadCompleted); modEventBus.addListener(CreateContexts::flwInit); modEventBus.addListener(AllMaterialSpecs::flwInit); - modEventBus.addListener(ContraptionRenderDispatcher::invalidateOnGatherContext); + modEventBus.addListener(ContraptionRenderDispatcher::gatherContext); ZAPPER_RENDER_HANDLER.register(forgeEventBus); POTATO_CANNON_RENDER_HANDLER.register(forgeEventBus); @@ -207,7 +207,7 @@ public class CreateClient { public static void invalidateRenderers() { BUFFER_CACHE.invalidate(); - ContraptionRenderDispatcher.invalidateAll(); + ContraptionRenderDispatcher.reset(); } public static void checkGraphicsFanciness() { diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionMatrices.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionMatrices.java index 6b383e933..202d5dddf 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionMatrices.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionMatrices.java @@ -11,7 +11,10 @@ import net.minecraft.util.math.vector.Matrix4f; public class ContraptionMatrices { - public static final ContraptionMatrices IDENTITY = new ContraptionMatrices(); + /** + * The results from using this are undefined. + */ + public static final ContraptionMatrices EMPTY = new ContraptionMatrices(); public final MatrixStack entityStack; public final MatrixStack contraptionStack; @@ -20,9 +23,7 @@ public class ContraptionMatrices { public final Matrix4f lightMatrix; private ContraptionMatrices() { - this.entityStack = new MatrixStack(); - this.contraptionStack = new MatrixStack(); - this.finalStack = new MatrixStack(); + this.entityStack = this.contraptionStack = this.finalStack = new MatrixStack(); this.entityMatrix = new Matrix4f(); this.lightMatrix = new Matrix4f(); } @@ -81,4 +82,9 @@ public class ContraptionMatrices { return cms; } + + public Matrix4f contraptionPose() { + return contraptionStack.last() + .pose(); + } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionRenderDispatcher.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionRenderDispatcher.java index f47cca99b..830335441 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionRenderDispatcher.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionRenderDispatcher.java @@ -6,6 +6,7 @@ import java.util.Random; import org.apache.commons.lang3.tuple.Pair; +import com.jozufozu.flywheel.backend.Backend; import com.jozufozu.flywheel.event.BeginFrameEvent; import com.jozufozu.flywheel.event.GatherContextEvent; import com.jozufozu.flywheel.event.ReloadRenderersEvent; @@ -54,7 +55,7 @@ public class ContraptionRenderDispatcher { private static final Lazy MODEL_RENDERER = Lazy.of(() -> new BlockModelRenderer(Minecraft.getInstance().getBlockColors())); private static final Lazy BLOCK_MODELS = Lazy.of(() -> Minecraft.getInstance().getModelManager().getBlockModelShaper()); - private static final WorldAttached WORLDS = new WorldAttached<>(WorldContraptions::new); + private static WorldAttached> WORLDS = new WorldAttached<>(SBBContraptionManager::new); public static final Compartment> CONTRAPTION = new Compartment<>(); @@ -76,11 +77,11 @@ public class ContraptionRenderDispatcher { @SubscribeEvent public static void onRendererReload(ReloadRenderersEvent event) { - invalidateAll(); + reset(); } - public static void invalidateOnGatherContext(GatherContextEvent e) { - invalidateAll(); + public static void gatherContext(GatherContextEvent e) { + reset(); } public static void render(AbstractContraptionEntity entity, Contraption contraption, IRenderTypeBuffer buffers) { @@ -202,7 +203,13 @@ public class ContraptionRenderDispatcher { return WorldRenderer.getLightColor(renderWorld, context.localPos); } - public static void invalidateAll() { - WORLDS.empty(WorldContraptions::invalidate); + public static void reset() { + WORLDS.empty(ContraptionRenderManager::delete); + + if (Backend.getInstance().available()) { + WORLDS = new WorldAttached<>(FlwContraptionManager::new); + } else { + WORLDS = new WorldAttached<>(SBBContraptionManager::new); + } } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionRenderInfo.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionRenderInfo.java index d69e9c47f..db8c3e764 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionRenderInfo.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionRenderInfo.java @@ -1,19 +1,19 @@ package com.simibubi.create.content.contraptions.components.structureMovement.render; -import com.mojang.blaze3d.matrix.MatrixStack; +import com.jozufozu.flywheel.event.BeginFrameEvent; import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; import com.simibubi.create.foundation.utility.AnimationTickHolder; import com.simibubi.create.foundation.utility.worldWrappers.PlacementSimulationWorld; -import net.minecraft.client.renderer.culling.ClippingHelper; import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.vector.Vector3d; public class ContraptionRenderInfo { public final Contraption contraption; public final PlacementSimulationWorld renderWorld; - private ContraptionMatrices matrices = ContraptionMatrices.IDENTITY; + private ContraptionMatrices matrices = ContraptionMatrices.EMPTY; private boolean visible; public ContraptionRenderInfo(Contraption contraption, PlacementSimulationWorld renderWorld) { @@ -29,22 +29,24 @@ public class ContraptionRenderInfo { return !contraption.entity.isAlive(); } - public void beginFrame(ClippingHelper clippingHelper, MatrixStack mainStack, double camX, double camY, double camZ) { + public void beginFrame(BeginFrameEvent event) { AbstractContraptionEntity entity = contraption.entity; - visible = clippingHelper.isVisible(entity.getBoundingBoxForCulling().inflate(2)); + visible = event.getClippingHelper().isVisible(entity.getBoundingBoxForCulling().inflate(2)); - mainStack.pushPose(); + event.getStack().pushPose(); - double x = MathHelper.lerp(AnimationTickHolder.getPartialTicks(), entity.xOld, entity.getX()) - camX; - double y = MathHelper.lerp(AnimationTickHolder.getPartialTicks(), entity.yOld, entity.getY()) - camY; - double z = MathHelper.lerp(AnimationTickHolder.getPartialTicks(), entity.zOld, entity.getZ()) - camZ; + Vector3d cameraPos = event.getInfo() + .getPosition(); + double x = MathHelper.lerp(AnimationTickHolder.getPartialTicks(), entity.xOld, entity.getX()) - cameraPos.x; + double y = MathHelper.lerp(AnimationTickHolder.getPartialTicks(), entity.yOld, entity.getY()) - cameraPos.y; + double z = MathHelper.lerp(AnimationTickHolder.getPartialTicks(), entity.zOld, entity.getZ()) - cameraPos.z; - mainStack.translate(x, y, z); + event.getStack().translate(x, y, z); - matrices = new ContraptionMatrices(mainStack, entity); + matrices = new ContraptionMatrices(event.getStack(), entity); - mainStack.popPose(); + event.getStack().popPose(); } public boolean isVisible() { diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionRenderManager.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionRenderManager.java new file mode 100644 index 000000000..57d9fa089 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionRenderManager.java @@ -0,0 +1,87 @@ +package com.simibubi.create.content.contraptions.components.structureMovement.render; + +import java.lang.ref.Reference; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import com.jozufozu.flywheel.event.BeginFrameEvent; +import com.jozufozu.flywheel.event.RenderLayerEvent; +import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; +import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; +import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionHandler; + +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import net.minecraft.world.IWorld; +import net.minecraft.world.World; + +public abstract class ContraptionRenderManager { + protected final World world; + + private int removalTimer; + + protected final Int2ObjectMap renderInfos = new Int2ObjectOpenHashMap<>(); + protected final List visible = new ObjectArrayList<>(); + + public ContraptionRenderManager(IWorld world) { + this.world = (World) world; + } + + public abstract void renderLayer(RenderLayerEvent event); + + protected abstract C create(Contraption c); + + public void tick() { + removalTimer++; + if (removalTimer >= 20) { + removeDeadRenderers(); + removalTimer = 0; + } + + ContraptionHandler.loadedContraptions.get(world) + .values() + .stream() + .map(Reference::get) + .filter(Objects::nonNull) + .map(AbstractContraptionEntity::getContraption) + .forEach(this::getRenderInfo); + } + + public void beginFrame(BeginFrameEvent event) { + visible.clear(); + + renderInfos.int2ObjectEntrySet() + .stream() + .map(Map.Entry::getValue) + .forEach(renderInfo -> renderInfo.beginFrame(event)); + + renderInfos.int2ObjectEntrySet() + .stream() + .map(Map.Entry::getValue) + .filter(ContraptionRenderInfo::isVisible) + .forEach(visible::add); + } + + public C getRenderInfo(Contraption c) { + int entityId = c.entity.getId(); + C renderInfo = renderInfos.get(entityId); + + if (renderInfo == null) { + renderInfo = create(c); + renderInfos.put(entityId, renderInfo); + } + + return renderInfo; + } + + public void delete() { + renderInfos.clear(); + } + + public void removeDeadRenderers() { + renderInfos.values().removeIf(ContraptionRenderInfo::isDead); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/FlwContraptionManager.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/FlwContraptionManager.java new file mode 100644 index 000000000..8bdb46d9f --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/FlwContraptionManager.java @@ -0,0 +1,99 @@ +package com.simibubi.create.content.contraptions.components.structureMovement.render; + +import static org.lwjgl.opengl.GL11.glBindTexture; +import static org.lwjgl.opengl.GL12.GL_TEXTURE_3D; + +import com.jozufozu.flywheel.backend.Backend; +import com.jozufozu.flywheel.backend.gl.GlTextureUnit; +import com.jozufozu.flywheel.backend.state.RenderLayer; +import com.jozufozu.flywheel.event.RenderLayerEvent; +import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; +import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionLighter; +import com.simibubi.create.foundation.config.AllConfigs; +import com.simibubi.create.foundation.render.AllProgramSpecs; +import com.simibubi.create.foundation.render.CreateContexts; +import com.simibubi.create.foundation.utility.worldWrappers.PlacementSimulationWorld; + +import net.minecraft.client.renderer.RenderType; +import net.minecraft.world.IWorld; + +public class FlwContraptionManager extends ContraptionRenderManager { + + public FlwContraptionManager(IWorld world) { + super(world); + } + + @Override + public void tick() { + super.tick(); + + for (RenderedContraption contraption : visible) { + ContraptionLighter lighter = contraption.getLighter(); + if (lighter.getBounds().volume() < AllConfigs.CLIENT.maxContraptionLightVolume.get()) + lighter.tick(contraption); + + contraption.kinetics.tick(); + } + } + + @Override + public void renderLayer(RenderLayerEvent event) { + if (visible.isEmpty()) return; + + RenderType layer = event.getType(); + + layer.setupRenderState(); + GlTextureUnit.T4.makeActive(); // the shaders expect light volumes to be in texture 4 + + ContraptionProgram structureShader = CreateContexts.STRUCTURE.getProgram(AllProgramSpecs.STRUCTURE); + + structureShader.bind(); + structureShader.uploadViewProjection(event.viewProjection); + structureShader.uploadCameraPos(event.camX, event.camY, event.camZ); + + for (RenderedContraption renderedContraption : visible) { + renderedContraption.doRenderLayer(layer, structureShader); + } + + if (Backend.getInstance().canUseInstancing()) { + RenderLayer renderLayer = event.getLayer(); + if (renderLayer != null) { + for (RenderedContraption renderer : visible) { + renderer.materialManager.render(renderLayer, event.viewProjection, event.camX, event.camY, event.camZ); + } + } + } + + // clear the light volume state + GlTextureUnit.T4.makeActive(); + glBindTexture(GL_TEXTURE_3D, 0); + + layer.clearRenderState(); + GlTextureUnit.T0.makeActive(); + } + + @Override + protected RenderedContraption create(Contraption c) { + PlacementSimulationWorld renderWorld = ContraptionRenderDispatcher.setupRenderWorld(world, c); + return new RenderedContraption(c, renderWorld); + } + + @Override + public void removeDeadRenderers() { + renderInfos.values().removeIf(renderer -> { + if (renderer.isDead()) { + renderer.invalidate(); + return true; + } + return false; + }); + } + + @Override + public void delete() { + for (RenderedContraption renderer : renderInfos.values()) { + renderer.invalidate(); + } + renderInfos.clear(); + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/RenderedContraption.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/RenderedContraption.java index 778102582..1d4d3309b 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/RenderedContraption.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/RenderedContraption.java @@ -18,9 +18,9 @@ import com.jozufozu.flywheel.backend.model.ArrayModelRenderer; import com.jozufozu.flywheel.backend.model.BufferedModel; import com.jozufozu.flywheel.backend.model.IndexedModel; import com.jozufozu.flywheel.backend.model.ModelRenderer; +import com.jozufozu.flywheel.event.BeginFrameEvent; import com.jozufozu.flywheel.light.GridAlignedBB; import com.jozufozu.flywheel.util.BufferBuilderReader; -import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionLighter; @@ -28,7 +28,6 @@ import com.simibubi.create.foundation.render.CreateContexts; import com.simibubi.create.foundation.utility.AnimationTickHolder; import com.simibubi.create.foundation.utility.worldWrappers.PlacementSimulationWorld; -import net.minecraft.client.renderer.ActiveRenderInfo; import net.minecraft.client.renderer.LightTexture; import net.minecraft.client.renderer.RenderType; import net.minecraft.tileentity.TileEntity; @@ -36,6 +35,7 @@ import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.vector.Matrix4f; +import net.minecraft.util.math.vector.Vector3d; import net.minecraft.world.World; public class RenderedContraption extends ContraptionRenderInfo { @@ -85,26 +85,28 @@ public class RenderedContraption extends ContraptionRenderInfo { } } - public void beginFrame(ActiveRenderInfo info, double camX, double camY, double camZ) { - kinetics.beginFrame(info); + public void beginFrame(BeginFrameEvent event) { + super.beginFrame(event); + + if (!isVisible()) return; + + kinetics.beginFrame(event.getInfo()); AbstractContraptionEntity entity = contraption.entity; float pt = AnimationTickHolder.getPartialTicks(); - - MatrixStack stack = new MatrixStack(); - - double x = MathHelper.lerp(pt, entity.xOld, entity.getX()) - camX; - double y = MathHelper.lerp(pt, entity.yOld, entity.getY()) - camY; - double z = MathHelper.lerp(pt, entity.zOld, entity.getZ()) - camZ; - stack.translate(x, y, z); - - entity.doLocalTransforms(pt, new MatrixStack[] { stack }); - - model = stack.last().pose(); - AxisAlignedBB lightBox = GridAlignedBB.toAABB(lighter.lightVolume.getTextureVolume()); - this.lightBox = lightBox.move(-camX, -camY, -camZ); + Vector3d cameraPos = event.getInfo() + .getPosition(); + + float x = (float) (MathHelper.lerp(pt, entity.xOld, entity.getX()) - cameraPos.x); + float y = (float) (MathHelper.lerp(pt, entity.yOld, entity.getY()) - cameraPos.y); + float z = (float) (MathHelper.lerp(pt, entity.zOld, entity.getZ()) - cameraPos.z); + model = Matrix4f.createTranslateMatrix(x, y, z); + + model.multiply(getMatrices().contraptionPose()); + + this.lightBox = lightBox.move(-cameraPos.x, -cameraPos.y, -cameraPos.z); } void setup(ContraptionProgram shader) { diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/SBBContraptionManager.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/SBBContraptionManager.java new file mode 100644 index 000000000..94f0fec6d --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/SBBContraptionManager.java @@ -0,0 +1,51 @@ +package com.simibubi.create.content.contraptions.components.structureMovement.render; + +import static com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionRenderDispatcher.CONTRAPTION; +import static com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionRenderDispatcher.buildStructureBuffer; + +import org.apache.commons.lang3.tuple.Pair; + +import com.jozufozu.flywheel.event.RenderLayerEvent; +import com.simibubi.create.CreateClient; +import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; +import com.simibubi.create.foundation.render.SuperByteBuffer; +import com.simibubi.create.foundation.utility.worldWrappers.PlacementSimulationWorld; + +import net.minecraft.client.renderer.RenderType; +import net.minecraft.world.IWorld; + +public class SBBContraptionManager extends ContraptionRenderManager { + public SBBContraptionManager(IWorld world) { + super(world); + } + + @Override + public void renderLayer(RenderLayerEvent event) { + visible.forEach(info -> renderContraptionLayerSBB(event, info)); + } + + @Override + protected ContraptionRenderInfo create(Contraption c) { + PlacementSimulationWorld renderWorld = ContraptionRenderDispatcher.setupRenderWorld(world, c); + return new ContraptionRenderInfo(c, renderWorld); + } + + private void renderContraptionLayerSBB(RenderLayerEvent event, ContraptionRenderInfo renderInfo) { + RenderType layer = event.getType(); + + if (!renderInfo.isVisible()) return; + + SuperByteBuffer contraptionBuffer = CreateClient.BUFFER_CACHE.get(CONTRAPTION, Pair.of(renderInfo.contraption, layer), () -> buildStructureBuffer(renderInfo.renderWorld, renderInfo.contraption, layer)); + + if (!contraptionBuffer.isEmpty()) { + + ContraptionMatrices matrices = renderInfo.getMatrices(); + contraptionBuffer.transform(matrices.contraptionStack) + .light(matrices.entityMatrix) + .hybridLight() + .renderInto(matrices.entityStack, event.buffers.bufferSource() + .getBuffer(layer)); + } + + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/WorldContraptions.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/WorldContraptions.java deleted file mode 100644 index e0626744c..000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/WorldContraptions.java +++ /dev/null @@ -1,234 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.render; - -import static com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionRenderDispatcher.CONTRAPTION; -import static com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionRenderDispatcher.buildStructureBuffer; -import static org.lwjgl.opengl.GL11.glBindTexture; -import static org.lwjgl.opengl.GL12.GL_TEXTURE_3D; - -import java.lang.ref.Reference; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.function.Consumer; - -import org.apache.commons.lang3.tuple.Pair; - -import com.jozufozu.flywheel.backend.Backend; -import com.jozufozu.flywheel.backend.gl.GlTextureUnit; -import com.jozufozu.flywheel.backend.state.RenderLayer; -import com.jozufozu.flywheel.event.BeginFrameEvent; -import com.jozufozu.flywheel.event.RenderLayerEvent; -import com.simibubi.create.CreateClient; -import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; -import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionHandler; -import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionLighter; -import com.simibubi.create.foundation.config.AllConfigs; -import com.simibubi.create.foundation.render.AllProgramSpecs; -import com.simibubi.create.foundation.render.CreateContexts; -import com.simibubi.create.foundation.render.SuperByteBuffer; -import com.simibubi.create.foundation.utility.worldWrappers.PlacementSimulationWorld; - -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; -import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.client.renderer.ActiveRenderInfo; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.world.IWorld; -import net.minecraft.world.World; - -public class WorldContraptions { - private final World world; - - private int worldHolderRefreshCounter; - - public final Int2ObjectMap flwRenderers = new Int2ObjectOpenHashMap<>(); - public final Int2ObjectMap renderInfos = new Int2ObjectOpenHashMap<>(); - private final List visible = new ObjectArrayList<>(); - private final List flwVisible = new ObjectArrayList<>(); - - public WorldContraptions(IWorld world) { - this.world = (World) world; - } - - public void tick() { - for (RenderedContraption contraption : flwRenderers.values()) { - ContraptionLighter lighter = contraption.getLighter(); - if (lighter.getBounds().volume() < AllConfigs.CLIENT.maxContraptionLightVolume.get()) - lighter.tick(contraption); - - contraption.kinetics.tick(); - } - - worldHolderRefreshCounter++; - if (worldHolderRefreshCounter >= 20) { - removeDeadHolders(); - removeDeadContraptions(); - worldHolderRefreshCounter = 0; - } - - Consumer setup; - if (Backend.getInstance().available()) { - setup = this::createRenderer; - } else { - setup = this::getRenderInfo; - } - - ContraptionHandler.loadedContraptions.get(world) - .values() - .stream() - .map(Reference::get) - .filter(Objects::nonNull) - .map(AbstractContraptionEntity::getContraption) - .forEach(setup); - } - - public void beginFrame(BeginFrameEvent event) { - ActiveRenderInfo info = event.getInfo(); - double camX = info.getPosition().x; - double camY = info.getPosition().y; - double camZ = info.getPosition().z; - - visible.clear(); - flwVisible.clear(); - - renderInfos.int2ObjectEntrySet() - .stream() - .map(Map.Entry::getValue) - .forEach(renderInfo -> { - renderInfo.beginFrame(event.getClippingHelper(), event.getStack(), camX, camY, camZ); - }); - - if (Backend.getInstance() - .available()) { - flwRenderers.int2ObjectEntrySet() - .stream() - .map(Map.Entry::getValue) - .forEach(flwVisible::add); - - for (RenderedContraption renderer : flwVisible) { - renderer.beginFrame(info, camX, camY, camZ); - } - } else { - renderInfos.int2ObjectEntrySet() - .stream() - .map(Map.Entry::getValue) - .forEach(visible::add); - } - } - - public void renderLayer(RenderLayerEvent event) { - if (Backend.getInstance().available()) { - renderLayerFlywheel(event); - } else { - renderLayerSBB(event); - } - } - - private void renderLayerFlywheel(RenderLayerEvent event) { - if (flwVisible.isEmpty()) return; - - RenderType layer = event.getType(); - - layer.setupRenderState(); - GlTextureUnit.T4.makeActive(); // the shaders expect light volumes to be in texture 4 - - ContraptionProgram structureShader = CreateContexts.STRUCTURE.getProgram(AllProgramSpecs.STRUCTURE); - - structureShader.bind(); - structureShader.uploadViewProjection(event.viewProjection); - structureShader.uploadCameraPos(event.camX, event.camY, event.camZ); - - for (RenderedContraption renderedContraption : flwVisible) { - renderedContraption.doRenderLayer(layer, structureShader); - } - - if (Backend.getInstance().canUseInstancing()) { - RenderLayer renderLayer = event.getLayer(); - if (renderLayer != null) { - for (RenderedContraption renderer : flwVisible) { - renderer.materialManager.render(renderLayer, event.viewProjection, event.camX, event.camY, event.camZ); - } - } - } - - // clear the light volume state - GlTextureUnit.T4.makeActive(); - glBindTexture(GL_TEXTURE_3D, 0); - - layer.clearRenderState(); - GlTextureUnit.T0.makeActive(); - } - - private void renderLayerSBB(RenderLayerEvent event) { - visible.forEach(info -> renderContraptionLayerSBB(event, info)); - } - - private void renderContraptionLayerSBB(RenderLayerEvent event, ContraptionRenderInfo renderInfo) { - RenderType layer = event.getType(); - - if (!renderInfo.isVisible()) return; - - SuperByteBuffer contraptionBuffer = CreateClient.BUFFER_CACHE.get(CONTRAPTION, Pair.of(renderInfo.contraption, layer), - () -> buildStructureBuffer(renderInfo.renderWorld, renderInfo.contraption, layer)); - - if (!contraptionBuffer.isEmpty()) { - - ContraptionMatrices matrices = renderInfo.getMatrices(); - contraptionBuffer.transform(matrices.contraptionStack) - .light(matrices.entityMatrix) - .hybridLight() - .renderInto(matrices.entityStack, event.buffers.bufferSource().getBuffer(layer)); - } - - } - - private void createRenderer(Contraption c) { - int entityId = c.entity.getId(); - RenderedContraption contraption = flwRenderers.get(entityId); - - if (contraption == null) { - PlacementSimulationWorld renderWorld = ContraptionRenderDispatcher.setupRenderWorld(world, c); - contraption = new RenderedContraption(c, renderWorld); - flwRenderers.put(entityId, contraption); - renderInfos.put(entityId, contraption); - } - - } - - public ContraptionRenderInfo getRenderInfo(Contraption c) { - int entityId = c.entity.getId(); - ContraptionRenderInfo renderInfo = renderInfos.get(entityId); - - if (renderInfo == null) { - PlacementSimulationWorld renderWorld = ContraptionRenderDispatcher.setupRenderWorld(world, c); - renderInfo = new ContraptionRenderInfo(c, renderWorld); - renderInfos.put(entityId, renderInfo); - } - - return renderInfo; - } - - public void invalidate() { - for (RenderedContraption renderer : flwRenderers.values()) { - renderer.invalidate(); - } - - flwRenderers.clear(); - renderInfos.clear(); - } - - public void removeDeadContraptions() { - flwRenderers.values().removeIf(renderer -> { - if (renderer.isDead()) { - renderer.invalidate(); - return true; - } - return false; - }); - } - - public void removeDeadHolders() { - renderInfos.values().removeIf(ContraptionRenderInfo::isDead); - } -}