From 5499fdbad0691d464140812addcb2d7f6d60b5bc Mon Sep 17 00:00:00 2001 From: JozsefA Date: Tue, 2 Mar 2021 15:54:31 -0800 Subject: [PATCH] The flappening. Tunnel and funnel flaps are now rendered with the new engine. --- .../com/simibubi/create/AllTileEntities.java | 5 + .../base/KineticRenderMaterials.java | 3 + .../render/ContraptionKineticRenderer.java | 2 + .../render/ContraptionRenderDispatcher.java | 15 +-- .../relays/belt/BeltTileEntity.java | 2 +- .../content/logistics/block/FlapData.java | 122 ++++++++++++++++++ .../logistics/block/FlapInstancedModel.java | 22 ++++ .../logistics/block/FlapVertexAttributes.java | 45 +++++++ .../belts/tunnel/BeltTunnelInstance.java | 106 +++++++++++++++ .../belts/tunnel/BeltTunnelRenderer.java | 5 + .../belts/tunnel/BeltTunnelTileEntity.java | 24 ++-- .../block/funnel/FunnelInstance.java | 93 +++++++++++++ .../block/funnel/FunnelRenderer.java | 3 +- .../block/funnel/FunnelTileEntity.java | 17 ++- .../foundation/mixin/RenderHooksMixin.java | 28 ++-- .../foundation/render/AllProgramSpecs.java | 18 +++ .../foundation/render/KineticRenderer.java | 2 + .../instancing/InstancedTileRenderer.java | 4 + .../instancing/TileEntityInstance.java | 7 +- .../resources/assets/create/shader/flap.vert | 104 +++++++++++++++ 20 files changed, 592 insertions(+), 35 deletions(-) create mode 100644 src/main/java/com/simibubi/create/content/logistics/block/FlapData.java create mode 100644 src/main/java/com/simibubi/create/content/logistics/block/FlapInstancedModel.java create mode 100644 src/main/java/com/simibubi/create/content/logistics/block/FlapVertexAttributes.java create mode 100644 src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BeltTunnelInstance.java create mode 100644 src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelInstance.java create mode 100644 src/main/resources/assets/create/shader/flap.vert diff --git a/src/main/java/com/simibubi/create/AllTileEntities.java b/src/main/java/com/simibubi/create/AllTileEntities.java index 1abb73271..7e24832ab 100644 --- a/src/main/java/com/simibubi/create/AllTileEntities.java +++ b/src/main/java/com/simibubi/create/AllTileEntities.java @@ -104,6 +104,7 @@ import com.simibubi.create.content.contraptions.relays.gearbox.GearboxInstance; import com.simibubi.create.content.contraptions.relays.gearbox.GearboxRenderer; import com.simibubi.create.content.contraptions.relays.gearbox.GearboxTileEntity; import com.simibubi.create.content.contraptions.relays.gearbox.GearshiftTileEntity; +import com.simibubi.create.content.logistics.block.belts.tunnel.BeltTunnelInstance; import com.simibubi.create.content.logistics.block.belts.tunnel.BeltTunnelRenderer; import com.simibubi.create.content.logistics.block.belts.tunnel.BeltTunnelTileEntity; import com.simibubi.create.content.logistics.block.belts.tunnel.BrassTunnelTileEntity; @@ -116,6 +117,7 @@ import com.simibubi.create.content.logistics.block.depot.DepotTileEntity; import com.simibubi.create.content.logistics.block.diodes.AdjustablePulseRepeaterTileEntity; import com.simibubi.create.content.logistics.block.diodes.AdjustableRepeaterRenderer; import com.simibubi.create.content.logistics.block.diodes.AdjustableRepeaterTileEntity; +import com.simibubi.create.content.logistics.block.funnel.FunnelInstance; import com.simibubi.create.content.logistics.block.funnel.FunnelRenderer; import com.simibubi.create.content.logistics.block.funnel.FunnelTileEntity; import com.simibubi.create.content.logistics.block.inventories.AdjustableCrateTileEntity; @@ -339,12 +341,14 @@ public class AllTileEntities { .tileEntity("andesite_tunnel", BeltTunnelTileEntity::new) .validBlocks(AllBlocks.ANDESITE_TUNNEL) .renderer(() -> BeltTunnelRenderer::new) + .onRegister(BeltTunnelInstance::register) .register(); public static final TileEntityEntry BRASS_TUNNEL = Create.registrate() .tileEntity("brass_tunnel", BrassTunnelTileEntity::new) .validBlocks(AllBlocks.BRASS_TUNNEL) .renderer(() -> BeltTunnelRenderer::new) + .onRegister(BeltTunnelInstance::register) .register(); public static final TileEntityEntry MECHANICAL_ARM = Create.registrate() @@ -591,6 +595,7 @@ public class AllTileEntities { .validBlocks(AllBlocks.BRASS_FUNNEL, AllBlocks.BRASS_BELT_FUNNEL, AllBlocks.ANDESITE_FUNNEL, AllBlocks.ANDESITE_BELT_FUNNEL) .renderer(() -> FunnelRenderer::new) + .onRegister(FunnelInstance::register) .register(); public static final TileEntityEntry CONTENT_OBSERVER = Create.registrate() diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/KineticRenderMaterials.java b/src/main/java/com/simibubi/create/content/contraptions/base/KineticRenderMaterials.java index 49223a3cb..8d3d32d31 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/base/KineticRenderMaterials.java +++ b/src/main/java/com/simibubi/create/content/contraptions/base/KineticRenderMaterials.java @@ -2,6 +2,7 @@ package com.simibubi.create.content.contraptions.base; import com.simibubi.create.content.contraptions.components.actors.ContraptionActorData; import com.simibubi.create.content.contraptions.relays.belt.BeltData; +import com.simibubi.create.content.logistics.block.FlapData; import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; import com.simibubi.create.foundation.render.backend.instancing.MaterialType; @@ -10,4 +11,6 @@ public class KineticRenderMaterials { public static final MaterialType> BELTS = new MaterialType<>(); public static final MaterialType> ACTORS = new MaterialType<>(); + + public static final MaterialType> FLAPS = new MaterialType<>(); } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionKineticRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionKineticRenderer.java index 6733cd22a..f5fe4a9b9 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionKineticRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionKineticRenderer.java @@ -4,6 +4,7 @@ import com.simibubi.create.content.contraptions.base.KineticRenderMaterials; import com.simibubi.create.content.contraptions.base.RotatingInstancedModel; import com.simibubi.create.content.contraptions.components.actors.RotatingActorModel; import com.simibubi.create.content.contraptions.relays.belt.BeltInstancedModel; +import com.simibubi.create.content.logistics.block.FlapInstancedModel; import com.simibubi.create.foundation.render.AllProgramSpecs; import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; import com.simibubi.create.foundation.render.backend.instancing.RenderMaterial; @@ -16,6 +17,7 @@ public class ContraptionKineticRenderer extends InstancedTileRenderer(this, AllProgramSpecs.CONTRAPTION_BELT, BeltInstancedModel::new)); materials.put(KineticRenderMaterials.ROTATING, new RenderMaterial<>(this, AllProgramSpecs.CONTRAPTION_ROTATING, RotatingInstancedModel::new)); + materials.put(KineticRenderMaterials.FLAPS, new RenderMaterial<>(this, AllProgramSpecs.CONTRAPTION_FLAPS, FlapInstancedModel::new)); materials.put(KineticRenderMaterials.ACTORS, new RenderMaterial<>(this, AllProgramSpecs.CONTRAPTION_ACTOR, RotatingActorModel::new)); } 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 b35305eed..346c3e244 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 @@ -104,20 +104,17 @@ public class ContraptionRenderDispatcher { return contraption; } + public static void beginFrame(double camX, double camY, double camZ) { + for (RenderedContraption renderer : renderers.values()) { + renderer.beginFrame(camX, camY, camZ); + } + } + public static void renderLayer(RenderType layer, Matrix4f viewProjection, double camX, double camY, double camZ) { removeDeadContraptions(); if (renderers.isEmpty()) return; - if (firstLayer) { - - for (RenderedContraption renderer : renderers.values()) { - renderer.beginFrame(camX, camY, camZ); - } - - firstLayer = false; - } - layer.startDrawing(); GL11.glEnable(GL13.GL_TEXTURE_3D); GL13.glActiveTexture(GL40.GL_TEXTURE4); // the shaders expect light volumes to be in texture 4 diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltTileEntity.java index a55c23825..f26ebceed 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltTileEntity.java @@ -521,7 +521,7 @@ public class BeltTileEntity extends KineticTileEntity { @Override public boolean shouldRenderAsTE() { - return isController(); + return BeltBlock.canTransportObjects(getBlockState()); } private void updateLight() { diff --git a/src/main/java/com/simibubi/create/content/logistics/block/FlapData.java b/src/main/java/com/simibubi/create/content/logistics/block/FlapData.java new file mode 100644 index 000000000..a42d8af3b --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/block/FlapData.java @@ -0,0 +1,122 @@ +package com.simibubi.create.content.logistics.block; + +import com.simibubi.create.foundation.render.backend.gl.attrib.VertexFormat; +import com.simibubi.create.foundation.render.backend.instancing.InstanceData; +import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; +import net.minecraft.client.renderer.Vector3f; +import net.minecraft.util.math.BlockPos; + +import java.nio.ByteBuffer; + +public class FlapData extends InstanceData { + + public static VertexFormat FORMAT = VertexFormat.builder() + .addAttributes(FlapVertexAttributes.class) + .build(); + + private float x; + private float y; + private float z; + private byte blockLight; + private byte skyLight; + + private float segmentOffsetX; + private float segmentOffsetY; + private float segmentOffsetZ; + + private float pivotX; + private float pivotY; + private float pivotZ; + + private float horizontalAngle; + private float intensity; + private float flapScale; + + private float flapness; + + public FlapData(InstancedModel owner) { + super(owner); + } + + public FlapData setPosition(BlockPos pos) { + return setPosition(pos.getX(), pos.getY(), pos.getZ()); + } + + public FlapData setPosition(Vector3f pos) { + return setPosition(pos.getX(), pos.getY(), pos.getZ()); + } + + public FlapData setPosition(int x, int y, int z) { + BlockPos origin = owner.renderer.getOriginCoordinate(); + + return setPosition((float) (x - origin.getX()), + (float) (y - origin.getY()), + (float) (z - origin.getZ())); + } + + public FlapData setPosition(float x, float y, float z) { + this.x = x; + this.y = y; + this.z = z; + return this; + } + + public FlapData setBlockLight(int blockLight) { + this.blockLight = (byte) ((blockLight & 0xF) << 4); + return this; + } + + public FlapData setSkyLight(int skyLight) { + this.skyLight = (byte) ((skyLight & 0xF) << 4); + return this; + } + + public FlapData setSegmentOffset(float x, float y, float z) { + this.segmentOffsetX = x; + this.segmentOffsetY = y; + this.segmentOffsetZ = z; + return this; + } + + public FlapData setIntensity(float intensity) { + this.intensity = intensity; + return this; + } + + public FlapData setHorizontalAngle(float horizontalAngle) { + this.horizontalAngle = horizontalAngle; + return this; + } + + public FlapData setFlapScale(float flapScale) { + this.flapScale = flapScale; + return this; + } + + public FlapData setFlapness(float flapness) { + this.flapness = flapness; + return this; + } + + public FlapData setPivotVoxelSpace(float x, float y, float z) { + pivotX = x / 16f; + pivotY = y / 16f; + pivotZ = z / 16f; + return this; + } + + @Override + public void write(ByteBuffer buf) { + putVec3(buf, x, y, z); + putVec2(buf, blockLight, skyLight); + + putVec3(buf, segmentOffsetX, segmentOffsetY, segmentOffsetZ); + putVec3(buf, pivotX, pivotY, pivotZ); + + put(buf, horizontalAngle); + put(buf, intensity); + put(buf, flapScale); + + put(buf, flapness); + } +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/FlapInstancedModel.java b/src/main/java/com/simibubi/create/content/logistics/block/FlapInstancedModel.java new file mode 100644 index 000000000..d9502bb4d --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/block/FlapInstancedModel.java @@ -0,0 +1,22 @@ +package com.simibubi.create.content.logistics.block; + +import com.simibubi.create.foundation.render.backend.gl.attrib.VertexFormat; +import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; +import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; +import net.minecraft.client.renderer.BufferBuilder; + +public class FlapInstancedModel extends InstancedModel { + public FlapInstancedModel(InstancedTileRenderer renderer, BufferBuilder buf) { + super(renderer, buf); + } + + @Override + protected FlapData newInstance() { + return new FlapData(this); + } + + @Override + protected VertexFormat getInstanceFormat() { + return FlapData.FORMAT; + } +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/FlapVertexAttributes.java b/src/main/java/com/simibubi/create/content/logistics/block/FlapVertexAttributes.java new file mode 100644 index 000000000..d32768a3f --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/block/FlapVertexAttributes.java @@ -0,0 +1,45 @@ +package com.simibubi.create.content.logistics.block; + +import com.simibubi.create.foundation.render.backend.gl.attrib.CommonAttributes; +import com.simibubi.create.foundation.render.backend.gl.attrib.IVertexAttrib; +import com.simibubi.create.foundation.render.backend.gl.attrib.VertexAttribSpec; + +public enum FlapVertexAttributes implements IVertexAttrib { + INSTANCE_POSITION("aInstancePos",CommonAttributes.VEC3), + LIGHT("aLight", CommonAttributes.LIGHT), + SEGMENT_OFFSET("aSegmentOffset", CommonAttributes.VEC3), + PIVOT("aPivot", CommonAttributes.VEC3), + HORIZONTAL_ANGLE("aHorizontalAngle", CommonAttributes.FLOAT), + INTENSITY("aIntensity", CommonAttributes.FLOAT), + FLAP_SCALE("aFlapScale", CommonAttributes.FLOAT), + FLAPNESS("aFlapness", CommonAttributes.FLOAT), + ; + + private final String name; + private final VertexAttribSpec spec; + + FlapVertexAttributes(String name, VertexAttribSpec spec) { + this.name = name; + this.spec = spec; + } + + @Override + public String attribName() { + return name; + } + + @Override + public VertexAttribSpec attribSpec() { + return spec; + } + + @Override + public int getDivisor() { + return 1; + } + + @Override + public int getBufferIndex() { + return 1; + } +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BeltTunnelInstance.java b/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BeltTunnelInstance.java new file mode 100644 index 000000000..5b38ee07f --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BeltTunnelInstance.java @@ -0,0 +1,106 @@ +package com.simibubi.create.content.logistics.block.belts.tunnel; + +import com.simibubi.create.AllBlockPartials; +import com.simibubi.create.content.contraptions.base.KineticRenderMaterials; +import com.simibubi.create.content.logistics.block.FlapData; +import com.simibubi.create.foundation.render.backend.instancing.*; +import com.simibubi.create.foundation.utility.AnimationTickHolder; +import net.minecraft.tileentity.TileEntityType; +import net.minecraft.util.Direction; +import net.minecraft.world.LightType; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.fml.DistExecutor; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.EnumMap; +import java.util.Map; + +public class BeltTunnelInstance extends TileEntityInstance { + public static void register(TileEntityType type) { + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> + InstancedTileRenderRegistry.instance.register(type, BeltTunnelInstance::new)); + } + + private Map>> tunnelFlaps; + + public BeltTunnelInstance(InstancedTileRenderer modelManager, BeltTunnelTileEntity tile) { + super(modelManager, tile); + } + + @Override + protected void init() { + tunnelFlaps = new EnumMap<>(Direction.class); + + InstancedModel model = modelManager.getMaterial(KineticRenderMaterials.FLAPS) + .getModel(AllBlockPartials.BELT_TUNNEL_FLAP, lastState); + + int blockLight = world.getLightLevel(LightType.BLOCK, pos); + int skyLight = world.getLightLevel(LightType.SKY, pos); + + tile.flaps.forEach((direction, flapValue) -> { + + float flapness = flapValue.get(AnimationTickHolder.getPartialTicks()); + + float horizontalAngle = direction.getOpposite().getHorizontalAngle(); + + float flapScale = direction.getAxis() == Direction.Axis.X ? 1 : -1; + + ArrayList> flaps = new ArrayList<>(4); + + for (int segment = 0; segment <= 3; segment++) { + float intensity = segment == 3 ? 1.5f : segment + 1; + float segmentOffset = -3 / 16f * segment; + + flaps.add(model.setupInstance(flapData -> { + flapData.setPosition(pos) + .setSegmentOffset(segmentOffset, 0, 0) + .setBlockLight(blockLight) + .setSkyLight(skyLight) + .setHorizontalAngle(horizontalAngle) + .setFlapness(flapness) + .setFlapScale(flapScale) + .setPivotVoxelSpace(0, 10, 1) + .setIntensity(intensity); + })); + } + + tunnelFlaps.put(direction, flaps); + }); + } + + @Override + public void tick() { + tunnelFlaps.forEach((direction, keys) -> { + + float flapness = tile.flaps.get(direction).get(AnimationTickHolder.getPartialTicks()); + for (InstanceKey key : keys) { + key.modifyInstance(data -> data.setFlapness(flapness)); + } + }); + } + + @Override + protected void onUpdate() { } + + @Override + public void updateLight() { + int blockLight = world.getLightLevel(LightType.BLOCK, pos); + int skyLight = world.getLightLevel(LightType.SKY, pos); + + for (ArrayList> instanceKeys : tunnelFlaps.values()) { + for (InstanceKey it : instanceKeys) { + it.modifyInstance(data -> data.setBlockLight(blockLight) + .setSkyLight(skyLight)); + } + } + } + + @Override + public void remove() { + tunnelFlaps.values() + .stream() + .flatMap(Collection::stream) + .forEach(InstanceKey::delete); + } +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BeltTunnelRenderer.java b/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BeltTunnelRenderer.java index 8751cf110..b605298bf 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BeltTunnelRenderer.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BeltTunnelRenderer.java @@ -4,6 +4,8 @@ import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.vertex.IVertexBuilder; import com.simibubi.create.AllBlockPartials; import com.simibubi.create.foundation.render.SuperByteBuffer; +import com.simibubi.create.foundation.render.backend.Backend; +import com.simibubi.create.foundation.render.backend.FastRenderDispatcher; import com.simibubi.create.foundation.tileEntity.renderer.SmartTileEntityRenderer; import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.Iterate; @@ -28,6 +30,9 @@ public class BeltTunnelRenderer extends SmartTileEntityRenderer flaps; + public Map flaps; public Set sides; protected LazyOptional cap = LazyOptional.empty(); @@ -43,7 +43,7 @@ public class BeltTunnelTileEntity extends SmartTileEntity { public BeltTunnelTileEntity(TileEntityType type) { super(type); - flaps = new HashMap<>(); + flaps = new EnumMap<>(Direction.class); sides = new HashSet<>(); flapsToSend = new LinkedList<>(); } @@ -174,7 +174,9 @@ public class BeltTunnelTileEntity extends SmartTileEntity { @Override public void initialize() { super.initialize(); -// updateTunnelConnections(); + updateTunnelConnections(); + if (world != null && world.isRemote) + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> CreateClient.kineticRenderer.add(this)); } @Override @@ -212,4 +214,8 @@ public class BeltTunnelTileEntity extends SmartTileEntity { return this.cap.cast(); } + @Override + public void onChunkLightUpdate() { + CreateClient.kineticRenderer.onLightUpdate(this); + } } diff --git a/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelInstance.java b/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelInstance.java new file mode 100644 index 000000000..21d838502 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelInstance.java @@ -0,0 +1,93 @@ +package com.simibubi.create.content.logistics.block.funnel; + +import com.simibubi.create.AllBlockPartials; +import com.simibubi.create.content.contraptions.base.KineticRenderMaterials; +import com.simibubi.create.content.logistics.block.FlapData; +import com.simibubi.create.foundation.render.backend.instancing.*; +import com.simibubi.create.foundation.utility.AnimationTickHolder; +import net.minecraft.tileentity.TileEntityType; +import net.minecraft.util.Direction; +import net.minecraft.world.LightType; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.fml.DistExecutor; + +import java.util.ArrayList; + +public class FunnelInstance extends TileEntityInstance { + public static void register(TileEntityType type) { + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> + InstancedTileRenderRegistry.instance.register(type, FunnelInstance::new)); + } + + private ArrayList> flaps; + + public FunnelInstance(InstancedTileRenderer modelManager, FunnelTileEntity tile) { + super(modelManager, tile); + } + + @Override + protected void init() { + flaps = new ArrayList<>(4); + + if (!tile.hasFlap()) return; + + AllBlockPartials flapPartial = (lastState.getBlock() instanceof FunnelBlock ? AllBlockPartials.FUNNEL_FLAP + : AllBlockPartials.BELT_FUNNEL_FLAP); + InstancedModel model = modelManager.getMaterial(KineticRenderMaterials.FLAPS) + .getModel(flapPartial, lastState); + + int blockLight = world.getLightLevel(LightType.BLOCK, pos); + int skyLight = world.getLightLevel(LightType.SKY, pos); + + Direction direction = FunnelBlock.getFunnelFacing(lastState); + + float flapness = tile.flap.get(AnimationTickHolder.getPartialTicks()); + float horizontalAngle = direction.getOpposite().getHorizontalAngle(); + + for (int segment = 0; segment <= 3; segment++) { + float intensity = segment == 3 ? 1.5f : segment + 1; + float segmentOffset = -3 / 16f * segment; + + flaps.add(model.setupInstance(flapData -> flapData.setPosition(pos) + .setSegmentOffset(segmentOffset, 0, -tile.getFlapOffset()) + .setBlockLight(blockLight) + .setSkyLight(skyLight) + .setHorizontalAngle(horizontalAngle) + .setFlapness(flapness) + .setFlapScale(-1) + .setPivotVoxelSpace(0, 10, 9.5f) + .setIntensity(intensity))); + } + } + + @Override + public void tick() { + if (flaps == null) return; + + float flapness = tile.flap.get(AnimationTickHolder.getPartialTicks()); + + for (InstanceKey key : flaps) { + key.modifyInstance(data -> data.setFlapness(flapness)); + } + } + + @Override + public void updateLight() { + if (flaps == null) return; + + int blockLight = world.getLightLevel(LightType.BLOCK, pos); + int skyLight = world.getLightLevel(LightType.SKY, pos); + + for (InstanceKey it : flaps) { + it.modifyInstance(data -> data.setBlockLight(blockLight) + .setSkyLight(skyLight)); + } + } + + @Override + public void remove() { + if (flaps == null) return; + + flaps.forEach(InstanceKey::delete); + } +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelRenderer.java b/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelRenderer.java index c8cb12583..0f2ea623a 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelRenderer.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelRenderer.java @@ -4,6 +4,7 @@ import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.vertex.IVertexBuilder; import com.simibubi.create.AllBlockPartials; import com.simibubi.create.foundation.render.SuperByteBuffer; +import com.simibubi.create.foundation.render.backend.FastRenderDispatcher; import com.simibubi.create.foundation.tileEntity.renderer.SmartTileEntityRenderer; import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.MatrixStacker; @@ -27,7 +28,7 @@ public class FunnelRenderer extends SmartTileEntityRenderer { int light, int overlay) { super.renderSafe(te, partialTicks, ms, buffer, light, overlay); - if (!te.hasFlap()) + if (!te.hasFlap() || FastRenderDispatcher.available(te.getWorld())) return; BlockState blockState = te.getBlockState(); diff --git a/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelTileEntity.java index a25b196cb..c2d8f3893 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelTileEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelTileEntity.java @@ -4,6 +4,7 @@ import java.lang.ref.WeakReference; import java.util.List; import com.simibubi.create.AllBlocks; +import com.simibubi.create.CreateClient; import com.simibubi.create.content.contraptions.components.saw.SawTileEntity; import com.simibubi.create.content.contraptions.goggles.IHaveHoveringInformation; import com.simibubi.create.content.contraptions.relays.belt.BeltHelper; @@ -14,6 +15,7 @@ import com.simibubi.create.content.logistics.block.funnel.BeltFunnelBlock.Shape; import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.gui.widgets.InterpolatedChasingValue; import com.simibubi.create.foundation.item.TooltipHelper; +import com.simibubi.create.foundation.render.backend.instancing.IInstanceRendered; import com.simibubi.create.foundation.tileEntity.SmartTileEntity; import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; import com.simibubi.create.foundation.tileEntity.behaviour.belt.DirectBeltInputBehaviour; @@ -33,11 +35,13 @@ import net.minecraft.util.Direction; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; +import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.fml.DistExecutor; import net.minecraftforge.items.CapabilityItemHandler; import net.minecraftforge.items.IItemHandler; -public class FunnelTileEntity extends SmartTileEntity implements IHaveHoveringInformation { +public class FunnelTileEntity extends SmartTileEntity implements IHaveHoveringInformation, IInstanceRendered { private FilteringBehaviour filtering; private InvManipulationBehaviour invManipulation; @@ -381,4 +385,15 @@ public class FunnelTileEntity extends SmartTileEntity implements IHaveHoveringIn return true; } + @Override + public void initialize() { + super.initialize(); + if (world != null && world.isRemote) + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> CreateClient.kineticRenderer.add(this)); + } + + @Override + public void onChunkLightUpdate() { + CreateClient.kineticRenderer.onLightUpdate(this); + } } diff --git a/src/main/java/com/simibubi/create/foundation/mixin/RenderHooksMixin.java b/src/main/java/com/simibubi/create/foundation/mixin/RenderHooksMixin.java index eb02006e8..d44d476b0 100644 --- a/src/main/java/com/simibubi/create/foundation/mixin/RenderHooksMixin.java +++ b/src/main/java/com/simibubi/create/foundation/mixin/RenderHooksMixin.java @@ -1,11 +1,7 @@ package com.simibubi.create.foundation.mixin; -import com.simibubi.create.foundation.render.backend.light.ILightListener; -import net.minecraft.client.Minecraft; -import net.minecraft.client.multiplayer.ClientChunkProvider; -import net.minecraft.util.math.SectionPos; -import net.minecraft.world.ILightReader; -import net.minecraft.world.chunk.Chunk; +import net.minecraft.client.renderer.*; +import net.minecraft.util.math.Vec3d; import org.lwjgl.opengl.GL20; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -20,15 +16,10 @@ import com.simibubi.create.foundation.render.backend.Backend; import com.simibubi.create.foundation.render.backend.FastRenderDispatcher; import com.simibubi.create.foundation.render.backend.OptifineHandler; -import net.minecraft.client.renderer.Matrix4f; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.WorldRenderer; import net.minecraft.client.world.ClientWorld; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; -import java.util.Map; - @OnlyIn(Dist.CLIENT) @Mixin(WorldRenderer.class) public class RenderHooksMixin { @@ -40,7 +31,7 @@ public class RenderHooksMixin { * layer-correct custom rendering. RenderWorldLast is not refined enough for rendering world objects. * This should probably be a forge event. */ - @Inject(at = @At(value = "TAIL"), method = "renderLayer") + @Inject(at = @At("TAIL"), method = "renderLayer") private void renderLayer(RenderType type, MatrixStack stack, double camX, double camY, double camZ, CallbackInfo ci) { if (!Backend.available()) return; @@ -54,7 +45,18 @@ public class RenderHooksMixin { GL20.glUseProgram(0); } - @Inject(at = @At(value = "TAIL"), method = "loadRenderers") + @Inject(at = @At(value = "INVOKE", target = "updateChunks(J)V"), method = "render") + private void setupFrame(MatrixStack p_228426_1_, float p_228426_2_, long p_228426_3_, boolean p_228426_5_, ActiveRenderInfo info, GameRenderer p_228426_7_, LightTexture p_228426_8_, Matrix4f p_228426_9_, CallbackInfo ci) { + Vec3d cameraPos = info.getProjectedView(); + double camX = cameraPos.getX(); + double camY = cameraPos.getY(); + double camZ = cameraPos.getZ(); + + CreateClient.kineticRenderer.beginFrame(camX, camY, camZ); + ContraptionRenderDispatcher.beginFrame(camX, camY, camZ); + } + + @Inject(at = @At("TAIL"), method = "loadRenderers") private void refresh(CallbackInfo ci) { CreateClient.kineticRenderer.invalidate(); ContraptionRenderDispatcher.invalidateAll(); diff --git a/src/main/java/com/simibubi/create/foundation/render/AllProgramSpecs.java b/src/main/java/com/simibubi/create/foundation/render/AllProgramSpecs.java index b5d5e991a..d943724d0 100644 --- a/src/main/java/com/simibubi/create/foundation/render/AllProgramSpecs.java +++ b/src/main/java/com/simibubi/create/foundation/render/AllProgramSpecs.java @@ -9,6 +9,7 @@ import com.simibubi.create.content.contraptions.components.actors.ActorVertexAtt import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionProgram; import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionVertexAttributes; import com.simibubi.create.content.contraptions.relays.belt.BeltVertexAttributes; +import com.simibubi.create.content.logistics.block.FlapVertexAttributes; import com.simibubi.create.foundation.render.backend.gl.BasicProgram; import com.simibubi.create.foundation.render.backend.gl.attrib.ModelVertexAttributes; import com.simibubi.create.foundation.render.backend.gl.shader.ProgramSpec; @@ -33,6 +34,13 @@ public class AllProgramSpecs { .setFrag(Locations.INSTANCED) .createProgramSpec()); + public static final ProgramSpec FLAPS = register(ProgramSpec.builder("flap", BasicProgram::new) + .addAttributes(ModelVertexAttributes.class) + .addAttributes(FlapVertexAttributes.class) + .setVert(Locations.FLAP) + .setFrag(Locations.INSTANCED) + .createProgramSpec()); + public static final ProgramSpec CONTRAPTION_STRUCTURE = register(ProgramSpec.builder("contraption_structure", ContraptionProgram::new) .addAttributes(ContraptionVertexAttributes.class) .setVert(Locations.CONTRAPTION_STRUCTURE) @@ -57,6 +65,14 @@ public class AllProgramSpecs { .setDefines(ShaderConstants.define("CONTRAPTION")) .createProgramSpec()); + public static final ProgramSpec CONTRAPTION_FLAPS = register(ProgramSpec.builder("contraption_flap", ContraptionProgram::new) + .addAttributes(ModelVertexAttributes.class) + .addAttributes(FlapVertexAttributes.class) + .setVert(Locations.FLAP) + .setFrag(Locations.CONTRAPTION) + .setDefines(ShaderConstants.define("CONTRAPTION")) + .createProgramSpec()); + public static final ProgramSpec CONTRAPTION_ACTOR = register(ProgramSpec.builder("contraption_actor", ContraptionProgram::new) .addAttributes(ModelVertexAttributes.class) .addAttributes(ActorVertexAttributes.class) @@ -64,12 +80,14 @@ public class AllProgramSpecs { .setFrag(Locations.CONTRAPTION) .createProgramSpec()); + public static class Locations { public static final ResourceLocation INSTANCED = loc("instanced.frag"); public static final ResourceLocation CONTRAPTION = loc("contraption.frag"); public static final ResourceLocation ROTATING = loc("rotating.vert"); public static final ResourceLocation BELT = loc("belt.vert"); + public static final ResourceLocation FLAP = loc("flap.vert"); public static final ResourceLocation CONTRAPTION_STRUCTURE = loc("contraption_structure.vert"); public static final ResourceLocation CONTRAPTION_ACTOR = loc("contraption_actor.vert"); diff --git a/src/main/java/com/simibubi/create/foundation/render/KineticRenderer.java b/src/main/java/com/simibubi/create/foundation/render/KineticRenderer.java index 8517b7d03..68cb7367e 100644 --- a/src/main/java/com/simibubi/create/foundation/render/KineticRenderer.java +++ b/src/main/java/com/simibubi/create/foundation/render/KineticRenderer.java @@ -5,6 +5,7 @@ import java.util.ArrayList; import com.simibubi.create.content.contraptions.base.KineticRenderMaterials; import com.simibubi.create.content.contraptions.base.RotatingInstancedModel; import com.simibubi.create.content.contraptions.relays.belt.BeltInstancedModel; +import com.simibubi.create.content.logistics.block.FlapInstancedModel; import com.simibubi.create.foundation.render.backend.gl.BasicProgram; import com.simibubi.create.foundation.render.backend.gl.shader.ShaderCallback; import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; @@ -26,6 +27,7 @@ public class KineticRenderer extends InstancedTileRenderer { public void registerMaterials() { materials.put(KineticRenderMaterials.BELTS, new RenderMaterial<>(this, AllProgramSpecs.BELT, BeltInstancedModel::new)); materials.put(KineticRenderMaterials.ROTATING, new RenderMaterial<>(this, AllProgramSpecs.ROTATING, RotatingInstancedModel::new)); + materials.put(KineticRenderMaterials.FLAPS, new RenderMaterial<>(this, AllProgramSpecs.FLAPS, FlapInstancedModel::new)); } @Override diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/instancing/InstancedTileRenderer.java b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/InstancedTileRenderer.java index 524d36a91..2f7c37288 100644 --- a/src/main/java/com/simibubi/create/foundation/render/backend/instancing/InstancedTileRenderer.java +++ b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/InstancedTileRenderer.java @@ -40,6 +40,10 @@ public abstract class InstancedTileRenderer

{ } } + public void beginFrame(double cameraX, double cameraY, double cameraZ) { + instances.values().forEach(TileEntityInstance::tick); + } + public void render(RenderType layer, Matrix4f viewProjection, double camX, double camY, double camZ) { render(layer, viewProjection, camX, camY, camZ, null); } diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/instancing/TileEntityInstance.java b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/TileEntityInstance.java index ed4b1f162..fd77e7fd3 100644 --- a/src/main/java/com/simibubi/create/foundation/render/backend/instancing/TileEntityInstance.java +++ b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/TileEntityInstance.java @@ -33,6 +33,11 @@ public abstract class TileEntityInstance { } } + /** + * Called every frame, this can be used to make more dynamic animations. + */ + public void tick() { } + /** * Acquire all {@link InstanceKey}s and initialize any data you may need to calculate the instance properties. */ @@ -42,7 +47,7 @@ public abstract class TileEntityInstance { * Update changed instance data using the {@link InstanceKey}s you got in {@link #init()}. * You don't have to update light data. That should be done in {@link #updateLight()} */ - protected abstract void onUpdate(); + protected void onUpdate() { } /** * Called when a light update occurs in the world. If your model needs it, update light here. diff --git a/src/main/resources/assets/create/shader/flap.vert b/src/main/resources/assets/create/shader/flap.vert new file mode 100644 index 000000000..bd982595d --- /dev/null +++ b/src/main/resources/assets/create/shader/flap.vert @@ -0,0 +1,104 @@ +#version 110 +#define PI 3.1415926538 + +attribute vec3 aPos; +attribute vec3 aNormal; +attribute vec2 aTexCoords; + +attribute vec3 aInstancePos; +attribute vec2 aLight; + +attribute vec3 aSegmentOffset; +attribute vec3 aPivot; +attribute float aHorizontalAngle; +attribute float aIntensity; +attribute float aFlapScale; + +attribute float aFlapness; + +// outputs +varying vec2 TexCoords; +varying vec4 Color; +varying float Diffuse; +varying vec2 Light; + +#if defined(CONTRAPTION) +varying vec3 BoxCoord; + +uniform vec3 uLightBoxSize; +uniform vec3 uLightBoxMin; +uniform mat4 uModel; +#endif + +uniform float uTime; +uniform mat4 uViewProjection; +uniform int uDebug; + +uniform vec3 uCameraPos; +varying float FragDistance; + +float diffuse(vec3 normal) { + float x = normal.x; + float y = normal.y; + float z = normal.z; + return min(x * x * .6 + y * y * ((3. + y) / 4.) + z * z * .8, 1.); +} + +mat4 rotate(vec3 axis, float angle) { + float s = sin(angle); + float c = cos(angle); + float oc = 1. - c; + + return mat4(oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s, 0., + oc * axis.x * axis.y + axis.z * s, oc * axis.y * axis.y + c, oc * axis.y * axis.z - axis.x * s, 0., + oc * axis.z * axis.x - axis.y * s, oc * axis.y * axis.z + axis.x * s, oc * axis.z * axis.z + c, 0., + 0., 0., 0., 1.); +} + +float toRad(float degrees) { + return fract(degrees / 360.) * PI * 2.; +} + +float getFlapAngle() { + float absFlap = abs(aFlapness); + + float angle = sin((1. - absFlap) * PI * aIntensity) * 30. * aFlapness * aFlapScale; + + float halfAngle = angle * 0.5; + + float which = step(0., aFlapness); + float degrees = which * halfAngle + (1. - which) * angle; // branchless conditional multiply + + return -toRad(degrees); +} + +void main() { + float flapAngle = getFlapAngle(); + + mat4 orientation = rotate(vec3(0., 1., 0.), toRad(aHorizontalAngle)); + mat4 flapRotation = rotate(vec3(1., 0., 0.), flapAngle); + + vec4 worldPos = flapRotation * vec4(aPos - aPivot, 1.) + vec4(aPivot + aSegmentOffset, 0.); + worldPos = orientation * vec4(worldPos.xyz - .5, 1.) + vec4(aInstancePos + .5, 0.); + + #ifdef CONTRAPTION + worldPos = uModel * worldPos; + mat4 normalMat = uModel * orientation * flapRotation; + + BoxCoord = (worldPos.xyz - uLightBoxMin) / uLightBoxSize; + FragDistance = length(worldPos.xyz); + #else + mat4 normalMat = orientation * flapRotation; + + FragDistance = length(worldPos.xyz - uCameraPos); + #endif + + vec3 norm = normalize(normalMat * vec4(aNormal, 0.)).xyz; + + Diffuse = diffuse(norm); + TexCoords = aTexCoords; + Light = aLight; + gl_Position = uViewProjection * worldPos; + + Color = vec4(1.); +}