diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/Contraption.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/Contraption.java index 66182fade..6453be2c4 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/Contraption.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/Contraption.java @@ -190,7 +190,7 @@ public abstract class Contraption { // Create subcontraptions for (BlockFace blockFace : pendingSubContraptions) { Direction face = blockFace.getFace(); - StabilizedContraption subContraption = new StabilizedContraption(face); + StabilizedContraption subContraption = new StabilizedContraption(this, face); World world = entity.world; BlockPos pos = blockFace.getPos(); if (!subContraption.assemble(world, pos)) 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 de960b40d..f18aa3349 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 @@ -13,6 +13,7 @@ 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; } 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 f54d09beb..cb5396eca 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 @@ -11,11 +11,14 @@ import net.minecraft.world.World; public class StabilizedContraption extends Contraption { + public Contraption parent; + private Direction facing; public StabilizedContraption() {} - public StabilizedContraption(Direction facing) { + public StabilizedContraption(Contraption parent, Direction facing) { + this.parent = parent; this.facing = facing; } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/PistonContraption.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/PistonContraption.java index 2895fb9bd..7ed8ab535 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/PistonContraption.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/PistonContraption.java @@ -5,6 +5,7 @@ import com.simibubi.create.content.contraptions.components.structureMovement.Blo import com.simibubi.create.content.contraptions.components.structureMovement.TranslatingContraption; import com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock.*; import com.simibubi.create.foundation.config.AllConfigs; +import com.simibubi.create.foundation.render.light.ContraptionLighter; import com.simibubi.create.foundation.utility.VecHelper; import net.minecraft.block.BlockState; import net.minecraft.block.CarpetBlock; @@ -18,6 +19,8 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.world.IWorld; import net.minecraft.world.World; import net.minecraft.world.gen.feature.template.Template.BlockInfo; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; import org.apache.commons.lang3.tuple.Pair; import java.util.ArrayList; @@ -226,4 +229,9 @@ public class PistonContraption extends TranslatingContraption { return tag; } + @OnlyIn(Dist.CLIENT) + @Override + public ContraptionLighter makeLighter() { + return new PistonLighter(this); + } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/PistonLighter.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/PistonLighter.java new file mode 100644 index 000000000..28d86c6dc --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/PistonLighter.java @@ -0,0 +1,35 @@ +package com.simibubi.create.content.contraptions.components.structureMovement.piston; + +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.Vec3i; + +public class PistonLighter extends ContraptionLighter { + public PistonLighter(PistonContraption contraption) { + super(contraption); + } + + @Override + public GridAlignedBB getContraptionBounds() { + GridAlignedBB bounds = GridAlignedBB.fromAABB(contraption.bounds); + bounds.translate(contraption.anchor); + + int length = contraption.extensionLength; + Vec3i direction = contraption.orientation.getDirectionVec(); + + int shift = length / 2; + int shiftX = direction.getX() * shift; + int shiftY = direction.getY() * shift; + int shiftZ = direction.getZ() * shift; + bounds.translate(shiftX, shiftY, shiftZ); + + int grow = (length + 1) / 2; + int extendX = Math.abs(direction.getX() * grow); + int extendY = Math.abs(direction.getY() * grow); + int extendZ = Math.abs(direction.getZ() * grow); + bounds.grow(extendX, extendY, extendZ); + + return bounds; + } +} diff --git a/src/main/java/com/simibubi/create/events/ClientEvents.java b/src/main/java/com/simibubi/create/events/ClientEvents.java index d0b8fce07..dd58db9cd 100644 --- a/src/main/java/com/simibubi/create/events/ClientEvents.java +++ b/src/main/java/com/simibubi/create/events/ClientEvents.java @@ -126,7 +126,7 @@ public class ClientEvents { CouplingRenderer.renderAll(ms, buffer); CreateClient.schematicHandler.render(ms, buffer); CreateClient.outliner.renderOutlines(ms, buffer); - LightVolumeDebugger.render(ms, buffer); +// LightVolumeDebugger.render(ms, buffer); // CollisionDebugger.render(ms, buffer); buffer.draw(); 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 3839ff718..5ca9e3d66 100644 --- a/src/main/java/com/simibubi/create/foundation/render/RenderMath.java +++ b/src/main/java/com/simibubi/create/foundation/render/RenderMath.java @@ -1,6 +1,12 @@ package com.simibubi.create.foundation.render; public class RenderMath { + public static final float SQRT2 = 1.41421356237f; + + public static int timesSqrt2(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/SafeDirectBuffer.java b/src/main/java/com/simibubi/create/foundation/render/SafeDirectBuffer.java deleted file mode 100644 index cb6a47172..000000000 --- a/src/main/java/com/simibubi/create/foundation/render/SafeDirectBuffer.java +++ /dev/null @@ -1,165 +0,0 @@ -package com.simibubi.create.foundation.render; - -import net.minecraft.client.renderer.GLAllocation; -import sun.nio.ch.DirectBuffer; - -import java.nio.*; - -public class SafeDirectBuffer implements AutoCloseable { - - private ByteBuffer wrapped; - - public SafeDirectBuffer(int capacity) { - this.wrapped = GLAllocation.createDirectByteBuffer(capacity); - } - - public void close() throws Exception { - if (wrapped instanceof DirectBuffer) { - ((DirectBuffer) wrapped).cleaner().clean(); - } - } - - /** - * Only use this function to pass information to OpenGL. - */ - @Deprecated - public ByteBuffer getBacking() { - return wrapped; - } - - public void order(ByteOrder bo) { - wrapped.order(bo); - } - - public void limit(int limit) { - wrapped.limit(limit); - } - - public void rewind() { - wrapped.rewind(); - } - - public byte get() { - return wrapped.get(); - } - - public ByteBuffer put(byte b) { - return wrapped.put(b); - } - - public byte get(int index) { - return wrapped.get(); - } - - public ByteBuffer put(int index, byte b) { - return wrapped.put(index, b); - } - - public ByteBuffer compact() { - return wrapped.compact(); - } - - public boolean isReadOnly() { - return wrapped.isReadOnly(); - } - - public boolean isDirect() { - return wrapped.isDirect(); - } - - public char getChar() { - return wrapped.getChar(); - } - - public ByteBuffer putChar(char value) { - return wrapped.putChar(value); - } - - public char getChar(int index) { - return wrapped.getChar(index); - } - - public ByteBuffer putChar(int index, char value) { - return wrapped.putChar(index, value); - } - - public short getShort() { - return wrapped.getShort(); - } - - public ByteBuffer putShort(short value) { - return wrapped.putShort(value); - } - - public short getShort(int index) { - return wrapped.getShort(index); - } - - public ByteBuffer putShort(int index, short value) { - return wrapped.putShort(index, value); - } - - public int getInt() { - return wrapped.getInt(); - } - - public ByteBuffer putInt(int value) { - return wrapped.putInt(value); - } - - public int getInt(int index) { - return wrapped.getInt(index); - } - - public ByteBuffer putInt(int index, int value) { - return wrapped.putInt(index, value); - } - - public long getLong() { - return wrapped.getLong(); - } - - public ByteBuffer putLong(long value) { - return wrapped.putLong(value); - } - - public long getLong(int index) { - return wrapped.getLong(index); - } - - public ByteBuffer putLong(int index, long value) { - return wrapped.putLong(index, value); - } - - public float getFloat() { - return wrapped.getFloat(); - } - - public ByteBuffer putFloat(float value) { - return wrapped.putFloat(value); - } - - public float getFloat(int index) { - return wrapped.getFloat(index); - } - - public ByteBuffer putFloat(int index, float value) { - return wrapped.putFloat(index, value); - } - - public double getDouble() { - return wrapped.getDouble(); - } - - public ByteBuffer putDouble(double value) { - return wrapped.putDouble(value); - } - - public double getDouble(int index) { - return wrapped.getDouble(index); - } - - public ByteBuffer putDouble(int index, double value) { - return wrapped.putDouble(index, value); - } -} diff --git a/src/main/java/com/simibubi/create/foundation/render/instancing/InstanceBuffer.java b/src/main/java/com/simibubi/create/foundation/render/instancing/InstanceBuffer.java index 371d7e5ca..0f88d52a3 100644 --- a/src/main/java/com/simibubi/create/foundation/render/instancing/InstanceBuffer.java +++ b/src/main/java/com/simibubi/create/foundation/render/instancing/InstanceBuffer.java @@ -4,7 +4,6 @@ package com.simibubi.create.foundation.render.instancing; import com.mojang.blaze3d.platform.GlStateManager; import com.simibubi.create.foundation.render.RenderMath; import com.simibubi.create.foundation.render.RenderWork; -import com.simibubi.create.foundation.render.SafeDirectBuffer; import com.simibubi.create.foundation.render.TemplateBuffer; import net.minecraft.client.renderer.BufferBuilder; import org.lwjgl.opengl.*; diff --git a/src/main/java/com/simibubi/create/foundation/render/light/ContraptionLighter.java b/src/main/java/com/simibubi/create/foundation/render/light/ContraptionLighter.java index 648055de4..44786f256 100644 --- a/src/main/java/com/simibubi/create/foundation/render/light/ContraptionLighter.java +++ b/src/main/java/com/simibubi/create/foundation/render/light/ContraptionLighter.java @@ -16,9 +16,10 @@ public abstract class ContraptionLighter { GridAlignedBB bounds = getContraptionBounds(); bounds.grow(1); // so we have at least enough data on the edges to avoid artifacts + GridAlignedBB importantArea = GridAlignedBB.copy(bounds); bounds.nextPowerOf2Centered(); - lightVolume = new LightVolume(bounds); + lightVolume = new LightVolume(bounds, importantArea); lightVolume.initialize(contraption.entity.world); } 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 03eb94efd..368b6883b 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 @@ -1,6 +1,7 @@ package com.simibubi.create.foundation.render.light; import com.simibubi.create.foundation.render.RenderMath; +import net.minecraft.util.Direction; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.SectionPos; @@ -79,12 +80,26 @@ public class GridAlignedBB { } public void translate(Vec3i by) { - this.minX += by.getX(); - this.minY += by.getY(); - this.minZ += by.getZ(); - this.maxX += by.getX(); - this.maxY += by.getY(); - this.maxZ += by.getZ(); + translate(by.getX(), by.getY(), by.getZ()); + } + + public void translate(int x, int y, int z) { + minX += x; + maxX += x; + minY += y; + maxY += y; + minZ += z; + maxZ += z; + } + + public void rotate45(Direction.Axis axis) { + if (axis == Direction.Axis.X) { + this.grow(0, RenderMath.timesSqrt2(sizeY()), RenderMath.timesSqrt2(sizeZ())); + } else if (axis == Direction.Axis.Y) { + this.grow(RenderMath.timesSqrt2(sizeX()), 0, RenderMath.timesSqrt2(sizeZ())); + } else if (axis == Direction.Axis.Z) { + this.grow(RenderMath.timesSqrt2(sizeX()), RenderMath.timesSqrt2(sizeY()), 0); + } } /** @@ -103,12 +118,12 @@ public class GridAlignedBB { int diffY = newSizeY - sizeY; int diffZ = newSizeZ - sizeZ; - this.minX -= diffX / 2; // floor division for the minimums - this.minY -= diffY / 2; - this.minZ -= diffZ / 2; - this.maxX += (diffX + 1) / 2; // ceiling divison for the maximums - this.maxY += (diffY + 1) / 2; - this.maxZ += (diffZ + 1) / 2; + minX -= diffX / 2; // floor division for the minimums + minY -= diffY / 2; + minZ -= diffZ / 2; + maxX += (diffX + 1) / 2; // ceiling divison for the maximums + maxY += (diffY + 1) / 2; + maxZ += (diffZ + 1) / 2; } /** @@ -134,12 +149,12 @@ public class GridAlignedBB { } public void grow(int x, int y, int z) { - this.minX -= x; - this.minY -= y; - this.minZ -= z; - this.maxX += x; - this.maxY += y; - this.maxZ += z; + minX -= x; + minY -= y; + minZ -= z; + maxX += x; + maxY += y; + maxZ += z; } public GridAlignedBB intersect(GridAlignedBB other) { 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 7ab56ccd8..fd2a59fce 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 @@ -10,70 +10,80 @@ import org.lwjgl.system.MemoryUtil; import java.nio.ByteBuffer; +// TODO: Don't immediately destroy light volumes. +// There's a high chance that a contraption will stop and soon after start again. +// By caching lightvolumes based on their volumes/locations, we can save having +// to reread all the lighting data in those cases. public class LightVolume { - private final GridAlignedBB volume; + private final GridAlignedBB sampleVolume; + private final GridAlignedBB textureVolume; private ByteBuffer lightData; private boolean bufferDirty; private int glTexture; - public LightVolume(GridAlignedBB volume) { + public LightVolume(GridAlignedBB textureVolume, GridAlignedBB sampleVolume) { // the gpu requires that all textures have power of 2 side lengths - if (!volume.hasPowerOf2Sides()) + if (!textureVolume.hasPowerOf2Sides()) throw new IllegalArgumentException("LightVolume must have power of 2 side lengths"); - this.volume = volume; + this.textureVolume = textureVolume; + this.sampleVolume = sampleVolume; this.glTexture = GL11.glGenTextures(); - this.lightData = MemoryUtil.memAlloc(this.volume.volume() * 2); // TODO: maybe figure out how to pack light coords into a single byte + this.lightData = MemoryUtil.memAlloc(this.textureVolume.volume() * 2); // TODO: maybe figure out how to pack light coords into a single byte } - public GridAlignedBB getBox() { - return GridAlignedBB.copy(volume); + public GridAlignedBB getTextureVolume() { + return GridAlignedBB.copy(textureVolume); + } + + public GridAlignedBB getSampleVolume() { + return GridAlignedBB.copy(sampleVolume); } public int getMinX() { - return volume.minX; + return textureVolume.minX; } public int getMinY() { - return volume.minY; + return textureVolume.minY; } public int getMinZ() { - return volume.minZ; + return textureVolume.minZ; } public int getMaxX() { - return volume.maxX; + return textureVolume.maxX; } public int getMaxY() { - return volume.maxY; + return textureVolume.maxY; } public int getMaxZ() { - return volume.maxZ; + return textureVolume.maxZ; } public int getSizeX() { - return volume.sizeX(); + return textureVolume.sizeX(); } public int getSizeY() { - return volume.sizeY(); + return textureVolume.sizeY(); } public int getSizeZ() { - return volume.sizeZ(); + return textureVolume.sizeZ(); } public void notifyLightUpdate(ILightReader world, LightType type, SectionPos location) { GridAlignedBB changedVolume = GridAlignedBB.fromSection(location); - changedVolume.intersectAssign(volume); // compute the region contained by us that has dirty lighting data. + changedVolume.intersectAssign(sampleVolume); // compute the region contained by us that has dirty lighting data. if (!changedVolume.empty()) { if (type == LightType.BLOCK) copyBlock(world, changedVolume); @@ -88,11 +98,11 @@ public class LightVolume { public void initialize(ILightReader world) { BlockPos.Mutable pos = new BlockPos.Mutable(); - int shiftX = volume.minX; - int shiftY = volume.minY; - int shiftZ = volume.minZ; + int shiftX = textureVolume.minX; + int shiftY = textureVolume.minY; + int shiftZ = textureVolume.minZ; - volume.forEachContained((x, y, z) -> { + textureVolume.forEachContained((x, y, z) -> { pos.setPos(x, y, z); int blockLight = world.getLightLevel(LightType.BLOCK, pos); @@ -111,9 +121,9 @@ public class LightVolume { public void copyBlock(ILightReader world, GridAlignedBB worldVolume) { BlockPos.Mutable pos = new BlockPos.Mutable(); - int xShift = volume.minX; - int yShift = volume.minY; - int zShift = volume.minZ; + int xShift = textureVolume.minX; + int yShift = textureVolume.minY; + int zShift = textureVolume.minZ; worldVolume.forEachContained((x, y, z) -> { pos.setPos(x, y, z); @@ -133,9 +143,9 @@ public class LightVolume { public void copySky(ILightReader world, GridAlignedBB worldVolume) { BlockPos.Mutable pos = new BlockPos.Mutable(); - int xShift = volume.minX; - int yShift = volume.minY; - int zShift = volume.minZ; + int xShift = textureVolume.minX; + int yShift = textureVolume.minY; + int zShift = textureVolume.minZ; worldVolume.forEachContained((x, y, z) -> { pos.setPos(x, y, z); @@ -159,7 +169,7 @@ public class LightVolume { 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); if (bufferDirty) { - GL12.glTexImage3D(GL12.GL_TEXTURE_3D, 0, GL40.GL_RG8, volume.sizeX(), volume.sizeY(), volume.sizeZ(), 0, GL40.GL_RG, GL40.GL_UNSIGNED_BYTE, lightData); + 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; } } @@ -199,6 +209,6 @@ public class LightVolume { } private int index(int x, int y, int z) { - return (x + volume.sizeX() * (y + z * volume.sizeY())) * 2; + return (x + textureVolume.sizeX() * (y + z * textureVolume.sizeY())) * 2; } } diff --git a/src/main/java/com/simibubi/create/foundation/render/light/LightVolumeDebugger.java b/src/main/java/com/simibubi/create/foundation/render/light/LightVolumeDebugger.java index 11991177c..287532a40 100644 --- a/src/main/java/com/simibubi/create/foundation/render/light/LightVolumeDebugger.java +++ b/src/main/java/com/simibubi/create/foundation/render/light/LightVolumeDebugger.java @@ -2,17 +2,33 @@ package com.simibubi.create.foundation.render.light; import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.foundation.render.ContraptionRenderDispatcher; -import com.simibubi.create.foundation.render.RenderedContraption; import com.simibubi.create.foundation.renderState.SuperRenderTypeBuffer; +import com.simibubi.create.foundation.utility.Pair; import com.simibubi.create.foundation.utility.outliner.AABBOutline; -import com.simibubi.create.foundation.utility.outliner.Outline; + +import java.util.ArrayList; public class LightVolumeDebugger { public static void render(MatrixStack ms, SuperRenderTypeBuffer buffer) { ContraptionRenderDispatcher.renderers.values() .stream() - .map(r -> r.getLighter().lightVolume.getBox()) - .map(volume -> new AABBOutline(GridAlignedBB.toAABB(volume))) + .flatMap(r -> { + GridAlignedBB texture = r.getLighter().lightVolume.getTextureVolume(); + GridAlignedBB sample = r.getLighter().lightVolume.getSampleVolume(); + + ArrayList> pairs = new ArrayList<>(2); + + pairs.add(Pair.of(texture, 0xFFFFFF)); + pairs.add(Pair.of(sample, 0xFFFF00)); + + return pairs.stream(); + }) + .map(pair -> { + AABBOutline outline = new AABBOutline(GridAlignedBB.toAABB(pair.getFirst())); + + outline.getParams().colored(pair.getSecond()); + return outline; + }) .forEach(outline -> outline.render(ms, buffer)); } }