diff --git a/src/main/java/com/simibubi/create/AllTileEntities.java b/src/main/java/com/simibubi/create/AllTileEntities.java index 9a6671797..219269b08 100644 --- a/src/main/java/com/simibubi/create/AllTileEntities.java +++ b/src/main/java/com/simibubi/create/AllTileEntities.java @@ -50,10 +50,7 @@ import com.simibubi.create.content.contraptions.components.press.PressInstance; import com.simibubi.create.content.contraptions.components.saw.SawInstance; import com.simibubi.create.content.contraptions.components.saw.SawRenderer; import com.simibubi.create.content.contraptions.components.saw.SawTileEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.bearing.BearingRenderer; -import com.simibubi.create.content.contraptions.components.structureMovement.bearing.ClockworkBearingTileEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.bearing.MechanicalBearingTileEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.bearing.WindmillBearingTileEntity; +import com.simibubi.create.content.contraptions.components.structureMovement.bearing.*; import com.simibubi.create.content.contraptions.components.structureMovement.chassis.ChassisTileEntity; import com.simibubi.create.content.contraptions.components.structureMovement.chassis.StickerInstance; import com.simibubi.create.content.contraptions.components.structureMovement.chassis.StickerRenderer; @@ -380,21 +377,21 @@ public class AllTileEntities { public static final TileEntityEntry WINDMILL_BEARING = Create.registrate() .tileEntity("windmill_bearing", WindmillBearingTileEntity::new) - .instance(() -> BackHalfShaftInstance::new) + .instance(() -> BearingInstance::new) .validBlocks(AllBlocks.WINDMILL_BEARING) .renderer(() -> BearingRenderer::new) .register(); public static final TileEntityEntry MECHANICAL_BEARING = Create.registrate() .tileEntity("mechanical_bearing", MechanicalBearingTileEntity::new) - .instance(() -> BackHalfShaftInstance::new) + .instance(() -> BearingInstance::new) .validBlocks(AllBlocks.MECHANICAL_BEARING) .renderer(() -> BearingRenderer::new) .register(); public static final TileEntityEntry CLOCKWORK_BEARING = Create.registrate() .tileEntity("clockwork_bearing", ClockworkBearingTileEntity::new) - .instance(() -> BackHalfShaftInstance::new) + .instance(() -> BearingInstance::new) .validBlocks(AllBlocks.CLOCKWORK_BEARING) .renderer(() -> BearingRenderer::new) .register(); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionCollider.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionCollider.java index b0554c42c..6004fdde3 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionCollider.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionCollider.java @@ -13,6 +13,7 @@ import org.apache.commons.lang3.mutable.MutableInt; import org.apache.commons.lang3.mutable.MutableObject; import com.google.common.base.Predicates; +import com.google.common.collect.ImmutableSet; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllMovementBehaviours; import com.simibubi.create.content.contraptions.components.actors.BlockBreakingMovementBehaviour; @@ -221,6 +222,7 @@ public class ContraptionCollider { totalResponse = VecHelper.rotate(totalResponse, yawOffset, Axis.Y); collisionNormal = rotationMatrix.transform(collisionNormal); collisionNormal = VecHelper.rotate(collisionNormal, yawOffset, Axis.Y); + collisionNormal = collisionNormal.normalize(); collisionLocation = rotationMatrix.transform(collisionLocation); collisionLocation = VecHelper.rotate(collisionLocation, yawOffset, Axis.Y); rotationMatrix.transpose(); @@ -248,16 +250,11 @@ public class ContraptionCollider { boolean hasNormal = !collisionNormal.equals(Vector3d.ZERO); boolean anyCollision = hardCollision || temporalCollision; - if (bounce > 0 && hasNormal && anyCollision) { - collisionNormal = collisionNormal.normalize(); - Vector3d newNormal = collisionNormal.crossProduct(collisionNormal.crossProduct(entityMotionNoTemporal)) - .normalize(); - if (bounceEntity(entity, newNormal, contraptionEntity, bounce)) { - entity.world.playSound(playerType == PlayerType.CLIENT ? (PlayerEntity) entity : null, - entity.getX(), entity.getY(), entity.getZ(), SoundEvents.BLOCK_SLIME_BLOCK_FALL, - SoundCategory.BLOCKS, .5f, 1); - continue; - } + if (bounce > 0 && hasNormal && anyCollision && bounceEntity(entity, collisionNormal, contraptionEntity, bounce)) { + entity.world.playSound(playerType == PlayerType.CLIENT ? (PlayerEntity) entity : null, + entity.getX(), entity.getY(), entity.getZ(), SoundEvents.BLOCK_SLIME_BLOCK_FALL, + SoundCategory.BLOCKS, .5f, 1); + continue; } if (temporalCollision) { @@ -288,7 +285,6 @@ public class ContraptionCollider { } if (bounce == 0 && slide > 0 && hasNormal && anyCollision && rotation.hasVerticalRotation()) { - collisionNormal = collisionNormal.normalize(); Vector3d motionIn = entityMotionNoTemporal.mul(0, 1, 0) .add(0, -.01f, 0); Vector3d slideNormal = collisionNormal.crossProduct(motionIn.crossProduct(collisionNormal)) @@ -346,35 +342,14 @@ public class ContraptionCollider { return false; if (entity.bypassesLandingEffects()) return false; - if (normal.equals(Vector3d.ZERO)) - return false; - Vector3d contraptionVec = Vector3d.ZERO; Vector3d contactPointMotion = contraption.getContactPointMotion(entity.getPositionVec()); - Vector3d motion = entity.getMotion() - .subtract(contactPointMotion); - - Vector3d v2 = motion.crossProduct(normal) - .normalize(); - if (v2 != Vector3d.ZERO) - contraptionVec = normal.scale(contraptionVec.dotProduct(normal)) - .add(v2.scale(contraptionVec.dotProduct(v2))); - else - v2 = normal.crossProduct(normal.add(Math.random(), Math.random(), Math.random())) - .normalize(); - - Vector3d v3 = normal.crossProduct(v2); - motion = motion.subtract(contraptionVec); - Vector3d lr = new Vector3d(factor * motion.dotProduct(normal), -motion.dotProduct(v2), -motion.dotProduct(v3)); - - if (lr.dotProduct(lr) > 1 / 16f) { - Vector3d newMot = contactPointMotion.add(normal.x * lr.x + v2.x * lr.y + v3.x * lr.z, - normal.y * lr.x + v2.y * lr.y + v3.y * lr.z, normal.z * lr.x + v2.z * lr.y + v3.z * lr.z); - entity.setMotion(newMot); - return true; - } - - return false; + Vector3d motion = entity.getMotion().subtract(contactPointMotion); + Vector3d deltav = normal.scale(factor*2*motion.dotProduct(normal)); + if (deltav.dotProduct(deltav) < 0.1f) + return false; + entity.setMotion(entity.getMotion().subtract(deltav)); + return true; } public static Vector3d getWorldToLocalTranslation(Entity entity, AbstractContraptionEntity contraptionEntity) { diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/NonStationaryLighter.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/NonStationaryLighter.java index 50ed095c8..9ce341586 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/NonStationaryLighter.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/NonStationaryLighter.java @@ -8,15 +8,6 @@ public class NonStationaryLighter extends ContraptionLigh super(contraption); } - @Override - protected GridAlignedBB contraptionBoundsToVolume(GridAlignedBB bounds) { - bounds.grow(2); // so we have at least enough data on the edges to avoid artifacts and have smooth lighting - bounds.minY = Math.max(bounds.minY, 0); - bounds.maxY = Math.min(bounds.maxY, 255); - - return bounds; - } - @Override public void tick(RenderedContraption owner) { super.tick(owner); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/BearingInstance.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/BearingInstance.java new file mode 100644 index 000000000..cb8177452 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/BearingInstance.java @@ -0,0 +1,77 @@ +package com.simibubi.create.content.contraptions.components.structureMovement.bearing; + +import net.minecraft.client.renderer.Quaternion; +import net.minecraft.client.renderer.Vector3f; +import net.minecraft.state.properties.BlockStateProperties; +import net.minecraft.util.Direction; + +import com.simibubi.create.AllBlockPartials; +import com.simibubi.create.content.contraptions.base.BackHalfShaftInstance; +import com.simibubi.create.content.contraptions.base.KineticTileEntity; +import com.simibubi.create.foundation.render.backend.core.OrientedData; +import com.simibubi.create.foundation.render.backend.instancing.IDynamicInstance; +import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; +import com.simibubi.create.foundation.utility.AngleHelper; +import com.simibubi.create.foundation.utility.AnimationTickHolder; + +public class BearingInstance extends BackHalfShaftInstance implements IDynamicInstance { + final B bearing; + + final OrientedData topInstance; + + final Vector3f rotationAxis; + final Quaternion blockOrientation; + + public BearingInstance(InstancedTileRenderer modelManager, B tile) { + super(modelManager, tile); + this.bearing = tile; + + Direction facing = blockState.get(BlockStateProperties.FACING); + rotationAxis = Direction.getFacingFromAxis(Direction.AxisDirection.POSITIVE, axis).getUnitVector(); + + blockOrientation = getBlockStateOrientation(facing); + + AllBlockPartials top = + bearing.isWoodenTop() ? AllBlockPartials.BEARING_TOP_WOODEN : AllBlockPartials.BEARING_TOP; + + topInstance = getOrientedMaterial().getModel(top, blockState).createInstance(); + + topInstance.setPosition(getInstancePosition()).setRotation(blockOrientation); + } + + @Override + public void beginFrame() { + + float interpolatedAngle = bearing.getInterpolatedAngle(AnimationTickHolder.getPartialTicks() - 1); + Quaternion rot = rotationAxis.getDegreesQuaternion(interpolatedAngle); + + rot.multiply(blockOrientation); + + topInstance.setRotation(rot); + } + + @Override + public void updateLight() { + super.updateLight(); + relight(pos, topInstance); + } + + @Override + public void remove() { + super.remove(); + topInstance.delete(); + } + + static Quaternion getBlockStateOrientation(Direction facing) { + Quaternion orientation; + + if (facing.getAxis().isHorizontal()) { + orientation = Vector3f.POSITIVE_Y.getDegreesQuaternion(AngleHelper.horizontalAngle(facing.getOpposite())); + } else { + orientation = Quaternion.IDENTITY.copy(); + } + + orientation.multiply(Vector3f.POSITIVE_X.getDegreesQuaternion(-90 - AngleHelper.verticalAngle(facing))); + return orientation; + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/BearingRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/BearingRenderer.java index f94d29e89..6a81320bd 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/BearingRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/BearingRenderer.java @@ -5,6 +5,7 @@ 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.render.SuperByteBuffer; +import com.simibubi.create.foundation.render.backend.FastRenderDispatcher; import com.simibubi.create.foundation.utility.AngleHelper; import net.minecraft.client.renderer.IRenderTypeBuffer; @@ -22,6 +23,9 @@ public class BearingRenderer extends KineticTileEntityRenderer { @Override protected void renderSafe(KineticTileEntity te, float partialTicks, MatrixStack ms, IRenderTypeBuffer buffer, int light, int overlay) { + + if (FastRenderDispatcher.available(te.getWorld())) return; + super.renderSafe(te, partialTicks, ms, buffer, light, overlay); IBearingTileEntity bearingTe = (IBearingTileEntity) te; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/StabilizedBearingInstance.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/StabilizedBearingInstance.java new file mode 100644 index 000000000..90d4b9bd5 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/StabilizedBearingInstance.java @@ -0,0 +1,51 @@ +package com.simibubi.create.content.contraptions.components.structureMovement.bearing; + +import net.minecraft.block.BlockState; +import net.minecraft.client.renderer.Quaternion; +import net.minecraft.client.renderer.Vector3f; +import net.minecraft.state.properties.BlockStateProperties; +import net.minecraft.util.Direction; + +import com.simibubi.create.AllBlockPartials; +import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; +import com.simibubi.create.content.contraptions.components.structureMovement.render.ActorInstance; +import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionKineticRenderer; +import com.simibubi.create.foundation.render.backend.core.OrientedData; +import com.simibubi.create.foundation.utility.AnimationTickHolder; + +public class StabilizedBearingInstance extends ActorInstance { + + final OrientedData topInstance; + + final Direction facing; + final Vector3f rotationAxis; + final Quaternion blockOrientation; + + public StabilizedBearingInstance(ContraptionKineticRenderer modelManager, MovementContext context) { + super(modelManager, context); + + BlockState blockState = context.state; + + facing = blockState.get(BlockStateProperties.FACING); + rotationAxis = Direction.getFacingFromAxis(Direction.AxisDirection.POSITIVE, facing.getAxis()).getUnitVector(); + + blockOrientation = BearingInstance.getBlockStateOrientation(facing); + + topInstance = modelManager.getOrientedMaterial().getModel(AllBlockPartials.BEARING_TOP, blockState).createInstance(); + + topInstance.setPosition(context.localPos) + .setRotation(blockOrientation) + .setBlockLight(localBlockLight()); + } + + @Override + public void beginFrame() { + float counterRotationAngle = StabilizedBearingMovementBehaviour.getCounterRotationAngle(context, facing, AnimationTickHolder.getPartialTicks()); + + Quaternion rotation = rotationAxis.getDegreesQuaternion(counterRotationAngle); + + rotation.multiply(blockOrientation); + + topInstance.setRotation(rotation); + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/StabilizedBearingMovementBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/StabilizedBearingMovementBehaviour.java index b2a517625..fda46bb8d 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/StabilizedBearingMovementBehaviour.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/StabilizedBearingMovementBehaviour.java @@ -7,12 +7,16 @@ import com.simibubi.create.content.contraptions.components.structureMovement.Con import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour; import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; import com.simibubi.create.content.contraptions.components.structureMovement.OrientedContraptionEntity; +import com.simibubi.create.content.contraptions.components.structureMovement.render.ActorInstance; +import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionKineticRenderer; import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionRenderDispatcher; import com.simibubi.create.foundation.render.SuperByteBuffer; +import com.simibubi.create.foundation.render.backend.FastRenderDispatcher; import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.AnimationTickHolder; import net.minecraft.client.renderer.IRenderTypeBuffer; +import net.minecraft.client.renderer.Quaternion; import net.minecraft.client.renderer.RenderType; import net.minecraft.state.properties.BlockStateProperties; import net.minecraft.util.Direction; @@ -20,28 +24,57 @@ import net.minecraft.util.Direction.Axis; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; +import javax.annotation.Nullable; + public class StabilizedBearingMovementBehaviour extends MovementBehaviour { @Override @OnlyIn(Dist.CLIENT) public void renderInContraption(MovementContext context, MatrixStack ms, MatrixStack msLocal, IRenderTypeBuffer buffer) { + if (FastRenderDispatcher.available()) return; + Direction facing = context.state.get(BlockStateProperties.FACING); AllBlockPartials top = AllBlockPartials.BEARING_TOP; SuperByteBuffer superBuffer = top.renderOn(context.state); float renderPartialTicks = AnimationTickHolder.getPartialTicks(); // rotate to match blockstate - Axis axis = facing.getAxis(); - if (axis.isHorizontal()) - superBuffer.rotateCentered(Direction.UP, - AngleHelper.rad(AngleHelper.horizontalAngle(facing.getOpposite()))); - superBuffer.rotateCentered(Direction.EAST, AngleHelper.rad(-90 - AngleHelper.verticalAngle(facing))); + Quaternion orientation = BearingInstance.getBlockStateOrientation(facing); // rotate against parent + float angle = getCounterRotationAngle(context, facing, renderPartialTicks) * facing.getAxisDirection().getOffset(); + + Quaternion rotation = facing.getUnitVector().getDegreesQuaternion(angle); + + rotation.multiply(orientation); + + orientation = rotation; + + superBuffer.rotateCentered(orientation); + + // render + superBuffer.light(msLocal.peek() + .getModel(), ContraptionRenderDispatcher.getLightOnContraption(context)); + superBuffer.renderInto(ms, buffer.getBuffer(RenderType.getSolid())); + } + + @Override + public boolean hasSpecialInstancedRendering() { + return true; + } + + @Nullable + @Override + public ActorInstance createInstance(ContraptionKineticRenderer kr, MovementContext context) { + return new StabilizedBearingInstance(kr, context); + } + + static float getCounterRotationAngle(MovementContext context, Direction facing, float renderPartialTicks) { float offset = 0; - int offsetMultiplier = facing.getAxisDirection().getOffset(); - + + Axis axis = facing.getAxis(); + AbstractContraptionEntity entity = context.contraption.entity; if (entity instanceof ControlledContraptionEntity) { ControlledContraptionEntity controlledCE = (ControlledContraptionEntity) entity; @@ -54,17 +87,12 @@ public class StabilizedBearingMovementBehaviour extends MovementBehaviour { offset = -orientedCE.getYaw(renderPartialTicks); else { if (orientedCE.isInitialOrientationPresent() && orientedCE.getInitialOrientation() - .getAxis() == axis) + .getAxis() == axis) offset = -orientedCE.getPitch(renderPartialTicks); } } - if (offset != 0) - superBuffer.rotateCentered(Direction.UP, AngleHelper.rad(offset * offsetMultiplier)); - - // render - superBuffer.light(msLocal.peek() - .getModel(), ContraptionRenderDispatcher.getLightOnContraption(context)); - superBuffer.renderInto(ms, buffer.getBuffer(RenderType.getSolid())); + return offset; } + } diff --git a/src/main/java/com/simibubi/create/content/curiosities/TreeFertilizerItem.java b/src/main/java/com/simibubi/create/content/curiosities/TreeFertilizerItem.java index ebed5db35..65768046d 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/TreeFertilizerItem.java +++ b/src/main/java/com/simibubi/create/content/curiosities/TreeFertilizerItem.java @@ -31,8 +31,8 @@ public class TreeFertilizerItem extends Item { return ActionResultType.SUCCESS; } - TreesDreamWorld world = new TreesDreamWorld((ServerWorld) context.getWorld(), context.getPos()); BlockPos saplingPos = context.getPos(); + TreesDreamWorld world = new TreesDreamWorld((ServerWorld) context.getWorld(), saplingPos); for (BlockPos pos : BlockPos.getAllInBoxMutable(-1, 0, -1, 1, 0, 1)) { if (context.getWorld() @@ -45,8 +45,8 @@ public class TreeFertilizerItem extends Item { state.with(SaplingBlock.STAGE, 1)); for (BlockPos pos : world.blocksAdded.keySet()) { - BlockPos actualPos = pos.add(saplingPos) - .down(10); + BlockPos actualPos = pos.add(saplingPos).down(10); + BlockState newState = world.blocksAdded.get(pos); // Don't replace Bedrock if (context.getWorld() @@ -54,21 +54,15 @@ public class TreeFertilizerItem extends Item { .getBlockHardness(context.getWorld(), actualPos) == -1) continue; // Don't replace solid blocks with leaves - if (!world.getBlockState(pos) - .isNormalCube(world, pos) + if (!newState.isNormalCube(world, pos) && !context.getWorld() .getBlockState(actualPos) .getCollisionShape(context.getWorld(), actualPos) .isEmpty()) continue; - if (world.getBlockState(pos) - .getBlock() == Blocks.GRASS_BLOCK - || world.getBlockState(pos) - .getBlock() == Blocks.PODZOL) - continue; context.getWorld() - .setBlockState(actualPos, world.getBlockState(pos)); + .setBlockState(actualPos, newState); } if (context.getPlayer() != null && !context.getPlayer() @@ -84,21 +78,27 @@ public class TreeFertilizerItem extends Item { private class TreesDreamWorld extends PlacementSimulationServerWorld { private final BlockPos saplingPos; + private final BlockState soil; protected TreesDreamWorld(ServerWorld wrapped, BlockPos saplingPos) { super(wrapped); this.saplingPos = saplingPos; + soil = wrapped.getBlockState(saplingPos.down()); } @Override public BlockState getBlockState(BlockPos pos) { if (pos.getY() <= 9) - return world.getBlockState(saplingPos.down()); + return soil; return super.getBlockState(pos); } + @Override + public boolean setBlockState(BlockPos pos, BlockState newState, int flags) { + if (newState.getBlock() == Blocks.PODZOL) + return true; + return super.setBlockState(pos, newState, flags); + } } - - } diff --git a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmInstance.java b/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmInstance.java index dfa54051f..4a6ada3c4 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmInstance.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmInstance.java @@ -30,9 +30,15 @@ public class ArmInstance extends SingleRotatingInstance implements IDynamicInsta private final ArrayList models; private final ArmTileEntity arm; + private final Boolean ceiling; private boolean firstTick = true; + private float baseAngle = Float.NaN; + private float lowerArmAngle = Float.NaN; + private float upperArmAngle = Float.NaN; + private float headAngle = Float.NaN; + public ArmInstance(InstancedTileRenderer modelManager, ArmTileEntity tile) { super(modelManager, tile); @@ -51,31 +57,49 @@ public class ArmInstance extends SingleRotatingInstance implements IDynamicInsta clawGrips = Lists.newArrayList(clawGrip1, clawGrip2); models = Lists.newArrayList(base, lowerBody, upperBody, head, claw, clawGrip1, clawGrip2); arm = tile; + ceiling = blockState.get(ArmBlock.CEILING); animateArm(false); } @Override public void beginFrame() { + if (arm.phase == ArmTileEntity.Phase.DANCING) { + animateArm(true); + return; + } - boolean settled = arm.baseAngle.settled() && arm.lowerArmAngle.settled() && arm.upperArmAngle.settled() && arm.headAngle.settled(); - boolean rave = arm.phase == ArmTileEntity.Phase.DANCING; + float pt = AnimationTickHolder.getPartialTicks(); - if (!settled || rave || firstTick) - animateArm(rave); + float baseAngleNow = this.arm.baseAngle.get(pt); + float lowerArmAngleNow = this.arm.lowerArmAngle.get(pt); + float upperArmAngleNow = this.arm.upperArmAngle.get(pt); + float headAngleNow = this.arm.headAngle.get(pt); + + boolean settled = MathHelper.epsilonEquals(baseAngle, baseAngleNow) + && MathHelper.epsilonEquals(lowerArmAngle, lowerArmAngleNow) + && MathHelper.epsilonEquals(upperArmAngle, upperArmAngleNow) + && MathHelper.epsilonEquals(headAngle, headAngleNow); + + this.baseAngle = baseAngleNow; + this.lowerArmAngle = lowerArmAngleNow; + this.upperArmAngle = upperArmAngleNow; + this.headAngle = headAngleNow; + + if (!settled || firstTick) + animateArm(false); if (settled) firstTick = false; } private void animateArm(boolean rave) { - float pt = AnimationTickHolder.getPartialTicks(); - int color = 0xFFFFFF; - float baseAngle = this.arm.baseAngle.get(pt); - float lowerArmAngle = this.arm.lowerArmAngle.get(pt) - 135; - float upperArmAngle = this.arm.upperArmAngle.get(pt) - 90; - float headAngle = this.arm.headAngle.get(pt); + int color; + float baseAngle; + float lowerArmAngle; + float upperArmAngle; + float headAngle; if (rave) { float renderTick = AnimationTickHolder.getRenderTime(this.arm.getWorld()) + (tile.hashCode() % 64); @@ -83,7 +107,15 @@ public class ArmInstance extends SingleRotatingInstance implements IDynamicInsta lowerArmAngle = MathHelper.lerp((MathHelper.sin(renderTick / 4) + 1) / 2, -45, 15); upperArmAngle = MathHelper.lerp((MathHelper.sin(renderTick / 8) + 1) / 4, -45, 95); headAngle = -lowerArmAngle; + color = ColorHelper.rainbowColor(AnimationTickHolder.getTicks() * 100); + } else { + baseAngle = this.baseAngle; + lowerArmAngle = this.lowerArmAngle - 135; + upperArmAngle = this.upperArmAngle - 90; + headAngle = this.headAngle; + + color = 0xFFFFFF; } MatrixStack msLocal = new MatrixStack(); @@ -91,7 +123,7 @@ public class ArmInstance extends SingleRotatingInstance implements IDynamicInsta msr.translate(getInstancePosition()); msr.centre(); - if (blockState.get(ArmBlock.CEILING)) + if (ceiling) msr.rotateX(180); ArmRenderer.transformBase(msr, baseAngle); diff --git a/src/main/java/com/simibubi/create/foundation/render/SuperByteBuffer.java b/src/main/java/com/simibubi/create/foundation/render/SuperByteBuffer.java index d15aa0bcd..415e62acf 100644 --- a/src/main/java/com/simibubi/create/foundation/render/SuperByteBuffer.java +++ b/src/main/java/com/simibubi/create/foundation/render/SuperByteBuffer.java @@ -196,11 +196,21 @@ public class SuperByteBuffer extends TemplateBuffer { return this; } + public SuperByteBuffer rotate(Quaternion q) { + transforms.multiply(q); + return this; + } + public SuperByteBuffer rotateCentered(Direction axis, float radians) { return translate(.5f, .5f, .5f).rotate(axis, radians) .translate(-.5f, -.5f, -.5f); } + public SuperByteBuffer rotateCentered(Quaternion q) { + return translate(.5f, .5f, .5f).rotate(q) + .translate(-.5f, -.5f, -.5f); + } + public SuperByteBuffer shiftUV(SpriteShiftEntry entry) { this.spriteShiftFunc = (builder, u, v) -> { float targetU = entry.getTarget().getInterpolatedU((getUnInterpolatedU(entry.getOriginal(), u))); diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/Backend.java b/src/main/java/com/simibubi/create/foundation/render/backend/Backend.java index 20292f6d7..b8393ae4a 100644 --- a/src/main/java/com/simibubi/create/foundation/render/backend/Backend.java +++ b/src/main/java/com/simibubi/create/foundation/render/backend/Backend.java @@ -1,19 +1,17 @@ package com.simibubi.create.foundation.render.backend; -import java.nio.FloatBuffer; import java.util.HashMap; import java.util.Map; import com.simibubi.create.foundation.render.backend.gl.GlFog; import com.simibubi.create.foundation.render.backend.gl.shader.*; -import com.simibubi.create.foundation.render.backend.gl.versioned.GlFeatureCompat; +import com.simibubi.create.foundation.render.backend.gl.versioned.GlCompat; import com.simibubi.create.foundation.render.backend.instancing.IFlywheelWorld; import net.minecraft.world.World; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.lwjgl.opengl.GL; import org.lwjgl.opengl.GLCapabilities; -import org.lwjgl.system.MemoryUtil; import com.simibubi.create.foundation.config.AllConfigs; @@ -28,7 +26,7 @@ public class Backend { public static final Logger log = LogManager.getLogger(Backend.class); public static GLCapabilities capabilities; - public static GlFeatureCompat compat; + public static GlCompat compat; private static boolean instancingAvailable; private static boolean enabled; @@ -97,7 +95,7 @@ public class Backend { public static void refresh() { capabilities = GL.createCapabilities(); - compat = new GlFeatureCompat(capabilities); + compat = new GlCompat(capabilities); instancingAvailable = compat.vertexArrayObjectsSupported() && compat.drawInstancedSupported() && diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/ShaderLoader.java b/src/main/java/com/simibubi/create/foundation/render/backend/ShaderLoader.java index c512fd8a7..4c6592720 100644 --- a/src/main/java/com/simibubi/create/foundation/render/backend/ShaderLoader.java +++ b/src/main/java/com/simibubi/create/foundation/render/backend/ShaderLoader.java @@ -1,17 +1,16 @@ package com.simibubi.create.foundation.render.backend; import com.google.common.collect.Lists; -import com.google.common.collect.Sets; import com.mojang.blaze3d.systems.RenderSystem; import com.simibubi.create.foundation.render.backend.gl.GlFogMode; import com.simibubi.create.foundation.render.backend.gl.shader.*; -import com.simibubi.create.foundation.render.backend.gl.versioned.GlFeatureCompat; + import net.minecraft.resources.IResource; import net.minecraft.resources.IResourceManager; import net.minecraft.util.ResourceLocation; import net.minecraftforge.resource.IResourceType; import net.minecraftforge.resource.VanillaResourceType; -import org.lwjgl.opengl.GL; + import org.lwjgl.system.MemoryUtil; import java.io.*; diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/GlShader.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/GlShader.java index 922b81b47..dc54e425b 100644 --- a/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/GlShader.java +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/GlShader.java @@ -4,6 +4,7 @@ import org.lwjgl.opengl.GL20; import com.simibubi.create.foundation.render.backend.Backend; import com.simibubi.create.foundation.render.backend.gl.GlObject; +import com.simibubi.create.foundation.render.backend.gl.versioned.GlCompat; import net.minecraft.util.ResourceLocation; @@ -17,7 +18,7 @@ public class GlShader extends GlObject { this.name = name; int handle = GL20.glCreateShader(type.glEnum); - GL20.glShaderSource(handle, source); + GlCompat.safeShaderSource(handle, source); GL20.glCompileShader(handle); String log = GL20.glGetShaderInfoLog(handle); diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/versioned/GlFeatureCompat.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/versioned/GlCompat.java similarity index 66% rename from src/main/java/com/simibubi/create/foundation/render/backend/gl/versioned/GlFeatureCompat.java rename to src/main/java/com/simibubi/create/foundation/render/backend/gl/versioned/GlCompat.java index b2eba08e1..9cb150a51 100644 --- a/src/main/java/com/simibubi/create/foundation/render/backend/gl/versioned/GlFeatureCompat.java +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/versioned/GlCompat.java @@ -1,6 +1,10 @@ package com.simibubi.create.foundation.render.backend.gl.versioned; +import org.lwjgl.PointerBuffer; +import org.lwjgl.opengl.GL20C; import org.lwjgl.opengl.GLCapabilities; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.system.MemoryUtil; import java.nio.ByteBuffer; import java.util.Arrays; @@ -13,7 +17,7 @@ import java.util.function.Consumer; * Each field stores an enum variant that provides access to the * most appropriate version of a feature for the current system. */ -public class GlFeatureCompat { +public class GlCompat { public final MapBuffer mapBuffer; public final VertexArrayObject vertexArrayObject; @@ -22,7 +26,7 @@ public class GlFeatureCompat { public final RGPixelFormat pixelFormat; - public GlFeatureCompat(GLCapabilities caps) { + public GlCompat(GLCapabilities caps) { mapBuffer = getLatest(MapBuffer.class, caps); vertexArrayObject = getLatest(VertexArrayObject.class, caps); @@ -85,5 +89,33 @@ public class GlFeatureCompat { return Arrays.stream(constants).filter(it -> it.supported(caps)).findFirst().get(); } + + /** + * Copied from: + *
https://github.com/grondag/canvas/commit/820bf754092ccaf8d0c169620c2ff575722d7d96 + * + *

Identical in function to {@link GL20C#glShaderSource(int, CharSequence)} but + * passes a null pointer for string length to force the driver to rely on the null + * terminator for string length. This is a workaround for an apparent flaw with some + * AMD drivers that don't receive or interpret the length correctly, resulting in + * an access violation when the driver tries to read past the string memory. + * + *

Hat tip to fewizz for the find and the fix. + */ + public static void safeShaderSource(int glId, CharSequence source) { + final MemoryStack stack = MemoryStack.stackGet(); + final int stackPointer = stack.getPointer(); + + try { + final ByteBuffer sourceBuffer = MemoryUtil.memUTF8(source, true); + final PointerBuffer pointers = stack.mallocPointer(1); + pointers.put(sourceBuffer); + + GL20C.nglShaderSource(glId, 1, pointers.address0(), 0); + org.lwjgl.system.APIUtil.apiArrayFree(pointers.address0(), 1); + } finally { + stack.setPointer(stackPointer); + } + } } diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/instancing/InstancedTileRenderer.java b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/InstancedTileRenderer.java index 5713dde47..78f07111d 100644 --- a/src/main/java/com/simibubi/create/foundation/render/backend/instancing/InstancedTileRenderer.java +++ b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/InstancedTileRenderer.java @@ -33,6 +33,7 @@ public abstract class InstancedTileRenderer

{ protected Map, RenderMaterial> materials = new HashMap<>(); protected int frame; + protected int tick; protected InstancedTileRenderer() { registerMaterials(); @@ -43,6 +44,8 @@ public abstract class InstancedTileRenderer

{ public abstract void registerMaterials(); public void tick(double cameraX, double cameraY, double cameraZ) { + tick++; + // integer camera pos int cX = (int) cameraX; int cY = (int) cameraY; @@ -61,7 +64,7 @@ public abstract class InstancedTileRenderer

{ int dY = pos.getY() - cY; int dZ = pos.getZ() - cZ; - if ((frame % getUpdateDivisor(dX, dY, dZ)) == 0) + if ((tick % getUpdateDivisor(dX, dY, dZ)) == 0) instance.tick(); } } @@ -198,9 +201,9 @@ public abstract class InstancedTileRenderer

{ int dY = worldPos.getY() - cY; int dZ = worldPos.getZ() - cZ; - float dot = dX * lookX + dY * lookY + dZ * lookZ; + float dot = (dX + lookX * 2) * lookX + (dY + lookY * 2) * lookY + (dZ + lookZ * 2) * lookZ; - if (dot < 0) return false; // is it behind the camera? + if (dot < 0) return false; // is it more than 2 blocks behind the camera? return (frame % getUpdateDivisor(dX, dY, dZ)) == 0; }