a bunch of refactoring to make things easier later

it's not any more stable but belts render on contraptions
rotating things almost do
actually fix a bunch of memory leaks
This commit is contained in:
JozsefA 2021-01-11 00:29:02 -08:00
parent 092a92f095
commit a56d08b78e
43 changed files with 916 additions and 396 deletions

View file

@ -9,12 +9,13 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.matrix.MatrixStack;
import com.simibubi.create.content.contraptions.base.KineticTileEntity;
import com.simibubi.create.content.contraptions.fluids.FluidTransportBehaviour.AttachmentTypes; import com.simibubi.create.content.contraptions.fluids.FluidTransportBehaviour.AttachmentTypes;
import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlock.HeatLevel; import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlock.HeatLevel;
import com.simibubi.create.content.contraptions.relays.belt.BeltTileEntity;
import com.simibubi.create.foundation.utility.*; import com.simibubi.create.foundation.utility.*;
import com.simibubi.create.foundation.utility.render.instancing.BeltBuffer; import com.simibubi.create.foundation.utility.render.instancing.*;
import com.simibubi.create.foundation.utility.render.instancing.RotatingBuffer;
import com.simibubi.create.foundation.utility.render.SuperByteBuffer; import com.simibubi.create.foundation.utility.render.SuperByteBuffer;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.client.renderer.model.IBakedModel; import net.minecraft.client.renderer.model.IBakedModel;
@ -217,19 +218,20 @@ public class AllBlockPartials {
return CreateClient.bufferCache.renderDirectionalPartial(this, referenceState, facing, ms); return CreateClient.bufferCache.renderDirectionalPartial(this, referenceState, facing, ms);
} }
public RotatingBuffer renderOnRotating(BlockState referenceState) { public <T extends KineticTileEntity> InstanceBuffer<RotatingData> renderOnRotating(InstanceContext<T> ctx, BlockState referenceState) {
return CreateClient.kineticRenderer.renderPartialRotating(this, referenceState); return ctx.getKinetics().renderPartialRotating(this, referenceState);
} }
public BeltBuffer renderOnBelt(BlockState referenceState) { public <T extends BeltTileEntity> InstanceBuffer<BeltData> renderOnBelt(InstanceContext<T> ctx, BlockState referenceState) {
return CreateClient.kineticRenderer.renderPartialBelt(this, referenceState); return ctx.getKinetics().renderPartialBelt(this, referenceState);
} }
public RotatingBuffer renderOnDirectionalSouthRotating(BlockState referenceState) { public <T extends KineticTileEntity> InstanceBuffer<RotatingData> renderOnDirectionalSouthRotating(InstanceContext<T> ctx, BlockState referenceState) {
Direction facing = referenceState.get(FACING); Direction facing = referenceState.get(FACING);
return renderOnDirectionalSouthRotating(referenceState, facing); return renderOnDirectionalSouthRotating(ctx, referenceState, facing);
} }
public RotatingBuffer renderOnDirectionalSouthRotating(BlockState referenceState, Direction facing) {
public <T extends KineticTileEntity> InstanceBuffer<RotatingData> renderOnDirectionalSouthRotating(InstanceContext<T> ctx, BlockState referenceState, Direction facing) {
MatrixStack ms = new MatrixStack(); MatrixStack ms = new MatrixStack();
// TODO 1.15 find a way to cache this model matrix computation // TODO 1.15 find a way to cache this model matrix computation
MatrixStacker.of(ms) MatrixStacker.of(ms)
@ -237,7 +239,7 @@ public class AllBlockPartials {
.rotateY(AngleHelper.horizontalAngle(facing)) .rotateY(AngleHelper.horizontalAngle(facing))
.rotateX(AngleHelper.verticalAngle(facing)) .rotateX(AngleHelper.verticalAngle(facing))
.unCentre(); .unCentre();
return CreateClient.kineticRenderer.renderDirectionalPartialInstanced(this, referenceState, facing, ms); return ctx.getKinetics().renderDirectionalPartialInstanced(this, referenceState, facing, ms);
} }
} }

View file

@ -16,6 +16,7 @@ import com.simibubi.create.foundation.block.render.CustomBlockModels;
import com.simibubi.create.foundation.block.render.SpriteShifter; import com.simibubi.create.foundation.block.render.SpriteShifter;
import com.simibubi.create.foundation.item.CustomItemModels; import com.simibubi.create.foundation.item.CustomItemModels;
import com.simibubi.create.foundation.item.CustomRenderedItems; import com.simibubi.create.foundation.item.CustomRenderedItems;
import com.simibubi.create.foundation.utility.render.FastContraptionRenderer;
import com.simibubi.create.foundation.utility.render.FastKineticRenderer; import com.simibubi.create.foundation.utility.render.FastKineticRenderer;
import com.simibubi.create.foundation.utility.render.SuperByteBufferCache; import com.simibubi.create.foundation.utility.render.SuperByteBufferCache;
import com.simibubi.create.foundation.utility.outliner.Outliner; import com.simibubi.create.foundation.utility.outliner.Outliner;
@ -73,8 +74,6 @@ public class CreateClient {
bufferCache.registerCompartment(ContraptionRenderer.CONTRAPTION, 20); bufferCache.registerCompartment(ContraptionRenderer.CONTRAPTION, 20);
kineticRenderer = new FastKineticRenderer(); kineticRenderer = new FastKineticRenderer();
kineticRenderer.registerCompartment(KineticTileEntityRenderer.KINETIC_TILE);
kineticRenderer.registerCompartment(ContraptionRenderer.CONTRAPTION, 20);
AllKeys.register(); AllKeys.register();
AllContainerTypes.registerScreenFactories(); AllContainerTypes.registerScreenFactories();
@ -180,4 +179,9 @@ public class CreateClient {
return casingConnectivity; return casingConnectivity;
} }
public static void invalidateRenderers() {
CreateClient.bufferCache.invalidate();
CreateClient.kineticRenderer.invalidate();
FastContraptionRenderer.invalidateAll();
}
} }

View file

@ -457,8 +457,14 @@ public abstract class KineticTileEntity extends SmartTileEntity
} }
public static AxisAlignedBB NOWHERE_AABB = new AxisAlignedBB(Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN); public static AxisAlignedBB NOWHERE_AABB = new AxisAlignedBB(Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN);
@Override @Override
public AxisAlignedBB getRenderBoundingBox() { public AxisAlignedBB getRenderBoundingBox() {
return super.getRenderBoundingBox(); return super.getRenderBoundingBox();
} }
@Override
public double getMaxRenderDistanceSquared() {
return 16384.0D; // TODO: make this a config option
}
} }

View file

@ -2,21 +2,17 @@ package com.simibubi.create.content.contraptions.base;
import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.matrix.MatrixStack;
import com.simibubi.create.AllBlocks; import com.simibubi.create.AllBlocks;
import com.simibubi.create.CreateClient;
import com.simibubi.create.content.contraptions.KineticDebugger; import com.simibubi.create.content.contraptions.KineticDebugger;
import com.simibubi.create.content.contraptions.relays.elementary.CogWheelBlock; import com.simibubi.create.content.contraptions.relays.elementary.CogWheelBlock;
import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer; import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer;
import com.simibubi.create.foundation.utility.AnimationTickHolder; import com.simibubi.create.foundation.utility.AnimationTickHolder;
import com.simibubi.create.foundation.utility.ColorHelper; import com.simibubi.create.foundation.utility.ColorHelper;
import com.simibubi.create.foundation.utility.render.instancing.IInstancedTileEntityRenderer; import com.simibubi.create.foundation.utility.render.instancing.*;
import com.simibubi.create.foundation.utility.render.instancing.RotatingBuffer;
import com.simibubi.create.foundation.utility.render.SuperByteBuffer; import com.simibubi.create.foundation.utility.render.SuperByteBuffer;
import com.simibubi.create.foundation.utility.render.SuperByteBufferCache.Compartment; import com.simibubi.create.foundation.utility.render.SuperByteBufferCache.Compartment;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.IRenderTypeBuffer;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.RenderTypeLookup;
import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher;
import net.minecraft.state.properties.BlockStateProperties; import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
@ -48,32 +44,36 @@ public class KineticTileEntityRenderer extends SafeTileEntityRenderer<KineticTil
// for (RenderType type : RenderType.getBlockLayers()) // for (RenderType type : RenderType.getBlockLayers())
// if (RenderTypeLookup.canRenderInLayer(te.getBlockState(), type)) // if (RenderTypeLookup.canRenderInLayer(te.getBlockState(), type))
// renderRotatingBuffer(te, getRotatedModel(te)); // renderRotatingBuffer(te, getRotatedModel(te));
addInstanceData(te);
addInstanceData(new InstanceContext.World<>(te));
} }
@Override @Override
public void addInstanceData(KineticTileEntity te) { public void addInstanceData(InstanceContext<KineticTileEntity> ctx) {
renderRotatingBuffer(te, getRotatedModel(te)); renderRotatingBuffer(ctx, getRotatedModel(ctx));
} }
public static void renderRotatingKineticBlock(KineticTileEntity te, BlockState renderedState) { public static <T extends KineticTileEntity> void renderRotatingKineticBlock(InstanceContext<T> ctx, BlockState renderedState) {
RotatingBuffer instancedRenderer = CreateClient.kineticRenderer.renderBlockInstanced(KINETIC_TILE, renderedState); InstanceBuffer<RotatingData> instancedRenderer = ctx.getKinetics().renderBlockInstanced(KINETIC_TILE, renderedState);
renderRotatingBuffer(te, instancedRenderer); renderRotatingBuffer(ctx, instancedRenderer);
} }
public static void renderRotatingBuffer(KineticTileEntity te, RotatingBuffer instancer) { public static <T extends KineticTileEntity> void renderRotatingBuffer(InstanceContext<T> ctx, InstanceBuffer<RotatingData> instancer) {
instancer.setupInstance(data -> { instancer.setupInstance(data -> {
T te = ctx.te;
final BlockPos pos = te.getPos(); final BlockPos pos = te.getPos();
Axis axis = ((IRotate) te.getBlockState() Axis axis = ((IRotate) te.getBlockState()
.getBlock()).getRotationAxis(te.getBlockState()); .getBlock()).getRotationAxis(te.getBlockState());
data data.setRotationalSpeed(te.getSpeed())
.setBlockLight(te.getWorld().getLightLevel(LightType.BLOCK, te.getPos()))
.setSkyLight(te.getWorld().getLightLevel(LightType.SKY, te.getPos()))
.setRotationalSpeed(te.getSpeed())
.setRotationOffset(getRotationOffsetForPosition(te, pos, axis)) .setRotationOffset(getRotationOffsetForPosition(te, pos, axis))
.setRotationAxis(Direction.getFacingFromAxis(AxisDirection.POSITIVE, axis).getUnitVector()) .setRotationAxis(Direction.getFacingFromAxis(AxisDirection.POSITIVE, axis).getUnitVector())
.setPosition(pos); .setPosition(pos);
if (ctx.checkWorldLight()) {
data.setBlockLight(te.getWorld().getLightLevel(LightType.BLOCK, te.getPos()))
.setSkyLight(te.getWorld().getLightLevel(LightType.SKY, te.getPos()));
}
}); });
} }
@ -139,8 +139,8 @@ public class KineticTileEntityRenderer extends SafeTileEntityRenderer<KineticTil
return te.getBlockState(); return te.getBlockState();
} }
protected RotatingBuffer getRotatedModel(KineticTileEntity te) { protected InstanceBuffer<RotatingData> getRotatedModel(InstanceContext<? extends KineticTileEntity> ctx) {
return CreateClient.kineticRenderer.renderBlockInstanced(KINETIC_TILE, getRenderedBlockState(te)); return ctx.getKinetics().renderBlockInstanced(KINETIC_TILE, getRenderedBlockState(ctx.te));
} }
} }

View file

@ -10,7 +10,8 @@ import com.simibubi.create.content.contraptions.components.structureMovement.Mov
import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.AngleHelper;
import com.simibubi.create.foundation.utility.AnimationTickHolder; import com.simibubi.create.foundation.utility.AnimationTickHolder;
import com.simibubi.create.foundation.utility.MatrixStacker; import com.simibubi.create.foundation.utility.MatrixStacker;
import com.simibubi.create.foundation.utility.render.instancing.RotatingBuffer; import com.simibubi.create.foundation.utility.render.instancing.InstanceBuffer;
import com.simibubi.create.foundation.utility.render.instancing.InstanceContext;
import com.simibubi.create.foundation.utility.render.SuperByteBuffer; import com.simibubi.create.foundation.utility.render.SuperByteBuffer;
import com.simibubi.create.foundation.utility.VecHelper; import com.simibubi.create.foundation.utility.VecHelper;
@ -28,8 +29,8 @@ public class DrillRenderer extends KineticTileEntityRenderer {
} }
@Override @Override
protected RotatingBuffer getRotatedModel(KineticTileEntity te) { protected InstanceBuffer<RotatingData> getRotatedModel(InstanceContext<? extends KineticTileEntity> ctx) {
return AllBlockPartials.DRILL_HEAD.renderOnDirectionalSouthRotating(te.getBlockState()); return AllBlockPartials.DRILL_HEAD.renderOnDirectionalSouthRotating(ctx, ctx.te.getBlockState());
} }
protected static SuperByteBuffer getRotatingModel(BlockState state) { protected static SuperByteBuffer getRotatingModel(BlockState state) {

View file

@ -8,7 +8,7 @@ import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer;
import com.simibubi.create.content.contraptions.components.clock.CuckooClockTileEntity.Animation; import com.simibubi.create.content.contraptions.components.clock.CuckooClockTileEntity.Animation;
import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.AngleHelper;
import com.simibubi.create.foundation.utility.render.instancing.InstanceBuffer; import com.simibubi.create.foundation.utility.render.instancing.InstanceBuffer;
import com.simibubi.create.foundation.utility.render.instancing.RotatingBuffer; import com.simibubi.create.foundation.utility.render.instancing.InstanceContext;
import com.simibubi.create.foundation.utility.render.SuperByteBuffer; import com.simibubi.create.foundation.utility.render.SuperByteBuffer;
import com.simibubi.create.foundation.utility.render.instancing.RotatingData; import com.simibubi.create.foundation.utility.render.instancing.RotatingData;
@ -93,14 +93,9 @@ public class CuckooClockRenderer extends KineticTileEntityRenderer {
} }
@Override @Override
protected RotatingBuffer getRotatedModel(KineticTileEntity te) { protected InstanceBuffer<RotatingData> getRotatedModel(InstanceContext<? extends KineticTileEntity> ctx) {
return transform(AllBlockPartials.SHAFT_HALF, te); BlockState blockState = ctx.te.getBlockState();
} return AllBlockPartials.SHAFT_HALF.renderOnDirectionalSouthRotating(ctx, blockState, blockState.get(CuckooClockBlock.HORIZONTAL_FACING).getOpposite());
private RotatingBuffer transform(AllBlockPartials partial, KineticTileEntity te) {
return partial.renderOnDirectionalSouthRotating(te.getBlockState(), te.getBlockState()
.get(CuckooClockBlock.HORIZONTAL_FACING)
.getOpposite());
} }
private SuperByteBuffer rotateHand(SuperByteBuffer buffer, float angle, Direction facing) { private SuperByteBuffer rotateHand(SuperByteBuffer buffer, float angle, Direction facing) {

View file

@ -20,6 +20,7 @@ import com.simibubi.create.foundation.utility.render.SuperByteBuffer;
import com.simibubi.create.foundation.utility.VecHelper; import com.simibubi.create.foundation.utility.VecHelper;
import com.simibubi.create.foundation.utility.render.instancing.IInstancedTileEntityRenderer; import com.simibubi.create.foundation.utility.render.instancing.IInstancedTileEntityRenderer;
import com.simibubi.create.foundation.utility.render.instancing.InstanceContext;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.IRenderTypeBuffer;
@ -51,12 +52,11 @@ public class DeployerRenderer extends SafeTileEntityRenderer<DeployerTileEntity>
FilteringRenderer.renderOnTileEntity(te, partialTicks, ms, buffer, light, overlay); FilteringRenderer.renderOnTileEntity(te, partialTicks, ms, buffer, light, overlay);
renderComponents(te, partialTicks, ms, buffer, light, overlay); renderComponents(te, partialTicks, ms, buffer, light, overlay);
addInstanceData(te);
} }
@Override @Override
public void addInstanceData(DeployerTileEntity te) { public void addInstanceData(InstanceContext<DeployerTileEntity> ctx) {
KineticTileEntityRenderer.renderRotatingKineticBlock(te, getRenderedBlockState(te)); KineticTileEntityRenderer.renderRotatingKineticBlock(ctx, getRenderedBlockState(ctx.te));
} }
protected void renderItem(DeployerTileEntity te, float partialTicks, MatrixStack ms, IRenderTypeBuffer buffer, protected void renderItem(DeployerTileEntity te, float partialTicks, MatrixStack ms, IRenderTypeBuffer buffer,
@ -110,7 +110,7 @@ public class DeployerRenderer extends SafeTileEntityRenderer<DeployerTileEntity>
protected void renderComponents(DeployerTileEntity te, float partialTicks, MatrixStack ms, IRenderTypeBuffer buffer, protected void renderComponents(DeployerTileEntity te, float partialTicks, MatrixStack ms, IRenderTypeBuffer buffer,
int light, int overlay) { int light, int overlay) {
IVertexBuilder vb = buffer.getBuffer(RenderType.getSolid()); IVertexBuilder vb = buffer.getBuffer(RenderType.getSolid());
KineticTileEntityRenderer.renderRotatingKineticBlock(te, getRenderedBlockState(te)); KineticTileEntityRenderer.renderRotatingKineticBlock(new InstanceContext.World<>(te), getRenderedBlockState(te));
BlockState blockState = te.getBlockState(); BlockState blockState = te.getBlockState();
BlockPos pos = te.getPos(); BlockPos pos = te.getPos();

View file

@ -8,7 +8,10 @@ import com.simibubi.create.content.contraptions.base.IRotate;
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.utility.render.instancing.InstanceBuffer;
import com.simibubi.create.foundation.utility.render.instancing.InstanceContext;
import com.simibubi.create.foundation.utility.render.instancing.RotatingBuffer; import com.simibubi.create.foundation.utility.render.instancing.RotatingBuffer;
import com.simibubi.create.foundation.utility.render.instancing.RotatingData;
import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.IRenderTypeBuffer;
import net.minecraft.client.renderer.WorldRenderer; import net.minecraft.client.renderer.WorldRenderer;
import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher;
@ -26,24 +29,21 @@ public class EncasedFanRenderer 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) {
addInstanceData(te); super.renderSafe(te, partialTicks, ms, buffer, light, overlay);
} }
@Override @Override
public void addInstanceData(KineticTileEntity te) { public void addInstanceData(InstanceContext<KineticTileEntity> ctx) {
KineticTileEntity te = ctx.te;
Direction direction = te.getBlockState() Direction direction = te.getBlockState()
.get(FACING); .get(FACING);
BlockPos inFront = te.getPos().offset(direction); InstanceBuffer<RotatingData> shaftHalf =
int blockLight = te.getWorld().getLightLevel(LightType.BLOCK, inFront); AllBlockPartials.SHAFT_HALF.renderOnDirectionalSouthRotating(ctx, te.getBlockState(), direction.getOpposite());
int skyLight = te.getWorld().getLightLevel(LightType.SKY, inFront); InstanceBuffer<RotatingData> fanInner =
AllBlockPartials.ENCASED_FAN_INNER.renderOnDirectionalSouthRotating(ctx, te.getBlockState(), direction.getOpposite());
RotatingBuffer shaftHalf = renderRotatingBuffer(ctx, shaftHalf);
AllBlockPartials.SHAFT_HALF.renderOnDirectionalSouthRotating(te.getBlockState(), direction.getOpposite());
RotatingBuffer fanInner =
AllBlockPartials.ENCASED_FAN_INNER.renderOnDirectionalSouthRotating(te.getBlockState(), direction.getOpposite());
renderRotatingBuffer(te, shaftHalf);
fanInner.setupInstance(data -> { fanInner.setupInstance(data -> {
final BlockPos pos = te.getPos(); final BlockPos pos = te.getPos();
Direction.Axis axis = ((IRotate) te.getBlockState() Direction.Axis axis = ((IRotate) te.getBlockState()
@ -55,12 +55,19 @@ public class EncasedFanRenderer extends KineticTileEntityRenderer {
if (speed < 0) if (speed < 0)
speed = MathHelper.clamp(speed, -64 * 20, -80); speed = MathHelper.clamp(speed, -64 * 20, -80);
data.setBlockLight(blockLight) data.setRotationalSpeed(speed)
.setSkyLight(skyLight)
.setRotationalSpeed(speed)
.setRotationOffset(getRotationOffsetForPosition(te, pos, axis)) .setRotationOffset(getRotationOffsetForPosition(te, pos, axis))
.setRotationAxis(Direction.getFacingFromAxis(Direction.AxisDirection.POSITIVE, axis).getUnitVector()) .setRotationAxis(Direction.getFacingFromAxis(Direction.AxisDirection.POSITIVE, axis).getUnitVector())
.setPosition(pos); .setPosition(pos);
if (ctx.checkWorldLight()) {
BlockPos inFront = te.getPos().offset(direction);
int blockLight = te.getWorld().getLightLevel(LightType.BLOCK, inFront);
int skyLight = te.getWorld().getLightLevel(LightType.SKY, inFront);
data.setBlockLight(blockLight)
.setSkyLight(skyLight);
}
}); });
} }
} }

View file

@ -9,10 +9,10 @@ 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.components.flywheel.FlywheelBlock.ConnectionState; import com.simibubi.create.content.contraptions.components.flywheel.FlywheelBlock.ConnectionState;
import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.AngleHelper;
import com.simibubi.create.foundation.utility.render.instancing.InstanceBuffer;
import com.simibubi.create.foundation.utility.render.SuperByteBuffer; import com.simibubi.create.foundation.utility.render.SuperByteBuffer;
import com.simibubi.create.foundation.utility.render.instancing.RotatingBuffer; import com.simibubi.create.foundation.utility.render.instancing.InstanceBuffer;
import com.simibubi.create.foundation.utility.render.instancing.InstanceContext;
import com.simibubi.create.foundation.utility.render.instancing.RotatingData; import com.simibubi.create.foundation.utility.render.instancing.RotatingData;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.IRenderTypeBuffer;
@ -77,8 +77,8 @@ public class FlywheelRenderer extends KineticTileEntityRenderer {
} }
@Override @Override
protected RotatingBuffer getRotatedModel(KineticTileEntity te) { protected InstanceBuffer<RotatingData> getRotatedModel(InstanceContext<? extends KineticTileEntity> ctx) {
return AllBlockPartials.SHAFT_HALF.renderOnDirectionalSouthRotating(te.getBlockState(), te.getBlockState() return AllBlockPartials.SHAFT_HALF.renderOnDirectionalSouthRotating(ctx, ctx.te.getBlockState(), ctx.te.getBlockState()
.get(HORIZONTAL_FACING) .get(HORIZONTAL_FACING)
.getOpposite()); .getOpposite());
} }

View file

@ -1,12 +1,11 @@
package com.simibubi.create.content.contraptions.components.millstone; package com.simibubi.create.content.contraptions.components.millstone;
import com.simibubi.create.AllBlockPartials; import com.simibubi.create.AllBlockPartials;
import com.simibubi.create.CreateClient;
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.utility.render.instancing.InstanceBuffer; import com.simibubi.create.foundation.utility.render.instancing.InstanceBuffer;
import com.simibubi.create.foundation.utility.render.instancing.RotatingBuffer; import com.simibubi.create.foundation.utility.render.instancing.InstanceContext;
import com.simibubi.create.foundation.utility.render.instancing.RotatingData; import com.simibubi.create.foundation.utility.render.instancing.RotatingData;
import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher;
@ -17,8 +16,8 @@ public class MillstoneRenderer extends KineticTileEntityRenderer {
} }
@Override @Override
protected RotatingBuffer getRotatedModel(KineticTileEntity te) { protected InstanceBuffer<RotatingData> getRotatedModel(InstanceContext<? extends KineticTileEntity> ctx) {
return CreateClient.kineticRenderer.renderPartialRotating(AllBlockPartials.MILLSTONE_COG, te.getBlockState()); return AllBlockPartials.MILLSTONE_COG.renderOnRotating(ctx, ctx.te.getBlockState());
} }
} }

View file

@ -5,7 +5,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.foundation.utility.render.instancing.InstanceBuffer; import com.simibubi.create.foundation.utility.render.instancing.InstanceBuffer;
import com.simibubi.create.foundation.utility.render.instancing.RotatingBuffer; import com.simibubi.create.foundation.utility.render.instancing.InstanceContext;
import com.simibubi.create.foundation.utility.render.instancing.RotatingData; import com.simibubi.create.foundation.utility.render.instancing.RotatingData;
import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher;
@ -16,8 +16,8 @@ public class CreativeMotorRenderer extends KineticTileEntityRenderer {
} }
@Override @Override
protected RotatingBuffer getRotatedModel(KineticTileEntity te) { protected InstanceBuffer<RotatingData> getRotatedModel(InstanceContext<? extends KineticTileEntity> ctx) {
return AllBlockPartials.SHAFT_HALF.renderOnDirectionalSouthRotating(te.getBlockState()); return AllBlockPartials.SHAFT_HALF.renderOnDirectionalSouthRotating(ctx, ctx.te.getBlockState());
} }
} }

View file

@ -12,8 +12,7 @@ import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringRe
import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer; import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer;
import com.simibubi.create.foundation.utility.*; import com.simibubi.create.foundation.utility.*;
import com.simibubi.create.foundation.utility.render.instancing.IInstancedTileEntityRenderer; import com.simibubi.create.foundation.utility.render.instancing.*;
import com.simibubi.create.foundation.utility.render.instancing.RotatingBuffer;
import com.simibubi.create.foundation.utility.render.SuperByteBuffer; import com.simibubi.create.foundation.utility.render.SuperByteBuffer;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
@ -43,12 +42,11 @@ public class SawRenderer extends SafeTileEntityRenderer<SawTileEntity> implement
renderItems(te, partialTicks, ms, buffer, light, overlay); renderItems(te, partialTicks, ms, buffer, light, overlay);
FilteringRenderer.renderOnTileEntity(te, partialTicks, ms, buffer, light, overlay); FilteringRenderer.renderOnTileEntity(te, partialTicks, ms, buffer, light, overlay);
addInstanceData(te);
} }
@Override @Override
public void addInstanceData(SawTileEntity te) { public void addInstanceData(InstanceContext<SawTileEntity> ctx) {
KineticTileEntityRenderer.renderRotatingBuffer(te, getRotatedModel(te)); KineticTileEntityRenderer.renderRotatingBuffer(ctx, getRotatedModel(ctx));
} }
protected void renderBlade(SawTileEntity te, MatrixStack ms, IRenderTypeBuffer buffer, int light){ protected void renderBlade(SawTileEntity te, MatrixStack ms, IRenderTypeBuffer buffer, int light){
@ -86,7 +84,7 @@ public class SawRenderer extends SafeTileEntityRenderer<SawTileEntity> implement
} }
protected void renderShaft(SawTileEntity te, MatrixStack ms, IRenderTypeBuffer buffer, int light, int overlay) { protected void renderShaft(SawTileEntity te, MatrixStack ms, IRenderTypeBuffer buffer, int light, int overlay) {
KineticTileEntityRenderer.renderRotatingBuffer(te, getRotatedModel(te)); //KineticTileEntityRenderer.renderRotatingBuffer(te, getRotatedModel(te));
} }
protected void renderItems(SawTileEntity te, float partialTicks, MatrixStack ms, IRenderTypeBuffer buffer, int light, protected void renderItems(SawTileEntity te, float partialTicks, MatrixStack ms, IRenderTypeBuffer buffer, int light,
@ -130,11 +128,12 @@ public class SawRenderer extends SafeTileEntityRenderer<SawTileEntity> implement
} }
} }
protected RotatingBuffer getRotatedModel(KineticTileEntity te) { protected InstanceBuffer<RotatingData> getRotatedModel(InstanceContext<SawTileEntity> ctx) {
KineticTileEntity te = ctx.te;
BlockState state = te.getBlockState(); BlockState state = te.getBlockState();
if (state.get(FACING).getAxis().isHorizontal()) if (state.get(FACING).getAxis().isHorizontal())
return AllBlockPartials.SHAFT_HALF.renderOnDirectionalSouthRotating(state.rotate(te.getWorld(), te.getPos(), Rotation.CLOCKWISE_180)); return AllBlockPartials.SHAFT_HALF.renderOnDirectionalSouthRotating(ctx, state.rotate(te.getWorld(), te.getPos(), Rotation.CLOCKWISE_180));
return CreateClient.kineticRenderer.renderBlockInstanced(KineticTileEntityRenderer.KINETIC_TILE, return ctx.getKinetics().renderBlockInstanced(KineticTileEntityRenderer.KINETIC_TILE,
getRenderedBlockState(te)); getRenderedBlockState(te));
} }

View file

@ -5,11 +5,12 @@ 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.utility.AngleHelper; import com.simibubi.create.foundation.utility.AngleHelper;
import com.simibubi.create.foundation.utility.render.instancing.InstanceBuffer;
import com.simibubi.create.foundation.utility.render.SuperByteBuffer; import com.simibubi.create.foundation.utility.render.SuperByteBuffer;
import com.simibubi.create.foundation.utility.render.instancing.RotatingBuffer; import com.simibubi.create.foundation.utility.render.instancing.InstanceBuffer;
import com.simibubi.create.foundation.utility.render.instancing.InstanceContext;
import com.simibubi.create.foundation.utility.render.instancing.RotatingData; import com.simibubi.create.foundation.utility.render.instancing.RotatingData;
import net.minecraft.block.BlockState;
import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.IRenderTypeBuffer;
import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher;
@ -46,10 +47,9 @@ public class BearingRenderer extends KineticTileEntityRenderer {
} }
@Override @Override
protected RotatingBuffer getRotatedModel(KineticTileEntity te) { protected InstanceBuffer<RotatingData> getRotatedModel(InstanceContext<? extends KineticTileEntity> ctx) {
return AllBlockPartials.SHAFT_HALF.renderOnDirectionalSouthRotating(te.getBlockState(), te.getBlockState() BlockState blockState = ctx.te.getBlockState();
.get(BearingBlock.FACING) return AllBlockPartials.SHAFT_HALF.renderOnDirectionalSouthRotating(ctx, blockState, blockState.get(BearingBlock.FACING).getOpposite());
.getOpposite());
} }
} }

View file

@ -6,10 +6,10 @@ 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.utility.AngleHelper; import com.simibubi.create.foundation.utility.AngleHelper;
import com.simibubi.create.foundation.utility.MatrixStacker; import com.simibubi.create.foundation.utility.MatrixStacker;
import com.simibubi.create.foundation.utility.render.instancing.InstanceBuffer;
import com.simibubi.create.foundation.utility.render.SuperByteBuffer; import com.simibubi.create.foundation.utility.render.SuperByteBuffer;
import com.simibubi.create.foundation.utility.render.instancing.RotatingBuffer; import com.simibubi.create.foundation.utility.render.instancing.InstanceBuffer;
import com.simibubi.create.foundation.utility.render.instancing.InstanceContext;
import com.simibubi.create.foundation.utility.render.instancing.RotatingData; import com.simibubi.create.foundation.utility.render.instancing.RotatingData;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.IRenderTypeBuffer;
@ -54,8 +54,8 @@ public class PumpRenderer extends KineticTileEntityRenderer {
} }
@Override @Override
protected RotatingBuffer getRotatedModel(KineticTileEntity te) { protected InstanceBuffer<RotatingData> getRotatedModel(InstanceContext<? extends KineticTileEntity> ctx) {
return AllBlockPartials.MECHANICAL_PUMP_COG.renderOnDirectionalSouthRotating(te.getBlockState()); return AllBlockPartials.MECHANICAL_PUMP_COG.renderOnDirectionalSouthRotating(ctx, ctx.te.getBlockState());
} }
} }

View file

@ -5,8 +5,7 @@ import com.simibubi.create.CreateClient;
import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer;
import com.simibubi.create.foundation.tileEntity.renderer.SmartTileEntityRenderer; import com.simibubi.create.foundation.tileEntity.renderer.SmartTileEntityRenderer;
import com.simibubi.create.foundation.utility.render.instancing.IInstancedTileEntityRenderer; import com.simibubi.create.foundation.utility.render.instancing.*;
import com.simibubi.create.foundation.utility.render.instancing.RotatingBuffer;
import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.IRenderTypeBuffer;
import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher;
@ -21,15 +20,14 @@ public class SpeedControllerRenderer extends SmartTileEntityRenderer<SpeedContro
IRenderTypeBuffer buffer, int light, int overlay) { IRenderTypeBuffer buffer, int light, int overlay) {
super.renderSafe(tileEntityIn, partialTicks, ms, buffer, light, overlay); super.renderSafe(tileEntityIn, partialTicks, ms, buffer, light, overlay);
addInstanceData(tileEntityIn);
} }
@Override @Override
public void addInstanceData(SpeedControllerTileEntity te) { public void addInstanceData(InstanceContext<SpeedControllerTileEntity> ctx) {
KineticTileEntityRenderer.renderRotatingBuffer(te, getRotatedModel(te)); KineticTileEntityRenderer.renderRotatingBuffer(ctx, getRotatedModel(ctx.te));
} }
private RotatingBuffer getRotatedModel(SpeedControllerTileEntity te) { private InstanceBuffer<RotatingData> getRotatedModel(SpeedControllerTileEntity te) {
return CreateClient.kineticRenderer.renderBlockInstanced(KineticTileEntityRenderer.KINETIC_TILE, return CreateClient.kineticRenderer.renderBlockInstanced(KineticTileEntityRenderer.KINETIC_TILE,
KineticTileEntityRenderer.shaft(KineticTileEntityRenderer.getRotationAxisOf(te))); KineticTileEntityRenderer.shaft(KineticTileEntityRenderer.getRotationAxisOf(te)));
} }

View file

@ -1,6 +1,8 @@
package com.simibubi.create.content.contraptions.relays.belt; package com.simibubi.create.content.contraptions.relays.belt;
import java.util.Random; import java.util.Random;
import java.util.function.BiFunction;
import java.util.function.Function;
import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.matrix.MatrixStack;
import com.simibubi.create.AllBlockPartials; import com.simibubi.create.AllBlockPartials;
@ -13,9 +15,9 @@ import com.simibubi.create.foundation.block.render.SpriteShiftEntry;
import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer; import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer;
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 com.simibubi.create.foundation.utility.render.instancing.BeltBuffer; import com.simibubi.create.foundation.utility.render.FastContraptionRenderer;
import com.simibubi.create.foundation.utility.render.instancing.IInstancedTileEntityRenderer; import com.simibubi.create.foundation.utility.render.FastKineticRenderer;
import com.simibubi.create.foundation.utility.render.instancing.RotatingBuffer; import com.simibubi.create.foundation.utility.render.instancing.*;
import com.simibubi.create.foundation.utility.render.ShadowRenderHelper; import com.simibubi.create.foundation.utility.render.ShadowRenderHelper;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
@ -51,13 +53,13 @@ public class BeltRenderer extends SafeTileEntityRenderer<BeltTileEntity> impleme
if (!AllBlocks.BELT.has(blockState)) if (!AllBlocks.BELT.has(blockState))
return; return;
addInstanceData(te); addInstanceData(new InstanceContext.World<>(te));
renderItems(te, partialTicks, ms, buffer, light, overlay); renderItems(te, partialTicks, ms, buffer, light, overlay);
} }
@Override @Override
public void addInstanceData(BeltTileEntity te) { public void addInstanceData(InstanceContext<BeltTileEntity> ctx) {
BeltTileEntity te = ctx.te;
BlockState blockState = te.getBlockState(); BlockState blockState = te.getBlockState();
if (!AllBlocks.BELT.has(blockState)) if (!AllBlocks.BELT.has(blockState))
return; return;
@ -83,6 +85,8 @@ public class BeltRenderer extends SafeTileEntityRenderer<BeltTileEntity> impleme
end = b; end = b;
} }
FastKineticRenderer fastKineticRenderer = ctx.getKinetics();
for (boolean bottom : Iterate.trueAndFalse) { for (boolean bottom : Iterate.trueAndFalse) {
AllBlockPartials beltPartial = diagonal AllBlockPartials beltPartial = diagonal
@ -94,7 +98,7 @@ public class BeltRenderer extends SafeTileEntityRenderer<BeltTileEntity> impleme
: start ? AllBlockPartials.BELT_START : start ? AllBlockPartials.BELT_START
: end ? AllBlockPartials.BELT_END : AllBlockPartials.BELT_MIDDLE; : end ? AllBlockPartials.BELT_END : AllBlockPartials.BELT_MIDDLE;
BeltBuffer beltBuffer = beltPartial.renderOnBelt(blockState); InstanceBuffer<BeltData> beltBuffer = beltPartial.renderOnBelt(ctx, blockState);
SpriteShiftEntry spriteShift = SpriteShiftEntry spriteShift =
diagonal ? AllSpriteShifts.BELT_DIAGONAL : bottom ? AllSpriteShifts.BELT_OFFSET : AllSpriteShifts.BELT; diagonal ? AllSpriteShifts.BELT_DIAGONAL : bottom ? AllSpriteShifts.BELT_OFFSET : AllSpriteShifts.BELT;
@ -139,9 +143,9 @@ public class BeltRenderer extends SafeTileEntityRenderer<BeltTileEntity> impleme
msr.rotateX(90); msr.rotateX(90);
msr.unCentre(); msr.unCentre();
RotatingBuffer rotatingBuffer = CreateClient.kineticRenderer InstanceBuffer<RotatingData> rotatingBuffer = fastKineticRenderer
.renderDirectionalPartialInstanced(AllBlockPartials.BELT_PULLEY, blockState, dir, modelTransform); .renderDirectionalPartialInstanced(AllBlockPartials.BELT_PULLEY, blockState, dir, modelTransform);
KineticTileEntityRenderer.renderRotatingBuffer(te, rotatingBuffer); KineticTileEntityRenderer.renderRotatingBuffer(ctx, rotatingBuffer);
} }
} }

View file

@ -7,7 +7,10 @@ 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.utility.Iterate; import com.simibubi.create.foundation.utility.Iterate;
import com.simibubi.create.foundation.utility.render.instancing.InstanceBuffer;
import com.simibubi.create.foundation.utility.render.instancing.InstanceContext;
import com.simibubi.create.foundation.utility.render.instancing.RotatingBuffer; import com.simibubi.create.foundation.utility.render.instancing.RotatingBuffer;
import com.simibubi.create.foundation.utility.render.instancing.RotatingData;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.IRenderTypeBuffer;
import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher;
@ -25,18 +28,26 @@ public class SplitShaftRenderer 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) {
super.renderSafe(te, partialTicks, ms, buffer, light, overlay);
addInstanceData(te);
} }
@Override @Override
public void addInstanceData(KineticTileEntity te) { public void addInstanceData(InstanceContext<KineticTileEntity> ctx) {
KineticTileEntity te = ctx.te;
Block block = te.getBlockState().getBlock(); Block block = te.getBlockState().getBlock();
final Axis boxAxis = ((IRotate) block).getRotationAxis(te.getBlockState()); final Axis boxAxis = ((IRotate) block).getRotationAxis(te.getBlockState());
final BlockPos pos = te.getPos(); final BlockPos pos = te.getPos();
int blockLight = te.getWorld().getLightLevel(LightType.BLOCK, te.getPos()); int blockLight;
int skyLight = te.getWorld().getLightLevel(LightType.SKY, te.getPos()); int skyLight;
if (ctx.checkWorldLight()) {
blockLight = te.getWorld().getLightLevel(LightType.BLOCK, te.getPos());
skyLight = te.getWorld().getLightLevel(LightType.SKY, te.getPos());
} else {
blockLight = 0;
skyLight = 0;
}
for (Direction direction : Iterate.directions) { for (Direction direction : Iterate.directions) {
Axis axis = direction.getAxis(); Axis axis = direction.getAxis();
@ -44,7 +55,7 @@ public class SplitShaftRenderer extends KineticTileEntityRenderer {
continue; continue;
RotatingBuffer shaft = AllBlockPartials.SHAFT_HALF.renderOnDirectionalSouthRotating(te.getBlockState(), direction); InstanceBuffer<RotatingData> shaft = AllBlockPartials.SHAFT_HALF.renderOnDirectionalSouthRotating(ctx, te.getBlockState(), direction);
shaft.setupInstance(data -> { shaft.setupInstance(data -> {
float speed = te.getSpeed(); float speed = te.getSpeed();

View file

@ -6,7 +6,10 @@ 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.utility.Iterate; import com.simibubi.create.foundation.utility.Iterate;
import com.simibubi.create.foundation.utility.render.instancing.InstanceBuffer;
import com.simibubi.create.foundation.utility.render.instancing.InstanceContext;
import com.simibubi.create.foundation.utility.render.instancing.RotatingBuffer; import com.simibubi.create.foundation.utility.render.instancing.RotatingBuffer;
import com.simibubi.create.foundation.utility.render.instancing.RotatingData;
import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.IRenderTypeBuffer;
import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher;
import net.minecraft.state.properties.BlockStateProperties; import net.minecraft.state.properties.BlockStateProperties;
@ -24,18 +27,32 @@ public class GearboxRenderer 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) {
super.renderSafe(te, partialTicks, ms, buffer, light, overlay);
}
@Override
public void addInstanceData(InstanceContext<KineticTileEntity> ctx) {
KineticTileEntity te = ctx.te;
final Axis boxAxis = te.getBlockState().get(BlockStateProperties.AXIS); final Axis boxAxis = te.getBlockState().get(BlockStateProperties.AXIS);
final BlockPos pos = te.getPos(); final BlockPos pos = te.getPos();
int blockLight = te.getWorld().getLightLevel(LightType.BLOCK, te.getPos()); int blockLight;
int skyLight = te.getWorld().getLightLevel(LightType.SKY, te.getPos()); int skyLight;
if (ctx.checkWorldLight()) {
blockLight = te.getWorld().getLightLevel(LightType.BLOCK, te.getPos());
skyLight = te.getWorld().getLightLevel(LightType.SKY, te.getPos());
} else {
blockLight = 0;
skyLight = 0;
}
for (Direction direction : Iterate.directions) { for (Direction direction : Iterate.directions) {
final Axis axis = direction.getAxis(); final Axis axis = direction.getAxis();
if (boxAxis == axis) if (boxAxis == axis)
continue; continue;
RotatingBuffer shaft = AllBlockPartials.SHAFT_HALF.renderOnDirectionalSouthRotating(te.getBlockState(), direction); InstanceBuffer<RotatingData> shaft = AllBlockPartials.SHAFT_HALF.renderOnDirectionalSouthRotating(ctx, te.getBlockState(), direction);
shaft.setupInstance(data -> { shaft.setupInstance(data -> {
float speed = te.getSpeed(); float speed = te.getSpeed();
@ -58,5 +75,4 @@ public class GearboxRenderer extends KineticTileEntityRenderer {
}); });
} }
} }
} }

View file

@ -8,9 +8,9 @@ import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer;
import com.simibubi.create.content.logistics.block.mechanicalArm.ArmTileEntity.Phase; import com.simibubi.create.content.logistics.block.mechanicalArm.ArmTileEntity.Phase;
import com.simibubi.create.foundation.utility.*; import com.simibubi.create.foundation.utility.*;
import com.simibubi.create.foundation.utility.render.instancing.InstanceBuffer;
import com.simibubi.create.foundation.utility.render.SuperByteBuffer; import com.simibubi.create.foundation.utility.render.SuperByteBuffer;
import com.simibubi.create.foundation.utility.render.instancing.RotatingBuffer; import com.simibubi.create.foundation.utility.render.instancing.InstanceBuffer;
import com.simibubi.create.foundation.utility.render.instancing.InstanceContext;
import com.simibubi.create.foundation.utility.render.instancing.RotatingData; import com.simibubi.create.foundation.utility.render.instancing.RotatingData;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
@ -118,8 +118,8 @@ public class ArmRenderer extends KineticTileEntityRenderer {
} }
@Override @Override
protected RotatingBuffer getRotatedModel(KineticTileEntity te) { protected InstanceBuffer<RotatingData> getRotatedModel(InstanceContext<? extends KineticTileEntity> ctx) {
return AllBlockPartials.ARM_COG.renderOnRotating(te.getBlockState()); return AllBlockPartials.ARM_COG.renderOnRotating(ctx, ctx.te.getBlockState());
} }
} }

View file

@ -37,6 +37,7 @@ import com.simibubi.create.foundation.utility.render.RenderWork;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.ActiveRenderInfo; import net.minecraft.client.renderer.ActiveRenderInfo;
import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.IRenderTypeBuffer;
import net.minecraft.client.renderer.Matrix4f;
import net.minecraft.client.renderer.texture.OverlayTexture; import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.fluid.Fluid; import net.minecraft.fluid.Fluid;
import net.minecraft.fluid.IFluidState; import net.minecraft.fluid.IFluidState;
@ -112,21 +113,25 @@ public class ClientEvents {
@SubscribeEvent @SubscribeEvent
public static void onLoadWorld(WorldEvent.Load event) { public static void onLoadWorld(WorldEvent.Load event) {
CreateClient.bufferCache.invalidate(); CreateClient.invalidateRenderers();
CreateClient.kineticRenderer.invalidate();
FastContraptionRenderer.invalidateAll();
} }
@SubscribeEvent @SubscribeEvent
public static void onRenderWorld(RenderWorldLastEvent event) { public static void onRenderWorld(RenderWorldLastEvent event) {
CreateClient.kineticRenderer.renderInstances(event); Matrix4f projection = event.getProjectionMatrix();
FastContraptionRenderer.renderAll(event); // view matrix
Vec3d cameraPos = Minecraft.getInstance().gameRenderer.getActiveRenderInfo().getProjectedView();
Matrix4f view = Matrix4f.translate((float) -cameraPos.x, (float) -cameraPos.y, (float) -cameraPos.z);
view.multiplyBackward(event.getMatrixStack().peek().getModel());
CreateClient.kineticRenderer.renderInstancesAsWorld(projection, view);
FastContraptionRenderer.renderAll(projection, view);
MatrixStack ms = event.getMatrixStack(); MatrixStack ms = event.getMatrixStack();
ActiveRenderInfo info = Minecraft.getInstance().gameRenderer.getActiveRenderInfo(); ActiveRenderInfo info = Minecraft.getInstance().gameRenderer.getActiveRenderInfo();
Vec3d view = info.getProjectedView();
ms.push(); ms.push();
ms.translate(-view.getX(), -view.getY(), -view.getZ()); ms.translate(-cameraPos.getX(), -cameraPos.getY(), -cameraPos.getZ());
SuperRenderTypeBuffer buffer = SuperRenderTypeBuffer.getInstance(); SuperRenderTypeBuffer buffer = SuperRenderTypeBuffer.getInstance();
CouplingRenderer.renderAll(ms, buffer); CouplingRenderer.renderAll(ms, buffer);

View file

@ -18,9 +18,7 @@ public class ResourceReloadHandler extends ReloadListener<Object> {
@Override @Override
protected void apply(Object $, IResourceManager resourceManagerIn, IProfiler profilerIn) { protected void apply(Object $, IResourceManager resourceManagerIn, IProfiler profilerIn) {
SpriteShifter.reloadUVs(); SpriteShifter.reloadUVs();
CreateClient.bufferCache.invalidate(); CreateClient.invalidateRenderers();
CreateClient.kineticRenderer.invalidate();
FastContraptionRenderer.invalidateAll();
} }
} }

View file

@ -23,8 +23,6 @@ public class ClearBufferCacheCommand {
@OnlyIn(Dist.CLIENT) @OnlyIn(Dist.CLIENT)
private static void execute() { private static void execute() {
CreateClient.bufferCache.invalidate(); CreateClient.invalidateRenderers();
CreateClient.kineticRenderer.invalidate();
FastContraptionRenderer.invalidateAll();
} }
} }

View file

@ -1,11 +1,9 @@
package com.simibubi.create.foundation.utility.render; package com.simibubi.create.foundation.utility.render;
import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.platform.GlStateManager;
import com.simibubi.create.CreateClient;
import com.simibubi.create.foundation.utility.render.instancing.VertexFormat; import com.simibubi.create.foundation.utility.render.instancing.VertexFormat;
import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.GLAllocation; import net.minecraft.client.renderer.GLAllocation;
import net.minecraft.client.renderer.WorldRenderer;
import net.minecraft.client.renderer.vertex.VertexFormatElement; import net.minecraft.client.renderer.vertex.VertexFormatElement;
import org.lwjgl.opengl.*; import org.lwjgl.opengl.*;
import org.lwjgl.system.MemoryUtil; import org.lwjgl.system.MemoryUtil;
@ -43,7 +41,7 @@ public class ContraptionBuffer extends TemplateBuffer {
GlStateManager.bindBuffers(GL15.GL_ELEMENT_ARRAY_BUFFER, ebo); GlStateManager.bindBuffers(GL15.GL_ELEMENT_ARRAY_BUFFER, ebo);
GL40.glDrawElements(GL11.GL_QUADS, count, GL11.GL_UNSIGNED_SHORT, 0); GL40.glDrawElements(GL11.GL_QUADS, vertexCount, GL11.GL_UNSIGNED_SHORT, 0);
for (int i = 0; i <= FORMAT.getNumAttributes(); i++) { for (int i = 0; i <= FORMAT.getNumAttributes(); i++) {
GL40.glDisableVertexAttribArray(i); GL40.glDisableVertexAttribArray(i);
@ -55,39 +53,35 @@ public class ContraptionBuffer extends TemplateBuffer {
private void setup() { private void setup() {
int stride = FORMAT.getStride(); int stride = FORMAT.getStride();
int invariantSize = count * stride; int invariantSize = vertexCount * stride;
ByteBuffer constant = GLAllocation.createDirectByteBuffer(invariantSize); GlStateManager.bindBuffers(GL15.GL_ARRAY_BUFFER, 0);
GlStateManager.bindBuffers(GL15.GL_ELEMENT_ARRAY_BUFFER, 0);
// Deselect (bind to 0) the VAO
GL30.glBindVertexArray(0);
try (SafeDirectBuffer constant = new SafeDirectBuffer(invariantSize)) {
constant.order(template.order()); constant.order(template.order());
((Buffer) constant).limit(invariantSize); constant.limit(invariantSize);
int indicesSize = count * VertexFormatElement.Type.USHORT.getSize();
ByteBuffer indices = GLAllocation.createDirectByteBuffer(indicesSize);
indices.order(template.order());
((Buffer) indices).limit(indicesSize);
int vertexCount = vertexCount(template);
for (int i = 0; i < vertexCount; i++) { for (int i = 0; i < vertexCount; i++) {
constant.putFloat(getX(template, i)); constant.putFloat(getX(template, i));
constant.putFloat(getY(template, i)); constant.putFloat(getY(template, i));
constant.putFloat(getZ(template, i)); constant.putFloat(getZ(template, i));
constant.putFloat(getNX(template, i)); constant.put(getNX(template, i));
constant.putFloat(getNY(template, i)); constant.put(getNY(template, i));
constant.putFloat(getNZ(template, i)); constant.put(getNZ(template, i));
constant.putFloat(getU(template, i)); constant.putFloat(getU(template, i));
constant.putFloat(getV(template, i)); constant.putFloat(getV(template, i));
constant.putFloat(getR(template, i) / 255f); constant.put(getR(template, i));
constant.putFloat(getG(template, i) / 255f); constant.put(getG(template, i));
constant.putFloat(getB(template, i) / 255f); constant.put(getB(template, i));
constant.putFloat(getA(template, i) / 255f); constant.put(getA(template, i));
indices.putShort((short) i);
} }
constant.rewind(); constant.rewind();
indices.rewind();
vao = GL30.glGenVertexArrays(); vao = GL30.glGenVertexArrays();
GL30.glBindVertexArray(vao); GL30.glBindVertexArray(vao);
@ -96,14 +90,13 @@ public class ContraptionBuffer extends TemplateBuffer {
vbo = GlStateManager.genBuffers(); vbo = GlStateManager.genBuffers();
GlStateManager.bindBuffers(GL15.GL_ARRAY_BUFFER, vbo); GlStateManager.bindBuffers(GL15.GL_ARRAY_BUFFER, vbo);
GlStateManager.bufferData(GL15.GL_ARRAY_BUFFER, constant, GL15.GL_STATIC_DRAW); GlStateManager.bufferData(GL15.GL_ARRAY_BUFFER, constant.getBacking(), GL15.GL_STATIC_DRAW);
MemoryUtil.memFree(constant); buildEBO(ebo);
GlStateManager.bindBuffers(GL15.GL_ELEMENT_ARRAY_BUFFER, ebo);
GlStateManager.bufferData(GL15.GL_ELEMENT_ARRAY_BUFFER, indices, GL15.GL_STATIC_DRAW);
MemoryUtil.memFree(indices);
FORMAT.informAttributes(0); FORMAT.informAttributes(0);
} catch (Exception e) {
}
GlStateManager.bindBuffers(GL15.GL_ARRAY_BUFFER, 0); GlStateManager.bindBuffers(GL15.GL_ARRAY_BUFFER, 0);
GlStateManager.bindBuffers(GL15.GL_ELEMENT_ARRAY_BUFFER, 0); GlStateManager.bindBuffers(GL15.GL_ELEMENT_ARRAY_BUFFER, 0);

View file

@ -2,6 +2,7 @@ package com.simibubi.create.foundation.utility.render;
import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; import com.simibubi.create.content.contraptions.components.structureMovement.Contraption;
import net.minecraft.client.renderer.GLAllocation; import net.minecraft.client.renderer.GLAllocation;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
@ -132,22 +133,19 @@ public class ContraptionLighter {
public void use() { public void use() {
if (texture == 0 || lightVolume == null) return; if (texture == 0 || lightVolume == null) return;
GL13.glEnable(GL31.GL_TEXTURE_3D);
GL13.glActiveTexture(GL40.GL_TEXTURE0 + 4);
GL12.glBindTexture(GL12.GL_TEXTURE_3D, texture); GL12.glBindTexture(GL12.GL_TEXTURE_3D, texture);
GL11.glTexParameteri(GL13.GL_TEXTURE_3D, GL13.GL_TEXTURE_MIN_FILTER, GL13.GL_LINEAR);
GL11.glTexParameteri(GL13.GL_TEXTURE_3D, GL13.GL_TEXTURE_MAG_FILTER, GL13.GL_LINEAR);
GL11.glTexParameteri(GL13.GL_TEXTURE_3D, GL13.GL_TEXTURE_WRAP_S, GL13.GL_CLAMP);
GL11.glTexParameteri(GL13.GL_TEXTURE_3D, GL13.GL_TEXTURE_WRAP_R, GL13.GL_CLAMP);
GL11.glTexParameteri(GL13.GL_TEXTURE_3D, GL13.GL_TEXTURE_WRAP_T, GL13.GL_CLAMP);
if (dirty) { if (dirty) {
GL12.glTexImage3D(GL12.GL_TEXTURE_3D, 0, GL40.GL_RG8, sizeX, sizeY, sizeZ, 0, GL40.GL_RG, GL40.GL_UNSIGNED_BYTE, lightVolume); GL12.glTexImage3D(GL12.GL_TEXTURE_3D, 0, GL40.GL_RG8, sizeX, sizeY, sizeZ, 0, GL40.GL_RG, GL40.GL_UNSIGNED_BYTE, lightVolume);
dirty = false; dirty = false;
} }
GL40.glTexParameteri(GL13.GL_TEXTURE_3D, GL13.GL_TEXTURE_MIN_FILTER, GL13.GL_LINEAR);
GL40.glTexParameteri(GL13.GL_TEXTURE_3D, GL13.GL_TEXTURE_MAG_FILTER, GL13.GL_LINEAR);
GL40.glTexParameteri(GL13.GL_TEXTURE_3D, GL13.GL_TEXTURE_WRAP_S, GL13.GL_CLAMP);
GL40.glTexParameteri(GL13.GL_TEXTURE_3D, GL13.GL_TEXTURE_WRAP_R, GL13.GL_CLAMP);
GL40.glTexParameteri(GL13.GL_TEXTURE_3D, GL13.GL_TEXTURE_WRAP_T, GL13.GL_CLAMP);
} }
public void release() { public void release() {
GL13.glActiveTexture(GL40.GL_TEXTURE0 + 4);
GL12.glBindTexture(GL12.GL_TEXTURE_3D, 0); GL12.glBindTexture(GL12.GL_TEXTURE_3D, 0);
} }
} }

View file

@ -1,16 +1,23 @@
package com.simibubi.create.foundation.utility.render; package com.simibubi.create.foundation.utility.render;
import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.platform.GlStateManager;
import com.simibubi.create.CreateClient;
import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; import com.simibubi.create.content.contraptions.components.structureMovement.Contraption;
import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionRenderer; import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionRenderer;
import com.simibubi.create.foundation.utility.render.instancing.IInstanceRendered;
import com.simibubi.create.foundation.utility.render.instancing.IInstancedTileEntityRenderer;
import com.simibubi.create.foundation.utility.render.shader.Shader; import com.simibubi.create.foundation.utility.render.shader.Shader;
import com.simibubi.create.foundation.utility.render.shader.ShaderCallback;
import com.simibubi.create.foundation.utility.render.shader.ShaderHelper; import com.simibubi.create.foundation.utility.render.shader.ShaderHelper;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.*; import net.minecraft.client.renderer.*;
import net.minecraft.client.renderer.tileentity.TileEntityRenderer;
import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraftforge.client.event.RenderWorldLastEvent; import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL13;
import org.lwjgl.opengl.GL40;
import java.nio.FloatBuffer; import java.nio.FloatBuffer;
import java.util.ArrayList; import java.util.ArrayList;
@ -25,6 +32,8 @@ public class FastContraptionRenderer extends ContraptionRenderer {
private ContraptionLighter lighter; private ContraptionLighter lighter;
public final FastKineticRenderer kinetics;
private Contraption c; private Contraption c;
private Vec3d renderPos; private Vec3d renderPos;
@ -33,18 +42,49 @@ public class FastContraptionRenderer extends ContraptionRenderer {
public FastContraptionRenderer(World world, Contraption c) { public FastContraptionRenderer(World world, Contraption c) {
this.c = c; this.c = c;
this.lighter = new ContraptionLighter(c); this.lighter = new ContraptionLighter(c);
this.kinetics = new FastKineticRenderer();
buildLayers(); buildLayers(c);
buildInstancedTiles(c);
}
private void buildLayers(Contraption c) {
for (ContraptionBuffer buffer : renderLayers) {
buffer.delete();
}
renderLayers.clear();
List<RenderType> blockLayers = RenderType.getBlockLayers();
for (RenderType layer : blockLayers) {
renderLayers.add(buildStructureBuffer(c, layer));
}
}
private void buildInstancedTiles(Contraption c) {
List<TileEntity> tileEntities = c.renderedTileEntities;
if (!tileEntities.isEmpty()) {
for (TileEntity te : tileEntities) {
if (te instanceof IInstanceRendered) {
TileEntityRenderer<TileEntity> renderer = TileEntityRendererDispatcher.instance.getRenderer(te);
if (renderer instanceof IInstancedTileEntityRenderer) {
kinetics.addInstancedData(this, te, (IInstancedTileEntityRenderer<? super TileEntity>) renderer);
}
}
}
}
kinetics.markAllDirty();
} }
public static void tick() { public static void tick() {
if (Minecraft.getInstance().isGamePaused()) return; if (Minecraft.getInstance().isGamePaused()) return;
RenderWork.enqueue(() -> {
for (FastContraptionRenderer renderer : renderers.values()) { for (FastContraptionRenderer renderer : renderers.values()) {
renderer.lighter.update(renderer.c); renderer.lighter.update(renderer.c);
} }
});
} }
private void setRenderSettings(Vec3d position, Vec3d rotation) { private void setRenderSettings(Vec3d position, Vec3d rotation) {
@ -52,9 +92,16 @@ public class FastContraptionRenderer extends ContraptionRenderer {
renderRot = rotation; renderRot = rotation;
} }
private void render(int shader) { private void setup(int shader) {
setupShaderUniforms(shader);
lighter.use(); lighter.use();
}
private void teardown() {
lighter.release();
}
private void setupShaderUniforms(int shader) {
FloatBuffer buf = ShaderHelper.VEC3_BUFFER; FloatBuffer buf = ShaderHelper.VEC3_BUFFER;
int lightBoxSize = GlStateManager.getUniformLocation(shader, "lightBoxSize"); int lightBoxSize = GlStateManager.getUniformLocation(shader, "lightBoxSize");
@ -84,26 +131,6 @@ public class FastContraptionRenderer extends ContraptionRenderer {
buf.put(2, (float) renderRot.z); buf.put(2, (float) renderRot.z);
buf.rewind(); buf.rewind();
GlStateManager.uniform3(cRot, buf); GlStateManager.uniform3(cRot, buf);
for (ContraptionBuffer layer : renderLayers) {
layer.render();
}
lighter.release();
}
private void buildLayers() {
for (ContraptionBuffer buffer : renderLayers) {
buffer.delete();
}
renderLayers.clear();
List<RenderType> blockLayers = RenderType.getBlockLayers();
for (RenderType layer : blockLayers) {
renderLayers.add(buildStructureBuffer(c, layer));
}
} }
private void invalidate() { private void invalidate() {
@ -113,6 +140,8 @@ public class FastContraptionRenderer extends ContraptionRenderer {
lighter.delete(); lighter.delete();
kinetics.invalidate();
renderLayers.clear(); renderLayers.clear();
} }
@ -133,26 +162,56 @@ public class FastContraptionRenderer extends ContraptionRenderer {
return renderer; return renderer;
} }
public static void renderAll(RenderWorldLastEvent event) { public static void renderAll(Matrix4f projectionMat, Matrix4f viewMat) {
removeDeadContraptions();
if (renderers.isEmpty()) return;
GameRenderer gameRenderer = Minecraft.getInstance().gameRenderer; GameRenderer gameRenderer = Minecraft.getInstance().gameRenderer;
CreateClient.kineticRenderer.setup(gameRenderer); FastKineticRenderer.setup(gameRenderer);
GlStateManager.enableCull(); GL11.glEnable(GL13.GL_TEXTURE_3D);
GL13.glActiveTexture(GL40.GL_TEXTURE4);
ShaderHelper.useShader(Shader.CONTRAPTION_STRUCTURE, ShaderHelper.getViewProjectionCallback(event)); ShaderCallback callback = ShaderHelper.getViewProjectionCallback(projectionMat, viewMat);
int shader = ShaderHelper.getShaderHandle(Shader.CONTRAPTION_STRUCTURE);
ArrayList<Integer> toRemove = new ArrayList<>();
int structureShader = ShaderHelper.useShader(Shader.CONTRAPTION_STRUCTURE, callback);
for (FastContraptionRenderer renderer : renderers.values()) { for (FastContraptionRenderer renderer : renderers.values()) {
if (renderer.c.entity.isAlive()) renderer.setup(structureShader);
renderer.render(shader); for (ContraptionBuffer layer : renderer.renderLayers) {
else layer.render();
toRemove.add(renderer.c.entity.getEntityId()); }
renderer.teardown();
}
int rotatingShader = ShaderHelper.useShader(Shader.CONTRAPTION_ROTATING, callback);
for (FastContraptionRenderer renderer : renderers.values()) {
renderer.setup(rotatingShader);
renderer.kinetics.renderRotating();
renderer.teardown();
}
int beltShader = ShaderHelper.useShader(Shader.CONTRAPTION_BELT, callback);
for (FastContraptionRenderer renderer : renderers.values()) {
renderer.setup(beltShader);
renderer.kinetics.renderBelts();
renderer.teardown();
} }
ShaderHelper.releaseShader(); ShaderHelper.releaseShader();
CreateClient.kineticRenderer.teardown(); GL11.glDisable(GL13.GL_TEXTURE_3D);
FastKineticRenderer.teardown();
}
public static void removeDeadContraptions() {
ArrayList<Integer> toRemove = new ArrayList<>();
for (FastContraptionRenderer renderer : renderers.values()) {
if (!renderer.c.entity.isAlive()) {
toRemove.add(renderer.c.entity.getEntityId());
renderer.invalidate();
}
}
for (Integer id : toRemove) { for (Integer id : toRemove) {
renderers.remove(id); renderers.remove(id);

View file

@ -3,9 +3,9 @@ package com.simibubi.create.foundation.utility.render;
import com.google.common.cache.Cache; import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheBuilder;
import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.matrix.MatrixStack;
import com.mojang.blaze3d.platform.GlStateManager;
import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.systems.RenderSystem;
import com.simibubi.create.AllBlockPartials; import com.simibubi.create.AllBlockPartials;
import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer;
import com.simibubi.create.foundation.utility.render.instancing.*; import com.simibubi.create.foundation.utility.render.instancing.*;
import com.simibubi.create.foundation.utility.render.shader.Shader; import com.simibubi.create.foundation.utility.render.shader.Shader;
import com.simibubi.create.foundation.utility.render.shader.ShaderCallback; import com.simibubi.create.foundation.utility.render.shader.ShaderCallback;
@ -21,7 +21,6 @@ import net.minecraft.inventory.container.PlayerContainer;
import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraftforge.client.event.RenderWorldLastEvent;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL13; import org.lwjgl.opengl.GL13;
@ -35,8 +34,8 @@ import java.util.function.Supplier;
import static com.simibubi.create.foundation.utility.render.SuperByteBufferCache.PARTIAL; import static com.simibubi.create.foundation.utility.render.SuperByteBufferCache.PARTIAL;
public class FastKineticRenderer { public class FastKineticRenderer {
Map<SuperByteBufferCache.Compartment<?>, Cache<Object, RotatingBuffer>> rotating; Map<SuperByteBufferCache.Compartment<?>, Cache<Object, InstanceBuffer<RotatingData>>> rotating;
Map<SuperByteBufferCache.Compartment<?>, Cache<Object, BeltBuffer>> belts; Map<SuperByteBufferCache.Compartment<?>, Cache<Object, InstanceBuffer<BeltData>>> belts;
boolean rebuild; boolean rebuild;
@ -46,6 +45,7 @@ public class FastKineticRenderer {
registerCompartment(SuperByteBufferCache.GENERIC_TILE); registerCompartment(SuperByteBufferCache.GENERIC_TILE);
registerCompartment(SuperByteBufferCache.PARTIAL); registerCompartment(SuperByteBufferCache.PARTIAL);
registerCompartment(SuperByteBufferCache.DIRECTIONAL_PARTIAL); registerCompartment(SuperByteBufferCache.DIRECTIONAL_PARTIAL);
registerCompartment(KineticTileEntityRenderer.KINETIC_TILE);
} }
public void buildTileEntityBuffers(World world) { public void buildTileEntityBuffers(World world) {
@ -65,66 +65,102 @@ public class FastKineticRenderer {
} }
} }
private <T extends TileEntity> void addInstancedData(T te, IInstancedTileEntityRenderer<T> renderer) { <T extends TileEntity> void addInstancedData(T te, IInstancedTileEntityRenderer<T> renderer) {
renderer.addInstanceData(te); renderer.addInstanceData(new InstanceContext.World<>(te));
}
<T extends TileEntity> void addInstancedData(FastContraptionRenderer c, T te, IInstancedTileEntityRenderer<T> renderer) {
renderer.addInstanceData(new InstanceContext.Contraption<>(te, c));
}
/**
* This function should be called after building instances.
* It must be called either on the render thread before committing to rendering, or in a place where there are
* guaranteed to be no race conditions with the render thread, i.e. when constructing a FastContraptionRenderer.
*/
public void markAllDirty() {
for (Cache<Object, InstanceBuffer<RotatingData>> cache : rotating.values()) {
for (InstanceBuffer<RotatingData> renderer : cache.asMap().values()) {
renderer.markDirty();
}
}
for (Cache<Object, InstanceBuffer<BeltData>> cache : belts.values()) {
for (InstanceBuffer<BeltData> renderer : cache.asMap().values()) {
renderer.markDirty();
}
}
} }
public void tick() { public void tick() {
// TODO: (later) detect changes in lighting with a mixin (or forge hook) to ClientChunkProvider.markLightChanged() // TODO: (later) detect changes in lighting with a mixin (or forge hook) to ClientChunkProvider.markLightChanged()
for (Cache<Object, RotatingBuffer> cache : rotating.values()) { for (Cache<Object, InstanceBuffer<RotatingData>> cache : rotating.values()) {
for (RotatingBuffer renderer : cache.asMap().values()) { for (InstanceBuffer<RotatingData> renderer : cache.asMap().values()) {
renderer.clearInstanceData(); renderer.clearInstanceData();
} }
} }
for (Cache<Object, BeltBuffer> cache : belts.values()) { for (Cache<Object, InstanceBuffer<BeltData>> cache : belts.values()) {
for (BeltBuffer renderer : cache.asMap().values()) { for (InstanceBuffer<BeltData> renderer : cache.asMap().values()) {
renderer.clearInstanceData(); renderer.clearInstanceData();
} }
} }
// rebuild = true; //buildTileEntityBuffers(Minecraft.getInstance().world);
rebuild = true;
} }
public void renderInstances(RenderWorldLastEvent event) { void renderBelts() {
for (Cache<Object, InstanceBuffer<BeltData>> cache : belts.values()) {
for (InstanceBuffer<BeltData> type : cache.asMap().values()) {
if (!type.isEmpty()) {
type.render();
}
}
}
}
void renderRotating() {
for (Cache<Object, InstanceBuffer<RotatingData>> cache : rotating.values()) {
for (InstanceBuffer<RotatingData> rotatingDataInstanceBuffer : cache.asMap().values()) {
if (!rotatingDataInstanceBuffer.isEmpty()) {
rotatingDataInstanceBuffer.render();
}
}
}
}
public void renderInstancesAsWorld(Matrix4f projection, Matrix4f view) {
GameRenderer gameRenderer = Minecraft.getInstance().gameRenderer; GameRenderer gameRenderer = Minecraft.getInstance().gameRenderer;
//
// if (rebuild) { if (rebuild) {
// buildTileEntityBuffers(Minecraft.getInstance().world); markAllDirty();
// rebuild = false; rebuild = false;
// } }
setup(gameRenderer); setup(gameRenderer);
ShaderCallback callback = ShaderHelper.getViewProjectionCallback(event); ShaderCallback callback = ShaderHelper.getViewProjectionCallback(projection, view);
ShaderHelper.useShader(Shader.ROTATING_INSTANCED, callback); ShaderHelper.useShader(Shader.ROTATING, callback);
renderRotating();
rotating.values() ShaderHelper.useShader(Shader.BELT, callback);
.stream() renderBelts();
.flatMap(cache -> cache.asMap().values().stream())
.filter(type -> !type.isEmpty())
.forEach(InstanceBuffer::render);
ShaderHelper.useShader(Shader.BELT_INSTANCED, callback);
belts.values()
.stream()
.flatMap(cache -> cache.asMap().values().stream())
.filter(type -> !type.isEmpty())
.forEach(InstanceBuffer::render);
ShaderHelper.releaseShader(); ShaderHelper.releaseShader();
teardown(); teardown();
} }
public void setup(GameRenderer gameRenderer) { public static void setup(GameRenderer gameRenderer) {
RenderSystem.enableBlend(); RenderSystem.enableBlend();
RenderSystem.blendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA); RenderSystem.defaultBlendFunc();
RenderSystem.enableLighting(); RenderSystem.enableLighting();
RenderSystem.enableDepthTest(); RenderSystem.enableDepthTest();
RenderSystem.enableCull();
GL11.glCullFace(GL11.GL_BACK); GL11.glCullFace(GL11.GL_BACK);
LightTexture lightManager = gameRenderer.getLightmapTextureManager(); LightTexture lightManager = gameRenderer.getLightmapTextureManager();
@ -149,9 +185,9 @@ public class FastKineticRenderer {
RenderSystem.enableTexture(); RenderSystem.enableTexture();
} }
public void teardown() { public static void teardown() {
GL13.glActiveTexture(GL40.GL_TEXTURE0 + 1); GL13.glActiveTexture(GL40.GL_TEXTURE1);
GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0); GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);
GL13.glActiveTexture(GL40.GL_TEXTURE0); GL13.glActiveTexture(GL40.GL_TEXTURE0);
@ -175,26 +211,26 @@ public class FastKineticRenderer {
belts.put(instance, CacheBuilder.newBuilder().expireAfterAccess(ticksUntilExpired * 50, TimeUnit.MILLISECONDS).build()); belts.put(instance, CacheBuilder.newBuilder().expireAfterAccess(ticksUntilExpired * 50, TimeUnit.MILLISECONDS).build());
} }
public RotatingBuffer renderPartialRotating(AllBlockPartials partial, BlockState referenceState) { public InstanceBuffer<RotatingData> renderPartialRotating(AllBlockPartials partial, BlockState referenceState) {
return getRotating(PARTIAL, partial, () -> rotatingInstancedRenderer(partial.get(), referenceState)); return getRotating(PARTIAL, partial, () -> rotatingInstancedRenderer(partial.get(), referenceState));
} }
public BeltBuffer renderPartialBelt(AllBlockPartials partial, BlockState referenceState) { public InstanceBuffer<BeltData> renderPartialBelt(AllBlockPartials partial, BlockState referenceState) {
return getBelt(PARTIAL, partial, () -> beltInstancedRenderer(partial.get(), referenceState)); return getBelt(PARTIAL, partial, () -> beltInstancedRenderer(partial.get(), referenceState));
} }
public RotatingBuffer renderDirectionalPartialInstanced(AllBlockPartials partial, BlockState referenceState, Direction dir, public InstanceBuffer<RotatingData> renderDirectionalPartialInstanced(AllBlockPartials partial, BlockState referenceState, Direction dir,
MatrixStack modelTransform) { MatrixStack modelTransform) {
return getRotating(SuperByteBufferCache.DIRECTIONAL_PARTIAL, Pair.of(dir, partial), return getRotating(SuperByteBufferCache.DIRECTIONAL_PARTIAL, Pair.of(dir, partial),
() -> rotatingInstancedRenderer(partial.get(), referenceState, modelTransform)); () -> rotatingInstancedRenderer(partial.get(), referenceState, modelTransform));
} }
public RotatingBuffer renderBlockInstanced(SuperByteBufferCache.Compartment<BlockState> compartment, BlockState toRender) { public InstanceBuffer<RotatingData> renderBlockInstanced(SuperByteBufferCache.Compartment<BlockState> compartment, BlockState toRender) {
return getRotating(compartment, toRender, () -> rotatingInstancedRenderer(toRender)); return getRotating(compartment, toRender, () -> rotatingInstancedRenderer(toRender));
} }
public <T> RotatingBuffer getRotating(SuperByteBufferCache.Compartment<T> compartment, T key, Supplier<RotatingBuffer> supplier) { public <T> InstanceBuffer<RotatingData> getRotating(SuperByteBufferCache.Compartment<T> compartment, T key, Supplier<InstanceBuffer<RotatingData>> supplier) {
Cache<Object, RotatingBuffer> compartmentCache = this.rotating.get(compartment); Cache<Object, InstanceBuffer<RotatingData>> compartmentCache = this.rotating.get(compartment);
try { try {
return compartmentCache.get(key, supplier::get); return compartmentCache.get(key, supplier::get);
} catch (ExecutionException e) { } catch (ExecutionException e) {
@ -203,8 +239,8 @@ public class FastKineticRenderer {
} }
} }
public <T> BeltBuffer getBelt(SuperByteBufferCache.Compartment<T> compartment, T key, Supplier<BeltBuffer> supplier) { public <T> InstanceBuffer<BeltData> getBelt(SuperByteBufferCache.Compartment<T> compartment, T key, Supplier<InstanceBuffer<BeltData>> supplier) {
Cache<Object, BeltBuffer> compartmentCache = this.belts.get(compartment); Cache<Object, InstanceBuffer<BeltData>> compartmentCache = this.belts.get(compartment);
try { try {
return compartmentCache.get(key, supplier::get); return compartmentCache.get(key, supplier::get);
} catch (ExecutionException e) { } catch (ExecutionException e) {
@ -214,40 +250,40 @@ public class FastKineticRenderer {
} }
private RotatingBuffer rotatingInstancedRenderer(BlockState renderedState) { private InstanceBuffer<RotatingData> rotatingInstancedRenderer(BlockState renderedState) {
BlockRendererDispatcher dispatcher = Minecraft.getInstance().getBlockRendererDispatcher(); BlockRendererDispatcher dispatcher = Minecraft.getInstance().getBlockRendererDispatcher();
return rotatingInstancedRenderer(dispatcher.getModelForState(renderedState), renderedState); return rotatingInstancedRenderer(dispatcher.getModelForState(renderedState), renderedState);
} }
private RotatingBuffer rotatingInstancedRenderer(IBakedModel model, BlockState renderedState) { private InstanceBuffer<RotatingData> rotatingInstancedRenderer(IBakedModel model, BlockState renderedState) {
return rotatingInstancedRenderer(model, renderedState, new MatrixStack()); return rotatingInstancedRenderer(model, renderedState, new MatrixStack());
} }
private BeltBuffer beltInstancedRenderer(IBakedModel model, BlockState renderedState) { private InstanceBuffer<BeltData> beltInstancedRenderer(IBakedModel model, BlockState renderedState) {
return beltInstancedRenderer(model, renderedState, new MatrixStack()); return beltInstancedRenderer(model, renderedState, new MatrixStack());
} }
private RotatingBuffer rotatingInstancedRenderer(IBakedModel model, BlockState referenceState, MatrixStack ms) { private InstanceBuffer<RotatingData> rotatingInstancedRenderer(IBakedModel model, BlockState referenceState, MatrixStack ms) {
BufferBuilder builder = SuperByteBufferCache.getBufferBuilder(model, referenceState, ms); BufferBuilder builder = SuperByteBufferCache.getBufferBuilder(model, referenceState, ms);
return new RotatingBuffer(builder); return new RotatingBuffer(builder);
} }
private BeltBuffer beltInstancedRenderer(IBakedModel model, BlockState referenceState, MatrixStack ms) { private InstanceBuffer<BeltData> beltInstancedRenderer(IBakedModel model, BlockState referenceState, MatrixStack ms) {
BufferBuilder builder = SuperByteBufferCache.getBufferBuilder(model, referenceState, ms); BufferBuilder builder = SuperByteBufferCache.getBufferBuilder(model, referenceState, ms);
return new BeltBuffer(builder); return new BeltBuffer(builder);
} }
public void invalidate() { public void invalidate() {
rotating.values().forEach(cache -> { for (Cache<Object, InstanceBuffer<RotatingData>> objectInstanceBufferCache : rotating.values()) {
cache.asMap().values().forEach(InstanceBuffer::delete); objectInstanceBufferCache.asMap().values().forEach(InstanceBuffer::delete);
cache.invalidateAll(); objectInstanceBufferCache.invalidateAll();
}); }
belts.values().forEach(cache -> { for (Cache<Object, InstanceBuffer<BeltData>> cache : belts.values()) {
cache.asMap().values().forEach(InstanceBuffer::delete); cache.asMap().values().forEach(InstanceBuffer::delete);
cache.invalidateAll(); cache.invalidateAll();
}); }
} }
} }

View file

@ -0,0 +1,172 @@
package com.simibubi.create.foundation.utility.render;
import net.minecraft.client.renderer.GLAllocation;
import org.lwjgl.system.MemoryStack;
import org.lwjgl.system.MemoryUtil;
import sun.misc.Cleaner;
import sun.nio.ch.DirectBuffer;
import java.nio.*;
public class SafeDirectBuffer implements AutoCloseable {
private ByteBuffer wrapped;
public SafeDirectBuffer(int capacity) {
this.wrapped = GLAllocation.createDirectByteBuffer(capacity);
}
public void close() throws Exception {
if (wrapped instanceof DirectBuffer) {
Cleaner cleaner = ((DirectBuffer) wrapped).cleaner();
if (!cleaner.isEnqueued()) {
cleaner.clean();
cleaner.enqueue();
}
}
}
/**
* Only use this function to pass information to OpenGL.
*/
@Deprecated
public ByteBuffer getBacking() {
return wrapped;
}
public void order(ByteOrder bo) {
wrapped.order(bo);
}
public void limit(int limit) {
wrapped.limit(limit);
}
public void rewind() {
wrapped.rewind();
}
public byte get() {
return wrapped.get();
}
public ByteBuffer put(byte b) {
return wrapped.put(b);
}
public byte get(int index) {
return wrapped.get();
}
public ByteBuffer put(int index, byte b) {
return wrapped.put(index, b);
}
public ByteBuffer compact() {
return wrapped.compact();
}
public boolean isReadOnly() {
return wrapped.isReadOnly();
}
public boolean isDirect() {
return wrapped.isDirect();
}
public char getChar() {
return wrapped.getChar();
}
public ByteBuffer putChar(char value) {
return wrapped.putChar(value);
}
public char getChar(int index) {
return wrapped.getChar(index);
}
public ByteBuffer putChar(int index, char value) {
return wrapped.putChar(index, value);
}
public short getShort() {
return wrapped.getShort();
}
public ByteBuffer putShort(short value) {
return wrapped.putShort(value);
}
public short getShort(int index) {
return wrapped.getShort(index);
}
public ByteBuffer putShort(int index, short value) {
return wrapped.putShort(index, value);
}
public int getInt() {
return wrapped.getInt();
}
public ByteBuffer putInt(int value) {
return wrapped.putInt(value);
}
public int getInt(int index) {
return wrapped.getInt(index);
}
public ByteBuffer putInt(int index, int value) {
return wrapped.putInt(index, value);
}
public long getLong() {
return wrapped.getLong();
}
public ByteBuffer putLong(long value) {
return wrapped.putLong(value);
}
public long getLong(int index) {
return wrapped.getLong(index);
}
public ByteBuffer putLong(int index, long value) {
return wrapped.putLong(index, value);
}
public float getFloat() {
return wrapped.getFloat();
}
public ByteBuffer putFloat(float value) {
return wrapped.putFloat(value);
}
public float getFloat(int index) {
return wrapped.getFloat(index);
}
public ByteBuffer putFloat(int index, float value) {
return wrapped.putFloat(index, value);
}
public double getDouble() {
return wrapped.getDouble();
}
public ByteBuffer putDouble(double value) {
return wrapped.putDouble(value);
}
public double getDouble(int index) {
return wrapped.getDouble(index);
}
public ByteBuffer putDouble(int index, double value) {
return wrapped.putDouble(index, value);
}
}

View file

@ -1,8 +1,10 @@
package com.simibubi.create.foundation.utility.render; package com.simibubi.create.foundation.utility.render;
import com.mojang.blaze3d.platform.GlStateManager;
import com.mojang.datafixers.util.Pair; import com.mojang.datafixers.util.Pair;
import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.GLAllocation; import net.minecraft.client.renderer.vertex.VertexFormatElement;
import org.lwjgl.opengl.GL15;
import java.nio.Buffer; import java.nio.Buffer;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
@ -11,7 +13,7 @@ import java.nio.ByteOrder;
public class TemplateBuffer { public class TemplateBuffer {
protected ByteBuffer template; protected ByteBuffer template;
protected int formatSize; protected int formatSize;
protected int count; protected int vertexCount;
public TemplateBuffer(BufferBuilder buf) { public TemplateBuffer(BufferBuilder buf) {
Pair<BufferBuilder.DrawState, ByteBuffer> state = buf.popData(); Pair<BufferBuilder.DrawState, ByteBuffer> state = buf.popData();
@ -20,8 +22,8 @@ public class TemplateBuffer {
formatSize = buf.getVertexFormat() formatSize = buf.getVertexFormat()
.getSize(); .getSize();
count = state.getFirst().getCount(); vertexCount = state.getFirst().getCount();
int size = count * formatSize; int size = vertexCount * formatSize;
template = ByteBuffer.allocate(size); template = ByteBuffer.allocate(size);
template.order(rendered.order()); template.order(rendered.order());
@ -30,6 +32,22 @@ public class TemplateBuffer {
((Buffer)template).rewind(); ((Buffer)template).rewind();
} }
protected void buildEBO(int ebo) throws Exception {
int indicesSize = vertexCount * VertexFormatElement.Type.USHORT.getSize();
try (SafeDirectBuffer indices = new SafeDirectBuffer(indicesSize)) {
indices.order(template.order());
indices.limit(indicesSize);
for (int i = 0; i < vertexCount; i++) {
indices.putShort((short) i);
}
indices.rewind();
GlStateManager.bindBuffers(GL15.GL_ELEMENT_ARRAY_BUFFER, ebo);
GlStateManager.bufferData(GL15.GL_ELEMENT_ARRAY_BUFFER, indices.getBacking(), GL15.GL_STATIC_DRAW);
}
}
public boolean isEmpty() { public boolean isEmpty() {
return ((Buffer) template).limit() == 0; return ((Buffer) template).limit() == 0;
} }

View file

@ -7,6 +7,7 @@ import com.simibubi.create.Create;
import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.config.AllConfigs;
import com.simibubi.create.foundation.utility.MatrixStacker; import com.simibubi.create.foundation.utility.MatrixStacker;
import com.simibubi.create.foundation.utility.render.instancing.IInstanceRendered;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.IRenderTypeBuffer;
import net.minecraft.client.renderer.Matrix4f; import net.minecraft.client.renderer.Matrix4f;
@ -30,6 +31,8 @@ public class TileEntityRenderHelper {
for (Iterator<TileEntity> iterator = customRenderTEs.iterator(); iterator.hasNext();) { for (Iterator<TileEntity> iterator = customRenderTEs.iterator(); iterator.hasNext();) {
TileEntity tileEntity = iterator.next(); TileEntity tileEntity = iterator.next();
if (tileEntity instanceof IInstanceRendered) continue; // TODO: some things still need to render
TileEntityRenderer<TileEntity> renderer = TileEntityRendererDispatcher.instance.getRenderer(tileEntity); TileEntityRenderer<TileEntity> renderer = TileEntityRendererDispatcher.instance.getRenderer(tileEntity);
if (renderer == null) { if (renderer == null) {
iterator.remove(); iterator.remove();

View file

@ -1,10 +1,9 @@
package com.simibubi.create.foundation.utility.render.instancing; package com.simibubi.create.foundation.utility.render.instancing;
import com.simibubi.create.foundation.utility.render.SafeDirectBuffer;
import net.minecraft.client.renderer.Vector3f; import net.minecraft.client.renderer.Vector3f;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import java.nio.ByteBuffer;
public class BasicData<D extends BasicData<D>> extends InstanceData { public class BasicData<D extends BasicData<D>> extends InstanceData {
private float x; private float x;
@ -38,7 +37,7 @@ public class BasicData<D extends BasicData<D>> extends InstanceData {
} }
@Override @Override
public void write(ByteBuffer buf) { public void write(SafeDirectBuffer buf) {
putVec3(buf, x, y, z); putVec3(buf, x, y, z);
putVec2(buf, blockLight, skyLight); putVec2(buf, blockLight, skyLight);

View file

@ -1,10 +1,8 @@
package com.simibubi.create.foundation.utility.render.instancing; package com.simibubi.create.foundation.utility.render.instancing;
import com.simibubi.create.foundation.block.render.SpriteShiftEntry; import com.simibubi.create.foundation.block.render.SpriteShiftEntry;
import com.simibubi.create.foundation.utility.render.SafeDirectBuffer;
import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.util.math.BlockPos;
import java.nio.ByteBuffer;
import static com.simibubi.create.foundation.utility.render.instancing.VertexAttribute.*; import static com.simibubi.create.foundation.utility.render.instancing.VertexAttribute.*;
@ -55,7 +53,7 @@ public class BeltData extends BasicData<BeltData> {
} }
@Override @Override
public void write(ByteBuffer buf) { public void write(SafeDirectBuffer buf) {
super.write(buf); super.write(buf);
putVec3(buf, rotX, rotY, rotZ); putVec3(buf, rotX, rotY, rotZ);

View file

@ -1,13 +1,19 @@
package com.simibubi.create.foundation.utility.render.instancing; package com.simibubi.create.foundation.utility.render.instancing;
import com.simibubi.create.AllBlockPartials;
import com.simibubi.create.content.contraptions.components.structureMovement.Contraption;
import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer; import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer;
import com.simibubi.create.foundation.utility.render.FastContraptionRenderer;
import net.minecraft.block.BlockState;
import net.minecraft.client.renderer.tileentity.TileEntityRenderer; import net.minecraft.client.renderer.tileentity.TileEntityRenderer;
import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher;
import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntity;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier; import java.util.function.Supplier;
public interface IInstancedTileEntityRenderer<T extends TileEntity> { public interface IInstancedTileEntityRenderer<T extends TileEntity> {
void addInstanceData(T te); void addInstanceData(InstanceContext<T> te);
} }

View file

@ -2,17 +2,12 @@ package com.simibubi.create.foundation.utility.render.instancing;
import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.platform.GlStateManager;
import com.simibubi.create.CreateClient;
import com.simibubi.create.foundation.utility.render.RenderWork; import com.simibubi.create.foundation.utility.render.RenderWork;
import com.simibubi.create.foundation.utility.render.SafeDirectBuffer;
import com.simibubi.create.foundation.utility.render.TemplateBuffer; import com.simibubi.create.foundation.utility.render.TemplateBuffer;
import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.GLAllocation;
import net.minecraft.client.renderer.vertex.VertexFormatElement;
import org.lwjgl.opengl.*; import org.lwjgl.opengl.*;
import org.lwjgl.system.MemoryUtil;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.function.Consumer; import java.util.function.Consumer;
@ -24,60 +19,53 @@ public abstract class InstanceBuffer<D extends InstanceData> extends TemplateBuf
protected int vao, ebo, invariantVBO, instanceVBO, instanceCount; protected int vao, ebo, invariantVBO, instanceVBO, instanceCount;
protected final ArrayList<D> data = new ArrayList<>(); protected final ArrayList<D> data = new ArrayList<>();
protected boolean rebuffer = false;
protected boolean shouldBuild = true; protected boolean shouldBuild = true;
public InstanceBuffer(BufferBuilder buf) { public InstanceBuffer(BufferBuilder buf) {
super(buf); super(buf);
setupMainData(); setup();
} }
private void setupMainData() { private void setup() {
int stride = FORMAT.getStride(); int stride = FORMAT.getStride();
int invariantSize = count * stride;
ByteBuffer constant = GLAllocation.createDirectByteBuffer(invariantSize); int invariantSize = vertexCount * stride;
vao = GL30.glGenVertexArrays();
ebo = GlStateManager.genBuffers();
invariantVBO = GlStateManager.genBuffers();
instanceVBO = GlStateManager.genBuffers();
try (SafeDirectBuffer constant = new SafeDirectBuffer(invariantSize)) {
constant.order(template.order()); constant.order(template.order());
((Buffer) constant).limit(invariantSize); constant.limit(invariantSize);
int indicesSize = count * VertexFormatElement.Type.USHORT.getSize();
ByteBuffer indices = GLAllocation.createDirectByteBuffer(indicesSize);
indices.order(template.order());
((Buffer) indices).limit(indicesSize);
int vertexCount = vertexCount(template);
for (int i = 0; i < vertexCount; i++) { for (int i = 0; i < vertexCount; i++) {
constant.putFloat(getX(template, i)); constant.putFloat(getX(template, i));
constant.putFloat(getY(template, i)); constant.putFloat(getY(template, i));
constant.putFloat(getZ(template, i)); constant.putFloat(getZ(template, i));
constant.putFloat(getNX(template, i)); constant.put(getNX(template, i));
constant.putFloat(getNY(template, i)); constant.put(getNY(template, i));
constant.putFloat(getNZ(template, i)); constant.put(getNZ(template, i));
constant.putFloat(getU(template, i)); constant.putFloat(getU(template, i));
constant.putFloat(getV(template, i)); constant.putFloat(getV(template, i));
indices.putShort((short) i);
} }
constant.rewind(); constant.rewind();
indices.rewind();
vao = GL30.glGenVertexArrays();
GL30.glBindVertexArray(vao); GL30.glBindVertexArray(vao);
ebo = GlStateManager.genBuffers();
invariantVBO = GlStateManager.genBuffers();
instanceVBO = GlStateManager.genBuffers();
GlStateManager.bindBuffers(GL15.GL_ARRAY_BUFFER, invariantVBO); GlStateManager.bindBuffers(GL15.GL_ARRAY_BUFFER, invariantVBO);
GlStateManager.bufferData(GL15.GL_ARRAY_BUFFER, constant, GL15.GL_STATIC_DRAW); GlStateManager.bufferData(GL15.GL_ARRAY_BUFFER, constant.getBacking(), GL15.GL_STATIC_DRAW);
MemoryUtil.memFree(constant);
GlStateManager.bindBuffers(GL15.GL_ELEMENT_ARRAY_BUFFER, ebo); buildEBO(ebo);
GlStateManager.bufferData(GL15.GL_ELEMENT_ARRAY_BUFFER, indices, GL15.GL_STATIC_DRAW);
MemoryUtil.memFree(indices);
FORMAT.informAttributes(0); FORMAT.informAttributes(0);
} catch (Exception e) {
delete();
}
GlStateManager.bindBuffers(GL15.GL_ARRAY_BUFFER, 0); GlStateManager.bindBuffers(GL15.GL_ARRAY_BUFFER, 0);
GlStateManager.bindBuffers(GL15.GL_ELEMENT_ARRAY_BUFFER, 0); GlStateManager.bindBuffers(GL15.GL_ELEMENT_ARRAY_BUFFER, 0);
@ -88,7 +76,7 @@ public abstract class InstanceBuffer<D extends InstanceData> extends TemplateBuf
protected abstract VertexFormat getInstanceFormat(); protected abstract VertexFormat getInstanceFormat();
public int numInstances() { public int numInstances() {
return instanceCount; return instanceCount + data.size();
} }
public boolean isEmpty() { public boolean isEmpty() {
@ -100,14 +88,20 @@ public abstract class InstanceBuffer<D extends InstanceData> extends TemplateBuf
shouldBuild = true; shouldBuild = true;
} }
public void markDirty() {
rebuffer = true;
}
public void delete() { public void delete() {
RenderWork.enqueue(() -> { RenderWork.enqueue(() -> {
GL15.glDeleteBuffers(invariantVBO); GL15.glDeleteBuffers(invariantVBO);
GL15.glDeleteBuffers(instanceVBO); GL15.glDeleteBuffers(instanceVBO);
GL15.glDeleteBuffers(ebo); GL15.glDeleteBuffers(ebo);
GL30.glDeleteVertexArrays(vao); GL30.glDeleteVertexArrays(vao);
vao = 0;
clearInstanceData(); ebo = 0;
invariantVBO = 0;
instanceVBO = 0;
}); });
} }
@ -120,10 +114,10 @@ public abstract class InstanceBuffer<D extends InstanceData> extends TemplateBuf
setup.accept(instanceData); setup.accept(instanceData);
data.add(instanceData); data.add(instanceData);
instanceCount++;
} }
public void render() { public void render() {
if (vao == 0) return;
GL30.glBindVertexArray(vao); GL30.glBindVertexArray(vao);
finishBuffering(); finishBuffering();
@ -135,7 +129,7 @@ public abstract class InstanceBuffer<D extends InstanceData> extends TemplateBuf
GlStateManager.bindBuffers(GL15.GL_ELEMENT_ARRAY_BUFFER, ebo); GlStateManager.bindBuffers(GL15.GL_ELEMENT_ARRAY_BUFFER, ebo);
GL40.glDrawElementsInstanced(GL11.GL_QUADS, count, GL11.GL_UNSIGNED_SHORT, 0, instanceCount); GL40.glDrawElementsInstanced(GL11.GL_QUADS, vertexCount, GL11.GL_UNSIGNED_SHORT, 0, instanceCount);
for (int i = 0; i <= numAttributes; i++) { for (int i = 0; i <= numAttributes; i++) {
GL40.glDisableVertexAttribArray(i); GL40.glDisableVertexAttribArray(i);
@ -146,21 +140,23 @@ public abstract class InstanceBuffer<D extends InstanceData> extends TemplateBuf
} }
private void finishBuffering() { private void finishBuffering() {
if (!shouldBuild) return; if (!rebuffer || isEmpty()) return;
instanceCount = data.size();
VertexFormat instanceFormat = getInstanceFormat(); VertexFormat instanceFormat = getInstanceFormat();
int instanceSize = instanceCount * instanceFormat.getStride(); int instanceSize = instanceCount * instanceFormat.getStride();
ByteBuffer buffer = GLAllocation.createDirectByteBuffer(instanceSize); try (SafeDirectBuffer buffer = new SafeDirectBuffer(instanceSize)) {
buffer.order(template.order()); buffer.order(template.order());
((Buffer) buffer).limit(instanceSize); buffer.limit(instanceSize);
data.forEach(instanceData -> instanceData.write(buffer)); data.forEach(instanceData -> instanceData.write(buffer));
buffer.rewind(); buffer.rewind();
GlStateManager.bindBuffers(GL15.GL_ARRAY_BUFFER, instanceVBO); GlStateManager.bindBuffers(GL15.GL_ARRAY_BUFFER, instanceVBO);
GlStateManager.bufferData(GL15.GL_ARRAY_BUFFER, buffer, GL15.GL_STATIC_DRAW); GlStateManager.bufferData(GL15.GL_ARRAY_BUFFER, buffer.getBacking(), GL15.GL_STATIC_DRAW);
int staticAttributes = FORMAT.getNumAttributes(); int staticAttributes = FORMAT.getNumAttributes();
instanceFormat.informAttributes(staticAttributes); instanceFormat.informAttributes(staticAttributes);
@ -168,11 +164,15 @@ public abstract class InstanceBuffer<D extends InstanceData> extends TemplateBuf
for (int i = 0; i < instanceFormat.getNumAttributes(); i++) { for (int i = 0; i < instanceFormat.getNumAttributes(); i++) {
GL40.glVertexAttribDivisor(i + staticAttributes, 1); GL40.glVertexAttribDivisor(i + staticAttributes, 1);
} }
} catch (Exception e) {
}
// Deselect (bind to 0) the VBO // Deselect (bind to 0) the VBO
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0); GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
shouldBuild = false; shouldBuild = false;
rebuffer = false;
data.clear(); data.clear();
} }
} }

View file

@ -0,0 +1,56 @@
package com.simibubi.create.foundation.utility.render.instancing;
import com.simibubi.create.CreateClient;
import com.simibubi.create.foundation.utility.render.FastContraptionRenderer;
import com.simibubi.create.foundation.utility.render.FastKineticRenderer;
import net.minecraft.tileentity.TileEntity;
public abstract class InstanceContext<T extends TileEntity> {
public final T te;
public InstanceContext(T te) {
this.te = te;
}
public abstract FastKineticRenderer getKinetics();
public abstract boolean checkWorldLight();
public static class Contraption<T extends TileEntity> extends InstanceContext<T> {
public final FastContraptionRenderer c;
public Contraption(T te, FastContraptionRenderer c) {
super(te);
this.c = c;
}
@Override
public FastKineticRenderer getKinetics() {
return c.kinetics;
}
@Override
public boolean checkWorldLight() {
return false;
}
}
public static class World<T extends TileEntity> extends InstanceContext<T> {
public World(T te) {
super(te);
}
@Override
public FastKineticRenderer getKinetics() {
return CreateClient.kineticRenderer;
}
@Override
public boolean checkWorldLight() {
return true;
}
}
}

View file

@ -1,30 +1,32 @@
package com.simibubi.create.foundation.utility.render.instancing; package com.simibubi.create.foundation.utility.render.instancing;
import com.simibubi.create.foundation.utility.render.SafeDirectBuffer;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
public abstract class InstanceData { public abstract class InstanceData {
public abstract void write(ByteBuffer buf); public abstract void write(SafeDirectBuffer buf);
public void putVec4(ByteBuffer buf, float x, float y, float z, float w) { public void putVec4(SafeDirectBuffer buf, float x, float y, float z, float w) {
putFloat(buf, x); putFloat(buf, x);
putFloat(buf, y); putFloat(buf, y);
putFloat(buf, z); putFloat(buf, z);
putFloat(buf, w); putFloat(buf, w);
} }
public void putVec3(ByteBuffer buf, float x, float y, float z) { public void putVec3(SafeDirectBuffer buf, float x, float y, float z) {
putFloat(buf, x); putFloat(buf, x);
putFloat(buf, y); putFloat(buf, y);
putFloat(buf, z); putFloat(buf, z);
} }
public void putVec2(ByteBuffer buf, float x, float y) { public void putVec2(SafeDirectBuffer buf, float x, float y) {
putFloat(buf, x); putFloat(buf, x);
putFloat(buf, y); putFloat(buf, y);
} }
public void putFloat(ByteBuffer buf, float f) { public void putFloat(SafeDirectBuffer buf, float f) {
buf.putFloat(f); buf.putFloat(f);
} }
} }

View file

@ -1,9 +1,7 @@
package com.simibubi.create.foundation.utility.render.instancing; package com.simibubi.create.foundation.utility.render.instancing;
import com.simibubi.create.foundation.utility.render.SafeDirectBuffer;
import net.minecraft.client.renderer.Vector3f; import net.minecraft.client.renderer.Vector3f;
import net.minecraft.util.math.BlockPos;
import java.nio.ByteBuffer;
import static com.simibubi.create.foundation.utility.render.instancing.VertexAttribute.*; import static com.simibubi.create.foundation.utility.render.instancing.VertexAttribute.*;
@ -41,7 +39,7 @@ public class RotatingData extends BasicData<RotatingData> {
} }
@Override @Override
public void write(ByteBuffer buf) { public void write(SafeDirectBuffer buf) {
super.write(buf); super.write(buf);
putFloat(buf, rotationalSpeed); putFloat(buf, rotationalSpeed);
putFloat(buf, rotationOffset); putFloat(buf, rotationOffset);

View file

@ -11,8 +11,8 @@ public class VertexAttribute {
public static final VertexAttribute FLOAT = new VertexAttribute(VertexFormatElement.Type.FLOAT, 1); public static final VertexAttribute FLOAT = new VertexAttribute(VertexFormatElement.Type.FLOAT, 1);
public static final VertexAttribute POSITION = VEC3; public static final VertexAttribute POSITION = VEC3;
public static final VertexAttribute NORMAL = VEC3; public static final VertexAttribute NORMAL = new VertexAttribute(VertexFormatElement.Type.BYTE, 3);
public static final VertexAttribute COLOR = VEC4; public static final VertexAttribute COLOR = new VertexAttribute(VertexFormatElement.Type.BYTE, 4);
public static final VertexAttribute UV = VEC2; public static final VertexAttribute UV = VEC2;
public static final VertexAttribute LIGHT= VEC2; public static final VertexAttribute LIGHT= VEC2;

View file

@ -1,9 +1,11 @@
package com.simibubi.create.foundation.utility.render.shader; package com.simibubi.create.foundation.utility.render.shader;
public enum Shader { public enum Shader {
ROTATING_INSTANCED("shader/rotating.vert", "shader/instanced.frag"), ROTATING("shader/rotating.vert", "shader/instanced.frag"),
BELT_INSTANCED("shader/belt.vert", "shader/instanced.frag"), BELT("shader/belt.vert", "shader/instanced.frag"),
CONTRAPTION_STRUCTURE("shader/contraption.vert", "shader/contraption.frag"), CONTRAPTION_STRUCTURE("shader/contraption.vert", "shader/contraption.frag"),
CONTRAPTION_ROTATING("shader/contraption_rotating.vert", "shader/contraption.frag"),
CONTRAPTION_BELT("shader/contraption_belt.vert", "shader/contraption.frag"),
; ;
public final String vert; public final String vert;

View file

@ -58,34 +58,28 @@ public class ShaderHelper {
return shaderProgram.getProgram(); return shaderProgram.getProgram();
} }
public static ShaderCallback getViewProjectionCallback(RenderWorldLastEvent event) { public static ShaderCallback getViewProjectionCallback(Matrix4f projectionMat, Matrix4f viewMat) {
return shader -> { return shader -> {
ShaderHelper.MATRIX_BUFFER.position(0); ShaderHelper.MATRIX_BUFFER.position(0);
event.getProjectionMatrix().write(ShaderHelper.MATRIX_BUFFER); projectionMat.write(ShaderHelper.MATRIX_BUFFER);
int projection = GlStateManager.getUniformLocation(shader, "projection"); int projection = GlStateManager.getUniformLocation(shader, "projection");
GlStateManager.uniformMatrix4(projection, false, ShaderHelper.MATRIX_BUFFER); GlStateManager.uniformMatrix4(projection, false, ShaderHelper.MATRIX_BUFFER);
// view matrix
Vec3d pos = Minecraft.getInstance().gameRenderer.getActiveRenderInfo().getProjectedView();
Matrix4f translate = Matrix4f.translate((float) -pos.x, (float) -pos.y, (float) -pos.z);
translate.multiplyBackward(event.getMatrixStack().peek().getModel());
ShaderHelper.MATRIX_BUFFER.position(0); ShaderHelper.MATRIX_BUFFER.position(0);
translate.write(ShaderHelper.MATRIX_BUFFER); viewMat.write(ShaderHelper.MATRIX_BUFFER);
int view = GlStateManager.getUniformLocation(shader, "view"); int view = GlStateManager.getUniformLocation(shader, "view");
GlStateManager.uniformMatrix4(view, false, ShaderHelper.MATRIX_BUFFER); GlStateManager.uniformMatrix4(view, false, ShaderHelper.MATRIX_BUFFER);
}; };
} }
public static void useShader(Shader shader) { public static int useShader(Shader shader) {
useShader(shader, null); return useShader(shader, null);
} }
public static void useShader(Shader shader, @Nullable ShaderCallback cb) { public static int useShader(Shader shader, @Nullable ShaderCallback cb) {
ShaderProgram prog = PROGRAMS.get(shader); ShaderProgram prog = PROGRAMS.get(shader);
if (prog == null) { if (prog == null) {
return; return -1;
} }
int program = prog.getProgram(); int program = prog.getProgram();
@ -102,6 +96,8 @@ public class ShaderHelper {
if (cb != null) { if (cb != null) {
cb.call(program); cb.call(program);
} }
return program;
} }
public static void releaseShader() { public static void releaseShader() {

View file

@ -16,7 +16,6 @@ vec4 light() {
return texture2D(LightMap, lm); return texture2D(LightMap, lm);
} }
void main() { void main() {
vec4 tex = texture2D(BlockAtlas, TexCoords); vec4 tex = texture2D(BlockAtlas, TexCoords);

View file

@ -21,8 +21,7 @@ uniform int ticks;
uniform mat4 projection; uniform mat4 projection;
uniform mat4 view; uniform mat4 view;
mat4 rotate(vec3 axis, float angle) mat4 rotate(vec3 axis, float angle) {
{
float s = sin(angle); float s = sin(angle);
float c = cos(angle); float c = cos(angle);
float oc = 1.0 - c; float oc = 1.0 - c;
@ -47,18 +46,11 @@ float diffuse(vec3 normal) {
void main() { void main() {
mat4 rotation = contraptionRotation(); mat4 rotation = contraptionRotation();
vec4 worldPos = (rotation * vec4(aPos - vec3(0.5), 1)) + vec4(cPos + vec3(0.5), 0);
vec4 rotatedPos = rotation * vec4(aPos - vec3(0.5), 1); BoxCoord = (worldPos.xyz - lightBoxMin) / lightBoxSize;
Diffuse = diffuse(normalize(rotation * vec4(aNormal, 0.)).xyz);
vec4 worldPos = rotatedPos + vec4(cPos + vec3(0.5), 0); Color = aColor;
vec3 boxCoord = (worldPos.xyz - lightBoxMin) / lightBoxSize;
float df = diffuse(normalize(aNormal));
Diffuse = diffuse(normalize((rotation * vec4(aNormal, 0.)).xyz));
Color = vec4(aColor.rgb / df, aColor.a);
BoxCoord = boxCoord;
TexCoords = aTexCoords; TexCoords = aTexCoords;
gl_Position = projection * view * worldPos; gl_Position = projection * view * worldPos;
} }

View file

@ -0,0 +1,79 @@
#version 330 core
#define PI 3.1415926538
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;
layout (location = 2) in vec2 aTexCoords;
layout (location = 3) in vec3 instancePos;
layout (location = 4) in vec2 light;
layout (location = 5) in vec3 rotationDegrees;
layout (location = 6) in float speed;
layout (location = 7) in vec2 sourceUV;
layout (location = 8) in vec4 scrollTexture;
layout (location = 9) in float scrollMult;
out float Diffuse;
out vec2 TexCoords;
out vec4 Color;
out vec3 BoxCoord;
uniform vec3 lightBoxSize;
uniform vec3 lightBoxMin;
uniform vec3 cPos;
uniform vec3 cRot;
uniform float time;
uniform int ticks;
uniform mat4 projection;
uniform mat4 view;
mat4 rotate(vec3 axis, float angle)
{
float s = sin(angle);
float c = cos(angle);
float oc = 1.0 - 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.);
}
mat4 rotation(vec3 rot) {
return rotate(vec3(0, 1, 0), rot.y) * rotate(vec3(0, 0, 1), rot.z) * rotate(vec3(1, 0, 0), rot.x);
}
mat4 contraptionRotation() {
vec3 rot = -fract(cRot / 360) * PI * 2;
return rotation(rot);
}
mat4 localRotation() {
vec3 rot = fract(rotationDegrees / 360) * PI * 2;
return rotation(rot);
}
float diffuse(vec3 normal) {
float x = normal.x;
float y = normal.y;
float z = normal.z;
return min(x * x * 0.6f + y * y * ((3f + y) / 4f) + z * z * 0.8f, 1f);
}
void main() {
mat4 localRotation = localRotation();
vec4 localPos = localRotation * vec4(aPos - 0.5, 1f) + vec4(instancePos, 0);
mat4 contraptionRotation = contraptionRotation();
vec4 worldPos = contraptionRotation * localPos + vec4(cPos + 0.5, 0);
float scrollSize = scrollTexture.w - scrollTexture.y;
float scroll = fract(speed * time / (36 * 16.)) * scrollSize * scrollMult;
BoxCoord = (worldPos.xyz - lightBoxMin) / lightBoxSize;
Diffuse = diffuse(normalize(contraptionRotation * localRotation * vec4(aNormal, 0.)).xyz);
Color = vec4(1.);
TexCoords = aTexCoords - sourceUV + scrollTexture.xy + vec2(0., scroll);
gl_Position = projection * view * worldPos;
}

View file

@ -0,0 +1,71 @@
#version 330 core
#define PI 3.1415926538
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;
layout (location = 2) in vec2 aTexCoords;
layout (location = 3) in vec3 instancePos;
layout (location = 4) in vec2 light;
layout (location = 5) in float speed;
layout (location = 6) in float rotationOffset;
layout (location = 7) in vec3 rotationAxis;
out float Diffuse;
out vec2 TexCoords;
out vec4 Color;
out vec3 BoxCoord;
uniform vec3 lightBoxSize;
uniform vec3 lightBoxMin;
uniform vec3 cPos;
uniform vec3 cRot;
uniform float time;
uniform int ticks;
uniform mat4 projection;
uniform mat4 view;
mat4 rotate(vec3 axis, float angle) {
float s = sin(angle);
float c = cos(angle);
float oc = 1.0 - 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.);
}
mat4 kineticRotation() {
float degrees = rotationOffset + time * speed * -3./10.;
float angle = fract(degrees / 360.) * PI * 2.;
vec3 axis = normalize(rotationAxis);
return rotate(axis, angle);
}
mat4 contraptionRotation() {
vec3 rot = -fract(cRot / 360) * PI * 2;
return rotate(vec3(0, 1, 0), rot.y) * rotate(vec3(0, 0, 1), rot.z) * rotate(vec3(1, 0, 0), rot.x);
}
float diffuse(vec3 normal) {
float x = normal.x;
float y = normal.y;
float z = normal.z;
return min(x * x * 0.6f + y * y * ((3f + y) / 4f) + z * z * 0.8f, 1f);
}
void main() {
mat4 kineticRotation = kineticRotation();
vec4 localPos = kineticRotation * vec4(aPos - 0.5, 1f) + vec4(instancePos, 0);
mat4 contraptionRotation = contraptionRotation();
vec4 worldPos = contraptionRotation * localPos + vec4(cPos + 0.5, 0);
BoxCoord = (worldPos.xyz - lightBoxMin) / lightBoxSize;
Diffuse = diffuse(normalize(contraptionRotation * localRotation * vec4(aNormal, 0.)).xyz);
Color = vec4(1.);
TexCoords = aTexCoords;
gl_Position = projection * view * worldPos;
}