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
This commit is contained in:
parent
cd9f18a8c9
commit
7c202ed491
9 changed files with 295 additions and 275 deletions
|
@ -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() {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<BlockModelRenderer> MODEL_RENDERER = Lazy.of(() -> new BlockModelRenderer(Minecraft.getInstance().getBlockColors()));
|
||||
private static final Lazy<BlockModelShapes> BLOCK_MODELS = Lazy.of(() -> Minecraft.getInstance().getModelManager().getBlockModelShaper());
|
||||
|
||||
private static final WorldAttached<WorldContraptions> WORLDS = new WorldAttached<>(WorldContraptions::new);
|
||||
private static WorldAttached<ContraptionRenderManager<?>> WORLDS = new WorldAttached<>(SBBContraptionManager::new);
|
||||
|
||||
public static final Compartment<Pair<Contraption, RenderType>> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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<C extends ContraptionRenderInfo> {
|
||||
protected final World world;
|
||||
|
||||
private int removalTimer;
|
||||
|
||||
protected final Int2ObjectMap<C> renderInfos = new Int2ObjectOpenHashMap<>();
|
||||
protected final List<C> 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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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<RenderedContraption> {
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
|
@ -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) {
|
||||
|
|
|
@ -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<ContraptionRenderInfo> {
|
||||
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));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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<RenderedContraption> flwRenderers = new Int2ObjectOpenHashMap<>();
|
||||
public final Int2ObjectMap<ContraptionRenderInfo> renderInfos = new Int2ObjectOpenHashMap<>();
|
||||
private final List<ContraptionRenderInfo> visible = new ObjectArrayList<>();
|
||||
private final List<RenderedContraption> 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<Contraption> 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);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue