The flappening.
Tunnel and funnel flaps are now rendered with the new engine.
This commit is contained in:
parent
1e28bc998a
commit
5499fdbad0
20 changed files with 592 additions and 35 deletions
|
@ -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()
|
||||
|
|
|
@ -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<>();
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -521,7 +521,7 @@ public class BeltTileEntity extends KineticTileEntity {
|
|||
|
||||
@Override
|
||||
public boolean shouldRenderAsTE() {
|
||||
return isController();
|
||||
return BeltBlock.canTransportObjects(getBlockState());
|
||||
}
|
||||
|
||||
private void updateLight() {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
104
src/main/resources/assets/create/shader/flap.vert
Normal file
104
src/main/resources/assets/create/shader/flap.vert
Normal 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.);
|
||||
}
|
Loading…
Reference in a new issue