Hazardous light

- BatchingEngine no longer resets the light matrices
- Fix flw_constantAmbientLight always being 0
- Move code from FlwMemoryTracker#*Block methods into MemoryBlockImpl
and TrackedMemoryBlockImpl
- Convert LightVolume to use MemoryBlock
- Add FlwMemoryTracker#callocBuffer
- Add javadoc to deprecated FlwMemoryTracker#*Buffer methods
- Update Mesh javadoc
- Organize imports
This commit is contained in:
PepperCode1 2022-08-14 21:42:44 -07:00
parent a1553b04e7
commit 9b39ba6c32
24 changed files with 288 additions and 296 deletions

View file

@ -22,7 +22,7 @@ public interface Material {
VertexTransformer getVertexTransformer();
public interface VertexTransformer {
interface VertexTransformer {
void transform(MutableVertexList vertexList, ClientLevel level);
}
}

View file

@ -29,7 +29,7 @@ public interface StructType<S extends InstancedPart> {
VertexTransformer<S> getVertexTransformer();
public interface VertexTransformer<S extends InstancedPart> {
interface VertexTransformer<S extends InstancedPart> {
void transform(MutableVertexList vertexList, S struct, ClientLevel level);
}

View file

@ -1,7 +1,5 @@
package com.jozufozu.flywheel.api.uniform;
import java.nio.ByteBuffer;
import com.jozufozu.flywheel.core.source.FileResolution;
public abstract class UniformProvider {

View file

@ -5,8 +5,8 @@ import org.lwjgl.opengl.GL32;
import com.jozufozu.flywheel.backend.gl.GlObject;
import com.jozufozu.flywheel.backend.gl.GlStateTracker;
import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType;
import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer;
import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType;
import com.jozufozu.flywheel.backend.gl.versioned.GlCompat;
import com.jozufozu.flywheel.core.layout.BufferLayout;
import com.mojang.blaze3d.platform.GlStateManager;

View file

@ -1,6 +1,12 @@
package com.jozufozu.flywheel.backend.gl.buffer;
import static org.lwjgl.opengl.GL32.*;
import static org.lwjgl.opengl.GL15.glBufferData;
import static org.lwjgl.opengl.GL15.glDeleteBuffers;
import static org.lwjgl.opengl.GL15.glGenBuffers;
import static org.lwjgl.opengl.GL15.nglBufferData;
import static org.lwjgl.opengl.GL30.GL_MAP_WRITE_BIT;
import static org.lwjgl.opengl.GL30.nglMapBufferRange;
import static org.lwjgl.opengl.GL31.glCopyBufferSubData;
import org.lwjgl.system.MemoryUtil;

View file

@ -13,9 +13,7 @@ import com.jozufozu.flywheel.backend.instancing.InstanceManager;
import com.jozufozu.flywheel.backend.instancing.TaskEngine;
import com.jozufozu.flywheel.core.RenderContext;
import com.jozufozu.flywheel.util.FlwUtil;
import com.mojang.blaze3d.platform.Lighting;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.math.Matrix4f;
import net.minecraft.client.Camera;
import net.minecraft.client.multiplayer.ClientLevel;
@ -73,15 +71,6 @@ public class BatchingEngine implements Engine {
return;
}
// FIXME: this probably breaks some vanilla stuff but it works much better for flywheel
Matrix4f mat = new Matrix4f();
mat.setIdentity();
if (context.level().effects().constantAmbientLight()) {
Lighting.setupNetherLevel(mat);
} else {
Lighting.setupLevel(mat);
}
batchTracker.endBatch();
}

View file

@ -83,20 +83,15 @@ public class TransformSet<D extends InstancedPart> {
vertexList.ptr(anchorPtr);
vertexList.setVertexCount(totalVertexCount);
material.getVertexTransformer().transform(vertexList, level);
applyPoseStack(vertexList, stack, false);
applyPoseStack(vertexList, stack);
}
private static void applyPoseStack(MutableVertexList vertexList, PoseStack stack, boolean applyNormalMatrix) {
private static void applyPoseStack(MutableVertexList vertexList, PoseStack stack) {
Vector4f pos = new Vector4f();
Vector3f normal = new Vector3f();
Matrix4f modelMatrix = stack.last().pose();
Matrix3f normalMatrix;
if (applyNormalMatrix) {
normalMatrix = stack.last().normal();
} else {
normalMatrix = null;
}
Matrix3f normalMatrix = stack.last().normal();
for (int i = 0; i < vertexList.getVertexCount(); i++) {
pos.set(
@ -110,18 +105,16 @@ public class TransformSet<D extends InstancedPart> {
vertexList.y(i, pos.y());
vertexList.z(i, pos.z());
if (applyNormalMatrix) {
normal.set(
vertexList.normalX(i),
vertexList.normalY(i),
vertexList.normalZ(i)
);
normal.transform(normalMatrix);
normal.normalize();
vertexList.normalX(i, normal.x());
vertexList.normalY(i, normal.y());
vertexList.normalZ(i, normal.z());
}
normal.set(
vertexList.normalX(i),
vertexList.normalY(i),
vertexList.normalZ(i)
);
normal.transform(normalMatrix);
normal.normalize();
vertexList.normalX(i, normal.x());
vertexList.normalY(i, normal.y());
vertexList.normalZ(i, normal.z());
}
}

View file

@ -8,10 +8,10 @@ import com.jozufozu.flywheel.api.instancer.InstancedPart;
import com.jozufozu.flywheel.api.struct.StructType;
import com.jozufozu.flywheel.api.struct.StructWriter;
import com.jozufozu.flywheel.backend.gl.array.GlVertexArray;
import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer;
import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType;
import com.jozufozu.flywheel.backend.gl.buffer.GlBufferUsage;
import com.jozufozu.flywheel.backend.gl.buffer.MappedBuffer;
import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer;
import com.jozufozu.flywheel.backend.instancing.AbstractInstancer;
import com.jozufozu.flywheel.core.layout.BufferLayout;

View file

@ -14,9 +14,9 @@ import com.jozufozu.flywheel.Flywheel;
import com.jozufozu.flywheel.api.vertex.VertexType;
import com.jozufozu.flywheel.backend.gl.GlPrimitive;
import com.jozufozu.flywheel.backend.gl.array.GlVertexArray;
import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer;
import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType;
import com.jozufozu.flywheel.backend.gl.buffer.MappedBuffer;
import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer;
import com.jozufozu.flywheel.core.layout.BufferLayout;
import com.jozufozu.flywheel.core.model.Mesh;
import com.jozufozu.flywheel.event.ReloadRenderersEvent;

View file

@ -6,7 +6,7 @@ import java.nio.ByteBuffer;
import org.lwjgl.system.MemoryUtil;
public class FlwMemoryTracker {
private static final Cleaner CLEANER = Cleaner.create();
static final Cleaner CLEANER = Cleaner.create();
private static long cpuMemory = 0;
private static long gpuMemory = 0;
@ -19,18 +19,11 @@ public class FlwMemoryTracker {
return ptr;
}
public static MemoryBlock mallocBlock(long size) {
MemoryBlock block = new MemoryBlockImpl(malloc(size), size);
_allocCPUMemory(block.size());
return block;
}
public static MemoryBlock mallocBlockTracked(long size) {
MemoryBlock block = new TrackedMemoryBlockImpl(malloc(size), size, CLEANER);
_allocCPUMemory(block.size());
return block;
}
/**
* @deprecated Use {@link MemoryBlock#malloc(long)} or {@link MemoryBlock#mallocTracked(long)} and
* {@link MemoryBlock#asBuffer()} instead. This method should only be used if specifically a {@linkplain ByteBuffer} is needed and it is
* short-lived.
*/
@Deprecated
public static ByteBuffer mallocBuffer(int size) {
ByteBuffer buffer = MemoryUtil.memByteBuffer(malloc(size), size);
@ -46,16 +39,16 @@ public class FlwMemoryTracker {
return ptr;
}
public static MemoryBlock callocBlock(long num, long size) {
MemoryBlock block = new MemoryBlockImpl(calloc(num, size), num * size);
_allocCPUMemory(block.size());
return block;
}
public static MemoryBlock callocBlockTracked(long num, long size) {
MemoryBlock block = new TrackedMemoryBlockImpl(calloc(num, size), num * size, CLEANER);
_allocCPUMemory(block.size());
return block;
/**
* @deprecated Use {@link MemoryBlock#calloc(long, long)} or {@link MemoryBlock#callocTracked(long, long)} and
* {@link MemoryBlock#asBuffer()} instead. This method should only be used if specifically a {@linkplain ByteBuffer} is needed and it is
* short-lived.
*/
@Deprecated
public static ByteBuffer callocBuffer(int num, int size) {
ByteBuffer buffer = MemoryUtil.memByteBuffer(calloc(num, size), num * size);
_allocCPUMemory(buffer.capacity());
return buffer;
}
public static long realloc(long ptr, long size) {
@ -66,20 +59,10 @@ public class FlwMemoryTracker {
return ptr;
}
public static MemoryBlock reallocBlock(MemoryBlock block, long size) {
MemoryBlock newBlock = new MemoryBlockImpl(realloc(block.ptr(), size), size);
_freeCPUMemory(block.size());
_allocCPUMemory(newBlock.size());
return newBlock;
}
public static MemoryBlock reallocBlockTracked(MemoryBlock block, long size) {
MemoryBlock newBlock = new TrackedMemoryBlockImpl(realloc(block.ptr(), size), size, CLEANER);
_freeCPUMemory(block.size());
_allocCPUMemory(newBlock.size());
return newBlock;
}
/**
* @deprecated Use {@link MemoryBlock#realloc(long)} or {@link MemoryBlock#reallocTracked(long)} instead. This method
* should only be used if specifically a {@linkplain ByteBuffer} is needed and it is short-lived.
*/
@Deprecated
public static ByteBuffer reallocBuffer(ByteBuffer buffer, int size) {
ByteBuffer newBuffer = MemoryUtil.memByteBuffer(realloc(MemoryUtil.memAddress(buffer), size), size);
@ -92,11 +75,10 @@ public class FlwMemoryTracker {
MemoryUtil.nmemFree(ptr);
}
public static void freeBlock(MemoryBlock block) {
free(block.ptr());
_freeCPUMemory(block.size());
}
/**
* @deprecated Use {@link MemoryBlock#free} instead. This method should only be used if specifically a {@linkplain ByteBuffer} is needed and
* it is short-lived.
*/
@Deprecated
public static void freeBuffer(ByteBuffer buffer) {
free(MemoryUtil.memAddress(buffer));

View file

@ -26,18 +26,18 @@ public sealed interface MemoryBlock permits MemoryBlockImpl {
void free();
static MemoryBlock malloc(long size) {
return FlwMemoryTracker.mallocBlock(size);
}
static MemoryBlock calloc(long num, long size) {
return FlwMemoryTracker.callocBlock(num, size);
return MemoryBlockImpl.mallocBlock(size);
}
static MemoryBlock mallocTracked(long size) {
return FlwMemoryTracker.mallocBlockTracked(size);
return TrackedMemoryBlockImpl.mallocBlockTracked(size);
}
static MemoryBlock calloc(long num, long size) {
return MemoryBlockImpl.callocBlock(num, size);
}
static MemoryBlock callocTracked(long num, long size) {
return FlwMemoryTracker.callocBlockTracked(num, size);
return TrackedMemoryBlockImpl.callocBlockTracked(num, size);
}
}

View file

@ -59,23 +59,42 @@ sealed class MemoryBlockImpl implements MemoryBlock permits TrackedMemoryBlockIm
return MemoryUtil.memByteBuffer(ptr, intSize);
}
void freeInner() {
FlwMemoryTracker._freeCPUMemory(size);
freed = true;
}
@Override
public MemoryBlock realloc(long size) {
MemoryBlock block = FlwMemoryTracker.reallocBlock(this, size);
freed = true;
MemoryBlock block = new MemoryBlockImpl(FlwMemoryTracker.realloc(ptr, size), size);
FlwMemoryTracker._allocCPUMemory(block.size());
freeInner();
return block;
}
@Override
public MemoryBlock reallocTracked(long size) {
MemoryBlock block = FlwMemoryTracker.reallocBlockTracked(this, size);
freed = true;
MemoryBlock block = new TrackedMemoryBlockImpl(FlwMemoryTracker.realloc(ptr, size), size, FlwMemoryTracker.CLEANER);
FlwMemoryTracker._allocCPUMemory(block.size());
freeInner();
return block;
}
@Override
public void free() {
FlwMemoryTracker.freeBlock(this);
freed = true;
FlwMemoryTracker.free(ptr);
freeInner();
}
static MemoryBlock mallocBlock(long size) {
MemoryBlock block = new MemoryBlockImpl(FlwMemoryTracker.malloc(size), size);
FlwMemoryTracker._allocCPUMemory(block.size());
return block;
}
static MemoryBlock callocBlock(long num, long size) {
MemoryBlock block = new MemoryBlockImpl(FlwMemoryTracker.calloc(num, size), num * size);
FlwMemoryTracker._allocCPUMemory(block.size());
return block;
}
}

View file

@ -17,32 +17,25 @@ final class TrackedMemoryBlockImpl extends MemoryBlockImpl {
return true;
}
@Override
void freeInner() {
freed = true;
super.freeInner();
cleaningAction.freed = true;
cleanable.clean();
}
@Override
public MemoryBlock realloc(long size) {
MemoryBlock block = FlwMemoryTracker.reallocBlock(this, size);
freeInner();
static MemoryBlock mallocBlockTracked(long size) {
MemoryBlock block = new TrackedMemoryBlockImpl(FlwMemoryTracker.malloc(size), size, FlwMemoryTracker.CLEANER);
FlwMemoryTracker._allocCPUMemory(block.size());
return block;
}
@Override
public MemoryBlock reallocTracked(long size) {
MemoryBlock block = FlwMemoryTracker.reallocBlockTracked(this, size);
freeInner();
static MemoryBlock callocBlockTracked(long num, long size) {
MemoryBlock block = new TrackedMemoryBlockImpl(FlwMemoryTracker.calloc(num, size), num * size, FlwMemoryTracker.CLEANER);
FlwMemoryTracker._allocCPUMemory(block.size());
return block;
}
@Override
public void free() {
FlwMemoryTracker.freeBlock(this);
freeInner();
}
static class CleaningAction implements Runnable {
final long ptr;
final long size;

View file

@ -8,9 +8,9 @@ import org.lwjgl.system.MemoryUtil;
import com.jozufozu.flywheel.Flywheel;
import com.jozufozu.flywheel.backend.gl.GlStateTracker;
import com.jozufozu.flywheel.backend.gl.array.GlVertexArray;
import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer;
import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType;
import com.jozufozu.flywheel.backend.gl.buffer.MappedBuffer;
import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer;
import com.jozufozu.flywheel.core.layout.BufferLayout;
import com.jozufozu.flywheel.core.layout.CommonItems;
import com.jozufozu.flywheel.util.Lazy;

View file

@ -5,9 +5,9 @@ import org.jetbrains.annotations.Nullable;
import org.lwjgl.system.MemoryUtil;
import com.jozufozu.flywheel.backend.gl.GlNumericType;
import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer;
import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType;
import com.jozufozu.flywheel.backend.gl.buffer.MappedBuffer;
import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer;
import com.jozufozu.flywheel.backend.instancing.instancing.ElementBuffer;
import com.jozufozu.flywheel.event.ReloadRenderersEvent;

View file

@ -6,24 +6,7 @@ import com.jozufozu.flywheel.backend.instancing.instancing.ElementBuffer;
import com.jozufozu.flywheel.core.QuadConverter;
/**
* A mesh that can be rendered by flywheel.
*
* <p>
* It is expected that the following assertion will not fail:
* </p>
*
* <pre>{@code
* Mesh mesh = ...;
* VecBuffer into = ...;
*
* int initial = VecBuffer.unwrap().position();
*
* mesh.buffer(into);
*
* int final = VecBuffer.unwrap().position();
*
* assert mesh.size() == final - initial;
* }</pre>
* A holder for arbitrary vertex data that can be written to memory or a vertex list.
*/
public interface Mesh {
@ -49,8 +32,18 @@ public interface Mesh {
return getVertexType().byteOffset(getVertexCount());
}
/**
* Write this mesh into memory. The written data will use the format defined by {@link #getVertexType()} and the amount of
* bytes written will be the same as the return value of {@link #size()}.
* @param ptr The address to which data is written to.
*/
void write(long ptr);
/**
* Write this mesh into a vertex list. Vertices with index {@literal <}0 or {@literal >=}{@link #getVertexCount()} will not be
* modified.
* @param vertexList The vertex list to which data is written to.
*/
void write(MutableVertexList vertexList);
/**

View file

@ -30,6 +30,8 @@ import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.client.model.data.IModelData;
public class BakedModelBuilder {
private static final int STARTING_CAPACITY = 64;
private final BakedModel bakedModel;
private boolean shadeSeparated = true;
private BlockAndTintGetter renderWorld;
@ -96,7 +98,7 @@ public class BakedModelBuilder {
if (shadeSeparated) {
ShadeSeparatedBufferFactory<BufferBuilder> bufferFactory = (renderType, shaded) -> {
BufferBuilder buffer = new BufferBuilder(64);
BufferBuilder buffer = new BufferBuilder(STARTING_CAPACITY);
buffer.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK);
return buffer;
};
@ -111,7 +113,7 @@ public class BakedModelBuilder {
ModelBufferingUtil.bufferSingleShadeSeparated(ModelUtil.VANILLA_RENDERER.getModelRenderer(), renderWorld, bakedModel, blockState, poseStack, bufferFactory, objects.shadeSeparatingBufferWrapper, objects.random, modelData, resultConsumer);
} else {
BufferFactory<BufferBuilder> bufferFactory = (renderType) -> {
BufferBuilder buffer = new BufferBuilder(64);
BufferBuilder buffer = new BufferBuilder(STARTING_CAPACITY);
buffer.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK);
return buffer;
};

View file

@ -28,6 +28,8 @@ import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.client.model.data.IModelData;
public class BlockModelBuilder {
private static final int STARTING_CAPACITY = 64;
private final BlockState state;
private boolean shadeSeparated = true;
private BlockAndTintGetter renderWorld;
@ -85,7 +87,7 @@ public class BlockModelBuilder {
if (shadeSeparated) {
ShadeSeparatedBufferFactory<BufferBuilder> bufferFactory = (renderType, shaded) -> {
BufferBuilder buffer = new BufferBuilder(64);
BufferBuilder buffer = new BufferBuilder(STARTING_CAPACITY);
buffer.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK);
return buffer;
};
@ -100,7 +102,7 @@ public class BlockModelBuilder {
ModelBufferingUtil.bufferBlockShadeSeparated(ModelUtil.VANILLA_RENDERER, renderWorld, state, poseStack, bufferFactory, objects.shadeSeparatingBufferWrapper, objects.random, modelData, resultConsumer);
} else {
BufferFactory<BufferBuilder> bufferFactory = (renderType) -> {
BufferBuilder buffer = new BufferBuilder(64);
BufferBuilder buffer = new BufferBuilder(STARTING_CAPACITY);
buffer.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK);
return buffer;
};

View file

@ -31,6 +31,8 @@ import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemp
import net.minecraftforge.client.model.data.IModelData;
public class MultiBlockModelBuilder {
private static final int STARTING_CAPACITY = 1024;
private final Collection<StructureTemplate.StructureBlockInfo> blocks;
private boolean shadeSeparated = true;
private VertexFormat vertexFormat;
@ -92,7 +94,7 @@ public class MultiBlockModelBuilder {
if (shadeSeparated) {
ShadeSeparatedBufferFactory<BufferBuilder> bufferFactory = (renderType, shaded) -> {
BufferBuilder buffer = new BufferBuilder(1024);
BufferBuilder buffer = new BufferBuilder(STARTING_CAPACITY);
buffer.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK);
return buffer;
};
@ -107,7 +109,7 @@ public class MultiBlockModelBuilder {
ModelBufferingUtil.bufferMultiBlockShadeSeparated(blocks, ModelUtil.VANILLA_RENDERER, renderWorld, poseStack, bufferFactory, objects.shadeSeparatingBufferWrapper, objects.random, modelDataMap, resultConsumer);
} else {
BufferFactory<BufferBuilder> bufferFactory = (renderType) -> {
BufferBuilder buffer = new BufferBuilder(1024);
BufferBuilder buffer = new BufferBuilder(STARTING_CAPACITY);
buffer.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK);
return buffer;
};

View file

@ -5,12 +5,11 @@ import java.util.Collection;
import java.util.List;
import org.lwjgl.opengl.GL32;
import org.lwjgl.system.MemoryUtil;
import com.google.common.collect.ImmutableList;
import com.jozufozu.flywheel.api.uniform.UniformProvider;
import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType;
import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer;
import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType;
import com.jozufozu.flywheel.backend.memory.MemoryBlock;
import com.jozufozu.flywheel.core.ComponentRegistry;
import com.jozufozu.flywheel.util.RenderMath;

View file

@ -56,7 +56,7 @@ public class ViewProvider extends UniformProvider {
MemoryUtil.memPutFloat(ptr + 64, camX);
MemoryUtil.memPutFloat(ptr + 68, camY);
MemoryUtil.memPutFloat(ptr + 72, camZ);
MemoryUtil.memPutInt(ptr + 76, constantAmbientLight);
MemoryUtil.memPutInt(ptr + 80, constantAmbientLight);
notifier.signalChanged();
}

View file

@ -73,7 +73,7 @@ public class GPULightVolume extends LightVolume {
public void bind() {
// just in case something goes wrong, or we accidentally call this before this volume is properly disposed of.
if (lightData == null || lightData.capacity() == 0) return;
if (lightData == null || lightData.size() == 0) return;
textureUnit.makeActive();
glTexture.bind();
@ -93,7 +93,7 @@ public class GPULightVolume extends LightVolume {
int sizeY = box.sizeY();
int sizeZ = box.sizeZ();
glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, sizeX, sizeY, sizeZ, GL30.GL_RG, GL_UNSIGNED_BYTE, lightData);
glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, sizeX, sizeY, sizeZ, GL30.GL_RG, GL_UNSIGNED_BYTE, lightData.ptr());
glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // 4 is the default
bufferDirty = false;

View file

@ -1,8 +1,8 @@
package com.jozufozu.flywheel.light;
import java.nio.ByteBuffer;
import org.lwjgl.system.MemoryUtil;
import com.jozufozu.flywheel.backend.memory.FlwMemoryTracker;
import com.jozufozu.flywheel.backend.memory.MemoryBlock;
import com.jozufozu.flywheel.util.box.GridAlignedBB;
import com.jozufozu.flywheel.util.box.ImmutableBox;
@ -14,13 +14,53 @@ public class LightVolume implements ImmutableBox, LightListener {
protected final BlockAndTintGetter level;
protected final GridAlignedBB box = new GridAlignedBB();
protected ByteBuffer lightData;
protected MemoryBlock lightData;
public LightVolume(BlockAndTintGetter level, ImmutableBox sampleVolume) {
this.level = level;
this.setBox(sampleVolume);
this.lightData = FlwMemoryTracker.mallocBuffer(this.box.volume() * 2);
this.lightData = MemoryBlock.malloc(this.box.volume() * 2);
}
@Override
public ImmutableBox getVolume() {
return box;
}
@Override
public int getMinX() {
return box.getMinX();
}
@Override
public int getMinY() {
return box.getMinY();
}
@Override
public int getMinZ() {
return box.getMinZ();
}
@Override
public int getMaxX() {
return box.getMaxX();
}
@Override
public int getMaxY() {
return box.getMaxY();
}
@Override
public int getMaxZ() {
return box.getMaxZ();
}
@Override
public boolean isListenerInvalid() {
return lightData == null;
}
protected void setBox(ImmutableBox box) {
@ -29,47 +69,143 @@ public class LightVolume implements ImmutableBox, LightListener {
public short getPackedLight(int x, int y, int z) {
if (box.contains(x, y, z)) {
return lightData.getShort(worldPosToBufferIndex(x, y, z));
return MemoryUtil.memGetShort(worldPosToPtr(x, y, z));
} else {
return 0;
}
}
public int getMinX() {
return box.getMinX();
}
public int getMinY() {
return box.getMinY();
}
public int getMinZ() {
return box.getMinZ();
}
public int getMaxX() {
return box.getMaxX();
}
public int getMaxY() {
return box.getMaxY();
}
public int getMaxZ() {
return box.getMaxZ();
}
public void move(ImmutableBox newSampleVolume) {
if (lightData == null) return;
setBox(newSampleVolume);
int neededCapacity = box.volume() * 2;
if (neededCapacity > lightData.capacity()) {
lightData = FlwMemoryTracker.reallocBuffer(lightData, neededCapacity);
if (neededCapacity > lightData.size()) {
lightData = lightData.realloc(neededCapacity);
}
initialize();
}
/**
* Completely (re)populate this volume with block and sky lighting data.
* This is expensive and should be avoided.
*/
public void initialize() {
if (lightData == null) return;
copyLight(getVolume());
markDirty();
}
protected void markDirty() {
// noop
}
public void delete() {
lightData.free();
lightData = null;
}
/**
* Copy all light from the world into this volume.
*
* @param worldVolume the region in the world to copy data from.
*/
public void copyLight(ImmutableBox worldVolume) {
BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos();
int xShift = box.getMinX();
int yShift = box.getMinY();
int zShift = box.getMinZ();
worldVolume.forEachContained((x, y, z) -> {
pos.set(x, y, z);
int block = this.level.getBrightness(LightLayer.BLOCK, pos);
int sky = this.level.getBrightness(LightLayer.SKY, pos);
writeLight(x - xShift, y - yShift, z - zShift, block, sky);
});
}
protected void writeLight(int x, int y, int z, int block, int sky) {
byte b = (byte) ((block & 0xF) << 4);
byte s = (byte) ((sky & 0xF) << 4);
long ptr = boxPosToPtr(x, y, z);
MemoryUtil.memPutByte(ptr, b);
MemoryUtil.memPutByte(ptr + 1, s);
}
/**
* Copy block light from the world into this volume.
*
* @param worldVolume the region in the world to copy data from.
*/
public void copyBlock(ImmutableBox worldVolume) {
var pos = new BlockPos.MutableBlockPos();
int xShift = box.getMinX();
int yShift = box.getMinY();
int zShift = box.getMinZ();
worldVolume.forEachContained((x, y, z) -> {
int light = this.level.getBrightness(LightLayer.BLOCK, pos.set(x, y, z));
writeBlock(x - xShift, y - yShift, z - zShift, light);
});
}
protected void writeBlock(int x, int y, int z, int block) {
byte b = (byte) ((block & 0xF) << 4);
MemoryUtil.memPutByte(boxPosToPtr(x, y, z), b);
}
/**
* Copy sky light from the world into this volume.
*
* @param worldVolume the region in the world to copy data from.
*/
public void copySky(ImmutableBox worldVolume) {
var pos = new BlockPos.MutableBlockPos();
int xShift = box.getMinX();
int yShift = box.getMinY();
int zShift = box.getMinZ();
worldVolume.forEachContained((x, y, z) -> {
int light = this.level.getBrightness(LightLayer.SKY, pos.set(x, y, z));
writeSky(x - xShift, y - yShift, z - zShift, light);
});
}
protected void writeSky(int x, int y, int z, int sky) {
byte s = (byte) ((sky & 0xF) << 4);
MemoryUtil.memPutByte(boxPosToPtr(x, y, z) + 1, s);
}
protected long worldPosToPtr(int x, int y, int z) {
return lightData.ptr() + worldPosToPtrOffset(x, y, z);
}
protected long boxPosToPtr(int x, int y, int z) {
return lightData.ptr() + boxPosToPtrOffset(x, y, z);
}
protected int worldPosToPtrOffset(int x, int y, int z) {
x -= box.getMinX();
y -= box.getMinY();
z -= box.getMinZ();
return boxPosToPtrOffset(x, y, z);
}
protected int boxPosToPtrOffset(int x, int y, int z) {
return (x + box.sizeX() * (y + z * box.sizeY())) * 2;
}
@Override
public void onLightUpdate(LightLayer type, ImmutableBox changedVolume) {
if (lightData == null) return;
@ -95,126 +231,4 @@ public class LightVolume implements ImmutableBox, LightListener {
markDirty();
}
/**
* Completely (re)populate this volume with block and sky lighting data.
* This is expensive and should be avoided.
*/
public void initialize() {
if (lightData == null) return;
copyLight(getVolume());
markDirty();
}
/**
* Copy block light from the world into this volume.
*
* @param worldVolume the region in the world to copy data from.
*/
public void copyBlock(ImmutableBox worldVolume) {
var pos = new BlockPos.MutableBlockPos();
int xShift = box.getMinX();
int yShift = box.getMinY();
int zShift = box.getMinZ();
worldVolume.forEachContained((x, y, z) -> {
int light = this.level.getBrightness(LightLayer.BLOCK, pos.set(x, y, z));
writeBlock(x - xShift, y - yShift, z - zShift, light);
});
}
/**
* Copy sky light from the world into this volume.
*
* @param worldVolume the region in the world to copy data from.
*/
public void copySky(ImmutableBox worldVolume) {
var pos = new BlockPos.MutableBlockPos();
int xShift = box.getMinX();
int yShift = box.getMinY();
int zShift = box.getMinZ();
worldVolume.forEachContained((x, y, z) -> {
int light = this.level.getBrightness(LightLayer.SKY, pos.set(x, y, z));
writeSky(x - xShift, y - yShift, z - zShift, light);
});
}
/**
* Copy all light from the world into this volume.
*
* @param worldVolume the region in the world to copy data from.
*/
public void copyLight(ImmutableBox worldVolume) {
BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos();
int xShift = box.getMinX();
int yShift = box.getMinY();
int zShift = box.getMinZ();
worldVolume.forEachContained((x, y, z) -> {
pos.set(x, y, z);
int block = this.level.getBrightness(LightLayer.BLOCK, pos);
int sky = this.level.getBrightness(LightLayer.SKY, pos);
writeLight(x - xShift, y - yShift, z - zShift, block, sky);
});
}
public void delete() {
FlwMemoryTracker.freeBuffer(lightData);
lightData = null;
}
protected void markDirty() {
// noop
}
protected void writeLight(int x, int y, int z, int block, int sky) {
byte b = (byte) ((block & 0xF) << 4);
byte s = (byte) ((sky & 0xF) << 4);
int i = boxPosToBufferIndex(x, y, z);
lightData.put(i, b);
lightData.put(i + 1, s);
}
protected void writeBlock(int x, int y, int z, int block) {
byte b = (byte) ((block & 0xF) << 4);
lightData.put(boxPosToBufferIndex(x, y, z), b);
}
protected void writeSky(int x, int y, int z, int sky) {
byte b = (byte) ((sky & 0xF) << 4);
lightData.put(boxPosToBufferIndex(x, y, z) + 1, b);
}
protected int worldPosToBufferIndex(int x, int y, int z) {
x -= box.getMinX();
y -= box.getMinY();
z -= box.getMinZ();
return boxPosToBufferIndex(x, y, z);
}
protected int boxPosToBufferIndex(int x, int y, int z) {
return (x + box.sizeX() * (y + z * box.sizeY())) * 2;
}
@Override
public ImmutableBox getVolume() {
return box;
}
@Override
public boolean isListenerInvalid() {
return lightData == null;
}
}

View file

@ -25,11 +25,11 @@ public class StringUtil {
if (bytes < 1024) {
return bytes + " B";
} else if (bytes < 1024 * 1024) {
return THREE_DECIMAL_PLACES.format(bytes / 1024f) + " KB";
return THREE_DECIMAL_PLACES.format(bytes / 1024f) + " KiB";
} else if (bytes < 1024 * 1024 * 1024) {
return THREE_DECIMAL_PLACES.format(bytes / 1024f / 1024f) + " MB";
return THREE_DECIMAL_PLACES.format(bytes / 1024f / 1024f) + " MiB";
} else {
return THREE_DECIMAL_PLACES.format(bytes / 1024f / 1024f / 1024f) + " GB";
return THREE_DECIMAL_PLACES.format(bytes / 1024f / 1024f / 1024f) + " GiB";
}
}