diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerRenderer.java index 40193fb67..e4e6b4031 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerRenderer.java @@ -39,6 +39,11 @@ public class DeployerRenderer extends SafeTileEntityRenderer super(dispatcher); } + @Override + public boolean isGlobalRenderer(DeployerTileEntity te) { + return true; + } + @Override protected void renderSafe(DeployerTileEntity te, float partialTicks, MatrixStack ms, IRenderTypeBuffer buffer, int light, int overlay) { diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerTileEntity.java index d0d0ea8cf..52c8ec809 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerTileEntity.java @@ -376,10 +376,4 @@ public class DeployerTileEntity extends KineticTileEntity { TooltipHelper.addHint(tooltip, "hint.full_deployer"); return true; } - - @Override - public boolean shouldRenderAsTE() { - return true; - } - } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/mixer/MechanicalMixerRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/mixer/MechanicalMixerRenderer.java index 2ab2d8e75..b6344d5bd 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/mixer/MechanicalMixerRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/mixer/MechanicalMixerRenderer.java @@ -24,6 +24,11 @@ public class MechanicalMixerRenderer extends KineticTileEntityRenderer { super(dispatcher); } + @Override + public boolean isGlobalRenderer(KineticTileEntity te) { + return true; + } + @Override protected void renderSafe(KineticTileEntity te, float partialTicks, MatrixStack ms, IRenderTypeBuffer buffer, int light, int overlay) { 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 650a68248..92a7b2ff9 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 @@ -9,6 +9,16 @@ public class NonStationaryLighter extends ContraptionLigh super(contraption); } + @Override + protected GridAlignedBB contraptionBoundsToVolume(GridAlignedBB bounds) { + bounds = bounds.copy(); + 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) { GridAlignedBB contraptionBounds = getContraptionBounds(); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/BearingLighter.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/BearingLighter.java index d49efaa43..31f3c79b8 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/BearingLighter.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/BearingLighter.java @@ -2,6 +2,10 @@ package com.simibubi.create.content.contraptions.components.structureMovement.be import com.simibubi.create.foundation.render.light.ContraptionLighter; import com.simibubi.create.foundation.render.light.GridAlignedBB; +import net.minecraft.util.Direction; +import net.minecraft.util.math.BlockPos; + +import java.util.Set; public class BearingLighter extends ContraptionLighter { @@ -11,9 +15,40 @@ public class BearingLighter extends ContraptionLighter { @Override public GridAlignedBB getContraptionBounds() { - GridAlignedBB localBounds = GridAlignedBB.fromAABB(contraption.bounds); - localBounds.rotate45(contraption.getFacing().getAxis()); - localBounds.translate(contraption.anchor); - return localBounds; + Set blocks = contraption.getBlocks().keySet(); + + Direction orientation = contraption.facing; + + float maxDistanceSq = -1; + for (BlockPos pos : blocks) { + float x = pos.getX(); + float y = pos.getY(); + float z = pos.getZ(); + + float distSq = x * x + y * y + z * z; + + if (distSq > maxDistanceSq) maxDistanceSq = distSq; + } + + int radius = (int) (Math.ceil(Math.sqrt(maxDistanceSq))); + + GridAlignedBB betterBounds = GridAlignedBB.ofRadius(radius); + GridAlignedBB contraptionBounds = GridAlignedBB.fromAABB(contraption.bounds); + + Direction.Axis axis = orientation.getAxis(); + + if (axis == Direction.Axis.X) { + betterBounds.maxX = contraptionBounds.maxX; + betterBounds.minX = contraptionBounds.minX; + } else if (axis == Direction.Axis.Y) { + betterBounds.maxY = contraptionBounds.maxY; + betterBounds.minY = contraptionBounds.minY; + } else if (axis == Direction.Axis.Z) { + betterBounds.maxZ = contraptionBounds.maxZ; + betterBounds.minZ = contraptionBounds.minZ; + } + + betterBounds.translate(contraption.anchor); + return betterBounds; } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/ClockworkBearingTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/ClockworkBearingTileEntity.java index aa465f4e9..91adc5d73 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/ClockworkBearingTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/ClockworkBearingTileEntity.java @@ -393,4 +393,8 @@ public class ClockworkBearingTileEntity extends KineticTileEntity implements IBe return pos; } + @Override + public boolean shouldRenderAsTE() { + return true; + } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/MechanicalBearingTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/MechanicalBearingTileEntity.java index b4dde3bc4..75521e7df 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/MechanicalBearingTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/MechanicalBearingTileEntity.java @@ -282,4 +282,8 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp return true; } + @Override + public boolean shouldRenderAsTE() { + return true; + } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/StabilizedContraption.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/StabilizedContraption.java index 5bb70f602..fc1dd4420 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/StabilizedContraption.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/StabilizedContraption.java @@ -26,7 +26,6 @@ public class StabilizedContraption extends Contraption { if (!searchMovedStructure(world, offset, null)) return false; startMoving(world); - expandBoundsAroundAxis(Axis.Y); if (blocks.isEmpty()) return false; return true; diff --git a/src/main/java/com/simibubi/create/content/contraptions/processing/BasinOperatingTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/processing/BasinOperatingTileEntity.java index 7c711358f..52e77bae2 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/processing/BasinOperatingTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/processing/BasinOperatingTileEntity.java @@ -143,8 +143,4 @@ public abstract class BasinOperatingTileEntity extends KineticTileEntity { protected abstract Object getRecipeCacheKey(); - @Override - public boolean shouldRenderAsTE() { - return true; - } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltRenderer.java index 7582ace97..8e4c1bcfd 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltRenderer.java @@ -50,6 +50,11 @@ public class BeltRenderer extends SafeTileEntityRenderer impleme renderItems(te, partialTicks, ms, buffer, light, overlay); } + @Override + public boolean isGlobalRenderer(BeltTileEntity te) { + return te.isController(); + } + @Override public void addInstanceData(InstanceContext ctx) { BeltTileEntity te = ctx.te; diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltTileEntity.java index c3ee377bf..c1f04f296 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltTileEntity.java @@ -465,11 +465,4 @@ public class BeltTileEntity extends KineticTileEntity { return new ModelDataMap.Builder().withInitial(CASING_PROPERTY, casing) .build(); } - - @Override - public boolean shouldRenderAsTE() { - // Since only the controller does the item rendering, we potentially - // save a *lot* of time by not processing the other belts. - return isController(); - } } diff --git a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmRenderer.java b/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmRenderer.java index ece88eec1..71b7224f1 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmRenderer.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmRenderer.java @@ -29,6 +29,11 @@ public class ArmRenderer extends KineticTileEntityRenderer { super(dispatcher); } + @Override + public boolean isGlobalRenderer(KineticTileEntity te) { + return true; + } + @Override protected void renderSafe(KineticTileEntity te, float pt, MatrixStack ms, IRenderTypeBuffer buffer, int light, int overlay) { diff --git a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmTileEntity.java index 0c56559d3..e088c50d0 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmTileEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmTileEntity.java @@ -513,8 +513,4 @@ public class ArmTileEntity extends KineticTileEntity { } } - @Override - public boolean shouldRenderAsTE() { - return true; - } } diff --git a/src/main/java/com/simibubi/create/events/ClientEvents.java b/src/main/java/com/simibubi/create/events/ClientEvents.java index 10dafa065..8abe10395 100644 --- a/src/main/java/com/simibubi/create/events/ClientEvents.java +++ b/src/main/java/com/simibubi/create/events/ClientEvents.java @@ -27,6 +27,7 @@ import com.simibubi.create.foundation.networking.LeftClickPacket; import com.simibubi.create.foundation.render.FastRenderDispatcher; import com.simibubi.create.foundation.render.RenderWork; import com.simibubi.create.foundation.render.contraption.ContraptionRenderDispatcher; +import com.simibubi.create.foundation.render.light.LightVolumeDebugger; import com.simibubi.create.foundation.renderState.SuperRenderTypeBuffer; import com.simibubi.create.foundation.tileEntity.behaviour.edgeInteraction.EdgeInteractionRenderer; import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringRenderer; diff --git a/src/main/java/com/simibubi/create/foundation/render/GPUBuffer.java b/src/main/java/com/simibubi/create/foundation/render/GPUBuffer.java index 0f7c3e167..8f1b845d6 100644 --- a/src/main/java/com/simibubi/create/foundation/render/GPUBuffer.java +++ b/src/main/java/com/simibubi/create/foundation/render/GPUBuffer.java @@ -1,18 +1,20 @@ package com.simibubi.create.foundation.render; -import com.mojang.blaze3d.platform.GlStateManager; +import com.simibubi.create.foundation.render.gl.GlBuffer; +import com.simibubi.create.foundation.render.gl.GlVertexArray; import com.simibubi.create.foundation.render.instancing.VertexFormat; import net.minecraft.client.renderer.BufferBuilder; -import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL15; -import org.lwjgl.opengl.GL30; import org.lwjgl.opengl.GL40; import java.nio.ByteBuffer; public abstract class GPUBuffer extends TemplateBuffer { - protected int vao, ebo, invariantVBO; + protected GlVertexArray vao; + + protected GlBuffer ebo; + protected GlBuffer invariantVBO; protected boolean removed; public GPUBuffer(BufferBuilder buf) { @@ -25,12 +27,18 @@ public abstract class GPUBuffer extends TemplateBuffer { int invariantSize = vertexCount * stride; - vao = GL30.glGenVertexArrays(); - ebo = GlStateManager.genBuffers(); - invariantVBO = GlStateManager.genBuffers(); + vao = new GlVertexArray(); + invariantVBO = new GlBuffer(); + ebo = createEBO(); - GL30.glBindVertexArray(vao); - GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, invariantVBO); + vao.bind(); + + int numAttributes = getTotalShaderAttributeCount(); + for (int i = 0; i <= numAttributes; i++) { + GL40.glEnableVertexAttribArray(i); + } + + invariantVBO.bind(GL15.GL_ARRAY_BUFFER); // allocate the buffer on the gpu GL15.glBufferData(GL15.GL_ARRAY_BUFFER, invariantSize, GL15.GL_STATIC_DRAW); @@ -44,14 +52,11 @@ public abstract class GPUBuffer extends TemplateBuffer { constant.rewind(); GL15.glUnmapBuffer(GL15.GL_ARRAY_BUFFER); - buildEBO(ebo); - getModelFormat().informAttributes(0); - GlStateManager.bindBuffers(GL15.GL_ARRAY_BUFFER, 0); - GlStateManager.bindBuffers(GL15.GL_ELEMENT_ARRAY_BUFFER, 0); + invariantVBO.unbind(GL15.GL_ARRAY_BUFFER); // Deselect (bind to 0) the VAO - GL30.glBindVertexArray(0); + vao.unbind(); } protected abstract void copyVertex(ByteBuffer to, int index); @@ -69,26 +74,17 @@ public abstract class GPUBuffer extends TemplateBuffer { } public void render() { - if (vao == 0 || removed) return; + if (vertexCount == 0 || removed) return; - GL30.glBindVertexArray(vao); + vao.bind(); preDrawTask(); - int numAttributes = getTotalShaderAttributeCount(); - for (int i = 0; i <= numAttributes; i++) { - GL40.glEnableVertexAttribArray(i); - } - - GlStateManager.bindBuffers(GL15.GL_ELEMENT_ARRAY_BUFFER, ebo); + ebo.bind(GL15.GL_ELEMENT_ARRAY_BUFFER); drawCall(); - for (int i = 0; i <= numAttributes; i++) { - GL40.glDisableVertexAttribArray(i); - } - - GlStateManager.bindBuffers(GL15.GL_ELEMENT_ARRAY_BUFFER, 0); - GL30.glBindVertexArray(0); + ebo.unbind(GL15.GL_ELEMENT_ARRAY_BUFFER); + vao.unbind(); } public void delete() { @@ -99,11 +95,8 @@ public abstract class GPUBuffer extends TemplateBuffer { } protected void deleteInternal() { - GL15.glDeleteBuffers(invariantVBO); - GL15.glDeleteBuffers(ebo); - GL30.glDeleteVertexArrays(vao); - vao = 0; - ebo = 0; - invariantVBO = 0; + invariantVBO.delete(); + ebo.delete(); + vao.delete(); } } diff --git a/src/main/java/com/simibubi/create/foundation/render/RenderMath.java b/src/main/java/com/simibubi/create/foundation/render/RenderMath.java index b9cb6c5be..3839ff718 100644 --- a/src/main/java/com/simibubi/create/foundation/render/RenderMath.java +++ b/src/main/java/com/simibubi/create/foundation/render/RenderMath.java @@ -1,12 +1,6 @@ package com.simibubi.create.foundation.render; public class RenderMath { - public static final float SQRT2 = 1.41421356237f; - - public static int rotateSideLength(int i) { - return (int) Math.floor((float) i * SQRT2 / 4f); - } - public static int nextPowerOf2(int a) { int h = Integer.highestOneBit(a); return (h == a) ? h : (h << 1); diff --git a/src/main/java/com/simibubi/create/foundation/render/TemplateBuffer.java b/src/main/java/com/simibubi/create/foundation/render/TemplateBuffer.java index c24e7261e..9f9fc7e0b 100644 --- a/src/main/java/com/simibubi/create/foundation/render/TemplateBuffer.java +++ b/src/main/java/com/simibubi/create/foundation/render/TemplateBuffer.java @@ -2,6 +2,7 @@ package com.simibubi.create.foundation.render; import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.datafixers.util.Pair; +import com.simibubi.create.foundation.render.gl.GlBuffer; import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.client.renderer.vertex.VertexFormatElement; import org.lwjgl.opengl.GL15; @@ -32,10 +33,13 @@ public class TemplateBuffer { ((Buffer)template).rewind(); } - protected void buildEBO(int ebo){ + protected final GlBuffer createEBO(){ + GlBuffer ebo = new GlBuffer(); + int indicesSize = vertexCount * VertexFormatElement.Type.USHORT.getSize(); - GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, ebo); + ebo.bind(GL15.GL_ELEMENT_ARRAY_BUFFER); + GL15.glBufferData(GL15.GL_ELEMENT_ARRAY_BUFFER, indicesSize, GL15.GL_STATIC_DRAW); ByteBuffer indices = GL15.glMapBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, GL15.GL_WRITE_ONLY); @@ -46,6 +50,10 @@ public class TemplateBuffer { indices.rewind(); GL15.glUnmapBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER); + + ebo.unbind(GL15.GL_ELEMENT_ARRAY_BUFFER); + + return ebo; } public boolean isEmpty() { diff --git a/src/main/java/com/simibubi/create/foundation/render/gl/GlBuffer.java b/src/main/java/com/simibubi/create/foundation/render/gl/GlBuffer.java new file mode 100644 index 000000000..59d30067f --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/gl/GlBuffer.java @@ -0,0 +1,21 @@ +package com.simibubi.create.foundation.render.gl; + +import org.lwjgl.opengl.GL20; + +public class GlBuffer extends GlObject { + public GlBuffer() { + setHandle(GL20.glGenBuffers()); + } + + public void bind(int target) { + GL20.glBindBuffer(target, handle()); + } + + public void unbind(int target) { + GL20.glBindBuffer(target, 0); + } + + protected void deleteInternal(int handle) { + GL20.glDeleteBuffers(handle); + } +} diff --git a/src/main/java/com/simibubi/create/foundation/render/gl/GlObject.java b/src/main/java/com/simibubi/create/foundation/render/gl/GlObject.java new file mode 100644 index 000000000..3921657bb --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/gl/GlObject.java @@ -0,0 +1,43 @@ +package com.simibubi.create.foundation.render.gl; + +// Utility class for safely dealing with gl object handles. +public abstract class GlObject { + private static final int INVALID_HANDLE = Integer.MIN_VALUE; + + private int handle = INVALID_HANDLE; + + protected final void setHandle(int handle) { + this.handle = handle; + } + + public final int handle() { + this.checkHandle(); + + return this.handle; + } + + protected final void checkHandle() { + if (!this.isHandleValid()) { + throw new IllegalStateException("Handle is not valid"); + } + } + + protected final boolean isHandleValid() { + return this.handle != INVALID_HANDLE; + } + + protected final void invalidateHandle() { + this.handle = INVALID_HANDLE; + } + + public final void delete() { + if (!isHandleValid()) { + throw new IllegalStateException("Handle already deleted."); + } + + deleteInternal(handle); + invalidateHandle(); + } + + protected abstract void deleteInternal(int handle); +} diff --git a/src/main/java/com/simibubi/create/foundation/render/gl/GlTexture.java b/src/main/java/com/simibubi/create/foundation/render/gl/GlTexture.java new file mode 100644 index 000000000..7c28e99c3 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/gl/GlTexture.java @@ -0,0 +1,25 @@ +package com.simibubi.create.foundation.render.gl; + +import org.lwjgl.opengl.GL20; + +public class GlTexture extends GlObject { + private final int textureType; + + public GlTexture(int textureType) { + this.textureType = textureType; + setHandle(GL20.glGenTextures()); + } + + @Override + protected void deleteInternal(int handle) { + GL20.glDeleteTextures(handle); + } + + public void bind() { + GL20.glBindTexture(textureType, handle()); + } + + public void unbind() { + GL20.glBindTexture(textureType, 0); + } +} diff --git a/src/main/java/com/simibubi/create/foundation/render/gl/GlVertexArray.java b/src/main/java/com/simibubi/create/foundation/render/gl/GlVertexArray.java new file mode 100644 index 000000000..64215e113 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/gl/GlVertexArray.java @@ -0,0 +1,21 @@ +package com.simibubi.create.foundation.render.gl; + +import org.lwjgl.opengl.GL30; + +public class GlVertexArray extends GlObject { + public GlVertexArray() { + setHandle(GL30.glGenVertexArrays()); + } + + public void bind() { + GL30.glBindVertexArray(handle()); + } + + public void unbind() { + GL30.glBindVertexArray(0); + } + + protected void deleteInternal(int handle) { + GL30.glDeleteVertexArrays(handle); + } +} diff --git a/src/main/java/com/simibubi/create/foundation/render/instancing/DynamicInstanceBuffer.java b/src/main/java/com/simibubi/create/foundation/render/instancing/DynamicInstanceBuffer.java index e4e90992d..540ec55e4 100644 --- a/src/main/java/com/simibubi/create/foundation/render/instancing/DynamicInstanceBuffer.java +++ b/src/main/java/com/simibubi/create/foundation/render/instancing/DynamicInstanceBuffer.java @@ -1,11 +1,12 @@ package com.simibubi.create.foundation.render.instancing; +import com.simibubi.create.foundation.render.gl.GlBuffer; import net.minecraft.client.renderer.BufferBuilder; import org.lwjgl.opengl.*; public abstract class DynamicInstanceBuffer extends InstanceBuffer { - protected int dynamicVBO; + protected GlBuffer dynamicVBO; protected int dynamicBufferSize = -1; @@ -16,7 +17,7 @@ public abstract class DynamicInstanceBuffer extends GPUBuffer { public static final VertexFormat FORMAT = new VertexFormat(POSITION, NORMAL, UV); - protected int instanceVBO; + protected GlBuffer instanceVBO; protected int instanceCount; protected int instanceBufferSize = -1; @@ -34,7 +35,7 @@ public abstract class InstanceBuffer extends GPUBuffer { @Override protected void setup() { super.setup(); - instanceVBO = GlStateManager.genBuffers(); + instanceVBO = new GlBuffer(); } @Override @@ -76,15 +77,8 @@ public abstract class InstanceBuffer extends GPUBuffer { } protected void deleteInternal() { - GL15.glDeleteBuffers(invariantVBO); - GL15.glDeleteBuffers(instanceVBO); - GL15.glDeleteBuffers(ebo); - GL30.glDeleteVertexArrays(vao); - vao = 0; - ebo = 0; - invariantVBO = 0; - instanceVBO = 0; - instanceBufferSize = -1; + super.deleteInternal(); + instanceVBO.delete(); } protected abstract D newInstance(); @@ -116,7 +110,7 @@ public abstract class InstanceBuffer extends GPUBuffer { int instanceSize = RenderMath.nextPowerOf2(instanceCount * instanceFormat.getStride()); - GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, instanceVBO); + instanceVBO.bind(GL15.GL_ARRAY_BUFFER); // this changes enough that it's not worth reallocating the entire buffer every time. if (instanceSize > instanceBufferSize) { @@ -137,8 +131,7 @@ public abstract class InstanceBuffer extends GPUBuffer { GL33.glVertexAttribDivisor(i + staticAttributes, 1); } - // Deselect (bind to 0) the VBO - GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0); + instanceVBO.unbind(GL15.GL_ARRAY_BUFFER); shouldBuild = false; rebuffer = false; diff --git a/src/main/java/com/simibubi/create/foundation/render/light/GridAlignedBB.java b/src/main/java/com/simibubi/create/foundation/render/light/GridAlignedBB.java index 210a74031..fd54986f4 100644 --- a/src/main/java/com/simibubi/create/foundation/render/light/GridAlignedBB.java +++ b/src/main/java/com/simibubi/create/foundation/render/light/GridAlignedBB.java @@ -9,7 +9,6 @@ import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3i; import static com.simibubi.create.foundation.render.RenderMath.isPowerOf2; -import static com.simibubi.create.foundation.render.RenderMath.rotateSideLength; public class GridAlignedBB { public int minX; @@ -28,6 +27,10 @@ public class GridAlignedBB { this.maxZ = maxZ; } + public static GridAlignedBB ofRadius(int radius) { + return new GridAlignedBB(-radius, -radius, -radius, radius + 1, radius + 1, radius + 1); + } + public static GridAlignedBB copy(GridAlignedBB bb) { return new GridAlignedBB(bb.minX, bb.minY, bb.minZ, bb.maxX, bb.maxY, bb.maxZ); } @@ -104,16 +107,6 @@ public class GridAlignedBB { maxZ += z; } - public void rotate45(Direction.Axis axis) { - if (axis == Direction.Axis.X) { - this.grow(0, rotateSideLength(sizeY()), rotateSideLength(sizeZ())); - } else if (axis == Direction.Axis.Y) { - this.grow(rotateSideLength(sizeX()), 0, rotateSideLength(sizeZ())); - } else if (axis == Direction.Axis.Z) { - this.grow(rotateSideLength(sizeX()), rotateSideLength(sizeY()), 0); - } - } - public void mirrorAbout(Direction.Axis axis) { Vec3i axisVec = Direction.getFacingFromAxis(Direction.AxisDirection.POSITIVE, axis).getDirectionVec(); int flipX = axisVec.getX() - 1; @@ -131,38 +124,6 @@ public class GridAlignedBB { this.minZ = maxZ; } - public void expandAroundAxis(Direction.Axis axis) { - int maxXDiff = Math.max(this.maxX - 1, -this.minX); - int maxYDiff = Math.max(this.maxY - 1, -this.minY); - int maxZDiff = Math.max(this.maxZ - 1, -this.minZ); - - int maxDiff; - if (axis == Direction.Axis.X) - maxDiff = Math.max(maxZDiff, maxYDiff); - else if (axis == Direction.Axis.Y) - maxDiff = Math.max(maxZDiff, maxXDiff); - else if (axis == Direction.Axis.Z) - maxDiff = Math.max(maxXDiff, maxYDiff); - else - maxDiff = 0; - - Vec3i axisVec = Direction.getFacingFromAxis(Direction.AxisDirection.POSITIVE, axis).getDirectionVec(); - int axisX = axisVec.getX(); - int axisY = axisVec.getY(); - int axisZ = axisVec.getZ(); - - int planeX = 1 - axisX; - int planeY = 1 - axisY; - int planeZ = 1 - axisZ; - - minX = axisX * minX - maxDiff * planeX; - minY = axisY * minY - maxDiff * planeY; - minZ = axisZ * minZ - maxDiff * planeZ; - maxX = axisX * maxX + (maxDiff + 1) * planeX; - maxY = axisY * maxY + (maxDiff + 1) * planeY; - maxZ = axisZ * maxZ + (maxDiff + 1) * planeZ; - } - /** * Grow this bounding box to have power of 2 side length, scaling from the center. */ @@ -269,6 +230,19 @@ public class GridAlignedBB { return this.intersects(other.minX, other.minY, other.minZ, other.maxX, other.maxY, other.maxZ); } + public boolean contains(GridAlignedBB other) { + return other.minX >= this.minX && + other.maxX <= this.maxX && + other.minY >= this.minY && + other.maxY <= this.maxY && + other.minZ >= this.minZ && + other.maxZ <= this.maxZ; + } + + public boolean isContainedBy(GridAlignedBB other) { + return other.contains(this); + } + public boolean intersects(int minX, int minY, int minZ, int maxX, int maxY, int maxZ) { return this.minX < maxX && this.maxX > minX && this.minY < maxY && this.maxY > minY && this.minZ < maxZ && this.maxZ > minZ; } @@ -292,12 +266,7 @@ public class GridAlignedBB { GridAlignedBB that = (GridAlignedBB) o; - if (minX != that.minX) return false; - if (minY != that.minY) return false; - if (minZ != that.minZ) return false; - if (maxX != that.maxX) return false; - if (maxY != that.maxY) return false; - return maxZ == that.maxZ; + return this.sameAs(that); } @Override diff --git a/src/main/java/com/simibubi/create/foundation/render/light/LightVolume.java b/src/main/java/com/simibubi/create/foundation/render/light/LightVolume.java index 836139b49..027e9bfd4 100644 --- a/src/main/java/com/simibubi/create/foundation/render/light/LightVolume.java +++ b/src/main/java/com/simibubi/create/foundation/render/light/LightVolume.java @@ -1,6 +1,7 @@ package com.simibubi.create.foundation.render.light; import com.simibubi.create.foundation.render.RenderWork; +import com.simibubi.create.foundation.render.gl.GlTexture; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.SectionPos; import net.minecraft.world.ILightReader; @@ -24,12 +25,12 @@ public class LightVolume { private boolean bufferDirty; private boolean removed; - private int glTexture; + private final GlTexture glTexture; public LightVolume(GridAlignedBB sampleVolume) { setSampleVolume(sampleVolume); - this.glTexture = GL11.glGenTextures(); + this.glTexture = new GlTexture(GL20.GL_TEXTURE_3D); this.lightData = MemoryUtil.memAlloc(this.textureVolume.volume() * 2); // TODO: maybe figure out how to pack light coords into a single byte } @@ -84,32 +85,48 @@ public class LightVolume { } public void move(ILightReader world, GridAlignedBB newSampleVolume) { - setSampleVolume(newSampleVolume); - initialize(world); + if (textureVolume.contains(newSampleVolume)) { + if (newSampleVolume.intersects(sampleVolume)) { + GridAlignedBB newArea = newSampleVolume.intersect(sampleVolume); + sampleVolume = newSampleVolume; + + copyLight(world, newArea); + } else { + sampleVolume = newSampleVolume; + initialize(world); + } + } else { + setSampleVolume(newSampleVolume); + int volume = textureVolume.volume(); + if (volume * 2 > lightData.capacity()) { + lightData = MemoryUtil.memRealloc(lightData, volume * 2); + } + initialize(world); + } } public void notifyLightUpdate(ILightReader world, LightType type, SectionPos location) { GridAlignedBB changedVolume = GridAlignedBB.fromSection(location); + if (!changedVolume.intersects(sampleVolume)) + return; changedVolume.intersectAssign(sampleVolume); // compute the region contained by us that has dirty lighting data. - if (!changedVolume.empty()) { - if (type == LightType.BLOCK) copyBlock(world, changedVolume); - else if (type == LightType.SKY) copySky(world, changedVolume); - } + if (type == LightType.BLOCK) copyBlock(world, changedVolume); + else if (type == LightType.SKY) copySky(world, changedVolume); } /** * Completely (re)populate this volume with block and sky lighting data. * This is expensive and should be avoided. */ - public synchronized void initialize(ILightReader world) { + public void initialize(ILightReader world) { BlockPos.Mutable pos = new BlockPos.Mutable(); int shiftX = textureVolume.minX; int shiftY = textureVolume.minY; int shiftZ = textureVolume.minZ; - textureVolume.forEachContained((x, y, z) -> { + sampleVolume.forEachContained((x, y, z) -> { pos.setPos(x, y, z); int blockLight = world.getLightLevel(LightType.BLOCK, pos); @@ -125,7 +142,7 @@ public class LightVolume { * Copy block light from the world into this volume. * @param worldVolume the region in the world to copy data from. */ - public synchronized void copyBlock(ILightReader world, GridAlignedBB worldVolume) { + public void copyBlock(ILightReader world, GridAlignedBB worldVolume) { BlockPos.Mutable pos = new BlockPos.Mutable(); int xShift = textureVolume.minX; @@ -147,7 +164,7 @@ public class LightVolume { * Copy sky light from the world into this volume. * @param worldVolume the region in the world to copy data from. */ - public synchronized void copySky(ILightReader world, GridAlignedBB worldVolume) { + public void copySky(ILightReader world, GridAlignedBB worldVolume) { BlockPos.Mutable pos = new BlockPos.Mutable(); int xShift = textureVolume.minX; @@ -165,37 +182,66 @@ public class LightVolume { bufferDirty = true; } + /** + * Copy all light from the world into this volume. + * @param worldVolume the region in the world to copy data from. + */ + public void copyLight(ILightReader world, GridAlignedBB worldVolume) { + BlockPos.Mutable pos = new BlockPos.Mutable(); + + int xShift = textureVolume.minX; + int yShift = textureVolume.minY; + int zShift = textureVolume.minZ; + + worldVolume.forEachContained((x, y, z) -> { + pos.setPos(x, y, z); + + int block = world.getLightLevel(LightType.BLOCK, pos); + int sky = world.getLightLevel(LightType.SKY, pos); + + writeLight(x - xShift, y - yShift, z - zShift, block, sky); + }); + + bufferDirty = true; + } + public void use() { // just in case something goes wrong or we accidentally call this before this volume is properly disposed of. - if (glTexture == 0 || lightData == null || removed) return; + if (lightData == null || removed) return; GL13.glActiveTexture(GL40.GL_TEXTURE4); - GL12.glBindTexture(GL12.GL_TEXTURE_3D, glTexture); + glTexture.bind(); GL11.glTexParameteri(GL13.GL_TEXTURE_3D, GL13.GL_TEXTURE_MIN_FILTER, GL13.GL_LINEAR); GL11.glTexParameteri(GL13.GL_TEXTURE_3D, GL13.GL_TEXTURE_MAG_FILTER, GL13.GL_LINEAR); GL11.glTexParameteri(GL13.GL_TEXTURE_3D, GL13.GL_TEXTURE_WRAP_S, GL20.GL_MIRRORED_REPEAT); GL11.glTexParameteri(GL13.GL_TEXTURE_3D, GL13.GL_TEXTURE_WRAP_R, GL20.GL_MIRRORED_REPEAT); GL11.glTexParameteri(GL13.GL_TEXTURE_3D, GL13.GL_TEXTURE_WRAP_T, GL20.GL_MIRRORED_REPEAT); + + uploadTexture(); + } + + private void uploadTexture() { if (bufferDirty) { - uploadTexture(); + int sizeX = textureVolume.sizeX(); + int sizeY = textureVolume.sizeY(); + int sizeZ = textureVolume.sizeZ(); + if (sizeX * sizeY * sizeZ * 2 > lightData.capacity()) + throw new IllegalStateException("Volume too big for buffer"); + + lightData.rewind(); + GL12.glTexImage3D(GL12.GL_TEXTURE_3D, 0, GL40.GL_RG8, sizeX, sizeY, sizeZ, 0, GL40.GL_RG, GL40.GL_UNSIGNED_BYTE, lightData); + bufferDirty = false; } } - private synchronized void uploadTexture() { - lightData.rewind(); - GL12.glTexImage3D(GL12.GL_TEXTURE_3D, 0, GL40.GL_RG8, textureVolume.sizeX(), textureVolume.sizeY(), textureVolume.sizeZ(), 0, GL40.GL_RG, GL40.GL_UNSIGNED_BYTE, lightData); - bufferDirty = false; - } - public void release() { - GL12.glBindTexture(GL12.GL_TEXTURE_3D, 0); + glTexture.unbind(); } public void delete() { removed = true; RenderWork.enqueue(() -> { - GL15.glDeleteTextures(glTexture); - glTexture = 0; + glTexture.delete(); MemoryUtil.memFree(lightData); lightData = null; });