The flappening.

Tunnel and funnel flaps are now rendered with the new engine.
This commit is contained in:
JozsefA 2021-03-02 15:54:31 -08:00
parent 1e28bc998a
commit 5499fdbad0
20 changed files with 592 additions and 35 deletions

View file

@ -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<BrassTunnelTileEntity> BRASS_TUNNEL = Create.registrate()
.tileEntity("brass_tunnel", BrassTunnelTileEntity::new)
.validBlocks(AllBlocks.BRASS_TUNNEL)
.renderer(() -> BeltTunnelRenderer::new)
.onRegister(BeltTunnelInstance::register)
.register();
public static final TileEntityEntry<ArmTileEntity> 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<ContentObserverTileEntity> CONTENT_OBSERVER = Create.registrate()

View file

@ -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<InstancedModel<BeltData>> BELTS = new MaterialType<>();
public static final MaterialType<InstancedModel<ContraptionActorData>> ACTORS = new MaterialType<>();
public static final MaterialType<InstancedModel<FlapData>> FLAPS = new MaterialType<>();
}

View file

@ -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<Contraptio
public void registerMaterials() {
materials.put(KineticRenderMaterials.BELTS, new RenderMaterial<>(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));
}

View file

@ -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

View file

@ -521,7 +521,7 @@ public class BeltTileEntity extends KineticTileEntity {
@Override
public boolean shouldRenderAsTE() {
return isController();
return BeltBlock.canTransportObjects(getBlockState());
}
private void updateLight() {

View file

@ -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);
}
}

View file

@ -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<FlapData> {
public FlapInstancedModel(InstancedTileRenderer<?> renderer, BufferBuilder buf) {
super(renderer, buf);
}
@Override
protected FlapData newInstance() {
return new FlapData(this);
}
@Override
protected VertexFormat getInstanceFormat() {
return FlapData.FORMAT;
}
}

View file

@ -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;
}
}

View file

@ -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<BeltTunnelTileEntity> {
public static void register(TileEntityType<? extends BeltTunnelTileEntity> type) {
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () ->
InstancedTileRenderRegistry.instance.register(type, BeltTunnelInstance::new));
}
private Map<Direction, ArrayList<InstanceKey<FlapData>>> tunnelFlaps;
public BeltTunnelInstance(InstancedTileRenderer<?> modelManager, BeltTunnelTileEntity tile) {
super(modelManager, tile);
}
@Override
protected void init() {
tunnelFlaps = new EnumMap<>(Direction.class);
InstancedModel<FlapData> 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<InstanceKey<FlapData>> 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<FlapData> 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<InstanceKey<FlapData>> instanceKeys : tunnelFlaps.values()) {
for (InstanceKey<FlapData> it : instanceKeys) {
it.modifyInstance(data -> data.setBlockLight(blockLight)
.setSkyLight(skyLight));
}
}
}
@Override
public void remove() {
tunnelFlaps.values()
.stream()
.flatMap(Collection::stream)
.forEach(InstanceKey::delete);
}
}

View file

@ -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<BeltTunnelTileEn
protected void renderSafe(BeltTunnelTileEntity te, float partialTicks, MatrixStack ms, IRenderTypeBuffer buffer,
int light, int overlay) {
super.renderSafe(te, partialTicks, ms, buffer, light, overlay);
if (FastRenderDispatcher.available(te.getWorld())) return;
SuperByteBuffer flapBuffer = AllBlockPartials.BELT_TUNNEL_FLAP.renderOn(te.getBlockState());
IVertexBuilder vb = buffer.getBuffer(RenderType.getSolid());
Vec3d pivot = VecHelper.voxelSpace(0, 10, 1f);

View file

@ -1,11 +1,11 @@
package com.simibubi.create.content.logistics.block.belts.tunnel;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.*;
import com.simibubi.create.CreateClient;
import com.simibubi.create.foundation.render.backend.instancing.IInstanceRendered;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.fml.DistExecutor;
import org.apache.commons.lang3.tuple.Pair;
import com.simibubi.create.AllBlocks;
@ -33,9 +33,9 @@ import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler;
public class BeltTunnelTileEntity extends SmartTileEntity {
public class BeltTunnelTileEntity extends SmartTileEntity implements IInstanceRendered {
public HashMap<Direction, InterpolatedChasingValue> flaps;
public Map<Direction, InterpolatedChasingValue> flaps;
public Set<Direction> sides;
protected LazyOptional<IItemHandler> cap = LazyOptional.empty();
@ -43,7 +43,7 @@ public class BeltTunnelTileEntity extends SmartTileEntity {
public BeltTunnelTileEntity(TileEntityType<? extends BeltTunnelTileEntity> 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);
}
}

View file

@ -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<FunnelTileEntity> {
public static void register(TileEntityType<? extends FunnelTileEntity> type) {
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () ->
InstancedTileRenderRegistry.instance.register(type, FunnelInstance::new));
}
private ArrayList<InstanceKey<FlapData>> 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<FlapData> 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<FlapData> 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<FlapData> it : flaps) {
it.modifyInstance(data -> data.setBlockLight(blockLight)
.setSkyLight(skyLight));
}
}
@Override
public void remove() {
if (flaps == null) return;
flaps.forEach(InstanceKey::delete);
}
}

View file

@ -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<FunnelTileEntity> {
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();

View file

@ -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);
}
}

View file

@ -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();

View file

@ -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<BasicProgram> FLAPS = register(ProgramSpec.builder("flap", BasicProgram::new)
.addAttributes(ModelVertexAttributes.class)
.addAttributes(FlapVertexAttributes.class)
.setVert(Locations.FLAP)
.setFrag(Locations.INSTANCED)
.createProgramSpec());
public static final ProgramSpec<ContraptionProgram> 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<ContraptionProgram> 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<ContraptionProgram> 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");

View file

@ -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<BasicProgram> {
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

View file

@ -40,6 +40,10 @@ public abstract class InstancedTileRenderer<P extends BasicProgram> {
}
}
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);
}

View file

@ -33,6 +33,11 @@ public abstract class TileEntityInstance<T extends TileEntity> {
}
}
/**
* 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<T extends TileEntity> {
* 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.

View file

@ -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.);
}