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 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.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.render.instancing.BeltBuffer;
import com.simibubi.create.foundation.utility.render.instancing.RotatingBuffer;
import com.simibubi.create.foundation.utility.render.instancing.*;
import com.simibubi.create.foundation.utility.render.SuperByteBuffer;
import net.minecraft.block.BlockState;
import net.minecraft.client.renderer.model.IBakedModel;
@ -217,19 +218,20 @@ public class AllBlockPartials {
return CreateClient.bufferCache.renderDirectionalPartial(this, referenceState, facing, ms);
}
public RotatingBuffer renderOnRotating(BlockState referenceState) {
return CreateClient.kineticRenderer.renderPartialRotating(this, referenceState);
public <T extends KineticTileEntity> InstanceBuffer<RotatingData> renderOnRotating(InstanceContext<T> ctx, BlockState referenceState) {
return ctx.getKinetics().renderPartialRotating(this, referenceState);
}
public BeltBuffer renderOnBelt(BlockState referenceState) {
return CreateClient.kineticRenderer.renderPartialBelt(this, referenceState);
public <T extends BeltTileEntity> InstanceBuffer<BeltData> renderOnBelt(InstanceContext<T> ctx, BlockState 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);
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();
// TODO 1.15 find a way to cache this model matrix computation
MatrixStacker.of(ms)
@ -237,7 +239,7 @@ public class AllBlockPartials {
.rotateY(AngleHelper.horizontalAngle(facing))
.rotateX(AngleHelper.verticalAngle(facing))
.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.item.CustomItemModels;
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.SuperByteBufferCache;
import com.simibubi.create.foundation.utility.outliner.Outliner;
@ -73,8 +74,6 @@ public class CreateClient {
bufferCache.registerCompartment(ContraptionRenderer.CONTRAPTION, 20);
kineticRenderer = new FastKineticRenderer();
kineticRenderer.registerCompartment(KineticTileEntityRenderer.KINETIC_TILE);
kineticRenderer.registerCompartment(ContraptionRenderer.CONTRAPTION, 20);
AllKeys.register();
AllContainerTypes.registerScreenFactories();
@ -180,4 +179,9 @@ public class CreateClient {
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);
@Override
public AxisAlignedBB 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.simibubi.create.AllBlocks;
import com.simibubi.create.CreateClient;
import com.simibubi.create.content.contraptions.KineticDebugger;
import com.simibubi.create.content.contraptions.relays.elementary.CogWheelBlock;
import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer;
import com.simibubi.create.foundation.utility.AnimationTickHolder;
import com.simibubi.create.foundation.utility.ColorHelper;
import com.simibubi.create.foundation.utility.render.instancing.IInstancedTileEntityRenderer;
import com.simibubi.create.foundation.utility.render.instancing.RotatingBuffer;
import com.simibubi.create.foundation.utility.render.instancing.*;
import com.simibubi.create.foundation.utility.render.SuperByteBuffer;
import com.simibubi.create.foundation.utility.render.SuperByteBufferCache.Compartment;
import net.minecraft.block.BlockState;
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.state.properties.BlockStateProperties;
import net.minecraft.util.Direction;
@ -48,32 +44,36 @@ public class KineticTileEntityRenderer extends SafeTileEntityRenderer<KineticTil
// for (RenderType type : RenderType.getBlockLayers())
// if (RenderTypeLookup.canRenderInLayer(te.getBlockState(), type))
// renderRotatingBuffer(te, getRotatedModel(te));
addInstanceData(te);
addInstanceData(new InstanceContext.World<>(te));
}
@Override
public void addInstanceData(KineticTileEntity te) {
renderRotatingBuffer(te, getRotatedModel(te));
public void addInstanceData(InstanceContext<KineticTileEntity> ctx) {
renderRotatingBuffer(ctx, getRotatedModel(ctx));
}
public static void renderRotatingKineticBlock(KineticTileEntity te, BlockState renderedState) {
RotatingBuffer instancedRenderer = CreateClient.kineticRenderer.renderBlockInstanced(KINETIC_TILE, renderedState);
renderRotatingBuffer(te, instancedRenderer);
public static <T extends KineticTileEntity> void renderRotatingKineticBlock(InstanceContext<T> ctx, BlockState renderedState) {
InstanceBuffer<RotatingData> instancedRenderer = ctx.getKinetics().renderBlockInstanced(KINETIC_TILE, renderedState);
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 -> {
T te = ctx.te;
final BlockPos pos = te.getPos();
Axis axis = ((IRotate) te.getBlockState()
.getBlock()).getRotationAxis(te.getBlockState());
data
.setBlockLight(te.getWorld().getLightLevel(LightType.BLOCK, te.getPos()))
.setSkyLight(te.getWorld().getLightLevel(LightType.SKY, te.getPos()))
.setRotationalSpeed(te.getSpeed())
.setRotationOffset(getRotationOffsetForPosition(te, pos, axis))
.setRotationAxis(Direction.getFacingFromAxis(AxisDirection.POSITIVE, axis).getUnitVector())
.setPosition(pos);
data.setRotationalSpeed(te.getSpeed())
.setRotationOffset(getRotationOffsetForPosition(te, pos, axis))
.setRotationAxis(Direction.getFacingFromAxis(AxisDirection.POSITIVE, axis).getUnitVector())
.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();
}
protected RotatingBuffer getRotatedModel(KineticTileEntity te) {
return CreateClient.kineticRenderer.renderBlockInstanced(KINETIC_TILE, getRenderedBlockState(te));
protected InstanceBuffer<RotatingData> getRotatedModel(InstanceContext<? extends KineticTileEntity> ctx) {
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.AnimationTickHolder;
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.VecHelper;
@ -28,8 +29,8 @@ public class DrillRenderer extends KineticTileEntityRenderer {
}
@Override
protected RotatingBuffer getRotatedModel(KineticTileEntity te) {
return AllBlockPartials.DRILL_HEAD.renderOnDirectionalSouthRotating(te.getBlockState());
protected InstanceBuffer<RotatingData> getRotatedModel(InstanceContext<? extends KineticTileEntity> ctx) {
return AllBlockPartials.DRILL_HEAD.renderOnDirectionalSouthRotating(ctx, ctx.te.getBlockState());
}
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.foundation.utility.AngleHelper;
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.instancing.RotatingData;
@ -93,14 +93,9 @@ public class CuckooClockRenderer extends KineticTileEntityRenderer {
}
@Override
protected RotatingBuffer getRotatedModel(KineticTileEntity te) {
return transform(AllBlockPartials.SHAFT_HALF, te);
}
private RotatingBuffer transform(AllBlockPartials partial, KineticTileEntity te) {
return partial.renderOnDirectionalSouthRotating(te.getBlockState(), te.getBlockState()
.get(CuckooClockBlock.HORIZONTAL_FACING)
.getOpposite());
protected InstanceBuffer<RotatingData> getRotatedModel(InstanceContext<? extends KineticTileEntity> ctx) {
BlockState blockState = ctx.te.getBlockState();
return AllBlockPartials.SHAFT_HALF.renderOnDirectionalSouthRotating(ctx, blockState, blockState.get(CuckooClockBlock.HORIZONTAL_FACING).getOpposite());
}
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.render.instancing.IInstancedTileEntityRenderer;
import com.simibubi.create.foundation.utility.render.instancing.InstanceContext;
import net.minecraft.block.BlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.IRenderTypeBuffer;
@ -51,12 +52,11 @@ public class DeployerRenderer extends SafeTileEntityRenderer<DeployerTileEntity>
FilteringRenderer.renderOnTileEntity(te, partialTicks, ms, buffer, light, overlay);
renderComponents(te, partialTicks, ms, buffer, light, overlay);
addInstanceData(te);
}
@Override
public void addInstanceData(DeployerTileEntity te) {
KineticTileEntityRenderer.renderRotatingKineticBlock(te, getRenderedBlockState(te));
public void addInstanceData(InstanceContext<DeployerTileEntity> ctx) {
KineticTileEntityRenderer.renderRotatingKineticBlock(ctx, getRenderedBlockState(ctx.te));
}
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,
int light, int overlay) {
IVertexBuilder vb = buffer.getBuffer(RenderType.getSolid());
KineticTileEntityRenderer.renderRotatingKineticBlock(te, getRenderedBlockState(te));
KineticTileEntityRenderer.renderRotatingKineticBlock(new InstanceContext.World<>(te), getRenderedBlockState(te));
BlockState blockState = te.getBlockState();
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.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.RotatingData;
import net.minecraft.client.renderer.IRenderTypeBuffer;
import net.minecraft.client.renderer.WorldRenderer;
import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher;
@ -26,24 +29,21 @@ public class EncasedFanRenderer extends KineticTileEntityRenderer {
@Override
protected void renderSafe(KineticTileEntity te, float partialTicks, MatrixStack ms, IRenderTypeBuffer buffer,
int light, int overlay) {
addInstanceData(te);
super.renderSafe(te, partialTicks, ms, buffer, light, overlay);
}
@Override
public void addInstanceData(KineticTileEntity te) {
public void addInstanceData(InstanceContext<KineticTileEntity> ctx) {
KineticTileEntity te = ctx.te;
Direction direction = te.getBlockState()
.get(FACING);
BlockPos inFront = te.getPos().offset(direction);
int blockLight = te.getWorld().getLightLevel(LightType.BLOCK, inFront);
int skyLight = te.getWorld().getLightLevel(LightType.SKY, inFront);
InstanceBuffer<RotatingData> shaftHalf =
AllBlockPartials.SHAFT_HALF.renderOnDirectionalSouthRotating(ctx, te.getBlockState(), direction.getOpposite());
InstanceBuffer<RotatingData> fanInner =
AllBlockPartials.ENCASED_FAN_INNER.renderOnDirectionalSouthRotating(ctx, te.getBlockState(), direction.getOpposite());
RotatingBuffer shaftHalf =
AllBlockPartials.SHAFT_HALF.renderOnDirectionalSouthRotating(te.getBlockState(), direction.getOpposite());
RotatingBuffer fanInner =
AllBlockPartials.ENCASED_FAN_INNER.renderOnDirectionalSouthRotating(te.getBlockState(), direction.getOpposite());
renderRotatingBuffer(te, shaftHalf);
renderRotatingBuffer(ctx, shaftHalf);
fanInner.setupInstance(data -> {
final BlockPos pos = te.getPos();
Direction.Axis axis = ((IRotate) te.getBlockState()
@ -55,12 +55,19 @@ public class EncasedFanRenderer extends KineticTileEntityRenderer {
if (speed < 0)
speed = MathHelper.clamp(speed, -64 * 20, -80);
data.setBlockLight(blockLight)
.setSkyLight(skyLight)
.setRotationalSpeed(speed)
data.setRotationalSpeed(speed)
.setRotationOffset(getRotationOffsetForPosition(te, pos, axis))
.setRotationAxis(Direction.getFacingFromAxis(Direction.AxisDirection.POSITIVE, axis).getUnitVector())
.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.components.flywheel.FlywheelBlock.ConnectionState;
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.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 net.minecraft.block.BlockState;
import net.minecraft.client.renderer.IRenderTypeBuffer;
@ -77,8 +77,8 @@ public class FlywheelRenderer extends KineticTileEntityRenderer {
}
@Override
protected RotatingBuffer getRotatedModel(KineticTileEntity te) {
return AllBlockPartials.SHAFT_HALF.renderOnDirectionalSouthRotating(te.getBlockState(), te.getBlockState()
protected InstanceBuffer<RotatingData> getRotatedModel(InstanceContext<? extends KineticTileEntity> ctx) {
return AllBlockPartials.SHAFT_HALF.renderOnDirectionalSouthRotating(ctx, ctx.te.getBlockState(), ctx.te.getBlockState()
.get(HORIZONTAL_FACING)
.getOpposite());
}

View File

@ -1,12 +1,11 @@
package com.simibubi.create.content.contraptions.components.millstone;
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.KineticTileEntityRenderer;
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 net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher;
@ -17,8 +16,8 @@ public class MillstoneRenderer extends KineticTileEntityRenderer {
}
@Override
protected RotatingBuffer getRotatedModel(KineticTileEntity te) {
return CreateClient.kineticRenderer.renderPartialRotating(AllBlockPartials.MILLSTONE_COG, te.getBlockState());
protected InstanceBuffer<RotatingData> getRotatedModel(InstanceContext<? extends KineticTileEntity> ctx) {
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.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 net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher;
@ -16,8 +16,8 @@ public class CreativeMotorRenderer extends KineticTileEntityRenderer {
}
@Override
protected RotatingBuffer getRotatedModel(KineticTileEntity te) {
return AllBlockPartials.SHAFT_HALF.renderOnDirectionalSouthRotating(te.getBlockState());
protected InstanceBuffer<RotatingData> getRotatedModel(InstanceContext<? extends KineticTileEntity> ctx) {
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.utility.*;
import com.simibubi.create.foundation.utility.render.instancing.IInstancedTileEntityRenderer;
import com.simibubi.create.foundation.utility.render.instancing.RotatingBuffer;
import com.simibubi.create.foundation.utility.render.instancing.*;
import com.simibubi.create.foundation.utility.render.SuperByteBuffer;
import net.minecraft.block.BlockState;
import net.minecraft.client.Minecraft;
@ -43,12 +42,11 @@ public class SawRenderer extends SafeTileEntityRenderer<SawTileEntity> implement
renderItems(te, partialTicks, ms, buffer, light, overlay);
FilteringRenderer.renderOnTileEntity(te, partialTicks, ms, buffer, light, overlay);
addInstanceData(te);
}
@Override
public void addInstanceData(SawTileEntity te) {
KineticTileEntityRenderer.renderRotatingBuffer(te, getRotatedModel(te));
public void addInstanceData(InstanceContext<SawTileEntity> ctx) {
KineticTileEntityRenderer.renderRotatingBuffer(ctx, getRotatedModel(ctx));
}
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) {
KineticTileEntityRenderer.renderRotatingBuffer(te, getRotatedModel(te));
//KineticTileEntityRenderer.renderRotatingBuffer(te, getRotatedModel(te));
}
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();
if (state.get(FACING).getAxis().isHorizontal())
return AllBlockPartials.SHAFT_HALF.renderOnDirectionalSouthRotating(state.rotate(te.getWorld(), te.getPos(), Rotation.CLOCKWISE_180));
return CreateClient.kineticRenderer.renderBlockInstanced(KineticTileEntityRenderer.KINETIC_TILE,
return AllBlockPartials.SHAFT_HALF.renderOnDirectionalSouthRotating(ctx, state.rotate(te.getWorld(), te.getPos(), Rotation.CLOCKWISE_180));
return ctx.getKinetics().renderBlockInstanced(KineticTileEntityRenderer.KINETIC_TILE,
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.KineticTileEntityRenderer;
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.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 net.minecraft.block.BlockState;
import net.minecraft.client.renderer.IRenderTypeBuffer;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher;
@ -46,10 +47,9 @@ public class BearingRenderer extends KineticTileEntityRenderer {
}
@Override
protected RotatingBuffer getRotatedModel(KineticTileEntity te) {
return AllBlockPartials.SHAFT_HALF.renderOnDirectionalSouthRotating(te.getBlockState(), te.getBlockState()
.get(BearingBlock.FACING)
.getOpposite());
protected InstanceBuffer<RotatingData> getRotatedModel(InstanceContext<? extends KineticTileEntity> ctx) {
BlockState blockState = ctx.te.getBlockState();
return AllBlockPartials.SHAFT_HALF.renderOnDirectionalSouthRotating(ctx, blockState, blockState.get(BearingBlock.FACING).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.foundation.utility.AngleHelper;
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.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 net.minecraft.block.BlockState;
import net.minecraft.client.renderer.IRenderTypeBuffer;
@ -54,8 +54,8 @@ public class PumpRenderer extends KineticTileEntityRenderer {
}
@Override
protected RotatingBuffer getRotatedModel(KineticTileEntity te) {
return AllBlockPartials.MECHANICAL_PUMP_COG.renderOnDirectionalSouthRotating(te.getBlockState());
protected InstanceBuffer<RotatingData> getRotatedModel(InstanceContext<? extends KineticTileEntity> ctx) {
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.foundation.tileEntity.renderer.SmartTileEntityRenderer;
import com.simibubi.create.foundation.utility.render.instancing.IInstancedTileEntityRenderer;
import com.simibubi.create.foundation.utility.render.instancing.RotatingBuffer;
import com.simibubi.create.foundation.utility.render.instancing.*;
import net.minecraft.client.renderer.IRenderTypeBuffer;
import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher;
@ -21,15 +20,14 @@ public class SpeedControllerRenderer extends SmartTileEntityRenderer<SpeedContro
IRenderTypeBuffer buffer, int light, int overlay) {
super.renderSafe(tileEntityIn, partialTicks, ms, buffer, light, overlay);
addInstanceData(tileEntityIn);
}
@Override
public void addInstanceData(SpeedControllerTileEntity te) {
KineticTileEntityRenderer.renderRotatingBuffer(te, getRotatedModel(te));
public void addInstanceData(InstanceContext<SpeedControllerTileEntity> ctx) {
KineticTileEntityRenderer.renderRotatingBuffer(ctx, getRotatedModel(ctx.te));
}
private RotatingBuffer getRotatedModel(SpeedControllerTileEntity te) {
private InstanceBuffer<RotatingData> getRotatedModel(SpeedControllerTileEntity te) {
return CreateClient.kineticRenderer.renderBlockInstanced(KineticTileEntityRenderer.KINETIC_TILE,
KineticTileEntityRenderer.shaft(KineticTileEntityRenderer.getRotationAxisOf(te)));
}

View File

@ -1,6 +1,8 @@
package com.simibubi.create.content.contraptions.relays.belt;
import java.util.Random;
import java.util.function.BiFunction;
import java.util.function.Function;
import com.mojang.blaze3d.matrix.MatrixStack;
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.utility.Iterate;
import com.simibubi.create.foundation.utility.MatrixStacker;
import com.simibubi.create.foundation.utility.render.instancing.BeltBuffer;
import com.simibubi.create.foundation.utility.render.instancing.IInstancedTileEntityRenderer;
import com.simibubi.create.foundation.utility.render.instancing.RotatingBuffer;
import com.simibubi.create.foundation.utility.render.FastContraptionRenderer;
import com.simibubi.create.foundation.utility.render.FastKineticRenderer;
import com.simibubi.create.foundation.utility.render.instancing.*;
import com.simibubi.create.foundation.utility.render.ShadowRenderHelper;
import net.minecraft.block.BlockState;
@ -51,13 +53,13 @@ public class BeltRenderer extends SafeTileEntityRenderer<BeltTileEntity> impleme
if (!AllBlocks.BELT.has(blockState))
return;
addInstanceData(te);
addInstanceData(new InstanceContext.World<>(te));
renderItems(te, partialTicks, ms, buffer, light, overlay);
}
@Override
public void addInstanceData(BeltTileEntity te) {
public void addInstanceData(InstanceContext<BeltTileEntity> ctx) {
BeltTileEntity te = ctx.te;
BlockState blockState = te.getBlockState();
if (!AllBlocks.BELT.has(blockState))
return;
@ -83,6 +85,8 @@ public class BeltRenderer extends SafeTileEntityRenderer<BeltTileEntity> impleme
end = b;
}
FastKineticRenderer fastKineticRenderer = ctx.getKinetics();
for (boolean bottom : Iterate.trueAndFalse) {
AllBlockPartials beltPartial = diagonal
@ -94,7 +98,7 @@ public class BeltRenderer extends SafeTileEntityRenderer<BeltTileEntity> impleme
: start ? AllBlockPartials.BELT_START
: end ? AllBlockPartials.BELT_END : AllBlockPartials.BELT_MIDDLE;
BeltBuffer beltBuffer = beltPartial.renderOnBelt(blockState);
InstanceBuffer<BeltData> beltBuffer = beltPartial.renderOnBelt(ctx, blockState);
SpriteShiftEntry spriteShift =
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.unCentre();
RotatingBuffer rotatingBuffer = CreateClient.kineticRenderer
InstanceBuffer<RotatingData> rotatingBuffer = fastKineticRenderer
.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.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.RotatingData;
import net.minecraft.block.Block;
import net.minecraft.client.renderer.IRenderTypeBuffer;
import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher;
@ -25,18 +28,26 @@ public class SplitShaftRenderer extends KineticTileEntityRenderer {
@Override
protected void renderSafe(KineticTileEntity te, float partialTicks, MatrixStack ms, IRenderTypeBuffer buffer,
int light, int overlay) {
addInstanceData(te);
super.renderSafe(te, partialTicks, ms, buffer, light, overlay);
}
@Override
public void addInstanceData(KineticTileEntity te) {
public void addInstanceData(InstanceContext<KineticTileEntity> ctx) {
KineticTileEntity te = ctx.te;
Block block = te.getBlockState().getBlock();
final Axis boxAxis = ((IRotate) block).getRotationAxis(te.getBlockState());
final BlockPos pos = te.getPos();
int blockLight = te.getWorld().getLightLevel(LightType.BLOCK, te.getPos());
int skyLight = te.getWorld().getLightLevel(LightType.SKY, te.getPos());
int blockLight;
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) {
Axis axis = direction.getAxis();
@ -44,7 +55,7 @@ public class SplitShaftRenderer extends KineticTileEntityRenderer {
continue;
RotatingBuffer shaft = AllBlockPartials.SHAFT_HALF.renderOnDirectionalSouthRotating(te.getBlockState(), direction);
InstanceBuffer<RotatingData> shaft = AllBlockPartials.SHAFT_HALF.renderOnDirectionalSouthRotating(ctx, te.getBlockState(), direction);
shaft.setupInstance(data -> {
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.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.RotatingData;
import net.minecraft.client.renderer.IRenderTypeBuffer;
import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher;
import net.minecraft.state.properties.BlockStateProperties;
@ -24,18 +27,32 @@ public class GearboxRenderer extends KineticTileEntityRenderer {
@Override
protected void renderSafe(KineticTileEntity te, float partialTicks, MatrixStack ms, IRenderTypeBuffer buffer,
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 BlockPos pos = te.getPos();
int blockLight = te.getWorld().getLightLevel(LightType.BLOCK, te.getPos());
int skyLight = te.getWorld().getLightLevel(LightType.SKY, te.getPos());
int blockLight;
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) {
final Axis axis = direction.getAxis();
if (boxAxis == axis)
continue;
RotatingBuffer shaft = AllBlockPartials.SHAFT_HALF.renderOnDirectionalSouthRotating(te.getBlockState(), direction);
InstanceBuffer<RotatingData> shaft = AllBlockPartials.SHAFT_HALF.renderOnDirectionalSouthRotating(ctx, te.getBlockState(), direction);
shaft.setupInstance(data -> {
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.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.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 net.minecraft.block.BlockState;
import net.minecraft.client.Minecraft;
@ -118,8 +118,8 @@ public class ArmRenderer extends KineticTileEntityRenderer {
}
@Override
protected RotatingBuffer getRotatedModel(KineticTileEntity te) {
return AllBlockPartials.ARM_COG.renderOnRotating(te.getBlockState());
protected InstanceBuffer<RotatingData> getRotatedModel(InstanceContext<? extends KineticTileEntity> ctx) {
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.renderer.ActiveRenderInfo;
import net.minecraft.client.renderer.IRenderTypeBuffer;
import net.minecraft.client.renderer.Matrix4f;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.fluid.Fluid;
import net.minecraft.fluid.IFluidState;
@ -112,21 +113,25 @@ public class ClientEvents {
@SubscribeEvent
public static void onLoadWorld(WorldEvent.Load event) {
CreateClient.bufferCache.invalidate();
CreateClient.kineticRenderer.invalidate();
FastContraptionRenderer.invalidateAll();
CreateClient.invalidateRenderers();
}
@SubscribeEvent
public static void onRenderWorld(RenderWorldLastEvent event) {
CreateClient.kineticRenderer.renderInstances(event);
FastContraptionRenderer.renderAll(event);
Matrix4f projection = event.getProjectionMatrix();
// 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();
ActiveRenderInfo info = Minecraft.getInstance().gameRenderer.getActiveRenderInfo();
Vec3d view = info.getProjectedView();
ms.push();
ms.translate(-view.getX(), -view.getY(), -view.getZ());
ms.translate(-cameraPos.getX(), -cameraPos.getY(), -cameraPos.getZ());
SuperRenderTypeBuffer buffer = SuperRenderTypeBuffer.getInstance();
CouplingRenderer.renderAll(ms, buffer);

View File

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

View File

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

View File

@ -1,11 +1,9 @@
package com.simibubi.create.foundation.utility.render;
import com.mojang.blaze3d.platform.GlStateManager;
import com.simibubi.create.CreateClient;
import com.simibubi.create.foundation.utility.render.instancing.VertexFormat;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.GLAllocation;
import net.minecraft.client.renderer.WorldRenderer;
import net.minecraft.client.renderer.vertex.VertexFormatElement;
import org.lwjgl.opengl.*;
import org.lwjgl.system.MemoryUtil;
@ -43,7 +41,7 @@ public class ContraptionBuffer extends TemplateBuffer {
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++) {
GL40.glDisableVertexAttribArray(i);
@ -55,55 +53,50 @@ public class ContraptionBuffer extends TemplateBuffer {
private void setup() {
int stride = FORMAT.getStride();
int invariantSize = count * stride;
int invariantSize = vertexCount * stride;
ByteBuffer constant = GLAllocation.createDirectByteBuffer(invariantSize);
constant.order(template.order());
((Buffer) constant).limit(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);
int indicesSize = count * VertexFormatElement.Type.USHORT.getSize();
ByteBuffer indices = GLAllocation.createDirectByteBuffer(indicesSize);
indices.order(template.order());
((Buffer) indices).limit(indicesSize);
try (SafeDirectBuffer constant = new SafeDirectBuffer(invariantSize)) {
constant.order(template.order());
constant.limit(invariantSize);
int vertexCount = vertexCount(template);
for (int i = 0; i < vertexCount; i++) {
constant.putFloat(getX(template, i));
constant.putFloat(getY(template, i));
constant.putFloat(getZ(template, i));
for (int i = 0; i < vertexCount; i++) {
constant.putFloat(getX(template, i));
constant.putFloat(getY(template, i));
constant.putFloat(getZ(template, i));
constant.putFloat(getNX(template, i));
constant.putFloat(getNY(template, i));
constant.putFloat(getNZ(template, i));
constant.put(getNX(template, i));
constant.put(getNY(template, i));
constant.put(getNZ(template, i));
constant.putFloat(getU(template, i));
constant.putFloat(getV(template, i));
constant.putFloat(getU(template, i));
constant.putFloat(getV(template, i));
constant.putFloat(getR(template, i) / 255f);
constant.putFloat(getG(template, i) / 255f);
constant.putFloat(getB(template, i) / 255f);
constant.putFloat(getA(template, i) / 255f);
constant.put(getR(template, i));
constant.put(getG(template, i));
constant.put(getB(template, i));
constant.put(getA(template, i));
}
constant.rewind();
vao = GL30.glGenVertexArrays();
GL30.glBindVertexArray(vao);
ebo = GlStateManager.genBuffers();
vbo = GlStateManager.genBuffers();
GlStateManager.bindBuffers(GL15.GL_ARRAY_BUFFER, vbo);
GlStateManager.bufferData(GL15.GL_ARRAY_BUFFER, constant.getBacking(), GL15.GL_STATIC_DRAW);
buildEBO(ebo);
FORMAT.informAttributes(0);
} catch (Exception e) {
indices.putShort((short) i);
}
constant.rewind();
indices.rewind();
vao = GL30.glGenVertexArrays();
GL30.glBindVertexArray(vao);
ebo = GlStateManager.genBuffers();
vbo = GlStateManager.genBuffers();
GlStateManager.bindBuffers(GL15.GL_ARRAY_BUFFER, vbo);
GlStateManager.bufferData(GL15.GL_ARRAY_BUFFER, constant, GL15.GL_STATIC_DRAW);
MemoryUtil.memFree(constant);
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);
GlStateManager.bindBuffers(GL15.GL_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 net.minecraft.client.renderer.GLAllocation;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
@ -132,22 +133,19 @@ public class ContraptionLighter {
public void use() {
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);
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) {
GL12.glTexImage3D(GL12.GL_TEXTURE_3D, 0, GL40.GL_RG8, sizeX, sizeY, sizeZ, 0, GL40.GL_RG, GL40.GL_UNSIGNED_BYTE, lightVolume);
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() {
GL13.glActiveTexture(GL40.GL_TEXTURE0 + 4);
GL12.glBindTexture(GL12.GL_TEXTURE_3D, 0);
}
}

View File

@ -1,16 +1,23 @@
package com.simibubi.create.foundation.utility.render;
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.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.ShaderCallback;
import com.simibubi.create.foundation.utility.render.shader.ShaderHelper;
import net.minecraft.client.Minecraft;
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.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.util.ArrayList;
@ -25,6 +32,8 @@ public class FastContraptionRenderer extends ContraptionRenderer {
private ContraptionLighter lighter;
public final FastKineticRenderer kinetics;
private Contraption c;
private Vec3d renderPos;
@ -33,18 +42,49 @@ public class FastContraptionRenderer extends ContraptionRenderer {
public FastContraptionRenderer(World world, Contraption c) {
this.c = 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() {
if (Minecraft.getInstance().isGamePaused()) return;
RenderWork.enqueue(() -> {
for (FastContraptionRenderer renderer : renderers.values()) {
renderer.lighter.update(renderer.c);
}
});
for (FastContraptionRenderer renderer : renderers.values()) {
renderer.lighter.update(renderer.c);
}
}
private void setRenderSettings(Vec3d position, Vec3d rotation) {
@ -52,9 +92,16 @@ public class FastContraptionRenderer extends ContraptionRenderer {
renderRot = rotation;
}
private void render(int shader) {
private void setup(int shader) {
setupShaderUniforms(shader);
lighter.use();
}
private void teardown() {
lighter.release();
}
private void setupShaderUniforms(int shader) {
FloatBuffer buf = ShaderHelper.VEC3_BUFFER;
int lightBoxSize = GlStateManager.getUniformLocation(shader, "lightBoxSize");
@ -84,26 +131,6 @@ public class FastContraptionRenderer extends ContraptionRenderer {
buf.put(2, (float) renderRot.z);
buf.rewind();
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() {
@ -113,6 +140,8 @@ public class FastContraptionRenderer extends ContraptionRenderer {
lighter.delete();
kinetics.invalidate();
renderLayers.clear();
}
@ -133,26 +162,56 @@ public class FastContraptionRenderer extends ContraptionRenderer {
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;
CreateClient.kineticRenderer.setup(gameRenderer);
GlStateManager.enableCull();
FastKineticRenderer.setup(gameRenderer);
GL11.glEnable(GL13.GL_TEXTURE_3D);
GL13.glActiveTexture(GL40.GL_TEXTURE4);
ShaderHelper.useShader(Shader.CONTRAPTION_STRUCTURE, ShaderHelper.getViewProjectionCallback(event));
int shader = ShaderHelper.getShaderHandle(Shader.CONTRAPTION_STRUCTURE);
ArrayList<Integer> toRemove = new ArrayList<>();
ShaderCallback callback = ShaderHelper.getViewProjectionCallback(projectionMat, viewMat);
int structureShader = ShaderHelper.useShader(Shader.CONTRAPTION_STRUCTURE, callback);
for (FastContraptionRenderer renderer : renderers.values()) {
if (renderer.c.entity.isAlive())
renderer.render(shader);
else
toRemove.add(renderer.c.entity.getEntityId());
renderer.setup(structureShader);
for (ContraptionBuffer layer : renderer.renderLayers) {
layer.render();
}
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();
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) {
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.CacheBuilder;
import com.mojang.blaze3d.matrix.MatrixStack;
import com.mojang.blaze3d.platform.GlStateManager;
import com.mojang.blaze3d.systems.RenderSystem;
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.shader.Shader;
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.util.Direction;
import net.minecraft.world.World;
import net.minecraftforge.client.event.RenderWorldLastEvent;
import org.apache.commons.lang3.tuple.Pair;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL13;
@ -35,8 +34,8 @@ import java.util.function.Supplier;
import static com.simibubi.create.foundation.utility.render.SuperByteBufferCache.PARTIAL;
public class FastKineticRenderer {
Map<SuperByteBufferCache.Compartment<?>, Cache<Object, RotatingBuffer>> rotating;
Map<SuperByteBufferCache.Compartment<?>, Cache<Object, BeltBuffer>> belts;
Map<SuperByteBufferCache.Compartment<?>, Cache<Object, InstanceBuffer<RotatingData>>> rotating;
Map<SuperByteBufferCache.Compartment<?>, Cache<Object, InstanceBuffer<BeltData>>> belts;
boolean rebuild;
@ -46,6 +45,7 @@ public class FastKineticRenderer {
registerCompartment(SuperByteBufferCache.GENERIC_TILE);
registerCompartment(SuperByteBufferCache.PARTIAL);
registerCompartment(SuperByteBufferCache.DIRECTIONAL_PARTIAL);
registerCompartment(KineticTileEntityRenderer.KINETIC_TILE);
}
public void buildTileEntityBuffers(World world) {
@ -65,66 +65,102 @@ public class FastKineticRenderer {
}
}
private <T extends TileEntity> void addInstancedData(T te, IInstancedTileEntityRenderer<T> renderer) {
renderer.addInstanceData(te);
<T extends TileEntity> void addInstancedData(T te, IInstancedTileEntityRenderer<T> renderer) {
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() {
// TODO: (later) detect changes in lighting with a mixin (or forge hook) to ClientChunkProvider.markLightChanged()
for (Cache<Object, RotatingBuffer> cache : rotating.values()) {
for (RotatingBuffer renderer : cache.asMap().values()) {
for (Cache<Object, InstanceBuffer<RotatingData>> cache : rotating.values()) {
for (InstanceBuffer<RotatingData> renderer : cache.asMap().values()) {
renderer.clearInstanceData();
}
}
for (Cache<Object, BeltBuffer> cache : belts.values()) {
for (BeltBuffer renderer : cache.asMap().values()) {
for (Cache<Object, InstanceBuffer<BeltData>> cache : belts.values()) {
for (InstanceBuffer<BeltData> renderer : cache.asMap().values()) {
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;
//
// if (rebuild) {
// buildTileEntityBuffers(Minecraft.getInstance().world);
// rebuild = false;
// }
if (rebuild) {
markAllDirty();
rebuild = false;
}
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()
.stream()
.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.useShader(Shader.BELT, callback);
renderBelts();
ShaderHelper.releaseShader();
teardown();
}
public void setup(GameRenderer gameRenderer) {
public static void setup(GameRenderer gameRenderer) {
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.enableDepthTest();
RenderSystem.enableCull();
GL11.glCullFace(GL11.GL_BACK);
LightTexture lightManager = gameRenderer.getLightmapTextureManager();
@ -149,9 +185,9 @@ public class FastKineticRenderer {
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);
GL13.glActiveTexture(GL40.GL_TEXTURE0);
@ -175,26 +211,26 @@ public class FastKineticRenderer {
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));
}
public BeltBuffer renderPartialBelt(AllBlockPartials partial, BlockState referenceState) {
public InstanceBuffer<BeltData> renderPartialBelt(AllBlockPartials partial, BlockState 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) {
return getRotating(SuperByteBufferCache.DIRECTIONAL_PARTIAL, Pair.of(dir, partial),
() -> 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));
}
public <T> RotatingBuffer getRotating(SuperByteBufferCache.Compartment<T> compartment, T key, Supplier<RotatingBuffer> supplier) {
Cache<Object, RotatingBuffer> compartmentCache = this.rotating.get(compartment);
public <T> InstanceBuffer<RotatingData> getRotating(SuperByteBufferCache.Compartment<T> compartment, T key, Supplier<InstanceBuffer<RotatingData>> supplier) {
Cache<Object, InstanceBuffer<RotatingData>> compartmentCache = this.rotating.get(compartment);
try {
return compartmentCache.get(key, supplier::get);
} catch (ExecutionException e) {
@ -203,8 +239,8 @@ public class FastKineticRenderer {
}
}
public <T> BeltBuffer getBelt(SuperByteBufferCache.Compartment<T> compartment, T key, Supplier<BeltBuffer> supplier) {
Cache<Object, BeltBuffer> compartmentCache = this.belts.get(compartment);
public <T> InstanceBuffer<BeltData> getBelt(SuperByteBufferCache.Compartment<T> compartment, T key, Supplier<InstanceBuffer<BeltData>> supplier) {
Cache<Object, InstanceBuffer<BeltData>> compartmentCache = this.belts.get(compartment);
try {
return compartmentCache.get(key, supplier::get);
} 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();
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());
}
private BeltBuffer beltInstancedRenderer(IBakedModel model, BlockState renderedState) {
private InstanceBuffer<BeltData> beltInstancedRenderer(IBakedModel model, BlockState renderedState) {
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);
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);
return new BeltBuffer(builder);
}
public void invalidate() {
rotating.values().forEach(cache -> {
cache.asMap().values().forEach(InstanceBuffer::delete);
cache.invalidateAll();
});
for (Cache<Object, InstanceBuffer<RotatingData>> objectInstanceBufferCache : rotating.values()) {
objectInstanceBufferCache.asMap().values().forEach(InstanceBuffer::delete);
objectInstanceBufferCache.invalidateAll();
}
belts.values().forEach(cache -> {
for (Cache<Object, InstanceBuffer<BeltData>> cache : belts.values()) {
cache.asMap().values().forEach(InstanceBuffer::delete);
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;
import com.mojang.blaze3d.platform.GlStateManager;
import com.mojang.datafixers.util.Pair;
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.ByteBuffer;
@ -11,7 +13,7 @@ import java.nio.ByteOrder;
public class TemplateBuffer {
protected ByteBuffer template;
protected int formatSize;
protected int count;
protected int vertexCount;
public TemplateBuffer(BufferBuilder buf) {
Pair<BufferBuilder.DrawState, ByteBuffer> state = buf.popData();
@ -20,8 +22,8 @@ public class TemplateBuffer {
formatSize = buf.getVertexFormat()
.getSize();
count = state.getFirst().getCount();
int size = count * formatSize;
vertexCount = state.getFirst().getCount();
int size = vertexCount * formatSize;
template = ByteBuffer.allocate(size);
template.order(rendered.order());
@ -30,6 +32,22 @@ public class TemplateBuffer {
((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() {
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.utility.MatrixStacker;
import com.simibubi.create.foundation.utility.render.instancing.IInstanceRendered;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.IRenderTypeBuffer;
import net.minecraft.client.renderer.Matrix4f;
@ -30,6 +31,8 @@ public class TileEntityRenderHelper {
for (Iterator<TileEntity> iterator = customRenderTEs.iterator(); iterator.hasNext();) {
TileEntity tileEntity = iterator.next();
if (tileEntity instanceof IInstanceRendered) continue; // TODO: some things still need to render
TileEntityRenderer<TileEntity> renderer = TileEntityRendererDispatcher.instance.getRenderer(tileEntity);
if (renderer == null) {
iterator.remove();

View File

@ -1,10 +1,9 @@
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.util.math.BlockPos;
import java.nio.ByteBuffer;
public class BasicData<D extends BasicData<D>> extends InstanceData {
private float x;
@ -38,7 +37,7 @@ public class BasicData<D extends BasicData<D>> extends InstanceData {
}
@Override
public void write(ByteBuffer buf) {
public void write(SafeDirectBuffer buf) {
putVec3(buf, x, y, z);
putVec2(buf, blockLight, skyLight);

View File

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

View File

@ -1,13 +1,19 @@
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.utility.render.FastContraptionRenderer;
import net.minecraft.block.BlockState;
import net.minecraft.client.renderer.tileentity.TileEntityRenderer;
import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher;
import net.minecraft.tileentity.TileEntity;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;
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.simibubi.create.CreateClient;
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 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.system.MemoryUtil;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.util.ArrayList;
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 final ArrayList<D> data = new ArrayList<>();
protected boolean rebuffer = false;
protected boolean shouldBuild = true;
public InstanceBuffer(BufferBuilder buf) {
super(buf);
setupMainData();
setup();
}
private void setupMainData() {
private void setup() {
int stride = FORMAT.getStride();
int invariantSize = count * stride;
ByteBuffer constant = GLAllocation.createDirectByteBuffer(invariantSize);
constant.order(template.order());
((Buffer) 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++) {
constant.putFloat(getX(template, i));
constant.putFloat(getY(template, i));
constant.putFloat(getZ(template, i));
constant.putFloat(getNX(template, i));
constant.putFloat(getNY(template, i));
constant.putFloat(getNZ(template, i));
constant.putFloat(getU(template, i));
constant.putFloat(getV(template, i));
indices.putShort((short) i);
}
constant.rewind();
indices.rewind();
int invariantSize = vertexCount * stride;
vao = GL30.glGenVertexArrays();
GL30.glBindVertexArray(vao);
ebo = GlStateManager.genBuffers();
invariantVBO = GlStateManager.genBuffers();
instanceVBO = GlStateManager.genBuffers();
GlStateManager.bindBuffers(GL15.GL_ARRAY_BUFFER, invariantVBO);
GlStateManager.bufferData(GL15.GL_ARRAY_BUFFER, constant, GL15.GL_STATIC_DRAW);
MemoryUtil.memFree(constant);
try (SafeDirectBuffer constant = new SafeDirectBuffer(invariantSize)) {
constant.order(template.order());
constant.limit(invariantSize);
GlStateManager.bindBuffers(GL15.GL_ELEMENT_ARRAY_BUFFER, ebo);
GlStateManager.bufferData(GL15.GL_ELEMENT_ARRAY_BUFFER, indices, GL15.GL_STATIC_DRAW);
MemoryUtil.memFree(indices);
for (int i = 0; i < vertexCount; i++) {
constant.putFloat(getX(template, i));
constant.putFloat(getY(template, i));
constant.putFloat(getZ(template, i));
FORMAT.informAttributes(0);
constant.put(getNX(template, i));
constant.put(getNY(template, i));
constant.put(getNZ(template, i));
constant.putFloat(getU(template, i));
constant.putFloat(getV(template, i));
}
constant.rewind();
GL30.glBindVertexArray(vao);
GlStateManager.bindBuffers(GL15.GL_ARRAY_BUFFER, invariantVBO);
GlStateManager.bufferData(GL15.GL_ARRAY_BUFFER, constant.getBacking(), GL15.GL_STATIC_DRAW);
buildEBO(ebo);
FORMAT.informAttributes(0);
} catch (Exception e) {
delete();
}
GlStateManager.bindBuffers(GL15.GL_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();
public int numInstances() {
return instanceCount;
return instanceCount + data.size();
}
public boolean isEmpty() {
@ -100,14 +88,20 @@ public abstract class InstanceBuffer<D extends InstanceData> extends TemplateBuf
shouldBuild = true;
}
public void markDirty() {
rebuffer = true;
}
public void delete() {
RenderWork.enqueue(() -> {
GL15.glDeleteBuffers(invariantVBO);
GL15.glDeleteBuffers(instanceVBO);
GL15.glDeleteBuffers(ebo);
GL30.glDeleteVertexArrays(vao);
clearInstanceData();
vao = 0;
ebo = 0;
invariantVBO = 0;
instanceVBO = 0;
});
}
@ -120,10 +114,10 @@ public abstract class InstanceBuffer<D extends InstanceData> extends TemplateBuf
setup.accept(instanceData);
data.add(instanceData);
instanceCount++;
}
public void render() {
if (vao == 0) return;
GL30.glBindVertexArray(vao);
finishBuffering();
@ -135,7 +129,7 @@ public abstract class InstanceBuffer<D extends InstanceData> extends TemplateBuf
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++) {
GL40.glDisableVertexAttribArray(i);
@ -146,33 +140,39 @@ public abstract class InstanceBuffer<D extends InstanceData> extends TemplateBuf
}
private void finishBuffering() {
if (!shouldBuild) return;
if (!rebuffer || isEmpty()) return;
instanceCount = data.size();
VertexFormat instanceFormat = getInstanceFormat();
int instanceSize = instanceCount * instanceFormat.getStride();
ByteBuffer buffer = GLAllocation.createDirectByteBuffer(instanceSize);
buffer.order(template.order());
((Buffer) buffer).limit(instanceSize);
try (SafeDirectBuffer buffer = new SafeDirectBuffer(instanceSize)) {
buffer.order(template.order());
buffer.limit(instanceSize);
data.forEach(instanceData -> instanceData.write(buffer));
buffer.rewind();
data.forEach(instanceData -> instanceData.write(buffer));
buffer.rewind();
GlStateManager.bindBuffers(GL15.GL_ARRAY_BUFFER, instanceVBO);
GlStateManager.bufferData(GL15.GL_ARRAY_BUFFER, buffer, GL15.GL_STATIC_DRAW);
GlStateManager.bindBuffers(GL15.GL_ARRAY_BUFFER, instanceVBO);
GlStateManager.bufferData(GL15.GL_ARRAY_BUFFER, buffer.getBacking(), GL15.GL_STATIC_DRAW);
int staticAttributes = FORMAT.getNumAttributes();
instanceFormat.informAttributes(staticAttributes);
int staticAttributes = FORMAT.getNumAttributes();
instanceFormat.informAttributes(staticAttributes);
for (int i = 0; i < instanceFormat.getNumAttributes(); i++) {
GL40.glVertexAttribDivisor(i + staticAttributes, 1);
}
} catch (Exception e) {
for (int i = 0; i < instanceFormat.getNumAttributes(); i++) {
GL40.glVertexAttribDivisor(i + staticAttributes, 1);
}
// Deselect (bind to 0) the VBO
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
shouldBuild = false;
rebuffer = false;
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;
import com.simibubi.create.foundation.utility.render.SafeDirectBuffer;
import java.nio.ByteBuffer;
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, y);
putFloat(buf, z);
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, y);
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, y);
}
public void putFloat(ByteBuffer buf, float f) {
public void putFloat(SafeDirectBuffer buf, float f) {
buf.putFloat(f);
}
}

View File

@ -1,9 +1,7 @@
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.util.math.BlockPos;
import java.nio.ByteBuffer;
import static com.simibubi.create.foundation.utility.render.instancing.VertexAttribute.*;
@ -41,7 +39,7 @@ public class RotatingData extends BasicData<RotatingData> {
}
@Override
public void write(ByteBuffer buf) {
public void write(SafeDirectBuffer buf) {
super.write(buf);
putFloat(buf, rotationalSpeed);
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 POSITION = VEC3;
public static final VertexAttribute NORMAL = VEC3;
public static final VertexAttribute COLOR = VEC4;
public static final VertexAttribute NORMAL = new VertexAttribute(VertexFormatElement.Type.BYTE, 3);
public static final VertexAttribute COLOR = new VertexAttribute(VertexFormatElement.Type.BYTE, 4);
public static final VertexAttribute UV = VEC2;
public static final VertexAttribute LIGHT= VEC2;

View File

@ -1,9 +1,11 @@
package com.simibubi.create.foundation.utility.render.shader;
public enum Shader {
ROTATING_INSTANCED("shader/rotating.vert", "shader/instanced.frag"),
BELT_INSTANCED("shader/belt.vert", "shader/instanced.frag"),
ROTATING("shader/rotating.vert", "shader/instanced.frag"),
BELT("shader/belt.vert", "shader/instanced.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;

View File

@ -58,34 +58,28 @@ public class ShaderHelper {
return shaderProgram.getProgram();
}
public static ShaderCallback getViewProjectionCallback(RenderWorldLastEvent event) {
public static ShaderCallback getViewProjectionCallback(Matrix4f projectionMat, Matrix4f viewMat) {
return shader -> {
ShaderHelper.MATRIX_BUFFER.position(0);
event.getProjectionMatrix().write(ShaderHelper.MATRIX_BUFFER);
projectionMat.write(ShaderHelper.MATRIX_BUFFER);
int projection = GlStateManager.getUniformLocation(shader, "projection");
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);
translate.write(ShaderHelper.MATRIX_BUFFER);
viewMat.write(ShaderHelper.MATRIX_BUFFER);
int view = GlStateManager.getUniformLocation(shader, "view");
GlStateManager.uniformMatrix4(view, false, ShaderHelper.MATRIX_BUFFER);
};
}
public static void useShader(Shader shader) {
useShader(shader, null);
public static int useShader(Shader shader) {
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);
if (prog == null) {
return;
return -1;
}
int program = prog.getProgram();
@ -102,6 +96,8 @@ public class ShaderHelper {
if (cb != null) {
cb.call(program);
}
return program;
}
public static void releaseShader() {

View File

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

View File

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