diff --git a/src/main/java/com/simibubi/create/AllEntityTypes.java b/src/main/java/com/simibubi/create/AllEntityTypes.java index 08a1a8d1a..1543d8eb7 100644 --- a/src/main/java/com/simibubi/create/AllEntityTypes.java +++ b/src/main/java/com/simibubi/create/AllEntityTypes.java @@ -1,11 +1,7 @@ package com.simibubi.create; import com.simibubi.create.content.contraptions.components.actors.SeatEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.ControlledContraptionEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.ControlledContraptionEntityRenderer; -import com.simibubi.create.content.contraptions.components.structureMovement.OrientedContraptionEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.OrientedContraptionEntityRenderer; +import com.simibubi.create.content.contraptions.components.structureMovement.*; import com.simibubi.create.content.contraptions.components.structureMovement.glue.SuperGlueEntity; import com.simibubi.create.content.contraptions.components.structureMovement.glue.SuperGlueRenderer; import com.simibubi.create.foundation.utility.Lang; @@ -51,7 +47,7 @@ public class AllEntityTypes { @OnlyIn(value = Dist.CLIENT) public static void registerRenderers() { RenderingRegistry.registerEntityRenderingHandler(CONTROLLED_CONTRAPTION.get(), - ControlledContraptionEntityRenderer::new); + ContraptionEntityRenderer::new); RenderingRegistry.registerEntityRenderingHandler(ORIENTED_CONTRAPTION.get(), OrientedContraptionEntityRenderer::new); RenderingRegistry.registerEntityRenderingHandler(SUPER_GLUE.get(), SuperGlueRenderer::new); diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/KineticData.java b/src/main/java/com/simibubi/create/content/contraptions/base/KineticData.java index bf543f563..a5f2889ba 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/base/KineticData.java +++ b/src/main/java/com/simibubi/create/content/contraptions/base/KineticData.java @@ -1,6 +1,7 @@ package com.simibubi.create.content.contraptions.base; import com.simibubi.create.foundation.render.backend.instancing.InstanceData; +import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; import com.simibubi.create.foundation.utility.ColorHelper; import net.minecraft.client.renderer.Vector3f; import net.minecraft.util.math.BlockPos; @@ -19,6 +20,10 @@ public class KineticData> extends InstanceData { private float rotationalSpeed; private float rotationOffset; + protected KineticData(InstancedModel owner) { + super(owner); + } + public D setTileEntity(KineticTileEntity te) { setPosition(te.getPos()); if (te.hasSource()) { @@ -37,6 +42,14 @@ public class KineticData> extends InstanceData { return setPosition(pos.getX(), pos.getY(), pos.getZ()); } + public D setPosition(int x, int y, int z) { + BlockPos origin = owner.renderer.getOriginCoordinate(); + + return setPosition((float) (x - origin.getX()), + (float) (y - origin.getY()), + (float) (z - origin.getZ())); + } + public D setPosition(float x, float y, float z) { this.x = x; this.y = y; diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/RotatingData.java b/src/main/java/com/simibubi/create/content/contraptions/base/RotatingData.java index c8afa2c35..75fca6a53 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/base/RotatingData.java +++ b/src/main/java/com/simibubi/create/content/contraptions/base/RotatingData.java @@ -1,6 +1,7 @@ package com.simibubi.create.content.contraptions.base; import com.simibubi.create.foundation.render.backend.gl.attrib.VertexFormat; +import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; import net.minecraft.client.renderer.Vector3f; import net.minecraft.util.Direction; @@ -16,6 +17,10 @@ public class RotatingData extends KineticData { private byte rotationAxisY; private byte rotationAxisZ; + protected RotatingData(InstancedModel owner) { + super(owner); + } + public RotatingData setRotationAxis(Direction.Axis axis) { Direction orientation = Direction.getFacingFromAxis(Direction.AxisDirection.POSITIVE, axis); setRotationAxis(orientation.getUnitVector()); diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/RotatingInstancedModel.java b/src/main/java/com/simibubi/create/content/contraptions/base/RotatingInstancedModel.java index 420121124..0b9a2e998 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/base/RotatingInstancedModel.java +++ b/src/main/java/com/simibubi/create/content/contraptions/base/RotatingInstancedModel.java @@ -2,16 +2,17 @@ package com.simibubi.create.content.contraptions.base; import com.simibubi.create.foundation.render.backend.gl.attrib.VertexFormat; import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; +import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; import net.minecraft.client.renderer.BufferBuilder; public class RotatingInstancedModel extends InstancedModel { - public RotatingInstancedModel(BufferBuilder buf) { - super(buf); + public RotatingInstancedModel(InstancedTileRenderer renderer, BufferBuilder buf) { + super(renderer, buf); } @Override protected RotatingData newInstance() { - return new RotatingData(); + return new RotatingData(this); } @Override diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/ContraptionActorData.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/ContraptionActorData.java index 5f6494a62..d7eb78b24 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/ContraptionActorData.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/actors/ContraptionActorData.java @@ -2,6 +2,7 @@ package com.simibubi.create.content.contraptions.components.actors; import com.simibubi.create.foundation.render.backend.gl.attrib.VertexFormat; import com.simibubi.create.foundation.render.backend.instancing.InstanceData; +import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; import net.minecraft.client.renderer.Vector3f; import net.minecraft.util.math.BlockPos; @@ -28,6 +29,11 @@ public class ContraptionActorData extends InstanceData { private byte rotationCenterY = 64; private byte rotationCenterZ = 64; + protected ContraptionActorData(InstancedModel owner) { + super(owner); + } + + public ContraptionActorData setPosition(BlockPos pos) { this.x = pos.getX(); this.y = pos.getY(); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/RotatingActorModel.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/RotatingActorModel.java index 481df3061..0efe011b0 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/RotatingActorModel.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/actors/RotatingActorModel.java @@ -2,11 +2,12 @@ package com.simibubi.create.content.contraptions.components.actors; import com.simibubi.create.foundation.render.backend.gl.attrib.VertexFormat; import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; +import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; import net.minecraft.client.renderer.BufferBuilder; public class RotatingActorModel extends InstancedModel { - public RotatingActorModel(BufferBuilder buf) { - super(buf); + public RotatingActorModel(InstancedTileRenderer renderer, BufferBuilder buf) { + super(renderer, buf); } @Override @@ -16,6 +17,6 @@ public class RotatingActorModel extends InstancedModel { @Override protected ContraptionActorData newInstance() { - return new ContraptionActorData(); + return new ContraptionActorData(this); } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/AbstractContraptionEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/AbstractContraptionEntity.java index 84b7f8b64..76e764d89 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/AbstractContraptionEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/AbstractContraptionEntity.java @@ -7,6 +7,7 @@ import java.util.Map; import java.util.Map.Entry; import java.util.UUID; +import com.mojang.blaze3d.matrix.MatrixStack; import org.apache.commons.lang3.mutable.MutableInt; import org.apache.commons.lang3.tuple.MutablePair; @@ -593,6 +594,9 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit return false; } + @OnlyIn(Dist.CLIENT) + public abstract void doLocalTransforms(float partialTicks, MatrixStack[] matrixStacks); + public static class ContraptionRotationState { static final ContraptionRotationState NONE = new ContraptionRotationState(); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/AbstractContraptionEntityRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionEntityRenderer.java similarity index 61% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/AbstractContraptionEntityRenderer.java rename to src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionEntityRenderer.java index 92b0baf9a..850d92446 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/AbstractContraptionEntityRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionEntityRenderer.java @@ -10,37 +10,26 @@ import net.minecraft.client.renderer.entity.EntityRendererManager; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.MathHelper; -public abstract class AbstractContraptionEntityRenderer extends EntityRenderer { +public class ContraptionEntityRenderer extends EntityRenderer { - protected AbstractContraptionEntityRenderer(EntityRendererManager p_i46179_1_) { + public ContraptionEntityRenderer(EntityRendererManager p_i46179_1_) { super(p_i46179_1_); } @Override - public ResourceLocation getEntityTexture(C p_110775_1_) { + public ResourceLocation getEntityTexture(C entity) { return null; } - protected abstract void transform(C contraptionEntity, float partialTicks, MatrixStack[] matrixStacks); - - public MatrixStack makeTransformMatrix(C contraptionEntity, float partialTicks) { - MatrixStack stack = getLocalTransform(contraptionEntity, partialTicks); - - transform(contraptionEntity, partialTicks, new MatrixStack[]{ stack }); - - return stack; - } - @Override - public boolean shouldRender(C entity, ClippingHelperImpl p_225626_2_, double p_225626_3_, double p_225626_5_, + public boolean shouldRender(C entity, ClippingHelperImpl clippingHelper, double p_225626_3_, double p_225626_5_, double p_225626_7_) { - if (!super.shouldRender(entity, p_225626_2_, p_225626_3_, p_225626_5_, p_225626_7_)) + if (entity.getContraption() == null) return false; if (!entity.isAlive()) return false; - if (entity.getContraption() == null) - return false; - return true; + + return super.shouldRender(entity, clippingHelper, p_225626_3_, p_225626_5_, p_225626_7_); } @Override @@ -49,11 +38,11 @@ public abstract class AbstractContraptionEntityRenderer { - - public ControlledContraptionEntityRenderer(EntityRendererManager p_i46179_1_) { - super(p_i46179_1_); - } - - @Override - protected void transform(ControlledContraptionEntity entity, float partialTicks, - MatrixStack[] matrixStacks) { - float angle = entity.getAngle(partialTicks); - Axis axis = entity.getRotationAxis(); - - for (MatrixStack stack : matrixStacks) - MatrixStacker.of(stack) - .nudge(entity.getEntityId()) - .centre() - .rotate(angle, axis) - .unCentre(); - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/OrientedContraptionEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/OrientedContraptionEntity.java index cf77d0a14..8b6df8b9b 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/OrientedContraptionEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/OrientedContraptionEntity.java @@ -7,6 +7,7 @@ import java.util.UUID; import javax.annotation.Nullable; +import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.AllEntityTypes; import com.simibubi.create.content.contraptions.components.structureMovement.bearing.StabilizedContraption; import com.simibubi.create.content.contraptions.components.structureMovement.mounted.CartAssemblerTileEntity.CartMovementMode; @@ -14,10 +15,7 @@ import com.simibubi.create.content.contraptions.components.structureMovement.mou import com.simibubi.create.content.contraptions.components.structureMovement.train.capability.CapabilityMinecartController; import com.simibubi.create.content.contraptions.components.structureMovement.train.capability.MinecartController; import com.simibubi.create.foundation.item.ItemHelper; -import com.simibubi.create.foundation.utility.AngleHelper; -import com.simibubi.create.foundation.utility.Couple; -import com.simibubi.create.foundation.utility.NBTHelper; -import com.simibubi.create.foundation.utility.VecHelper; +import com.simibubi.create.foundation.utility.*; import net.minecraft.block.BlockState; import net.minecraft.entity.Entity; @@ -40,6 +38,8 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.common.util.LazyOptional; /** @@ -494,4 +494,89 @@ public class OrientedContraptionEntity extends AbstractContraptionEntity { yaw = angle; } + @Override + @OnlyIn(Dist.CLIENT) + public void doLocalTransforms(float partialTicks, MatrixStack[] matrixStacks) { + float angleInitialYaw = getInitialYaw(); + float angleYaw = getYaw(partialTicks); + float anglePitch = getPitch(partialTicks); + + for (MatrixStack stack : matrixStacks) + stack.translate(-.5f, 0, -.5f); + + Entity ridingEntity = getRidingEntity(); + if (ridingEntity instanceof AbstractMinecartEntity) + repositionOnCart(partialTicks, matrixStacks, ridingEntity); + else if (ridingEntity instanceof AbstractContraptionEntity) { + if (ridingEntity.getRidingEntity() instanceof AbstractMinecartEntity) + repositionOnCart(partialTicks, matrixStacks, ridingEntity.getRidingEntity()); + else + repositionOnContraption(partialTicks, matrixStacks, ridingEntity); + } + + for (MatrixStack stack : matrixStacks) + MatrixStacker.of(stack) + .nudge(getEntityId()) + .centre() + .rotateY(angleYaw) + .rotateZ(anglePitch) + .rotateY(angleInitialYaw) + .unCentre(); + } + + @OnlyIn(Dist.CLIENT) + private void repositionOnContraption(float partialTicks, MatrixStack[] matrixStacks, Entity ridingEntity) { + Vec3d pos = getContraptionOffset(partialTicks, ridingEntity); + for (MatrixStack stack : matrixStacks) + stack.translate(pos.x, pos.y, pos.z); + } + + // Minecarts do not always render at their exact location, so the contraption + // has to adjust aswell + @OnlyIn(Dist.CLIENT) + private void repositionOnCart(float partialTicks, MatrixStack[] matrixStacks, Entity ridingEntity) { + Vec3d cartPos = getCartOffset(partialTicks, ridingEntity); + + if (cartPos == Vec3d.ZERO) return; + + for (MatrixStack stack : matrixStacks) + stack.translate(cartPos.x, cartPos.y, cartPos.z); + } + + @OnlyIn(Dist.CLIENT) + private Vec3d getContraptionOffset(float partialTicks, Entity ridingEntity) { + AbstractContraptionEntity parent = (AbstractContraptionEntity) ridingEntity; + Vec3d passengerPosition = parent.getPassengerPosition(this, partialTicks); + double x = passengerPosition.x - MathHelper.lerp(partialTicks, this.lastTickPosX, this.getX()); + double y = passengerPosition.y - MathHelper.lerp(partialTicks, this.lastTickPosY, this.getY()); + double z = passengerPosition.z - MathHelper.lerp(partialTicks, this.lastTickPosZ, this.getZ()); + + return new Vec3d(x, y, z); + } + + @OnlyIn(Dist.CLIENT) + private Vec3d getCartOffset(float partialTicks, Entity ridingEntity) { + AbstractMinecartEntity cart = (AbstractMinecartEntity) ridingEntity; + double cartX = MathHelper.lerp(partialTicks, cart.lastTickPosX, cart.getX()); + double cartY = MathHelper.lerp(partialTicks, cart.lastTickPosY, cart.getY()); + double cartZ = MathHelper.lerp(partialTicks, cart.lastTickPosZ, cart.getZ()); + Vec3d cartPos = cart.getPos(cartX, cartY, cartZ); + + if (cartPos != null) { + Vec3d cartPosFront = cart.getPosOffset(cartX, cartY, cartZ, (double) 0.3F); + Vec3d cartPosBack = cart.getPosOffset(cartX, cartY, cartZ, (double) -0.3F); + if (cartPosFront == null) + cartPosFront = cartPos; + if (cartPosBack == null) + cartPosBack = cartPos; + + cartX = cartPos.x - cartX; + cartY = (cartPosFront.y + cartPosBack.y) / 2.0D - cartY; + cartZ = cartPos.z - cartZ; + + return new Vec3d(cartX, cartY, cartZ); + } + + return Vec3d.ZERO; + } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/OrientedContraptionEntityRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/OrientedContraptionEntityRenderer.java index 8f563a92b..f1b42cda4 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/OrientedContraptionEntityRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/OrientedContraptionEntityRenderer.java @@ -1,113 +1,20 @@ package com.simibubi.create.content.contraptions.components.structureMovement; -import com.mojang.blaze3d.matrix.MatrixStack; -import com.simibubi.create.foundation.utility.MatrixStacker; - import net.minecraft.client.renderer.culling.ClippingHelperImpl; import net.minecraft.client.renderer.entity.EntityRendererManager; -import net.minecraft.entity.Entity; -import net.minecraft.entity.item.minecart.AbstractMinecartEntity; -import net.minecraft.util.Direction; -import net.minecraft.util.math.MathHelper; -import net.minecraft.util.math.Vec3d; -public class OrientedContraptionEntityRenderer extends AbstractContraptionEntityRenderer { +public class OrientedContraptionEntityRenderer extends ContraptionEntityRenderer { public OrientedContraptionEntityRenderer(EntityRendererManager p_i46179_1_) { super(p_i46179_1_); } @Override - public boolean shouldRender(OrientedContraptionEntity entity, ClippingHelperImpl p_225626_2_, double p_225626_3_, + public boolean shouldRender(OrientedContraptionEntity entity, ClippingHelperImpl clippingHelper, double p_225626_3_, double p_225626_5_, double p_225626_7_) { - if (!super.shouldRender(entity, p_225626_2_, p_225626_3_, p_225626_5_, p_225626_7_)) + if (!super.shouldRender(entity, clippingHelper, p_225626_3_, p_225626_5_, p_225626_7_)) return false; - if (entity.getContraption() - .getType() == AllContraptionTypes.MOUNTED && entity.getRidingEntity() == null) - return false; - return true; + + return entity.getContraption().getType() != AllContraptionTypes.MOUNTED || entity.getRidingEntity() != null; } - - @Override - protected void transform(OrientedContraptionEntity entity, float partialTicks, MatrixStack[] matrixStacks) { - float angleInitialYaw = entity.getInitialYaw(); - float angleYaw = entity.getYaw(partialTicks); - float anglePitch = entity.getPitch(partialTicks); - - for (MatrixStack stack : matrixStacks) - stack.translate(-.5f, 0, -.5f); - - Entity ridingEntity = entity.getRidingEntity(); - if (ridingEntity instanceof AbstractMinecartEntity) - repositionOnCart(partialTicks, matrixStacks, ridingEntity); - else if (ridingEntity instanceof AbstractContraptionEntity) { - if (ridingEntity.getRidingEntity() instanceof AbstractMinecartEntity) - repositionOnCart(partialTicks, matrixStacks, ridingEntity.getRidingEntity()); - else - repositionOnContraption(entity, partialTicks, matrixStacks, ridingEntity); - } - - for (MatrixStack stack : matrixStacks) - MatrixStacker.of(stack) - .nudge(entity.getEntityId()) - .centre() - .rotateY(angleYaw) - .rotateZ(anglePitch) - .rotateY(angleInitialYaw) - .unCentre(); - } - - private void repositionOnContraption(OrientedContraptionEntity entity, float partialTicks, - MatrixStack[] matrixStacks, Entity ridingEntity) { - Vec3d pos = getContraptionOffset(entity, partialTicks, ridingEntity); - for (MatrixStack stack : matrixStacks) - stack.translate(pos.x, pos.y, pos.z); - } - - // Minecarts do not always render at their exact location, so the contraption - // has to adjust aswell - private void repositionOnCart(float partialTicks, MatrixStack[] matrixStacks, Entity ridingEntity) { - Vec3d cartPos = getCartOffset(partialTicks, ridingEntity); - - if (cartPos == Vec3d.ZERO) return; - - for (MatrixStack stack : matrixStacks) - stack.translate(cartPos.x, cartPos.y, cartPos.z); - } - - private Vec3d getContraptionOffset(OrientedContraptionEntity entity, float partialTicks, Entity ridingEntity) { - AbstractContraptionEntity parent = (AbstractContraptionEntity) ridingEntity; - Vec3d passengerPosition = parent.getPassengerPosition(entity, partialTicks); - double x = passengerPosition.x - MathHelper.lerp(partialTicks, entity.lastTickPosX, entity.getX()); - double y = passengerPosition.y - MathHelper.lerp(partialTicks, entity.lastTickPosY, entity.getY()); - double z = passengerPosition.z - MathHelper.lerp(partialTicks, entity.lastTickPosZ, entity.getZ()); - - return new Vec3d(x, y, z); - } - - private Vec3d getCartOffset(float partialTicks, Entity ridingEntity) { - AbstractMinecartEntity cart = (AbstractMinecartEntity) ridingEntity; - double cartX = MathHelper.lerp(partialTicks, cart.lastTickPosX, cart.getX()); - double cartY = MathHelper.lerp(partialTicks, cart.lastTickPosY, cart.getY()); - double cartZ = MathHelper.lerp(partialTicks, cart.lastTickPosZ, cart.getZ()); - Vec3d cartPos = cart.getPos(cartX, cartY, cartZ); - - if (cartPos != null) { - Vec3d cartPosFront = cart.getPosOffset(cartX, cartY, cartZ, (double) 0.3F); - Vec3d cartPosBack = cart.getPosOffset(cartX, cartY, cartZ, (double) -0.3F); - if (cartPosFront == null) - cartPosFront = cartPos; - if (cartPosBack == null) - cartPosBack = cartPos; - - cartX = cartPos.x - cartX; - cartY = (cartPosFront.y + cartPosBack.y) / 2.0D - cartY; - cartZ = cartPos.z - cartZ; - - return new Vec3d(cartX, cartY, cartZ); - } - - return Vec3d.ZERO; - } - } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionKineticRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionKineticRenderer.java index c35a87c18..d670c354f 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionKineticRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionKineticRenderer.java @@ -7,13 +7,20 @@ import com.simibubi.create.content.contraptions.base.KineticRenderMaterials; import com.simibubi.create.foundation.render.backend.instancing.RenderMaterial; import com.simibubi.create.content.contraptions.base.RotatingInstancedModel; import com.simibubi.create.content.contraptions.components.actors.RotatingActorModel; +import net.minecraft.util.math.BlockPos; public class ContraptionKineticRenderer extends InstancedTileRenderer { @Override public void registerMaterials() { - materials.put(KineticRenderMaterials.BELTS, new RenderMaterial<>(AllProgramSpecs.CONTRAPTION_BELT, BeltInstancedModel::new)); - materials.put(KineticRenderMaterials.ROTATING, new RenderMaterial<>(AllProgramSpecs.CONTRAPTION_ROTATING, RotatingInstancedModel::new)); - materials.put(KineticRenderMaterials.ACTORS, new RenderMaterial<>(AllProgramSpecs.CONTRAPTION_ACTOR, RotatingActorModel::new)); + materials.put(KineticRenderMaterials.BELTS, new RenderMaterial<>(this, AllProgramSpecs.CONTRAPTION_BELT, BeltInstancedModel::new)); + materials.put(KineticRenderMaterials.ROTATING, new RenderMaterial<>(this, AllProgramSpecs.CONTRAPTION_ROTATING, RotatingInstancedModel::new)); + materials.put(KineticRenderMaterials.ACTORS, new RenderMaterial<>(this, AllProgramSpecs.CONTRAPTION_ACTOR, RotatingActorModel::new)); + } + + @Override + public BlockPos getOriginCoordinate() { + return BlockPos.ZERO; } } + diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionProgram.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionProgram.java index 6a2ee017e..ce2aede88 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionProgram.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionProgram.java @@ -4,6 +4,7 @@ import com.simibubi.create.foundation.render.backend.gl.BasicProgram; import com.simibubi.create.foundation.render.backend.light.GridAlignedBB; import net.minecraft.client.renderer.Matrix4f; import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.AxisAlignedBB; import org.lwjgl.opengl.GL20; public class ContraptionProgram extends BasicProgram { @@ -26,9 +27,12 @@ public class ContraptionProgram extends BasicProgram { uLightVolume = setSamplerBinding("uLightVolume", 4); } - public void bind(Matrix4f model, GridAlignedBB lightVolume) { - GL20.glUniform3f(uLightBoxSize, lightVolume.sizeX(), lightVolume.sizeY(), lightVolume.sizeZ()); - GL20.glUniform3f(uLightBoxMin, lightVolume.minX, lightVolume.minY, lightVolume.minZ); + public void bind(Matrix4f model, AxisAlignedBB lightVolume) { + double sizeX = lightVolume.maxX - lightVolume.minX; + double sizeY = lightVolume.maxY - lightVolume.minY; + double sizeZ = lightVolume.maxZ - lightVolume.minZ; + GL20.glUniform3f(uLightBoxSize, (float) sizeX, (float) sizeY, (float) sizeZ); + GL20.glUniform3f(uLightBoxMin, (float) lightVolume.minX, (float) lightVolume.minY, (float) lightVolume.minZ); uploadMatrixUniform(uModel, model); } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionRenderDispatcher.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionRenderDispatcher.java index 80310c7aa..5c3d4f8af 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionRenderDispatcher.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionRenderDispatcher.java @@ -38,60 +38,34 @@ import org.lwjgl.opengl.GL40; import java.lang.ref.WeakReference; import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.ForkJoinPool; public class ContraptionRenderDispatcher { public static final Int2ObjectMap renderers = new Int2ObjectOpenHashMap<>(); public static final Compartment> CONTRAPTION = new Compartment<>(); protected static PlacementSimulationWorld renderWorld; + private static boolean firstLayer = true; + public static void notifyLightUpdate(ILightReader world, LightType type, SectionPos pos) { for (RenderedContraption renderer : renderers.values()) { renderer.getLighter().lightVolume.notifyLightUpdate(world, type, pos); } } - public static void renderTick(TickEvent.RenderTickEvent event) { - if (!Backend.canUseVBOs()) return; - - ClientWorld world = Minecraft.getInstance().world; - if (event.phase == TickEvent.Phase.START && world != null) { - Map> map = ContraptionHandler.loadedContraptions.get(world); - - for (WeakReference weakReference : map.values()) { - AbstractContraptionEntity entity = weakReference.get(); - - if (entity == null) continue; - - EntityRendererManager renderManager = Minecraft.getInstance().getRenderManager(); - - EntityRenderer renderer = renderManager.getRenderer(entity); - - if (renderer instanceof AbstractContraptionEntityRenderer) { - updateTransform(entity, (AbstractContraptionEntityRenderer) renderer); - } - } - } + public static void renderTick() { + firstLayer = true; } public static void renderTileEntities(World world, Contraption c, MatrixStack ms, MatrixStack msLocal, IRenderTypeBuffer buffer) { - if (Backend.canUseInstancing()) { + PlacementSimulationWorld renderWorld = null; + if (Backend.canUseVBOs()) { RenderedContraption renderer = getRenderer(world, c); - TileEntityRenderHelper.renderTileEntities(world, renderer.renderWorld, c.specialRenderedTileEntities, ms, msLocal, buffer); - } else { - TileEntityRenderHelper.renderTileEntities(world, c.specialRenderedTileEntities, ms, msLocal, buffer); + renderWorld = renderer.renderWorld; } - } + TileEntityRenderHelper.renderTileEntities(world, renderWorld, c.specialRenderedTileEntities, ms, msLocal, buffer); - private static void updateTransform(C c, AbstractContraptionEntityRenderer entityRenderer) { - MatrixStack stack = entityRenderer.makeTransformMatrix(c, AnimationTickHolder.getPartialTicks()); - - Contraption c1 = c.getContraption(); - getRenderer(c1.entity.world, c1).setRenderSettings(stack.peek().getModel()); } public static void tick() { @@ -112,11 +86,20 @@ public class ContraptionRenderDispatcher { return contraption; } - public static void renderLayer(RenderType layer, Matrix4f viewProjection, float camX, float camY, float camZ) { + public static void renderLayer(RenderType layer, Matrix4f viewProjection, double camX, double camY, double camZ) { removeDeadContraptions(); if (renderers.isEmpty()) return; + if (firstLayer) { + + for (RenderedContraption renderer : renderers.values()) { + renderer.beginFrame(camX, camY, camZ); + } + + firstLayer = false; + } + layer.startDrawing(); GL11.glEnable(GL13.GL_TEXTURE_3D); GL13.glActiveTexture(GL40.GL_TEXTURE4); // the shaders expect light volumes to be in texture 4 @@ -142,19 +125,13 @@ public class ContraptionRenderDispatcher { } public static void removeDeadContraptions() { - ArrayList toRemove = new ArrayList<>(); - - for (RenderedContraption renderer : renderers.values()) { + renderers.values().removeIf(renderer -> { if (renderer.isDead()) { - toRemove.add(renderer.getEntityId()); renderer.invalidate(); + return true; } - } - - - for (Integer id : toRemove) { - renderers.remove(id); - } + return false; + }); } public static void invalidateAll() { diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/RenderedContraption.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/RenderedContraption.java index ddcf78be9..32fed725d 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/RenderedContraption.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/RenderedContraption.java @@ -3,23 +3,26 @@ package com.simibubi.create.content.contraptions.components.structureMovement.re import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.AllMovementBehaviours; import com.simibubi.create.content.contraptions.base.KineticRenderMaterials; -import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; -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.*; import com.simibubi.create.foundation.render.backend.Backend; import com.simibubi.create.foundation.render.backend.instancing.*; import com.simibubi.create.content.contraptions.components.actors.ContraptionActorData; -import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionLighter; +import com.simibubi.create.foundation.render.backend.light.GridAlignedBB; +import com.simibubi.create.foundation.utility.AnimationTickHolder; import com.simibubi.create.foundation.utility.worldWrappers.PlacementSimulationWorld; import net.minecraft.block.BlockRenderType; import net.minecraft.block.BlockState; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.*; +import net.minecraft.client.renderer.entity.EntityRenderer; +import net.minecraft.client.renderer.entity.EntityRendererManager; import net.minecraft.client.renderer.model.IBakedModel; import net.minecraft.client.renderer.texture.OverlayTexture; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; import net.minecraft.world.World; import net.minecraft.world.gen.feature.template.Template; import net.minecraft.world.lighting.WorldLightManager; @@ -45,6 +48,7 @@ public class RenderedContraption { public Contraption contraption; private Matrix4f model; + private AxisAlignedBB lightBox; public RenderedContraption(World world, Contraption contraption) { this.contraption = contraption; @@ -76,14 +80,55 @@ public class RenderedContraption { } public void doRenderLayer(RenderType layer, ContraptionProgram shader) { - ContraptionModel buffer = renderLayers.get(layer); - if (buffer != null) { + ContraptionModel structure = renderLayers.get(layer); + if (structure != null) { setup(shader); - buffer.render(); + structure.render(); teardown(); } } + public void beginFrame(double camX, double camY, double camZ) { + AbstractContraptionEntity entity = contraption.entity; + float pt = AnimationTickHolder.getPartialTicks(); + + MatrixStack stack = new MatrixStack(); + + double x = MathHelper.lerp(pt, entity.lastTickPosX, entity.getX()) - camX; + double y = MathHelper.lerp(pt, entity.lastTickPosY, entity.getY()) - camY; + double z = MathHelper.lerp(pt, entity.lastTickPosZ, entity.getZ()) - camZ; + stack.translate(x, y, z); + + entity.doLocalTransforms(pt, new MatrixStack[]{ stack }); + + model = stack.peek().getModel(); + + AxisAlignedBB lightBox = GridAlignedBB.toAABB(lighter.lightVolume.getTextureVolume()); + + this.lightBox = lightBox.offset(-camX, -camY, -camZ); + } + + void setup(ContraptionProgram shader) { + if (model == null || lightBox == null) return; + shader.bind(model, lightBox); + lighter.lightVolume.bind(); + } + + void teardown() { + lighter.lightVolume.unbind(); + } + + void invalidate() { + for (ContraptionModel buffer : renderLayers.values()) { + buffer.delete(); + } + renderLayers.clear(); + + lighter.lightVolume.delete(); + + kinetics.invalidate(); + } + private void buildLayers() { for (ContraptionModel buffer : renderLayers.values()) { buffer.delete(); @@ -128,37 +173,12 @@ public class RenderedContraption { } } - void setRenderSettings(Matrix4f model) { - this.model = model; - } - - void setup(ContraptionProgram shader) { - if (model == null) return; - shader.bind(model, lighter.lightVolume.getTextureVolume()); - lighter.lightVolume.use(); - } - - void teardown() { - lighter.lightVolume.release(); - } - - void invalidate() { - for (ContraptionModel buffer : renderLayers.values()) { - buffer.delete(); - } - renderLayers.clear(); - - lighter.lightVolume.delete(); - - kinetics.invalidate(); - } - private static ContraptionModel buildStructureModel(PlacementSimulationWorld renderWorld, Contraption c, RenderType layer) { BufferBuilder builder = buildStructure(renderWorld, c, layer); return new ContraptionModel(builder); } - public static PlacementSimulationWorld setupRenderWorld(World world, Contraption c) { + private static PlacementSimulationWorld setupRenderWorld(World world, Contraption c) { PlacementSimulationWorld renderWorld = new PlacementSimulationWorld(world); renderWorld.setTileEntities(c.presentTileEntities.values()); @@ -176,7 +196,7 @@ public class RenderedContraption { return renderWorld; } - public static BufferBuilder buildStructure(PlacementSimulationWorld renderWorld, Contraption c, RenderType layer) { + private static BufferBuilder buildStructure(PlacementSimulationWorld renderWorld, Contraption c, RenderType layer) { ForgeHooksClient.setRenderLayer(layer); MatrixStack ms = new MatrixStack(); diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltData.java b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltData.java index 02fa03770..cbd2ee461 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltData.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltData.java @@ -4,6 +4,7 @@ import com.simibubi.create.foundation.block.render.SpriteShiftEntry; import com.simibubi.create.foundation.render.backend.gl.attrib.VertexFormat; import com.simibubi.create.content.contraptions.base.KineticVertexAttributes; import com.simibubi.create.content.contraptions.base.KineticData; +import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import java.nio.ByteBuffer; @@ -25,6 +26,10 @@ public class BeltData extends KineticData { private float maxV; private byte scrollMult; + protected BeltData(InstancedModel owner) { + super(owner); + } + public BeltData setRotation(float rotX, float rotY, float rotZ) { this.rotX = rotX; this.rotY = rotY; @@ -32,7 +37,6 @@ public class BeltData extends KineticData { return this; } - public BeltData setScrollTexture(SpriteShiftEntry spriteShift) { TextureAtlasSprite source = spriteShift.getOriginal(); TextureAtlasSprite target = spriteShift.getTarget(); diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltInstancedModel.java b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltInstancedModel.java index b2e805d25..cb8c64082 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltInstancedModel.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltInstancedModel.java @@ -2,16 +2,17 @@ package com.simibubi.create.content.contraptions.relays.belt; import com.simibubi.create.foundation.render.backend.gl.attrib.VertexFormat; import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; +import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; import net.minecraft.client.renderer.BufferBuilder; public class BeltInstancedModel extends InstancedModel { - public BeltInstancedModel(BufferBuilder buf) { - super(buf); + public BeltInstancedModel(InstancedTileRenderer renderer, BufferBuilder buf) { + super(renderer, buf); } @Override protected BeltData newInstance() { - return new BeltData(); + return new BeltData(this); } @Override diff --git a/src/main/java/com/simibubi/create/content/schematics/client/SchematicRendererWithInstancing.java b/src/main/java/com/simibubi/create/content/schematics/client/SchematicRendererWithInstancing.java deleted file mode 100644 index afbefca53..000000000 --- a/src/main/java/com/simibubi/create/content/schematics/client/SchematicRendererWithInstancing.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.simibubi.create.content.schematics.client; - -import com.mojang.blaze3d.matrix.MatrixStack; -import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionKineticRenderer; -import com.simibubi.create.foundation.renderState.SuperRenderTypeBuffer; -import net.minecraft.client.Minecraft; - -public class SchematicRendererWithInstancing extends SchematicRenderer { - public final ContraptionKineticRenderer tiles; - - public SchematicRendererWithInstancing() { - this.tiles = new ContraptionKineticRenderer(); - } - - @Override - protected void redraw(Minecraft minecraft) { - super.redraw(minecraft); - - tiles.invalidate(); - - schematic.getRenderedTileEntities().forEach(tiles::add); - } - - @Override - public void render(MatrixStack ms, SuperRenderTypeBuffer buffer) { - super.render(ms, buffer); - - //tiles.render(RenderType.getCutoutMipped(), FastRenderDispatcher.getProjectionMatrix(), ); - } -} diff --git a/src/main/java/com/simibubi/create/events/ClientEvents.java b/src/main/java/com/simibubi/create/events/ClientEvents.java index f4c4d6a01..b5c83a913 100644 --- a/src/main/java/com/simibubi/create/events/ClientEvents.java +++ b/src/main/java/com/simibubi/create/events/ClientEvents.java @@ -195,7 +195,7 @@ public class ClientEvents { if (!isGameActive()) return; TurntableHandler.gameRenderTick(); - ContraptionRenderDispatcher.renderTick(event); + ContraptionRenderDispatcher.renderTick(); } protected static boolean isGameActive() { diff --git a/src/main/java/com/simibubi/create/foundation/mixin/RenderHooksMixin.java b/src/main/java/com/simibubi/create/foundation/mixin/RenderHooksMixin.java index 0014fea7c..c3fecc726 100644 --- a/src/main/java/com/simibubi/create/foundation/mixin/RenderHooksMixin.java +++ b/src/main/java/com/simibubi/create/foundation/mixin/RenderHooksMixin.java @@ -1,6 +1,7 @@ package com.simibubi.create.foundation.mixin; import com.mojang.blaze3d.matrix.MatrixStack; +import com.mojang.blaze3d.platform.GlStateManager; import com.simibubi.create.CreateClient; import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionRenderDispatcher; import com.simibubi.create.foundation.render.backend.Backend; @@ -38,17 +39,12 @@ public class RenderHooksMixin { private void renderLayer(RenderType type, MatrixStack stack, double camX, double camY, double camZ, CallbackInfo ci) { if (!Backend.available()) return; - float cameraX = (float) camX; - float cameraY = (float) camY; - float cameraZ = (float) camZ; - - Matrix4f viewProjection = Matrix4f.translate(-cameraX, -cameraY, -cameraZ); - viewProjection.multiplyBackward(stack.peek().getModel()); + Matrix4f viewProjection = stack.peek().getModel().copy(); viewProjection.multiplyBackward(FastRenderDispatcher.getProjectionMatrix()); - FastRenderDispatcher.renderLayer(type, viewProjection, cameraX, cameraY, cameraZ); + FastRenderDispatcher.renderLayer(type, viewProjection, camX, camY, camZ); - ContraptionRenderDispatcher.renderLayer(type, viewProjection, cameraX, cameraY, cameraZ); + ContraptionRenderDispatcher.renderLayer(type, viewProjection, camX, camY, camZ); GL20.glUseProgram(0); } @@ -60,6 +56,6 @@ public class RenderHooksMixin { OptifineHandler.refresh(); Backend.refresh(); - if (world != null) world.loadedTileEntityList.forEach(CreateClient.kineticRenderer::add); + if (Backend.canUseInstancing() && world != null) world.loadedTileEntityList.forEach(CreateClient.kineticRenderer::add); } } diff --git a/src/main/java/com/simibubi/create/foundation/render/KineticRenderer.java b/src/main/java/com/simibubi/create/foundation/render/KineticRenderer.java index 2e75eeeca..40e9de47a 100644 --- a/src/main/java/com/simibubi/create/foundation/render/KineticRenderer.java +++ b/src/main/java/com/simibubi/create/foundation/render/KineticRenderer.java @@ -4,12 +4,73 @@ import com.simibubi.create.content.contraptions.base.KineticRenderMaterials; import com.simibubi.create.content.contraptions.base.RotatingInstancedModel; import com.simibubi.create.content.contraptions.relays.belt.BeltInstancedModel; import com.simibubi.create.foundation.render.backend.gl.BasicProgram; +import com.simibubi.create.foundation.render.backend.gl.shader.ShaderCallback; import com.simibubi.create.foundation.render.backend.instancing.*; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.Matrix4f; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.world.ClientWorld; +import net.minecraft.entity.Entity; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.math.BlockPos; + +import java.util.ArrayList; public class KineticRenderer extends InstancedTileRenderer { + public static int MAX_ORIGIN_DISTANCE = 1000; + + public BlockPos originCoordinate = BlockPos.ZERO; + @Override public void registerMaterials() { - materials.put(KineticRenderMaterials.BELTS, new RenderMaterial<>(AllProgramSpecs.BELT, BeltInstancedModel::new)); - materials.put(KineticRenderMaterials.ROTATING, new RenderMaterial<>(AllProgramSpecs.ROTATING, RotatingInstancedModel::new)); + materials.put(KineticRenderMaterials.BELTS, new RenderMaterial<>(this, AllProgramSpecs.BELT, BeltInstancedModel::new)); + materials.put(KineticRenderMaterials.ROTATING, new RenderMaterial<>(this, AllProgramSpecs.ROTATING, RotatingInstancedModel::new)); + } + + @Override + public BlockPos getOriginCoordinate() { + return originCoordinate; + } + + @Override + public void tick() { + super.tick(); + + Minecraft mc = Minecraft.getInstance(); + Entity renderViewEntity = mc.renderViewEntity; + + if (renderViewEntity == null) return; + + BlockPos renderViewPosition = renderViewEntity.getPosition(); + + int dX = Math.abs(renderViewPosition.getX() - originCoordinate.getX()); + int dY = Math.abs(renderViewPosition.getY() - originCoordinate.getY()); + int dZ = Math.abs(renderViewPosition.getZ() - originCoordinate.getZ()); + + if (dX > MAX_ORIGIN_DISTANCE || + dY > MAX_ORIGIN_DISTANCE || + dZ > MAX_ORIGIN_DISTANCE) { + + originCoordinate = renderViewPosition; + + ArrayList instancedTiles = new ArrayList<>(instances.keySet()); + invalidate(); + instancedTiles.forEach(this::add); + } + } + + @Override + public void render(RenderType layer, Matrix4f viewProjection, double camX, double camY, double camZ, ShaderCallback callback) { + BlockPos originCoordinate = getOriginCoordinate(); + + camX -= originCoordinate.getX(); + camY -= originCoordinate.getY(); + camZ -= originCoordinate.getZ(); + + Matrix4f translate = Matrix4f.translate((float) -camX, (float) -camY, (float) -camZ); + + translate.multiplyBackward(viewProjection); + + super.render(layer, translate, camX, camY, camZ, callback); } } 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 597b22279..5218b3a98 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 @@ -34,8 +34,6 @@ import java.util.function.Predicate; public class Backend { public static final Logger log = LogManager.getLogger(Backend.class); - public static final FloatBuffer FLOAT_BUFFER = MemoryUtil.memAllocFloat(1); // TODO: these leak 80 bytes of memory per program launch - public static final FloatBuffer VEC4_BUFFER = MemoryUtil.memAllocFloat(4); public static final FloatBuffer MATRIX_BUFFER = MemoryUtil.memAllocFloat(16); private static final Map> registry = new HashMap<>(); diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/FastRenderDispatcher.java b/src/main/java/com/simibubi/create/foundation/render/backend/FastRenderDispatcher.java index e5f40c872..07e7e91bf 100644 --- a/src/main/java/com/simibubi/create/foundation/render/backend/FastRenderDispatcher.java +++ b/src/main/java/com/simibubi/create/foundation/render/backend/FastRenderDispatcher.java @@ -29,7 +29,6 @@ import java.util.function.Consumer; public class FastRenderDispatcher { public static WorldAttached> queuedUpdates = new WorldAttached<>(ConcurrentHashMap::newKeySet); - public static WorldAttached> addedLastTick = new WorldAttached<>(ConcurrentHashMap::new); private static Matrix4f projectionMatrixThisFrame = null; @@ -44,26 +43,7 @@ public class FastRenderDispatcher { public static void tick() { ClientWorld world = Minecraft.getInstance().world; - // Clean up twice a second. This doesn't have to happen every tick, - // but this does need to be run to ensure we don't miss anything. - int ticks = AnimationTickHolder.getTicks(); - - ConcurrentHashMap map = addedLastTick.get(world); - map - .entrySet() - .stream() - .filter(it -> ticks - it.getValue() > 10) - .map(Map.Entry::getKey) - .forEach(te -> { - map.remove(te); - - CreateClient.kineticRenderer.onLightUpdate(te); - }); - - - if (ticks % 10 == 0) { - CreateClient.kineticRenderer.clean(); - } + CreateClient.kineticRenderer.tick(); runQueue(queuedUpdates.get(world), CreateClient.kineticRenderer::update); } @@ -98,7 +78,7 @@ public class FastRenderDispatcher { } } - public static void renderLayer(RenderType layer, Matrix4f viewProjection, float cameraX, float cameraY, float cameraZ) { + public static void renderLayer(RenderType layer, Matrix4f viewProjection, double cameraX, double cameraY, double cameraZ) { if (!Backend.canUseInstancing()) return; layer.startDrawing(); diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/BasicProgram.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/BasicProgram.java index c75fa89eb..260921c56 100644 --- a/src/main/java/com/simibubi/create/foundation/render/backend/gl/BasicProgram.java +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/BasicProgram.java @@ -37,14 +37,14 @@ public class BasicProgram extends GlProgram { uLightMap = setSamplerBinding("uLightMap", 2); } - public void bind(Matrix4f viewProjection, float camX, float camY, float camZ, int debugMode) { + public void bind(Matrix4f viewProjection, double camX, double camY, double camZ, int debugMode) { super.bind(); GL20.glUniform1i(uDebug, debugMode); GL20.glUniform1f(uTime, AnimationTickHolder.getRenderTick()); uploadMatrixUniform(uViewProjection, viewProjection); - GL20.glUniform3f(uCameraPos, camX, camY, camZ); + GL20.glUniform3f(uCameraPos, (float) camX, (float) camY, (float) camZ); GL20.glUniform2f(uFogRange, GlFog.getFogStart(), GlFog.getFogEnd()); GL20.glUniform4fv(uFogColor, GlFog.FOG_COLOR); diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/instancing/InstanceData.java b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/InstanceData.java index f713b04c1..2facfb415 100644 --- a/src/main/java/com/simibubi/create/foundation/render/backend/instancing/InstanceData.java +++ b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/InstanceData.java @@ -4,6 +4,12 @@ import java.nio.ByteBuffer; public abstract class InstanceData { + protected final InstancedModel owner; + + protected InstanceData(InstancedModel owner) { + this.owner = owner; + } + public abstract void write(ByteBuffer buf); public void putVec4(ByteBuffer buf, float x, float y, float z, float w) { diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/instancing/InstancedModel.java b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/InstancedModel.java index 42c7e2acf..c82c6bd38 100644 --- a/src/main/java/com/simibubi/create/foundation/render/backend/instancing/InstancedModel.java +++ b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/InstancedModel.java @@ -17,6 +17,8 @@ import java.util.function.Consumer; public abstract class InstancedModel extends BufferedModel { public static final VertexFormat FORMAT = VertexFormat.builder().addAttributes(ModelVertexAttributes.class).build(); + public final InstancedTileRenderer renderer; + protected GlVertexArray vao; protected GlBuffer instanceVBO; protected int glBufferSize = -1; @@ -27,8 +29,9 @@ public abstract class InstancedModel extends BufferedMod protected int minIndexChanged = -1; protected int maxIndexChanged = -1; - public InstancedModel(BufferBuilder buf) { + public InstancedModel(InstancedTileRenderer renderer, BufferBuilder buf) { super(buf); + this.renderer = renderer; } @Override 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 35507966f..ab30eaa36 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 @@ -1,19 +1,27 @@ package com.simibubi.create.foundation.render.backend.instancing; +import com.simibubi.create.CreateClient; import com.simibubi.create.foundation.render.backend.FastRenderDispatcher; import com.simibubi.create.foundation.render.backend.gl.BasicProgram; import com.simibubi.create.foundation.render.backend.Backend; import com.simibubi.create.foundation.render.backend.gl.shader.ShaderCallback; import com.simibubi.create.foundation.utility.AnimationTickHolder; +import com.simibubi.create.foundation.utility.WorldAttached; +import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.Matrix4f; import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.world.ClientWorld; import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.math.BlockPos; import javax.annotation.Nullable; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; public abstract class InstancedTileRenderer

{ + public static WorldAttached> addedLastTick = new WorldAttached<>(ConcurrentHashMap::new); + protected Map> instances = new HashMap<>(); protected Map, RenderMaterial> materials = new HashMap<>(); @@ -22,8 +30,35 @@ public abstract class InstancedTileRenderer

{ registerMaterials(); } + public abstract BlockPos getOriginCoordinate(); + public abstract void registerMaterials(); + public void tick() { + ClientWorld world = Minecraft.getInstance().world; + + int ticks = AnimationTickHolder.getTicks(); + + ConcurrentHashMap map = addedLastTick.get(world); + map + .entrySet() + .stream() + .filter(it -> ticks - it.getValue() > 10) + .map(Map.Entry::getKey) + .forEach(te -> { + map.remove(te); + + onLightUpdate(te); + }); + + + // Clean up twice a second. This doesn't have to happen every tick, + // but this does need to be run to ensure we don't miss anything. + if (ticks % 10 == 0) { + clean(); + } + } + @SuppressWarnings("unchecked") public > RenderMaterial getMaterial(MaterialType materialType) { return (RenderMaterial) materials.get(materialType); @@ -47,7 +82,7 @@ public abstract class InstancedTileRenderer

{ TileEntityInstance renderer = InstancedTileRenderRegistry.instance.create(this, tile); if (renderer != null) { - FastRenderDispatcher.addedLastTick.get(tile.getWorld()).put(tile, AnimationTickHolder.getTicks()); + addedLastTick.get(tile.getWorld()).put(tile, AnimationTickHolder.getTicks()); instances.put(tile, renderer); } @@ -58,6 +93,8 @@ public abstract class InstancedTileRenderer

{ } public void onLightUpdate(T tile) { + if (!Backend.canUseInstancing()) return; + if (tile instanceof IInstanceRendered) { TileEntityInstance instance = getInstance(tile, false); @@ -67,12 +104,16 @@ public abstract class InstancedTileRenderer

{ } public void add(T tile) { + if (!Backend.canUseInstancing()) return; + if (tile instanceof IInstanceRendered) { getInstance(tile); } } public void update(T tile) { + if (!Backend.canUseInstancing()) return; + if (tile instanceof IInstanceRendered) { TileEntityInstance instance = getInstance(tile, false); @@ -82,6 +123,8 @@ public abstract class InstancedTileRenderer

{ } public void remove(T tile) { + if (!Backend.canUseInstancing()) return; + if (tile instanceof IInstanceRendered) { TileEntityInstance instance = getInstance(tile, false); @@ -103,11 +146,11 @@ public abstract class InstancedTileRenderer

{ instances.clear(); } - public void render(RenderType layer, Matrix4f viewProjection, float camX, float camY, float camZ) { + public void render(RenderType layer, Matrix4f viewProjection, double camX, double camY, double camZ) { render(layer, viewProjection, camX, camY, camZ, null); } - public void render(RenderType layer, Matrix4f viewProjection, float camX, float camY, float camZ, ShaderCallback

callback) { + public void render(RenderType layer, Matrix4f viewProjection, double camX, double camY, double camZ, ShaderCallback

callback) { for (RenderMaterial material : materials.values()) { if (material.canRenderInLayer(layer)) material.render(layer, viewProjection, camX, camY, camZ, callback); diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/instancing/ModelFactory.java b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/ModelFactory.java index bc358f799..61d7e36ff 100644 --- a/src/main/java/com/simibubi/create/foundation/render/backend/instancing/ModelFactory.java +++ b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/ModelFactory.java @@ -4,5 +4,5 @@ import net.minecraft.client.renderer.BufferBuilder; @FunctionalInterface public interface ModelFactory> { - B convert(BufferBuilder buf); + B makeModel(InstancedTileRenderer renderer, BufferBuilder buf); } diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/instancing/RenderMaterial.java b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/RenderMaterial.java index 64e5eac46..1234f3900 100644 --- a/src/main/java/com/simibubi/create/foundation/render/backend/instancing/RenderMaterial.java +++ b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/RenderMaterial.java @@ -33,6 +33,7 @@ import static com.simibubi.create.foundation.render.Compartment.PARTIAL; public class RenderMaterial

> { + protected final InstancedTileRenderer renderer; protected final Map, Cache> models; protected final ModelFactory factory; protected final ProgramSpec

programSpec; @@ -41,11 +42,12 @@ public class RenderMaterial

programSpec, ModelFactory factory) { - this(programSpec, factory, type -> type == RenderType.getCutoutMipped()); + public RenderMaterial(InstancedTileRenderer renderer, ProgramSpec

programSpec, ModelFactory factory) { + this(renderer, programSpec, factory, type -> type == RenderType.getCutoutMipped()); } - public RenderMaterial(ProgramSpec

programSpec, ModelFactory factory, Predicate layerPredicate) { + public RenderMaterial(InstancedTileRenderer renderer, ProgramSpec

programSpec, ModelFactory factory, Predicate layerPredicate) { + this.renderer = renderer; this.models = new HashMap<>(); this.factory = factory; this.programSpec = programSpec; @@ -59,11 +61,11 @@ public class RenderMaterial

setup) { + public void render(RenderType layer, Matrix4f viewProjection, double camX, double camY, double camZ, ShaderCallback

setup) { P program = Backend.getProgram(programSpec); program.bind(viewProjection, camX, camY, camZ, FastRenderDispatcher.getDebugMode()); @@ -142,7 +144,7 @@ public class RenderMaterial

{ init(); } - protected abstract void init(); - public final void update() { BlockState currentState = tile.getBlockState(); if (lastState == currentState) { @@ -35,9 +33,24 @@ public abstract class TileEntityInstance { } } + /** + * Acquire all {@link InstanceKey}s and initialize any data you may need to calculate the instance properties. + */ + protected abstract void init(); + + /** + * Update changed instance data using the {@link InstanceKey}s you got in {@link #init()}. + * You don't have to update light data. That should be done in {@link #updateLight()} + */ protected abstract void onUpdate(); - public abstract void updateLight(); + /** + * Called when a light update occurs in the world. If your model needs it, update light here. + */ + public void updateLight() { } + /** + * Call {@link InstanceKey#delete()} on all acquired keys. + */ public abstract void remove(); } diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/light/LightVolume.java b/src/main/java/com/simibubi/create/foundation/render/backend/light/LightVolume.java index 94c2e5ac5..97f12c48f 100644 --- a/src/main/java/com/simibubi/create/foundation/render/backend/light/LightVolume.java +++ b/src/main/java/com/simibubi/create/foundation/render/backend/light/LightVolume.java @@ -212,7 +212,7 @@ public class LightVolume { bufferDirty = true; } - public void use() { + public void bind() { // just in case something goes wrong or we accidentally call this before this volume is properly disposed of. if (lightData == null || removed) return; @@ -246,7 +246,7 @@ public class LightVolume { } } - public void release() { + public void unbind() { glTexture.unbind(); } diff --git a/src/main/resources/assets/create/shader/belt.vert b/src/main/resources/assets/create/shader/belt.vert index a8bfe94f5..c150f012b 100644 --- a/src/main/resources/assets/create/shader/belt.vert +++ b/src/main/resources/assets/create/shader/belt.vert @@ -67,13 +67,15 @@ void main() { vec4 worldPos = localRotation * vec4(aPos - .5, 1.) + vec4(aInstancePos + .5, 0.); #ifdef CONTRAPTION - worldPos = uModel * worldPos; - BoxCoord = (worldPos.xyz - uLightBoxMin) / uLightBoxSize; - mat4 normalMat = uModel * localRotation; + + BoxCoord = (worldPos.xyz - uLightBoxMin) / uLightBoxSize; + FragDistance = length(worldPos.xyz); #else mat4 normalMat = localRotation; + + FragDistance = length(worldPos.xyz - uCameraPos); #endif vec3 norm = normalize(normalMat * vec4(aNormal, 0.)).xyz; @@ -84,7 +86,6 @@ void main() { Diffuse = diffuse(norm); TexCoords = aTexCoords - aSourceTexture + aScrollTexture.xy + vec2(0, scroll); Light = aLight; - FragDistance = length(worldPos.xyz - uCameraPos); gl_Position = uViewProjection * worldPos; #ifdef CONTRAPTION diff --git a/src/main/resources/assets/create/shader/contraption_actor.vert b/src/main/resources/assets/create/shader/contraption_actor.vert index 5623e01ca..7dbae771c 100644 --- a/src/main/resources/assets/create/shader/contraption_actor.vert +++ b/src/main/resources/assets/create/shader/contraption_actor.vert @@ -77,7 +77,7 @@ void main() { Diffuse = diffuse(norm); TexCoords = aTexCoords; Light = aModelLight; - FragDistance = length(worldPos.xyz - uCameraPos); + FragDistance = length(worldPos.xyz); gl_Position = uViewProjection * worldPos; if (uDebug == 2) { diff --git a/src/main/resources/assets/create/shader/contraption_structure.vert b/src/main/resources/assets/create/shader/contraption_structure.vert index da8ef4cc8..a665ea8ff 100644 --- a/src/main/resources/assets/create/shader/contraption_structure.vert +++ b/src/main/resources/assets/create/shader/contraption_structure.vert @@ -43,17 +43,17 @@ float diffuse(vec3 normal) { } void main() { - vec4 worldPos = uModel * vec4(aPos, 1.); + vec4 viewPos = uModel * vec4(aPos, 1.); vec3 norm = (uModel * vec4(aNormal, 0.)).xyz; - BoxCoord = (worldPos.xyz - uLightBoxMin) / uLightBoxSize; + BoxCoord = (viewPos.xyz - uLightBoxMin) / uLightBoxSize; Diffuse = diffuse(norm); Color = aColor / diffuse(aNormal); TexCoords = aTexCoords; Light = aModelLight; - FragDistance = length(worldPos.xyz - uCameraPos); - gl_Position = uViewProjection * worldPos; + FragDistance = length(viewPos.xyz); + gl_Position = uViewProjection * viewPos; if (uDebug == 2) { Color = vec4(norm, 1.); diff --git a/src/main/resources/assets/create/shader/rotating.vert b/src/main/resources/assets/create/shader/rotating.vert index 3871b6d4f..a1f803139 100644 --- a/src/main/resources/assets/create/shader/rotating.vert +++ b/src/main/resources/assets/create/shader/rotating.vert @@ -65,13 +65,15 @@ void main() { vec4 worldPos = kineticRotation * vec4(aPos - .5, 1.) + vec4(aInstancePos + .5, 0.); #ifdef CONTRAPTION - worldPos = uModel * worldPos; - BoxCoord = (worldPos.xyz - uLightBoxMin) / uLightBoxSize; - mat4 normalMat = uModel * kineticRotation; + + BoxCoord = (worldPos.xyz - uLightBoxMin) / uLightBoxSize; + FragDistance = length(worldPos.xyz); #else mat4 normalMat = kineticRotation; + + FragDistance = length(worldPos.xyz - uCameraPos); #endif vec3 norm = normalize(normalMat * vec4(aNormal, 0.)).xyz; @@ -79,7 +81,6 @@ void main() { Diffuse = diffuse(norm); TexCoords = aTexCoords; Light = aLight; - FragDistance = length(worldPos.xyz - uCameraPos); gl_Position = uViewProjection * worldPos; #ifdef CONTRAPTION