Instanced Gauges and Valves, DRY lighting.

This commit is contained in:
JozsefA 2021-03-15 14:20:13 -07:00
parent 8281c5746a
commit 52eed2bab3
29 changed files with 383 additions and 107 deletions

View file

@ -77,6 +77,7 @@ import com.simibubi.create.content.contraptions.relays.belt.BeltRenderer;
import com.simibubi.create.content.contraptions.relays.belt.BeltTileEntity; import com.simibubi.create.content.contraptions.relays.belt.BeltTileEntity;
import com.simibubi.create.content.contraptions.relays.elementary.SimpleKineticTileEntity; import com.simibubi.create.content.contraptions.relays.elementary.SimpleKineticTileEntity;
import com.simibubi.create.content.contraptions.relays.encased.*; import com.simibubi.create.content.contraptions.relays.encased.*;
import com.simibubi.create.content.contraptions.relays.gauge.GaugeInstance;
import com.simibubi.create.content.contraptions.relays.gauge.GaugeRenderer; import com.simibubi.create.content.contraptions.relays.gauge.GaugeRenderer;
import com.simibubi.create.content.contraptions.relays.gauge.SpeedGaugeTileEntity; import com.simibubi.create.content.contraptions.relays.gauge.SpeedGaugeTileEntity;
import com.simibubi.create.content.contraptions.relays.gauge.StressGaugeTileEntity; import com.simibubi.create.content.contraptions.relays.gauge.StressGaugeTileEntity;
@ -260,7 +261,7 @@ public class AllTileEntities {
public static final TileEntityEntry<FluidValveTileEntity> FLUID_VALVE = Create.registrate() public static final TileEntityEntry<FluidValveTileEntity> FLUID_VALVE = Create.registrate()
.tileEntity("fluid_valve", FluidValveTileEntity::new) .tileEntity("fluid_valve", FluidValveTileEntity::new)
.instance(() -> ShaftInstance::new) .instance(() -> FluidValveInstance::new)
.validBlocks(AllBlocks.FLUID_VALVE) .validBlocks(AllBlocks.FLUID_VALVE)
.renderer(() -> FluidValveRenderer::new) .renderer(() -> FluidValveRenderer::new)
.register(); .register();
@ -515,14 +516,14 @@ public class AllTileEntities {
public static final TileEntityEntry<SpeedGaugeTileEntity> SPEEDOMETER = Create.registrate() public static final TileEntityEntry<SpeedGaugeTileEntity> SPEEDOMETER = Create.registrate()
.tileEntity("speedometer", SpeedGaugeTileEntity::new) .tileEntity("speedometer", SpeedGaugeTileEntity::new)
.instance(() -> ShaftInstance::new) .instance(() -> GaugeInstance.Speed::new)
.validBlocks(AllBlocks.SPEEDOMETER) .validBlocks(AllBlocks.SPEEDOMETER)
.renderer(() -> GaugeRenderer::speed) .renderer(() -> GaugeRenderer::speed)
.register(); .register();
public static final TileEntityEntry<StressGaugeTileEntity> STRESSOMETER = Create.registrate() public static final TileEntityEntry<StressGaugeTileEntity> STRESSOMETER = Create.registrate()
.tileEntity("stressometer", StressGaugeTileEntity::new) .tileEntity("stressometer", StressGaugeTileEntity::new)
.instance(() -> ShaftInstance::new) .instance(() -> GaugeInstance.Stress::new)
.validBlocks(AllBlocks.STRESSOMETER) .validBlocks(AllBlocks.STRESSOMETER)
.renderer(() -> GaugeRenderer::stress) .renderer(() -> GaugeRenderer::stress)
.register(); .register();

View file

@ -4,12 +4,13 @@ import java.nio.ByteBuffer;
import com.simibubi.create.foundation.render.backend.instancing.InstanceData; import com.simibubi.create.foundation.render.backend.instancing.InstanceData;
import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; import com.simibubi.create.foundation.render.backend.instancing.InstancedModel;
import com.simibubi.create.foundation.render.backend.instancing.impl.IFlatLight;
import com.simibubi.create.foundation.utility.ColorHelper; import com.simibubi.create.foundation.utility.ColorHelper;
import net.minecraft.client.renderer.Vector3f; import net.minecraft.client.renderer.Vector3f;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
public class KineticData<D extends KineticData<D>> extends InstanceData { public class KineticData<D extends KineticData<D>> extends InstanceData implements IFlatLight<D> {
private float x; private float x;
private float y; private float y;
private float z; private float z;
@ -65,11 +66,13 @@ public class KineticData<D extends KineticData<D>> extends InstanceData {
return (D) this; return (D) this;
} }
@Override
public D setBlockLight(int blockLight) { public D setBlockLight(int blockLight) {
this.blockLight = (byte) ((blockLight & 0xF) << 4); this.blockLight = (byte) ((blockLight & 0xF) << 4);
return (D) this; return (D) this;
} }
@Override
public D setSkyLight(int skyLight) { public D setSkyLight(int skyLight) {
this.skyLight = (byte) ((skyLight & 0xF) << 4); this.skyLight = (byte) ((skyLight & 0xF) << 4);
return (D) this; return (D) this;

View file

@ -36,12 +36,6 @@ public abstract class KineticTileInstance<T extends KineticTileEntity> extends T
return key; return key;
} }
protected final void relight(InstanceKey<? extends KineticData<?>> key) {
key.getInstance()
.setBlockLight(world.getLightLevel(LightType.BLOCK, pos))
.setSkyLight(world.getLightLevel(LightType.SKY, pos));
}
protected float getRotationOffset(final Direction.Axis axis) { protected float getRotationOffset(final Direction.Axis axis) {
float offset = CogWheelBlock.isLargeCog(lastState) ? 11.25f : 0; float offset = CogWheelBlock.isLargeCog(lastState) ? 11.25f : 0;
double d = (((axis == Direction.Axis.X) ? 0 : pos.getX()) + ((axis == Direction.Axis.Y) ? 0 : pos.getY()) double d = (((axis == Direction.Axis.X) ? 0 : pos.getX()) + ((axis == Direction.Axis.Y) ? 0 : pos.getY())

View file

@ -4,14 +4,10 @@ import static com.simibubi.create.content.contraptions.base.KineticTileEntityRen
import com.simibubi.create.foundation.render.backend.instancing.InstanceKey; import com.simibubi.create.foundation.render.backend.instancing.InstanceKey;
import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; import com.simibubi.create.foundation.render.backend.instancing.InstancedModel;
import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderRegistry;
import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.fml.DistExecutor;
public class SingleRotatingInstance extends KineticTileInstance<KineticTileEntity> { public class SingleRotatingInstance extends KineticTileInstance<KineticTileEntity> {
@ -35,7 +31,7 @@ public class SingleRotatingInstance extends KineticTileInstance<KineticTileEntit
@Override @Override
public void updateLight() { public void updateLight() {
relight(rotatingModelKey); relight(pos, rotatingModelKey.getInstance());
} }
@Override @Override

View file

@ -82,19 +82,10 @@ public class FanInstance extends KineticTileInstance<EncasedFanTileEntity> {
final Direction direction = lastState.get(FACING); final Direction direction = lastState.get(FACING);
BlockPos behind = pos.offset(direction.getOpposite()); BlockPos behind = pos.offset(direction.getOpposite());
putLight(shaft, behind); relight(behind, shaft.getInstance());
BlockPos inFront = pos.offset(direction); BlockPos inFront = pos.offset(direction);
putLight(fan, inFront); relight(inFront, fan.getInstance());
}
private void putLight(InstanceKey<RotatingData> key, BlockPos pos) {
int blockLight = world.getLightLevel(LightType.BLOCK, pos);
int skyLight = world.getLightLevel(LightType.SKY, pos);
key.getInstance()
.setBlockLight(blockLight)
.setSkyLight(skyLight);
} }
@Override @Override

View file

@ -150,20 +150,10 @@ public class FlyWheelInstance extends KineticTileInstance<FlywheelTileEntity> im
@Override @Override
public void updateLight() { public void updateLight() {
int block = world.getLightLevel(LightType.BLOCK, pos); relight(pos, shaft.getInstance(), wheel.getInstance());
int sky = world.getLightLevel(LightType.SKY, pos);
shaft.getInstance().setBlockLight(block).setSkyLight(sky);
wheel.getInstance().setBlockLight(block).setSkyLight(sky);
if (connection != null) { if (connection != null) {
BlockPos pos = this.pos.offset(connection); relight(this.pos.offset(connection), connectors.stream().map(InstanceKey::getInstance));
int connectionBlock = world.getLightLevel(LightType.BLOCK, pos);
int connectionSky = world.getLightLevel(LightType.SKY, pos);
connectors.stream()
.map(InstanceKey::getInstance)
.forEach(data -> data.setBlockLight(connectionBlock).setSkyLight(connectionSky));
} }
} }

View file

@ -66,9 +66,6 @@ public class EngineInstance extends TileEntityInstance<EngineTileEntity> {
@Override @Override
public void updateLight() { public void updateLight() {
int block = world.getLightLevel(LightType.BLOCK, pos); relight(pos, frame.getInstance());
int sky = world.getLightLevel(LightType.SKY, pos);
frame.getInstance().setBlockLight(block).setSkyLight(sky);
} }
} }

View file

@ -92,14 +92,9 @@ public class MixerInstance extends ShaftlessCogInstance implements ITickableInst
public void updateLight() { public void updateLight() {
super.updateLight(); super.updateLight();
BlockPos down = pos.down(); relight(pos.down(), mixerHead.getInstance());
mixerHead.getInstance()
.setBlockLight(world.getLightLevel(LightType.BLOCK, down))
.setSkyLight(world.getLightLevel(LightType.SKY, down));
mixerPole.getInstance() relight(pos, mixerPole.getInstance());
.setBlockLight(world.getLightLevel(LightType.BLOCK, pos))
.setSkyLight(world.getLightLevel(LightType.SKY, pos));
} }
@Override @Override

View file

@ -67,9 +67,7 @@ public class PressInstance extends ShaftInstance implements ITickableInstance {
public void updateLight() { public void updateLight() {
super.updateLight(); super.updateLight();
pressHead.getInstance() relight(pos, pressHead.getInstance());
.setBlockLight(world.getLightLevel(LightType.BLOCK, pos))
.setSkyLight(world.getLightLevel(LightType.SKY, pos));
} }
@Override @Override

View file

@ -63,9 +63,7 @@ public class StickerInstance extends TileEntityInstance<StickerTileEntity> imple
@Override @Override
public void updateLight() { public void updateLight() {
head.getInstance() relight(pos, head.getInstance());
.setBlockLight(world.getLightLevel(LightType.BLOCK, pos))
.setSkyLight(world.getLightLevel(LightType.SKY, pos));
} }
@Override @Override

View file

@ -81,9 +81,7 @@ public class GantryCarriageInstance extends ShaftInstance implements ITickableIn
@Override @Override
public void updateLight() { public void updateLight() {
gantryCogs.getInstance() relight(pos, gantryCogs.getInstance());
.setBlockLight(world.getLightLevel(LightType.BLOCK, pos))
.setSkyLight(world.getLightLevel(LightType.SKY, pos));
} }
@Override @Override

View file

@ -25,6 +25,8 @@ import net.minecraft.world.TickPriority;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraft.world.server.ServerWorld; import net.minecraft.world.server.ServerWorld;
import javax.annotation.Nonnull;
public class FluidValveBlock extends DirectionalAxisKineticBlock implements IAxisPipe { public class FluidValveBlock extends DirectionalAxisKineticBlock implements IAxisPipe {
public static final BooleanProperty ENABLED = BooleanProperty.create("enabled"); public static final BooleanProperty ENABLED = BooleanProperty.create("enabled");
@ -60,9 +62,10 @@ public class FluidValveBlock extends DirectionalAxisKineticBlock implements IAxi
return AllTileEntities.FLUID_VALVE.create(); return AllTileEntities.FLUID_VALVE.create();
} }
@Nonnull
public static Axis getPipeAxis(BlockState state) { public static Axis getPipeAxis(BlockState state) {
if (!(state.getBlock() instanceof FluidValveBlock)) if (!(state.getBlock() instanceof FluidValveBlock))
return null; throw new IllegalStateException("Provided BlockState is for a different block.");
Direction facing = state.get(FACING); Direction facing = state.get(FACING);
boolean alongFirst = !state.get(AXIS_ALONG_FIRST_COORDINATE); boolean alongFirst = !state.get(AXIS_ALONG_FIRST_COORDINATE);
for (Axis axis : Iterate.axes) { for (Axis axis : Iterate.axes) {
@ -74,7 +77,7 @@ public class FluidValveBlock extends DirectionalAxisKineticBlock implements IAxi
} }
return axis; return axis;
} }
return null; throw new IllegalStateException("Impossible axis.");
} }
@Override @Override

View file

@ -0,0 +1,91 @@
package com.simibubi.create.content.contraptions.fluids.pipes;
import com.mojang.blaze3d.matrix.MatrixStack;
import com.simibubi.create.AllBlockPartials;
import com.simibubi.create.content.contraptions.base.KineticTileEntity;
import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer;
import com.simibubi.create.content.contraptions.relays.encased.ShaftInstance;
import com.simibubi.create.foundation.render.SuperByteBuffer;
import com.simibubi.create.foundation.render.backend.RenderMaterials;
import com.simibubi.create.foundation.render.backend.instancing.ITickableInstance;
import com.simibubi.create.foundation.render.backend.instancing.InstanceKey;
import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer;
import com.simibubi.create.foundation.render.backend.instancing.impl.ModelData;
import com.simibubi.create.foundation.utility.AngleHelper;
import com.simibubi.create.foundation.utility.AnimationTickHolder;
import com.simibubi.create.foundation.utility.MatrixStacker;
import net.minecraft.block.BlockState;
import net.minecraft.util.Direction;
import net.minecraft.util.math.MathHelper;
public class FluidValveInstance extends ShaftInstance implements ITickableInstance {
protected InstanceKey<ModelData> pointer;
protected double xRot;
protected double yRot;
protected int pointerRotationOffset;
public FluidValveInstance(InstancedTileRenderer<?> dispatcher, KineticTileEntity tile) {
super(dispatcher, tile);
}
@Override
protected void init() {
super.init();
Direction facing = lastState.get(FluidValveBlock.FACING);
yRot = AngleHelper.horizontalAngle(facing);
xRot = facing == Direction.UP ? 0 : facing == Direction.DOWN ? 180 : 90;
Direction.Axis pipeAxis = FluidValveBlock.getPipeAxis(lastState);
Direction.Axis shaftAxis = KineticTileEntityRenderer.getRotationAxisOf(tile);
pointerRotationOffset = 0;
if (pipeAxis.isHorizontal() && shaftAxis == Direction.Axis.Z || pipeAxis.isVertical())
pointerRotationOffset = 90;
pointer = modelManager.basicMaterial().getModel(AllBlockPartials.FLUID_VALVE_POINTER, lastState).createInstance();
updateLight();
transformPointer((FluidValveTileEntity) tile);
}
@Override
public void tick() {
FluidValveTileEntity valve = (FluidValveTileEntity) tile;
if (valve.pointer.settled()) return;
transformPointer(valve);
}
private void transformPointer(FluidValveTileEntity valve) {
float pointerRotation = MathHelper.lerp(valve.pointer.getValue(AnimationTickHolder.getPartialTicks()), 0, -90);
MatrixStack ms = new MatrixStack();
MatrixStacker.of(ms)
.translate(getFloatingPos())
.centre()
.rotateY(yRot)
.rotateX(xRot)
.rotateY(pointerRotationOffset + pointerRotation)
.unCentre();
pointer.getInstance().setTransform(ms);
}
@Override
public void updateLight() {
super.updateLight();
relight(pos, pointer.getInstance());
}
@Override
public void remove() {
super.remove();
pointer.delete();
}
}

View file

@ -5,6 +5,7 @@ import com.simibubi.create.AllBlockPartials;
import com.simibubi.create.content.contraptions.base.KineticTileEntity; import com.simibubi.create.content.contraptions.base.KineticTileEntity;
import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer;
import com.simibubi.create.foundation.render.SuperByteBuffer; import com.simibubi.create.foundation.render.SuperByteBuffer;
import com.simibubi.create.foundation.render.backend.FastRenderDispatcher;
import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.AngleHelper;
import com.simibubi.create.foundation.utility.MatrixStacker; import com.simibubi.create.foundation.utility.MatrixStacker;
@ -25,6 +26,9 @@ public class FluidValveRenderer extends KineticTileEntityRenderer {
@Override @Override
protected void renderSafe(KineticTileEntity te, float partialTicks, MatrixStack ms, IRenderTypeBuffer buffer, protected void renderSafe(KineticTileEntity te, float partialTicks, MatrixStack ms, IRenderTypeBuffer buffer,
int light, int overlay) { int light, int overlay) {
if (FastRenderDispatcher.available(te.getWorld())) return;
super.renderSafe(te, partialTicks, ms, buffer, light, overlay); super.renderSafe(te, partialTicks, ms, buffer, light, overlay);
BlockState blockState = te.getBlockState(); BlockState blockState = te.getBlockState();
SuperByteBuffer pointer = AllBlockPartials.FLUID_VALVE_POINTER.renderOn(blockState); SuperByteBuffer pointer = AllBlockPartials.FLUID_VALVE_POINTER.renderOn(blockState);

View file

@ -1,29 +1,24 @@
package com.simibubi.create.content.contraptions.relays.belt; package com.simibubi.create.content.contraptions.relays.belt;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.function.Consumer;
import java.util.function.Supplier; import java.util.function.Supplier;
import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.matrix.MatrixStack;
import com.simibubi.create.AllBlockPartials; import com.simibubi.create.AllBlockPartials;
import com.simibubi.create.AllBlocks; import com.simibubi.create.AllBlocks;
import com.simibubi.create.content.contraptions.base.KineticData;
import com.simibubi.create.content.contraptions.base.KineticTileInstance; import com.simibubi.create.content.contraptions.base.KineticTileInstance;
import com.simibubi.create.content.contraptions.base.RotatingData; import com.simibubi.create.content.contraptions.base.RotatingData;
import com.simibubi.create.foundation.block.render.SpriteShiftEntry; import com.simibubi.create.foundation.block.render.SpriteShiftEntry;
import com.simibubi.create.foundation.render.backend.instancing.InstanceKey; import com.simibubi.create.foundation.render.backend.instancing.InstanceKey;
import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; import com.simibubi.create.foundation.render.backend.instancing.InstancedModel;
import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderRegistry;
import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer;
import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.Iterate;
import com.simibubi.create.foundation.utility.MatrixStacker; import com.simibubi.create.foundation.utility.MatrixStacker;
import net.minecraft.item.DyeColor; import net.minecraft.item.DyeColor;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.LightType; import net.minecraft.world.LightType;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.fml.DistExecutor;
public class BeltInstance extends KineticTileInstance<BeltTileEntity> { public class BeltInstance extends KineticTileInstance<BeltTileEntity> {
@ -103,9 +98,9 @@ public class BeltInstance extends KineticTileInstance<BeltTileEntity> {
@Override @Override
public void updateLight() { public void updateLight() {
keys.forEach(this::relight); relight(pos, keys.stream().map(InstanceKey::getInstance));
if (pulleyKey != null) relight(pulleyKey); if (pulleyKey != null) relight(pos, pulleyKey.getInstance());
} }
@Override @Override

View file

@ -4,19 +4,16 @@ import java.util.ArrayList;
import com.simibubi.create.AllBlockPartials; import com.simibubi.create.AllBlockPartials;
import com.simibubi.create.content.contraptions.base.IRotate; import com.simibubi.create.content.contraptions.base.IRotate;
import com.simibubi.create.content.contraptions.base.KineticData;
import com.simibubi.create.content.contraptions.base.KineticTileInstance; import com.simibubi.create.content.contraptions.base.KineticTileInstance;
import com.simibubi.create.content.contraptions.base.RotatingData; import com.simibubi.create.content.contraptions.base.RotatingData;
import com.simibubi.create.foundation.render.backend.instancing.InstanceKey; import com.simibubi.create.foundation.render.backend.instancing.InstanceKey;
import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; import com.simibubi.create.foundation.render.backend.instancing.InstancedModel;
import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderRegistry;
import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer;
import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.Iterate;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.fml.DistExecutor;
public class SplitShaftInstance extends KineticTileInstance<SplitShaftTileEntity> { public class SplitShaftInstance extends KineticTileInstance<SplitShaftTileEntity> {
@ -59,7 +56,7 @@ public class SplitShaftInstance extends KineticTileInstance<SplitShaftTileEntity
@Override @Override
public void updateLight() { public void updateLight() {
keys.forEach(this::relight); keys.forEach(key -> relight(pos, ((InstanceKey<? extends KineticData<?>>) key).getInstance()));
} }
@Override @Override

View file

@ -0,0 +1,173 @@
package com.simibubi.create.content.contraptions.relays.gauge;
import com.mojang.blaze3d.matrix.MatrixStack;
import com.simibubi.create.AllBlockPartials;
import com.simibubi.create.content.contraptions.base.KineticTileEntity;
import com.simibubi.create.content.contraptions.relays.encased.ShaftInstance;
import com.simibubi.create.foundation.render.backend.RenderMaterials;
import com.simibubi.create.foundation.render.backend.instancing.ITickableInstance;
import com.simibubi.create.foundation.render.backend.instancing.InstanceKey;
import com.simibubi.create.foundation.render.backend.instancing.InstancedModel;
import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer;
import com.simibubi.create.foundation.render.backend.instancing.impl.ModelData;
import com.simibubi.create.foundation.utility.*;
import net.minecraft.util.Direction;
import net.minecraft.util.math.MathHelper;
import java.util.ArrayList;
public abstract class GaugeInstance extends ShaftInstance implements ITickableInstance {
protected ArrayList<DialFace> faces;
protected MatrixStack ms;
protected GaugeInstance(InstancedTileRenderer<?> dispatcher, KineticTileEntity tile) {
super(dispatcher, tile);
}
@Override
protected void init() {
super.init();
faces = new ArrayList<>(2);
GaugeTileEntity gaugeTile = (GaugeTileEntity) tile;
GaugeBlock gaugeBlock = (GaugeBlock) lastState.getBlock();
InstancedModel<ModelData> dialModel = modelManager.getMaterial(RenderMaterials.MODELS).getModel(AllBlockPartials.GAUGE_DIAL, lastState);
InstancedModel<ModelData> headModel = getHeadModel();
ms = new MatrixStack();
MatrixStacker msr = MatrixStacker.of(ms);
msr.translate(getFloatingPos());
float progress = MathHelper.lerp(AnimationTickHolder.getPartialTicks(), gaugeTile.prevDialState, gaugeTile.dialState);
for (Direction facing : Iterate.directions) {
if (!gaugeBlock.shouldRenderHeadOnFace(world, pos, lastState, facing))
continue;
DialFace face = makeFace(facing, dialModel, headModel);
faces.add(face);
face.setupTransform(msr, progress);
}
updateLight();
}
private DialFace makeFace(Direction face, InstancedModel<ModelData> dialModel, InstancedModel<ModelData> headModel) {
return new DialFace(face, dialModel.createInstance(), headModel.createInstance());
}
@Override
public void tick() {
GaugeTileEntity gaugeTile = (GaugeTileEntity) tile;
if (MathHelper.epsilonEquals(gaugeTile.prevDialState, gaugeTile.dialState))
return;
float progress = MathHelper.lerp(AnimationTickHolder.getPartialTicks(), gaugeTile.prevDialState, gaugeTile.dialState);
MatrixStacker msr = MatrixStacker.of(ms);
for (DialFace faceEntry : faces) {
faceEntry.updateTransform(msr, progress);
}
}
@Override
public void updateLight() {
super.updateLight();
relight(pos, faces.stream()
.flatMap(Couple::stream)
.map(InstanceKey::getInstance));
}
@Override
public void remove() {
super.remove();
faces.forEach(DialFace::delete);
}
protected abstract InstancedModel<ModelData> getHeadModel();
private class DialFace extends Couple<InstanceKey<ModelData>> {
Direction face;
public DialFace(Direction face, InstanceKey<ModelData> first, InstanceKey<ModelData> second) {
super(first, second);
this.face = face;
}
private void setupTransform(MatrixStacker msr, float progress) {
float dialPivot = 5.75f / 16;
ms.push();
rotateToFace(msr);
getSecond().getInstance().setTransform(ms);
msr.translate(0, dialPivot, dialPivot)
.rotate(Direction.EAST, (float) (Math.PI / 2 * -progress))
.translate(0, -dialPivot, -dialPivot);
getFirst().getInstance().setTransform(ms);
ms.pop();
}
private void updateTransform(MatrixStacker msr, float progress) {
float dialPivot = 5.75f / 16;
ms.push();
rotateToFace(msr)
.translate(0, dialPivot, dialPivot)
.rotate(Direction.EAST, (float) (Math.PI / 2 * -progress))
.translate(0, -dialPivot, -dialPivot);
getFirst().getInstance().setTransform(ms);
ms.pop();
}
protected MatrixStacker rotateToFace(MatrixStacker msr) {
return msr.centre()
.rotate(Direction.UP, (float) ((-face.getHorizontalAngle() - 90) / 180 * Math.PI))
.unCentre();
}
private void delete() {
getFirst().delete();
getSecond().delete();
}
}
public static class Speed extends GaugeInstance {
public Speed(InstancedTileRenderer<?> dispatcher, KineticTileEntity tile) {
super(dispatcher, tile);
}
@Override
protected InstancedModel<ModelData> getHeadModel() {
return modelManager.getMaterial(RenderMaterials.MODELS).getModel(AllBlockPartials.GAUGE_HEAD_SPEED, lastState);
}
}
public static class Stress extends GaugeInstance {
public Stress(InstancedTileRenderer<?> dispatcher, KineticTileEntity tile) {
super(dispatcher, tile);
}
@Override
protected InstancedModel<ModelData> getHeadModel() {
return modelManager.getMaterial(RenderMaterials.MODELS).getModel(AllBlockPartials.GAUGE_HEAD_STRESS, lastState);
}
}
}

View file

@ -7,6 +7,7 @@ import com.simibubi.create.content.contraptions.base.KineticTileEntity;
import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer;
import com.simibubi.create.content.contraptions.relays.gauge.GaugeBlock.Type; import com.simibubi.create.content.contraptions.relays.gauge.GaugeBlock.Type;
import com.simibubi.create.foundation.render.SuperByteBuffer; import com.simibubi.create.foundation.render.SuperByteBuffer;
import com.simibubi.create.foundation.render.backend.FastRenderDispatcher;
import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.Iterate;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
@ -37,6 +38,8 @@ public class GaugeRenderer extends KineticTileEntityRenderer {
@Override @Override
protected void renderSafe(KineticTileEntity te, float partialTicks, MatrixStack ms, IRenderTypeBuffer buffer, protected void renderSafe(KineticTileEntity te, float partialTicks, MatrixStack ms, IRenderTypeBuffer buffer,
int light, int overlay) { int light, int overlay) {
if (FastRenderDispatcher.available(te.getWorld())) return;
super.renderSafe(te, partialTicks, ms, buffer, light, overlay); super.renderSafe(te, partialTicks, ms, buffer, light, overlay);
BlockState gaugeState = te.getBlockState(); BlockState gaugeState = te.getBlockState();
GaugeTileEntity gaugeTE = (GaugeTileEntity) te; GaugeTileEntity gaugeTE = (GaugeTileEntity) te;
@ -47,14 +50,14 @@ public class GaugeRenderer extends KineticTileEntityRenderer {
.renderOn(gaugeState); .renderOn(gaugeState);
SuperByteBuffer dialBuffer = AllBlockPartials.GAUGE_DIAL.renderOn(gaugeState); SuperByteBuffer dialBuffer = AllBlockPartials.GAUGE_DIAL.renderOn(gaugeState);
float dialPivot = 5.75f / 16;
float progress = MathHelper.lerp(partialTicks, gaugeTE.prevDialState, gaugeTE.dialState);
for (Direction facing : Iterate.directions) { for (Direction facing : Iterate.directions) {
if (!((GaugeBlock) gaugeState.getBlock()).shouldRenderHeadOnFace(te.getWorld(), te.getPos(), gaugeState, if (!((GaugeBlock) gaugeState.getBlock()).shouldRenderHeadOnFace(te.getWorld(), te.getPos(), gaugeState,
facing)) facing))
continue; continue;
float dialPivot = 5.75f / 16;
float progress = MathHelper.lerp(partialTicks, gaugeTE.prevDialState, gaugeTE.dialState);
IVertexBuilder vb = buffer.getBuffer(RenderType.getSolid()); IVertexBuilder vb = buffer.getBuffer(RenderType.getSolid());
rotateBufferTowards(dialBuffer, facing).translate(0, dialPivot, dialPivot) rotateBufferTowards(dialBuffer, facing).translate(0, dialPivot, dialPivot)
.rotate(Direction.EAST, (float) (Math.PI / 2 * -progress)) .rotate(Direction.EAST, (float) (Math.PI / 2 * -progress))

View file

@ -99,14 +99,7 @@ public class GearboxInstance extends KineticTileInstance<GearboxTileEntity> {
@Override @Override
public void updateLight() { public void updateLight() {
int blockLight = tile.getWorld().getLightLevel(LightType.BLOCK, pos); relight(pos, keys.values().stream().map(InstanceKey::getInstance));
int skyLight = tile.getWorld().getLightLevel(LightType.SKY, pos);
for (InstanceKey<RotatingData> key : keys.values()) {
key.getInstance()
.setBlockLight(blockLight)
.setSkyLight(skyLight);
}
} }
@Override @Override

View file

@ -73,7 +73,7 @@ public class ArmInstance extends SingleRotatingInstance implements ITickableInst
public void tick() { public void tick() {
ArmTileEntity arm = (ArmTileEntity) tile; ArmTileEntity arm = (ArmTileEntity) tile;
boolean settled = Stream.of(arm.baseAngle, arm.lowerArmAngle, arm.upperArmAngle, arm.headAngle).allMatch(InterpolatedValue::settled); boolean settled = arm.baseAngle.settled() && arm.lowerArmAngle.settled() && arm.upperArmAngle.settled() && arm.headAngle.settled();
boolean rave = arm.phase == ArmTileEntity.Phase.DANCING; boolean rave = arm.phase == ArmTileEntity.Phase.DANCING;
if (!settled || rave || firstTick) if (!settled || rave || firstTick)
@ -154,13 +154,8 @@ public class ArmInstance extends SingleRotatingInstance implements ITickableInst
@Override @Override
public void updateLight() { public void updateLight() {
super.updateLight(); super.updateLight();
int block = world.getLightLevel(LightType.BLOCK, pos);
int sky = world.getLightLevel(LightType.SKY, pos);
relight(pos, models.stream().map(InstanceKey::getInstance));
models.stream()
.map(InstanceKey::getInstance)
.forEach(data -> data.setSkyLight(sky).setBlockLight(block));
} }
@Override @Override

View file

@ -81,15 +81,6 @@ public class SchematicannonInstance extends TileEntityInstance<SchematicannonTil
@Override @Override
public void updateLight() { public void updateLight() {
int block = world.getLightLevel(LightType.BLOCK, pos); relight(pos, connector.getInstance(), pipe.getInstance());
int sky = world.getLightLevel(LightType.SKY, pos);
connector.getInstance()
.setBlockLight(block)
.setSkyLight(sky);
pipe.getInstance()
.setBlockLight(block)
.setSkyLight(sky);
} }
} }

View file

@ -34,6 +34,8 @@ public abstract class InstancedModel<D extends InstanceData> extends BufferedMod
protected int minIndexChanged = -1; protected int minIndexChanged = -1;
protected int maxIndexChanged = -1; protected int maxIndexChanged = -1;
protected boolean anyToRemove;
public InstancedModel(InstancedTileRenderer<?> renderer, BufferBuilder buf) { public InstancedModel(InstancedTileRenderer<?> renderer, BufferBuilder buf) {
super(buf); super(buf);
this.renderer = renderer; this.renderer = renderer;
@ -73,6 +75,8 @@ public abstract class InstancedModel<D extends InstanceData> extends BufferedMod
verifyKey(key); verifyKey(key);
key.invalidate(); key.invalidate();
anyToRemove = true;
} }
public D getInstance(InstanceKey<D> key) { public D getInstance(InstanceKey<D> key) {
@ -161,6 +165,8 @@ public abstract class InstancedModel<D extends InstanceData> extends BufferedMod
// copied from ArrayList#removeIf // copied from ArrayList#removeIf
protected boolean doRemoval() { protected boolean doRemoval() {
if (!anyToRemove) return false;
// figure out which elements are to be removed // figure out which elements are to be removed
// any exception thrown from the filter predicate at this stage // any exception thrown from the filter predicate at this stage
// will leave the collection unmodified // will leave the collection unmodified
@ -198,6 +204,8 @@ public abstract class InstancedModel<D extends InstanceData> extends BufferedMod
maxIndexChanged = newSize - 1; maxIndexChanged = newSize - 1;
} }
this.anyToRemove = false;
return anyToRemove; return anyToRemove;
} }

View file

@ -6,8 +6,10 @@ import javax.annotation.Nullable;
import com.simibubi.create.foundation.ponder.PonderWorld; import com.simibubi.create.foundation.ponder.PonderWorld;
import com.simibubi.create.foundation.render.backend.Backend; import com.simibubi.create.foundation.render.backend.Backend;
import com.simibubi.create.foundation.render.backend.RenderMaterials;
import com.simibubi.create.foundation.render.backend.gl.BasicProgram; 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.gl.shader.ShaderCallback;
import com.simibubi.create.foundation.render.backend.instancing.impl.ModelData;
import com.simibubi.create.foundation.utility.AnimationTickHolder; import com.simibubi.create.foundation.utility.AnimationTickHolder;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
@ -67,6 +69,10 @@ public abstract class InstancedTileRenderer<P extends BasicProgram> {
return (RenderMaterial<P, M>) materials.get(materialType); return (RenderMaterial<P, M>) materials.get(materialType);
} }
public RenderMaterial<P, InstancedModel<ModelData>> basicMaterial() {
return getMaterial(RenderMaterials.MODELS);
}
@Nullable @Nullable
public <T extends TileEntity> TileEntityInstance<? super T> getInstance(T tile) { public <T extends TileEntity> TileEntityInstance<? super T> getInstance(T tile) {
return getInstance(tile, true); return getInstance(tile, true);

View file

@ -1,5 +1,6 @@
package com.simibubi.create.foundation.render.backend.instancing; package com.simibubi.create.foundation.render.backend.instancing;
import com.simibubi.create.foundation.render.backend.instancing.impl.IFlatLight;
import com.simibubi.create.foundation.render.backend.instancing.impl.ModelData; import com.simibubi.create.foundation.render.backend.instancing.impl.ModelData;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntity;
@ -7,6 +8,9 @@ import net.minecraft.util.math.BlockPos;
import net.minecraft.world.LightType; import net.minecraft.world.LightType;
import net.minecraft.world.World; import net.minecraft.world.World;
import java.util.Arrays;
import java.util.stream.Stream;
public abstract class TileEntityInstance<T extends TileEntity> { public abstract class TileEntityInstance<T extends TileEntity> {
protected final InstancedTileRenderer<?> modelManager; protected final InstancedTileRenderer<?> modelManager;
@ -60,13 +64,19 @@ public abstract class TileEntityInstance<T extends TileEntity> {
return pos.subtract(modelManager.getOriginCoordinate()); return pos.subtract(modelManager.getOriginCoordinate());
} }
protected void relight(BlockPos pos, ModelData... models) { protected <L extends IFlatLight<?>> void relight(BlockPos pos, IFlatLight<?>... models) {
relight(world.getLightLevel(LightType.BLOCK, pos), world.getLightLevel(LightType.SKY, pos), models); relight(world.getLightLevel(LightType.BLOCK, pos), world.getLightLevel(LightType.SKY, pos), models);
} }
protected void relight(int block, int sky, ModelData... models) { protected <L extends IFlatLight<?>> void relight(BlockPos pos, Stream<IFlatLight<?>> models) {
for (ModelData model : models) { relight(world.getLightLevel(LightType.BLOCK, pos), world.getLightLevel(LightType.SKY, pos), models);
model.setBlockLight(block).setSkyLight(sky);
} }
protected <L extends IFlatLight<?>> void relight(int block, int sky, IFlatLight<?>... models) {
relight(block, sky, Arrays.stream(models));
}
protected <L extends IFlatLight<?>> void relight(int block, int sky, Stream<IFlatLight<?>> models) {
models.forEach(model -> model.setBlockLight(block).setSkyLight(sky));
} }
} }

View file

@ -0,0 +1,26 @@
package com.simibubi.create.foundation.render.backend.instancing.impl;
import com.simibubi.create.foundation.render.backend.instancing.InstanceData;
/**
* An interface that implementors of {@link InstanceData} should also implement
* if they wish to make use of Flywheel's provided light update methods.
*
* This only covers flat lighting, smooth lighting is still TODO.
* @param <D> The name of the class that implements this interface.
*/
public interface IFlatLight<D extends InstanceData & IFlatLight<D>> {
/**
* @param blockLight An integer in the range [0, 15] representing the
* amount of block light this instance should receive.
* @return <code>this</code>
*/
D setBlockLight(int blockLight);
/**
* @param skyLight An integer in the range [0, 15] representing the
* amount of sky light this instance should receive.
* @return <code>this</code>
*/
D setSkyLight(int skyLight);
}

View file

@ -9,7 +9,7 @@ import net.minecraft.client.renderer.Matrix4f;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
public class ModelData extends InstanceData { public class ModelData extends InstanceData implements IFlatLight<ModelData> {
private static final Matrix4f IDENT4 = new Matrix4f(); private static final Matrix4f IDENT4 = new Matrix4f();
private static final Matrix3f IDENT3 = new Matrix3f(); private static final Matrix3f IDENT3 = new Matrix3f();
static { static {
@ -54,11 +54,13 @@ public class ModelData extends InstanceData {
return this; return this;
} }
@Override
public ModelData setBlockLight(int blockLight) { public ModelData setBlockLight(int blockLight) {
this.blockLight = (byte) (blockLight << 4); this.blockLight = (byte) (blockLight << 4);
return this; return this;
} }
@Override
public ModelData setSkyLight(int skyLight) { public ModelData setSkyLight(int skyLight) {
this.skyLight = (byte) (skyLight << 4); this.skyLight = (byte) (skyLight << 4);
return this; return this;

View file

@ -6,6 +6,7 @@ import java.util.function.BiConsumer;
import java.util.function.BiFunction; import java.util.function.BiFunction;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Stream;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
@ -104,6 +105,10 @@ public class Couple<T> extends Pair<T, T> implements Iterable<T> {
return new Couplerator<>(this); return new Couplerator<>(this);
} }
public Stream<T> stream() {
return Stream.of(first, second);
}
private static class Couplerator<T> implements Iterator<T> { private static class Couplerator<T> implements Iterator<T> {
int state; int state;

View file

@ -24,6 +24,15 @@ public class MatrixStacker {
return instance; return instance;
} }
public MatrixStacker restoreIdentity() {
MatrixStack.Entry entry = ms.peek();
entry.getModel().loadIdentity();
entry.getNormal().loadIdentity();
return this;
}
public MatrixStacker rotate(Direction axis, float radians) { public MatrixStacker rotate(Direction axis, float radians) {
if (radians == 0) if (radians == 0)
return this; return this;

View file

@ -81,6 +81,10 @@ public class LerpedFloat {
return MathHelper.lerp(partialTicks, previousValue, value); return MathHelper.lerp(partialTicks, previousValue, value);
} }
public boolean settled() {
return MathHelper.epsilonEquals(previousValue, value);
}
public float getChaseTarget() { public float getChaseTarget() {
return chaseTarget; return chaseTarget;
} }