WorldAttached contraption rendering

- ContraptionRenderDispatcher's meat was moved to WorldContraptions
 - Rename ContraptionWorldHolder to ContraptionRenderInfo
 - One ContraptionMatrices per contraption per frame
 - Cull contraptions
 - Bump flywheel version
This commit is contained in:
Jozufozu 2021-07-28 18:21:07 -07:00
parent ce2e2be2c2
commit cd9f18a8c9
11 changed files with 365 additions and 245 deletions

View file

@ -16,7 +16,7 @@ cursegradle_version = 1.4.0
# dependency versions
registrate_version = 1.0.4
flywheel_version = 1.16-0.2.0.31
flywheel_version = 1.16-0.2.0.32
jei_version = 7.7.1.110
# curseforge information

View file

@ -37,10 +37,9 @@ public class ContraptionEntityRenderer<C extends AbstractContraptionEntity> exte
int overlay) {
super.render(entity, yaw, partialTicks, ms, buffers, overlay);
ContraptionMatrices matrices = new ContraptionMatrices(ms, entity);
Contraption contraption = entity.getContraption();
if (contraption != null) {
ContraptionRenderDispatcher.render(entity, contraption, matrices, buffers);
ContraptionRenderDispatcher.render(entity, contraption, buffers);
}
}

View file

@ -10,41 +10,52 @@ import net.minecraft.util.math.vector.Matrix3f;
import net.minecraft.util.math.vector.Matrix4f;
public class ContraptionMatrices {
public static final ContraptionMatrices IDENTITY = new ContraptionMatrices();
public final MatrixStack entityStack;
public final MatrixStack contraptionStack;
public final MatrixStack finalStack;
public final Matrix4f entityMatrix;
public final Matrix4f lightMatrix;
private ContraptionMatrices() {
this.entityStack = new MatrixStack();
this.contraptionStack = new MatrixStack();
this.finalStack = new MatrixStack();
this.entityMatrix = new Matrix4f();
this.lightMatrix = new Matrix4f();
}
public ContraptionMatrices(MatrixStack entityStack, AbstractContraptionEntity entity) {
this.entityStack = entityStack;
this.entityStack = copyStack(entityStack);
this.contraptionStack = new MatrixStack();
float partialTicks = AnimationTickHolder.getPartialTicks();
entity.doLocalTransforms(partialTicks, new MatrixStack[] { this.contraptionStack });
entityMatrix = translateTo(entity, partialTicks);
lightMatrix = entityMatrix.copy();
lightMatrix.multiply(contraptionStack.last().pose());
finalStack = copyStack(entityStack);
transform(finalStack, contraptionStack);
}
public MatrixStack getFinalStack() {
MatrixStack finalStack = new MatrixStack();
transform(finalStack, entityStack);
transform(finalStack, contraptionStack);
return finalStack;
}
public Matrix4f getFinalModel() {
Matrix4f finalModel = entityStack.last().pose().copy();
finalModel.multiply(contraptionStack.last().pose());
return finalModel;
return finalStack.last().pose();
}
public Matrix3f getFinalNormal() {
Matrix3f finalNormal = entityStack.last().normal().copy();
finalNormal.mul(contraptionStack.last().normal());
return finalNormal;
return finalStack.last().normal();
}
public Matrix4f getFinalLight() {
Matrix4f lightTransform = entityMatrix.copy();
lightTransform.multiply(contraptionStack.last().pose());
return lightTransform;
return lightMatrix;
}
public static Matrix4f translateTo(Entity entity, float partialTicks) {
@ -62,4 +73,12 @@ public class ContraptionMatrices {
.mul(transform.last()
.normal());
}
public static MatrixStack copyStack(MatrixStack ms) {
MatrixStack cms = new MatrixStack();
transform(cms, ms);
return cms;
}
}

View file

@ -1,47 +1,31 @@
package com.simibubi.create.content.contraptions.components.structureMovement.render;
import static org.lwjgl.opengl.GL11.GL_QUADS;
import static org.lwjgl.opengl.GL11.glBindTexture;
import static org.lwjgl.opengl.GL12.GL_TEXTURE_3D;
import java.lang.ref.Reference;
import java.util.Objects;
import java.util.Random;
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.GatherContextEvent;
import com.jozufozu.flywheel.event.ReloadRenderersEvent;
import com.jozufozu.flywheel.event.RenderLayerEvent;
import com.jozufozu.flywheel.util.WorldAttached;
import com.jozufozu.flywheel.util.transform.MatrixTransformStack;
import com.mojang.blaze3d.matrix.MatrixStack;
import com.simibubi.create.AllMovementBehaviours;
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.content.contraptions.components.structureMovement.MovementBehaviour;
import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext;
import com.simibubi.create.foundation.config.AllConfigs;
import com.simibubi.create.foundation.render.AllProgramSpecs;
import com.simibubi.create.foundation.render.Compartment;
import com.simibubi.create.foundation.render.CreateContexts;
import com.simibubi.create.foundation.render.SuperByteBuffer;
import com.simibubi.create.foundation.render.TileEntityRenderHelper;
import com.simibubi.create.foundation.utility.AnimationTickHolder;
import com.simibubi.create.foundation.utility.worldWrappers.PlacementSimulationWorld;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import net.minecraft.block.BlockRenderType;
import net.minecraft.block.BlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.ActiveRenderInfo;
import net.minecraft.client.renderer.BlockModelRenderer;
import net.minecraft.client.renderer.BlockModelShapes;
import net.minecraft.client.renderer.BufferBuilder;
@ -53,7 +37,6 @@ import net.minecraft.client.renderer.WorldRenderer;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.LightType;
import net.minecraft.world.World;
import net.minecraft.world.gen.feature.template.Template;
@ -70,123 +53,25 @@ import net.minecraftforge.fml.common.Mod;
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 int worldHolderRefreshCounter;
public static final Int2ObjectMap<RenderedContraption> RENDERERS = new Int2ObjectOpenHashMap<>();
public static final Int2ObjectMap<ContraptionWorldHolder> WORLD_HOLDERS = new Int2ObjectOpenHashMap<>();
private static final WorldAttached<WorldContraptions> WORLDS = new WorldAttached<>(WorldContraptions::new);
public static final Compartment<Pair<Contraption, RenderType>> CONTRAPTION = new Compartment<>();
public static void tick() {
public static void tick(World world) {
if (Minecraft.getInstance().isPaused()) return;
for (RenderedContraption contraption : RENDERERS.values()) {
ContraptionLighter<?> lighter = contraption.getLighter();
if (lighter.getBounds().volume() < AllConfigs.CLIENT.maxContraptionLightVolume.get())
lighter.tick(contraption);
contraption.kinetics.tick();
}
worldHolderRefreshCounter++;
if (worldHolderRefreshCounter >= 20) {
removeDeadHolders();
worldHolderRefreshCounter = 0;
}
WORLDS.get(world).tick();
}
@SubscribeEvent
public static void beginFrame(BeginFrameEvent event) {
ActiveRenderInfo info = event.getInfo();
double camX = info.getPosition().x;
double camY = info.getPosition().y;
double camZ = info.getPosition().z;
for (RenderedContraption renderer : RENDERERS.values()) {
renderer.beginFrame(info, camX, camY, camZ);
}
WORLDS.get(event.getWorld()).beginFrame(event);
}
@SubscribeEvent
public static void renderLayer(RenderLayerEvent event) {
if (Backend.getInstance().available()) {
renderLayerFlywheel(event);
} else {
renderLayerSBB(event);
}
}
private static void renderLayerFlywheel(RenderLayerEvent event) {
removeDeadContraptions();
if (RENDERERS.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 renderer : RENDERERS.values()) {
renderer.doRenderLayer(layer, structureShader);
}
if (Backend.getInstance().canUseInstancing()) {
RenderLayer renderLayer = event.getLayer();
if (renderLayer != null) {
for (RenderedContraption renderer : RENDERERS.values()) {
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 static void renderLayerSBB(RenderLayerEvent event) {
ContraptionHandler.loadedContraptions.get(event.getWorld())
.values()
.stream()
.map(Reference::get)
.filter(Objects::nonNull)
.forEach(entity -> renderContraptionLayerSBB(event, entity));
}
private static void renderContraptionLayerSBB(RenderLayerEvent event, AbstractContraptionEntity entity) {
RenderType layer = event.getType();
Contraption contraption = entity.getContraption();
Pair<Contraption, RenderType> key = Pair.of(contraption, layer);
SuperByteBuffer contraptionBuffer = CreateClient.BUFFER_CACHE.get(CONTRAPTION, key, () -> buildStructureBuffer(getWorldHolder(entity.level, contraption).renderWorld, contraption, layer));
if (!contraptionBuffer.isEmpty()) {
MatrixStack stack = event.stack;
stack.pushPose();
double x = MathHelper.lerp(AnimationTickHolder.getPartialTicks(), entity.xOld, entity.getX()) - event.camX;
double y = MathHelper.lerp(AnimationTickHolder.getPartialTicks(), entity.yOld, entity.getY()) - event.camY;
double z = MathHelper.lerp(AnimationTickHolder.getPartialTicks(), entity.zOld, entity.getZ()) - event.camZ;
stack.translate(x, y, z);
ContraptionMatrices matrices = new ContraptionMatrices(stack, entity);
contraptionBuffer.transform(matrices.contraptionStack)
.light(matrices.entityMatrix)
.hybridLight()
.renderInto(matrices.entityStack, event.buffers.bufferSource().getBuffer(layer));
stack.popPose();
}
WORLDS.get(event.getWorld()).renderLayer(event);
}
@SubscribeEvent
@ -198,44 +83,13 @@ public class ContraptionRenderDispatcher {
invalidateAll();
}
public static void render(AbstractContraptionEntity entity, Contraption contraption,
ContraptionMatrices matrices, IRenderTypeBuffer buffers) {
public static void render(AbstractContraptionEntity entity, Contraption contraption, IRenderTypeBuffer buffers) {
World world = entity.level;
if (Backend.getInstance().available()) {
getRenderer(world, contraption); // hack to create the RenderedContraption when using Flywheel
}
ContraptionRenderInfo renderInfo = WORLDS.get(world)
.getRenderInfo(contraption);
PlacementSimulationWorld renderWorld = getWorldHolder(world, contraption).renderWorld;
ContraptionRenderDispatcher.renderDynamic(world, renderWorld, contraption, matrices, buffers);
}
private static RenderedContraption getRenderer(World world, Contraption c) {
int entityId = c.entity.getId();
RenderedContraption contraption = RENDERERS.get(entityId);
if (contraption == null) {
PlacementSimulationWorld renderWorld = setupRenderWorld(world, c);
contraption = new RenderedContraption(c, renderWorld);
RENDERERS.put(entityId, contraption);
WORLD_HOLDERS.put(entityId, contraption);
}
return contraption;
}
private static ContraptionWorldHolder getWorldHolder(World world, Contraption c) {
int entityId = c.entity.getId();
ContraptionWorldHolder holder = WORLD_HOLDERS.get(entityId);
if (holder == null) {
PlacementSimulationWorld renderWorld = setupRenderWorld(world, c);
holder = new ContraptionWorldHolder(c, renderWorld);
WORLD_HOLDERS.put(entityId, holder);
}
return holder;
renderDynamic(world, renderInfo.renderWorld, contraption, renderInfo.getMatrices(), buffers);
}
public static PlacementSimulationWorld setupRenderWorld(World world, Contraption c) {
@ -291,7 +145,7 @@ public class ContraptionRenderDispatcher {
}
}
private static SuperByteBuffer buildStructureBuffer(PlacementSimulationWorld renderWorld, Contraption c, RenderType layer) {
public static SuperByteBuffer buildStructureBuffer(PlacementSimulationWorld renderWorld, Contraption c, RenderType layer) {
BufferBuilder builder = buildStructure(renderWorld, c, layer);
return new SuperByteBuffer(builder);
}
@ -349,26 +203,6 @@ public class ContraptionRenderDispatcher {
}
public static void invalidateAll() {
for (RenderedContraption renderer : RENDERERS.values()) {
renderer.invalidate();
}
RENDERERS.clear();
WORLD_HOLDERS.clear();
WORLDS.empty(WorldContraptions::invalidate);
}
public static void removeDeadContraptions() {
RENDERERS.values().removeIf(renderer -> {
if (renderer.isDead()) {
renderer.invalidate();
return true;
}
return false;
});
}
public static void removeDeadHolders() {
WORLD_HOLDERS.values().removeIf(ContraptionWorldHolder::isDead);
}
}

View file

@ -0,0 +1,57 @@
package com.simibubi.create.content.contraptions.components.structureMovement.render;
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.foundation.utility.AnimationTickHolder;
import com.simibubi.create.foundation.utility.worldWrappers.PlacementSimulationWorld;
import net.minecraft.client.renderer.culling.ClippingHelper;
import net.minecraft.util.math.MathHelper;
public class ContraptionRenderInfo {
public final Contraption contraption;
public final PlacementSimulationWorld renderWorld;
private ContraptionMatrices matrices = ContraptionMatrices.IDENTITY;
private boolean visible;
public ContraptionRenderInfo(Contraption contraption, PlacementSimulationWorld renderWorld) {
this.contraption = contraption;
this.renderWorld = renderWorld;
}
public int getEntityId() {
return contraption.entity.getId();
}
public boolean isDead() {
return !contraption.entity.isAlive();
}
public void beginFrame(ClippingHelper clippingHelper, MatrixStack mainStack, double camX, double camY, double camZ) {
AbstractContraptionEntity entity = contraption.entity;
visible = clippingHelper.isVisible(entity.getBoundingBoxForCulling().inflate(2));
mainStack.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;
mainStack.translate(x, y, z);
matrices = new ContraptionMatrices(mainStack, entity);
mainStack.popPose();
}
public boolean isVisible() {
return visible && contraption.entity.isAlive();
}
public ContraptionMatrices getMatrices() {
return matrices;
}
}

View file

@ -1,22 +0,0 @@
package com.simibubi.create.content.contraptions.components.structureMovement.render;
import com.simibubi.create.content.contraptions.components.structureMovement.Contraption;
import com.simibubi.create.foundation.utility.worldWrappers.PlacementSimulationWorld;
public class ContraptionWorldHolder {
public final Contraption contraption;
public final PlacementSimulationWorld renderWorld;
public ContraptionWorldHolder(Contraption contraption, PlacementSimulationWorld renderWorld) {
this.contraption = contraption;
this.renderWorld = renderWorld;
}
public int getEntityId() {
return contraption.entity.getId();
}
public boolean isDead() {
return !contraption.entity.isAlive();
}
}

View file

@ -11,25 +11,25 @@ import com.simibubi.create.foundation.utility.outliner.AABBOutline;
public class LightVolumeDebugger {
public static void render(MatrixStack ms, SuperRenderTypeBuffer buffer) {
ContraptionRenderDispatcher.RENDERERS.values()
.stream()
.flatMap(r -> {
GridAlignedBB texture = r.getLighter().lightVolume.getTextureVolume();
GridAlignedBB sample = r.getLighter().lightVolume.getSampleVolume();
ArrayList<Pair<GridAlignedBB, Integer>> pairs = new ArrayList<>(2);
pairs.add(Pair.of(texture, 0xFFFFFF));
pairs.add(Pair.of(sample, 0xFFFF00));
return pairs.stream();
})
.map(pair -> {
AABBOutline outline = new AABBOutline(GridAlignedBB.toAABB(pair.getFirst()));
outline.getParams().colored(pair.getSecond());
return outline;
})
.forEach(outline -> outline.render(ms, buffer, AnimationTickHolder.getPartialTicks()));
// ContraptionRenderDispatcher.RENDERERS.values()
// .stream()
// .flatMap(r -> {
// GridAlignedBB texture = r.getLighter().lightVolume.getTextureVolume();
// GridAlignedBB sample = r.getLighter().lightVolume.getSampleVolume();
//
// ArrayList<Pair<GridAlignedBB, Integer>> pairs = new ArrayList<>(2);
//
// pairs.add(Pair.of(texture, 0xFFFFFF));
// pairs.add(Pair.of(sample, 0xFFFF00));
//
// return pairs.stream();
// })
// .map(pair -> {
// AABBOutline outline = new AABBOutline(GridAlignedBB.toAABB(pair.getFirst()));
//
// outline.getParams().colored(pair.getSecond());
// return outline;
// })
// .forEach(outline -> outline.render(ms, buffer, AnimationTickHolder.getPartialTicks()));
}
}

View file

@ -12,10 +12,7 @@ import javax.annotation.Nullable;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.gl.attrib.CommonAttributes;
import com.jozufozu.flywheel.backend.gl.attrib.VertexFormat;
import com.jozufozu.flywheel.backend.instancing.IInstanceRendered;
import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher;
import com.jozufozu.flywheel.backend.instancing.InstancedRenderRegistry;
import com.jozufozu.flywheel.backend.material.MaterialGroup;
import com.jozufozu.flywheel.backend.material.MaterialManager;
import com.jozufozu.flywheel.backend.model.ArrayModelRenderer;
import com.jozufozu.flywheel.backend.model.BufferedModel;
@ -41,7 +38,7 @@ import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.vector.Matrix4f;
import net.minecraft.world.World;
public class RenderedContraption extends ContraptionWorldHolder {
public class RenderedContraption extends ContraptionRenderInfo {
public static final VertexFormat FORMAT = VertexFormat.builder()
.addAttributes(CommonAttributes.VEC3,
CommonAttributes.NORMAL,

View file

@ -0,0 +1,234 @@
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);
}
}

View file

@ -141,7 +141,7 @@ public class ClientEvents {
PlacementHelpers.tick();
CreateClient.OUTLINER.tickOutlines();
CreateClient.GHOST_BLOCKS.tickGhosts();
ContraptionRenderDispatcher.tick();
ContraptionRenderDispatcher.tick(world);
BlueprintOverlayRenderer.tick();
}

View file

@ -6,17 +6,19 @@ import java.util.List;
import java.util.Map;
import java.util.function.Function;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import net.minecraft.world.IWorld;
import net.minecraftforge.common.util.NonNullFunction;
public class WorldAttached<T> {
static List<Map<IWorld, ?>> allMaps = new ArrayList<>();
Map<IWorld, T> attached;
private Function<IWorld, T> factory;
private final NonNullFunction<IWorld, T> factory;
public WorldAttached(Function<IWorld, T> factory) {
public WorldAttached(NonNullFunction<IWorld, T> factory) {
this.factory = factory;
attached = new HashMap<>();
allMaps.add(attached);
@ -26,7 +28,7 @@ public class WorldAttached<T> {
allMaps.forEach(m -> m.remove(world));
}
@Nullable
@Nonnull
public T get(IWorld world) {
T t = attached.get(world);
if (t != null)