smarter light volumes
start the process of creating sane gl abstractions stabilized contraption bounds now fit tightly with them fix global tile entity issues
This commit is contained in:
parent
7bac93a03c
commit
93353b61d6
25 changed files with 328 additions and 158 deletions
|
@ -39,6 +39,11 @@ public class DeployerRenderer extends SafeTileEntityRenderer<DeployerTileEntity>
|
|||
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) {
|
||||
|
|
|
@ -376,10 +376,4 @@ public class DeployerTileEntity extends KineticTileEntity {
|
|||
TooltipHelper.addHint(tooltip, "hint.full_deployer");
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldRenderAsTE() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -9,6 +9,16 @@ public class NonStationaryLighter<C extends Contraption> 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();
|
||||
|
|
|
@ -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<BearingContraption> {
|
||||
|
||||
|
@ -11,9 +15,40 @@ public class BearingLighter extends ContraptionLighter<BearingContraption> {
|
|||
|
||||
@Override
|
||||
public GridAlignedBB getContraptionBounds() {
|
||||
GridAlignedBB localBounds = GridAlignedBB.fromAABB(contraption.bounds);
|
||||
localBounds.rotate45(contraption.getFacing().getAxis());
|
||||
localBounds.translate(contraption.anchor);
|
||||
return localBounds;
|
||||
Set<BlockPos> 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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -393,4 +393,8 @@ public class ClockworkBearingTileEntity extends KineticTileEntity implements IBe
|
|||
return pos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldRenderAsTE() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -282,4 +282,8 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldRenderAsTE() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -143,8 +143,4 @@ public abstract class BasinOperatingTileEntity extends KineticTileEntity {
|
|||
|
||||
protected abstract Object getRecipeCacheKey();
|
||||
|
||||
@Override
|
||||
public boolean shouldRenderAsTE() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,6 +50,11 @@ public class BeltRenderer extends SafeTileEntityRenderer<BeltTileEntity> impleme
|
|||
renderItems(te, partialTicks, ms, buffer, light, overlay);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isGlobalRenderer(BeltTileEntity te) {
|
||||
return te.isController();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addInstanceData(InstanceContext<BeltTileEntity> ctx) {
|
||||
BeltTileEntity te = ctx.te;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -513,8 +513,4 @@ public class ArmTileEntity extends KineticTileEntity {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldRenderAsTE() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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<S extends InstanceData, D extends InstanceData> extends InstanceBuffer<S> {
|
||||
|
||||
protected int dynamicVBO;
|
||||
protected GlBuffer dynamicVBO;
|
||||
|
||||
protected int dynamicBufferSize = -1;
|
||||
|
||||
|
@ -16,7 +17,7 @@ public abstract class DynamicInstanceBuffer<S extends InstanceData, D extends In
|
|||
@Override
|
||||
protected void setup() {
|
||||
super.setup();
|
||||
dynamicVBO = GL20.glGenBuffers();
|
||||
dynamicVBO = new GlBuffer();
|
||||
}
|
||||
|
||||
protected abstract VertexFormat getDynamicFormat();
|
||||
|
@ -31,7 +32,11 @@ public abstract class DynamicInstanceBuffer<S extends InstanceData, D extends In
|
|||
@Override
|
||||
protected void preDrawTask() {
|
||||
super.preDrawTask();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void deleteInternal() {
|
||||
super.deleteInternal();
|
||||
dynamicVBO.delete();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import com.simibubi.create.foundation.render.GPUBuffer;
|
|||
import com.simibubi.create.foundation.render.RenderMath;
|
||||
import com.simibubi.create.foundation.render.RenderWork;
|
||||
import com.simibubi.create.foundation.render.TemplateBuffer;
|
||||
import com.simibubi.create.foundation.render.gl.GlBuffer;
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import org.lwjgl.opengl.*;
|
||||
|
||||
|
@ -18,7 +19,7 @@ import static com.simibubi.create.foundation.render.instancing.VertexAttribute.*
|
|||
public abstract class InstanceBuffer<D extends InstanceData> 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<D extends InstanceData> extends GPUBuffer {
|
|||
@Override
|
||||
protected void setup() {
|
||||
super.setup();
|
||||
instanceVBO = GlStateManager.genBuffers();
|
||||
instanceVBO = new GlBuffer();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -76,15 +77,8 @@ public abstract class InstanceBuffer<D extends InstanceData> 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<D extends InstanceData> 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<D extends InstanceData> 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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue