Compare commits

...

5 commits

Author SHA1 Message Date
Jozufozu
68daac8659 Debugging broken overlay/lighting
- Break instance overlay/light back into 2 layout elements
- Write light directly as an int
- Make light a short backed float element
- Clamp overlay coords in common.frag to avoid explosions
- Explosions: integer vertex attributes sometimes blow up to massive
  sizes, greater than Short.MAX_VALUE which should not be possible.
- Reorganize some texture/uniform binding code
2024-02-21 12:37:46 -06:00
Jozufozu
df83277692 Buffer buffers
- Do not map buffers
- Strip down GlBuffer, so it only contains upload methods
- Remove buffer mapping and copy wrappers
- Add subdata wrapper
2024-02-21 09:29:27 -06:00
Jozufozu
0e00c7019d Cool and normal
- Reimplement normal debug mode
- Add debug mode for instance ID and light coordinates
- Pass an id into _flw_main
- Allow specifying how the debug color is applied, not sure if I want
  to keep it though
- Do not store the debug mode in config
2024-02-21 09:29:23 -06:00
Jozufozu
83119040d2 Pool party!
- Move index buffer logic into IndexPool class, should let us avoid
  unnecessary uploads and make it easier to manage
2024-02-20 11:09:39 -06:00
Jozufozu
dd23e1d4f8 A mesh unbound
- Clear a mesh's set of bound vaos when it's uploaded
- Fixes visual glitches on instancing when removing instances
2024-02-20 10:46:30 -06:00
23 changed files with 311 additions and 260 deletions

View file

@ -4,9 +4,9 @@ import java.util.List;
import com.jozufozu.flywheel.Flywheel;
import com.jozufozu.flywheel.api.layout.FloatRepr;
import com.jozufozu.flywheel.api.layout.IntegerRepr;
import com.jozufozu.flywheel.api.layout.Layout;
import com.jozufozu.flywheel.api.layout.LayoutBuilder;
import com.jozufozu.flywheel.api.layout.UnsignedIntegerRepr;
import com.jozufozu.flywheel.api.vertex.VertexView;
import com.jozufozu.flywheel.backend.engine.LayoutAttributes;
import com.jozufozu.flywheel.backend.gl.array.VertexAttribute;
@ -19,7 +19,7 @@ public final class InternalVertex {
.vector("position", FloatRepr.FLOAT, 3)
.vector("color", FloatRepr.NORMALIZED_UNSIGNED_BYTE, 4)
.vector("tex", FloatRepr.FLOAT, 2)
.vector("overlay_light", UnsignedIntegerRepr.UNSIGNED_SHORT, 4)
.vector("overlay_light", IntegerRepr.SHORT, 4)
.vector("normal", FloatRepr.NORMALIZED_BYTE, 3)
.build();

View file

@ -0,0 +1,89 @@
package com.jozufozu.flywheel.backend.engine;
import com.jozufozu.flywheel.api.model.IndexSequence;
import com.jozufozu.flywheel.backend.gl.GlNumericType;
import com.jozufozu.flywheel.backend.gl.array.GlVertexArray;
import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer;
import com.jozufozu.flywheel.lib.memory.MemoryBlock;
import it.unimi.dsi.fastutil.objects.Reference2IntMap;
import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap;
public class IndexPool {
private final GlBuffer ebo;
private final Reference2IntMap<IndexSequence> indexCounts;
private final Reference2IntMap<IndexSequence> firstIndices;
private boolean dirty;
public IndexPool() {
ebo = new GlBuffer();
indexCounts = new Reference2IntOpenHashMap<>();
firstIndices = new Reference2IntOpenHashMap<>();
indexCounts.defaultReturnValue(0);
}
public int firstIndex(IndexSequence sequence) {
return firstIndices.getInt(sequence);
}
public void reset() {
indexCounts.clear();
firstIndices.clear();
dirty = true;
}
public void updateCount(IndexSequence sequence, int indexCount) {
int oldCount = indexCounts.getInt(sequence);
int newCount = Math.max(oldCount, indexCount);
if (newCount > oldCount) {
indexCounts.put(sequence, newCount);
dirty = true;
}
}
public void flush() {
if (!dirty) {
return;
}
firstIndices.clear();
dirty = false;
long totalIndexCount = 0;
for (int count : indexCounts.values()) {
totalIndexCount += count;
}
final var indexBlock = MemoryBlock.malloc(totalIndexCount * GlNumericType.UINT.byteWidth());
final long indexPtr = indexBlock.ptr();
int firstIndex = 0;
for (Reference2IntMap.Entry<IndexSequence> entries : indexCounts.reference2IntEntrySet()) {
var indexSequence = entries.getKey();
var indexCount = entries.getIntValue();
firstIndices.put(indexSequence, firstIndex);
indexSequence.fill(indexPtr + (long) firstIndex * GlNumericType.UINT.byteWidth(), indexCount);
firstIndex += indexCount;
}
ebo.upload(indexBlock);
indexBlock.free();
}
public void bind(GlVertexArray vertexArray) {
vertexArray.setElementBuffer(ebo.handle());
}
public void delete() {
ebo.delete();
}
}

View file

@ -9,27 +9,24 @@ import java.util.Set;
import org.jetbrains.annotations.Nullable;
import org.lwjgl.opengl.GL32;
import com.jozufozu.flywheel.api.model.IndexSequence;
import com.jozufozu.flywheel.api.model.Mesh;
import com.jozufozu.flywheel.api.vertex.VertexView;
import com.jozufozu.flywheel.backend.InternalVertex;
import com.jozufozu.flywheel.backend.gl.GlNumericType;
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.lib.memory.MemoryBlock;
import it.unimi.dsi.fastutil.objects.Reference2IntMap;
import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap;
import it.unimi.dsi.fastutil.objects.ReferenceArraySet;
public class MeshPool {
private final VertexView vertexView;
private final Map<Mesh, BufferedMesh> meshes = new HashMap<>();
private final List<BufferedMesh> meshList = new ArrayList<>();
private final List<BufferedMesh> recentlyAllocated = new ArrayList<>();
private final GlBuffer vbo;
private final GlBuffer ebo;
private final IndexPool indexPool;
private boolean dirty;
private boolean anyToRemove;
@ -40,7 +37,7 @@ public class MeshPool {
public MeshPool() {
vertexView = InternalVertex.createVertexView();
vbo = new GlBuffer();
ebo = new GlBuffer();
indexPool = new IndexPool();
}
/**
@ -56,6 +53,7 @@ public class MeshPool {
private BufferedMesh _alloc(Mesh m) {
BufferedMesh bufferedModel = new BufferedMesh(m);
meshList.add(bufferedModel);
recentlyAllocated.add(bufferedModel);
dirty = true;
return bufferedModel;
@ -74,9 +72,23 @@ public class MeshPool {
if (anyToRemove) {
anyToRemove = false;
processDeletions();
// Might want to shrink the index pool if something was removed.
indexPool.reset();
for (BufferedMesh mesh : meshList) {
indexPool.updateCount(mesh.mesh.indexSequence(), mesh.indexCount());
}
} else {
// Otherwise, just update the index with the new counts.
for (BufferedMesh mesh : recentlyAllocated) {
indexPool.updateCount(mesh.mesh.indexSequence(), mesh.indexCount());
}
}
uploadAll();
// Always need to flush the index pool.
indexPool.flush();
uploadAll();
dirty = false;
}
@ -93,41 +105,8 @@ public class MeshPool {
private void uploadAll() {
long neededSize = 0;
Reference2IntMap<IndexSequence> indexCounts = new Reference2IntOpenHashMap<>();
indexCounts.defaultReturnValue(0);
for (BufferedMesh mesh : meshList) {
neededSize += mesh.byteSize();
int count = indexCounts.getInt(mesh.mesh.indexSequence());
int newCount = Math.max(count, mesh.indexCount());
if (newCount > count) {
indexCounts.put(mesh.mesh.indexSequence(), newCount);
}
}
long totalIndexCount = 0;
for (int count : indexCounts.values()) {
totalIndexCount += count;
}
final var indexBlock = MemoryBlock.malloc(totalIndexCount * GlNumericType.UINT.byteWidth());
final long indexPtr = indexBlock.ptr();
Reference2IntMap<IndexSequence> firstIndices = new Reference2IntOpenHashMap<>();
int firstIndex = 0;
for (Reference2IntMap.Entry<IndexSequence> entries : indexCounts.reference2IntEntrySet()) {
var indexSequence = entries.getKey();
var indexCount = entries.getIntValue();
firstIndices.put(indexSequence, firstIndex);
indexSequence.fill(indexPtr + (long) firstIndex * GlNumericType.UINT.byteWidth(), indexCount);
firstIndex += indexCount;
}
final var vertexBlock = MemoryBlock.malloc(neededSize);
@ -144,25 +123,25 @@ public class MeshPool {
byteIndex += mesh.byteSize();
baseVertex += mesh.vertexCount();
mesh.firstIndex = firstIndices.getInt(mesh.mesh.indexSequence());
mesh.firstIndex = indexPool.firstIndex(mesh.mesh.indexSequence());
mesh.boundTo.clear();
}
vbo.upload(vertexBlock);
ebo.upload(indexBlock);
vertexBlock.free();
indexBlock.free();
}
public void bind(GlVertexArray vertexArray) {
vertexArray.setElementBuffer(ebo.handle());
indexPool.bind(vertexArray);
vertexArray.bindVertexBuffer(0, vbo.handle(), 0, InternalVertex.STRIDE);
vertexArray.bindAttributes(0, 0, InternalVertex.ATTRIBUTES);
}
public void delete() {
vbo.delete();
ebo.delete();
indexPool.delete();
meshes.clear();
meshList.clear();
}
@ -228,12 +207,13 @@ public class MeshPool {
}
public void setup(GlVertexArray vao) {
if (boundTo.add(vao)) {
vao.setElementBuffer(MeshPool.this.ebo.handle());
vao.bindVertexBuffer(0, MeshPool.this.vbo.handle(), byteIndex, InternalVertex.STRIDE);
vao.bindAttributes(0, 0, InternalVertex.ATTRIBUTES);
}
}
if (!boundTo.add(vao)) {
return;
}
MeshPool.this.indexPool.bind(vao);
vao.bindVertexBuffer(0, MeshPool.this.vbo.handle(), byteIndex, InternalVertex.STRIDE);
vao.bindAttributes(0, 0, InternalVertex.ATTRIBUTES);
}
public void acquire() {
referenceCount++;

View file

@ -7,7 +7,6 @@ import java.util.Set;
import org.jetbrains.annotations.Nullable;
import com.jozufozu.flywheel.Flywheel;
import com.jozufozu.flywheel.api.context.Context;
import com.jozufozu.flywheel.api.instance.Instance;
import com.jozufozu.flywheel.api.instance.InstanceType;
@ -18,7 +17,7 @@ import com.jozufozu.flywheel.backend.gl.array.GlVertexArray;
import com.jozufozu.flywheel.backend.gl.array.VertexAttribute;
import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer;
import com.jozufozu.flywheel.backend.gl.buffer.GlBufferUsage;
import com.jozufozu.flywheel.backend.gl.buffer.MappedBuffer;
import com.jozufozu.flywheel.lib.memory.MemoryBlock;
public class InstancedInstancer<I extends Instance> extends AbstractInstancer<I> {
private final List<VertexAttribute> instanceAttributes;
@ -45,7 +44,6 @@ public class InstancedInstancer<I extends Instance> extends AbstractInstancer<I>
}
vbo = new GlBuffer(GlBufferUsage.DYNAMIC_DRAW);
vbo.growthFunction(l -> Math.max(l + (long) instanceStride * 16, (long) (l * 1.6)));
}
public void update() {
@ -59,28 +57,61 @@ public class InstancedInstancer<I extends Instance> extends AbstractInstancer<I>
}
int byteSize = instanceStride * instances.size();
if (vbo.ensureCapacity(byteSize)) {
// The vbo has moved, so we need to re-bind attributes
boundTo.clear();
if (needsToGrow(byteSize)) {
// TODO: Should this memory block be persistent?
var temp = MemoryBlock.malloc(increaseSize(byteSize));
writeAll(temp.ptr());
vbo.upload(temp);
temp.free();
} else {
writeChanged();
}
try (MappedBuffer buf = vbo.map()) {
writeChanged(buf.ptr());
changed.clear();
} catch (Exception e) {
Flywheel.LOGGER.error("Error updating InstancedInstancer:", e);
}
changed.clear();
}
private void writeChanged(long ptr) {
private void writeChanged() {
changed.forEachSetSpan((startInclusive, endInclusive) -> {
var temp = MemoryBlock.malloc((long) instanceStride * (endInclusive - startInclusive + 1));
long ptr = temp.ptr();
for (int i = startInclusive; i <= endInclusive; i++) {
writer.write(ptr + (long) instanceStride * i, instances.get(i));
writer.write(ptr, instances.get(i));
ptr += instanceStride;
}
vbo.uploadSpan((long) startInclusive * instanceStride, temp);
temp.free();
});
}
private void writeAll(long ptr) {
for (I instance : instances) {
writer.write(ptr, instance);
ptr += instanceStride;
}
}
private long increaseSize(long capacity) {
return Math.max(capacity + (long) instanceStride * 16, (long) (capacity * 1.6));
}
public boolean needsToGrow(long capacity) {
if (capacity < 0) {
throw new IllegalArgumentException("Size " + capacity + " < 0");
}
if (capacity == 0) {
return false;
}
return capacity > vbo.size();
}
/**
* Bind this instancer's vbo to the given vao if it hasn't already been bound.
* @param vao The vao to bind to.

View file

@ -64,6 +64,7 @@ public class InstancingEngine extends AbstractEngine {
}
try (var state = GlStateTracker.getRestoreState()) {
Uniforms.bindForDraw();
render(drawSet);
}
}
@ -104,7 +105,6 @@ public class InstancingEngine extends AbstractEngine {
var program = programs.get(shader.instanceType(), context.contextShader());
program.bind();
Uniforms.bindForDraw();
uploadMaterialUniform(program, material);
context.prepare(material, program, textures);

View file

@ -48,14 +48,15 @@ public class TextureBinder {
public static void bindLightAndOverlay() {
var gameRenderer = Minecraft.getInstance().gameRenderer;
gameRenderer.overlayTexture()
.setupOverlayColor();
gameRenderer.lightTexture()
.turnOnLightLayer();
GlTextureUnit.T1.makeActive();
gameRenderer.overlayTexture()
.setupOverlayColor();
RenderSystem.bindTexture(RenderSystem.getShaderTexture(1));
GlTextureUnit.T2.makeActive();
gameRenderer.lightTexture()
.turnOnLightLayer();
RenderSystem.bindTexture(RenderSystem.getShaderTexture(2));
}

View file

@ -15,8 +15,10 @@ import net.minecraft.world.phys.Vec3;
public class FrameUniforms implements UniformProvider {
public static final int SIZE = 304;
public int debugMode;
public int debugOverlay;
@Nullable
@Nullable
private RenderContext context;
private final Matrix4f viewProjection = new Matrix4f();
@ -70,7 +72,10 @@ public class FrameUniforms implements UniformProvider {
MemoryUtil.memPutInt(ptr, getConstantAmbientLightFlag(context));
ptr += 4;
writeTime(ptr);
ptr = writeTime(ptr);
MemoryUtil.memPutInt(ptr, debugMode);
MemoryUtil.memPutInt(ptr + 4, debugOverlay);
}
private long writeMatrices(long ptr) {

View file

@ -3,6 +3,8 @@ package com.jozufozu.flywheel.backend.engine.uniform;
import com.jozufozu.flywheel.api.event.ReloadLevelRendererEvent;
import com.jozufozu.flywheel.api.event.RenderContext;
import com.jozufozu.flywheel.backend.gl.GlStateTracker;
import com.jozufozu.flywheel.config.DebugMode;
import com.jozufozu.flywheel.config.DebugOverlay;
public class Uniforms {
public static boolean frustumPaused = false;
@ -53,6 +55,11 @@ public class Uniforms {
ubo.update();
}
public static void setDebugMode(DebugMode mode, DebugOverlay visual) {
frame().provider.debugMode = mode.ordinal();
frame().provider.debugOverlay = visual.ordinal();
}
public static void onReloadLevelRenderer(ReloadLevelRendererEvent event) {
if (frame != null) {
frame.delete();

View file

@ -1,8 +1,6 @@
package com.jozufozu.flywheel.backend.gl.buffer;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL30;
import org.lwjgl.opengl.GL31;
import org.lwjgl.opengl.GL45C;
import org.lwjgl.system.Checks;
@ -15,11 +13,7 @@ public interface Buffer {
void data(int vbo, long size, long ptr, int glEnum);
void copyData(int src, int dst, long srcOffset, long dstOffset, long size);
long mapRange(int handle, int offset, long size, int access);
void unmap(int handle);
void subData(int vbo, long offset, long size, long ptr);
class DSA implements Buffer {
@Override
@ -33,18 +27,8 @@ public interface Buffer {
}
@Override
public void copyData(int src, int dst, long srcOffset, long dstOffset, long size) {
GL45C.glCopyNamedBufferSubData(src, dst, srcOffset, dstOffset, size);
}
@Override
public long mapRange(int handle, int offset, long size, int access) {
return GL45C.nglMapNamedBufferRange(handle, offset, size, access);
}
@Override
public void unmap(int handle) {
GL45C.glUnmapNamedBuffer(handle);
public void subData(int vbo, long offset, long size, long ptr) {
GL45C.nglNamedBufferSubData(vbo, offset, size, ptr);
}
public Buffer fallback() {
@ -73,23 +57,9 @@ public interface Buffer {
}
@Override
public void copyData(int src, int dst, long size, long srcOffset, long dstOffset) {
GlBufferType.COPY_READ_BUFFER.bind(src);
GlBufferType.COPY_WRITE_BUFFER.bind(dst);
GL31.glCopyBufferSubData(GlBufferType.COPY_READ_BUFFER.glEnum, GlBufferType.COPY_WRITE_BUFFER.glEnum, srcOffset, dstOffset, size);
}
@Override
public long mapRange(int handle, int offset, long size, int access) {
GlBufferType.COPY_READ_BUFFER.bind(handle);
return GL30.nglMapBufferRange(GlBufferType.COPY_READ_BUFFER.glEnum, 0, size, access);
}
@Override
public void unmap(int handle) {
GlBufferType.COPY_READ_BUFFER.bind(handle);
GL15.glUnmapBuffer(GlBufferType.COPY_READ_BUFFER.glEnum);
public void subData(int vbo, long offset, long size, long ptr) {
GlBufferType.COPY_WRITE_BUFFER.bind(vbo);
GL15.nglBufferSubData(GlBufferType.COPY_WRITE_BUFFER.glEnum, offset, size, ptr);
}
}
}

View file

@ -1,24 +1,16 @@
package com.jozufozu.flywheel.backend.gl.buffer;
import org.lwjgl.system.MemoryUtil;
import com.jozufozu.flywheel.backend.gl.GlObject;
import com.jozufozu.flywheel.lib.memory.FlwMemoryTracker;
import com.jozufozu.flywheel.lib.memory.MemoryBlock;
import com.mojang.blaze3d.platform.GlStateManager;
import it.unimi.dsi.fastutil.longs.LongUnaryOperator;
public class GlBuffer extends GlObject {
protected final GlBufferUsage usage;
/**
* The size (in bytes) of the buffer on the GPU.
*/
protected long size;
/**
* A mapping to adjust the size of the buffer when allocating.
*/
protected LongUnaryOperator growthFunction = LongUnaryOperator.identity();
public GlBuffer() {
this(GlBufferUsage.STATIC_DRAW);
@ -29,63 +21,9 @@ public class GlBuffer extends GlObject {
this.usage = usage;
}
/**
* @return true if the buffer was recreated.
*/
public boolean ensureCapacity(long capacity) {
if (capacity < 0) {
throw new IllegalArgumentException("Size " + capacity + " < 0");
}
if (capacity == 0) {
return false;
}
if (size == 0) {
alloc(capacity);
return true;
}
if (capacity > size) {
realloc(capacity);
return true;
}
return false;
}
private void alloc(long capacity) {
increaseSize(capacity);
Buffer.IMPL.data(handle(), size, MemoryUtil.NULL, usage.glEnum);
FlwMemoryTracker._allocGPUMemory(size);
}
private void realloc(long capacity) {
FlwMemoryTracker._freeGPUMemory(size);
var oldSize = size;
increaseSize(capacity);
int oldHandle = handle();
int newHandle = Buffer.IMPL.create();
Buffer.IMPL.data(newHandle, size, MemoryUtil.NULL, usage.glEnum);
Buffer.IMPL.copyData(oldHandle, newHandle, 0, 0, oldSize);
GlStateManager._glDeleteBuffers(oldHandle);
handle(newHandle);
FlwMemoryTracker._allocGPUMemory(size);
}
/**
* Increase the size of the buffer to at least the given capacity.
*/
private void increaseSize(long capacity) {
size = growthFunction.apply(capacity);
}
public void upload(MemoryBlock memoryBlock) {
upload(memoryBlock.ptr(), memoryBlock.size());
}
public void upload(long ptr, long size) {
FlwMemoryTracker._freeGPUMemory(this.size);
Buffer.IMPL.data(handle(), size, ptr, usage.glEnum);
@ -93,12 +31,12 @@ public class GlBuffer extends GlObject {
FlwMemoryTracker._allocGPUMemory(this.size);
}
public MappedBuffer map() {
return new MappedBuffer(handle(), size);
public void uploadSpan(long offset, MemoryBlock memoryBlock) {
uploadSpan(offset, memoryBlock.ptr(), memoryBlock.size());
}
public void growthFunction(LongUnaryOperator growthFunction) {
this.growthFunction = growthFunction;
public void uploadSpan(long offset, long ptr, long size) {
Buffer.IMPL.subData(handle(), offset, size, ptr);
}
public long size() {

View file

@ -1,38 +0,0 @@
package com.jozufozu.flywheel.backend.gl.buffer;
import static org.lwjgl.opengl.GL30.GL_MAP_WRITE_BIT;
import static org.lwjgl.system.MemoryUtil.NULL;
import org.lwjgl.system.MemoryUtil;
import com.jozufozu.flywheel.backend.gl.error.GlError;
import com.jozufozu.flywheel.backend.gl.error.GlException;
public class MappedBuffer implements AutoCloseable {
private final int glBuffer;
private long ptr;
public MappedBuffer(int glBuffer, long size) {
this.glBuffer = glBuffer;
ptr = Buffer.IMPL.mapRange(glBuffer, 0, size, GL_MAP_WRITE_BIT);
if (ptr == MemoryUtil.NULL) {
throw new GlException(GlError.poll(), "Could not map buffer");
}
}
public long ptr() {
return ptr;
}
@Override
public void close() {
if (ptr == NULL) {
return;
}
Buffer.IMPL.unmap(glBuffer);
ptr = NULL;
}
}

View file

@ -1,16 +0,0 @@
package com.jozufozu.flywheel.backend.gl.buffer;
import org.lwjgl.opengl.GL15C;
public enum MappedBufferUsage {
READ_ONLY(GL15C.GL_READ_ONLY),
WRITE_ONLY(GL15C.GL_WRITE_ONLY),
READ_WRITE(GL15C.GL_READ_WRITE),
;
int glEnum;
MappedBufferUsage(int glEnum) {
this.glEnum = glEnum;
}
}

View file

@ -0,0 +1,8 @@
package com.jozufozu.flywheel.config;
public enum DebugMode {
NONE,
NORMALS,
INSTANCE_ID,
LIGHT,
}

View file

@ -0,0 +1,7 @@
package com.jozufozu.flywheel.config;
public enum DebugOverlay {
NONE,
MUL,
OVERRIDE,
}

View file

@ -23,6 +23,7 @@ import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.Entity;
import net.minecraftforge.client.event.RegisterClientCommandsEvent;
import net.minecraftforge.common.ForgeConfigSpec.ConfigValue;
import net.minecraftforge.server.command.EnumArgument;
public class FlwCommands {
public static void registerClientCommands(RegisterClientCommandsEvent event) {
@ -101,18 +102,32 @@ public class FlwCommands {
}
));
// TODO
command.then(Commands.literal("debugNormals"))
.executes(context -> {
LocalPlayer player = Minecraft.getInstance().player;
if (player == null) return 0;
command.then(Commands.literal("debug")
.then(Commands.argument("mode", EnumArgument.enumArgument(DebugMode.class))
.executes(context -> {
LocalPlayer player = Minecraft.getInstance().player;
if (player == null) return 0;
player.displayClientMessage(Component.literal("This command is not yet implemented."), false);
DebugMode mode = context.getArgument("mode", DebugMode.class);
return Command.SINGLE_SUCCESS;
});
Uniforms.setDebugMode(mode, DebugOverlay.OVERRIDE);
command.then(Commands.literal("debugCrumbling")
return Command.SINGLE_SUCCESS;
})
.then(Commands.argument("overlay", EnumArgument.enumArgument(DebugOverlay.class))
.executes(context -> {
LocalPlayer player = Minecraft.getInstance().player;
if (player == null) return 0;
DebugMode mode = context.getArgument("mode", DebugMode.class);
DebugOverlay visual = context.getArgument("overlay", DebugOverlay.class);
Uniforms.setDebugMode(mode, visual);
return Command.SINGLE_SUCCESS;
}))));
command.then(Commands.literal("crumbling")
.then(Commands.argument("pos", BlockPosArgument.blockPos())
.then(Commands.argument("stage", IntegerArgumentType.integer(0, 9))
.executes(context -> {
@ -132,12 +147,7 @@ public class FlwCommands {
return Command.SINGLE_SUCCESS;
}))));
command.then(Commands.literal("debugFrustum")
.then(Commands.literal("pause")
.executes(context -> {
Uniforms.frustumPaused = true;
return 1;
}))
command.then(Commands.literal("frustum")
.then(Commands.literal("unpause")
.executes(context -> {
Uniforms.frustumPaused = false;

View file

@ -14,7 +14,8 @@ public final class InstanceTypes {
public static final InstanceType<TransformedInstance> TRANSFORMED = SimpleInstanceType.builder(TransformedInstance::new)
.layout(LayoutBuilder.create()
.vector("color", FloatRepr.NORMALIZED_UNSIGNED_BYTE, 4)
.vector("overlay_light", IntegerRepr.SHORT, 4)
.vector("overlay", IntegerRepr.SHORT, 2)
.vector("light", FloatRepr.UNSIGNED_SHORT, 2)
.matrix("pose", FloatRepr.FLOAT, 4)
.matrix("normal", FloatRepr.FLOAT, 3)
.build())
@ -24,8 +25,7 @@ public final class InstanceTypes {
MemoryUtil.memPutByte(ptr + 2, instance.b);
MemoryUtil.memPutByte(ptr + 3, instance.a);
MemoryUtil.memPutInt(ptr + 4, instance.overlay);
MemoryUtil.memPutShort(ptr + 8, instance.blockLight);
MemoryUtil.memPutShort(ptr + 10, instance.skyLight);
MemoryUtil.memPutInt(ptr + 8, (int) instance.blockLight | (int) instance.skyLight << 16);
MatrixMath.writeUnsafe(instance.model, ptr + 12);
MatrixMath.writeUnsafe(instance.normal, ptr + 76);
})
@ -36,7 +36,8 @@ public final class InstanceTypes {
public static final InstanceType<OrientedInstance> ORIENTED = SimpleInstanceType.builder(OrientedInstance::new)
.layout(LayoutBuilder.create()
.vector("color", FloatRepr.NORMALIZED_UNSIGNED_BYTE, 4)
.vector("overlay_light", IntegerRepr.SHORT, 4)
.vector("overlay", IntegerRepr.SHORT, 2)
.vector("light", FloatRepr.UNSIGNED_SHORT, 2)
.vector("position", FloatRepr.FLOAT, 3)
.vector("pivot", FloatRepr.FLOAT, 3)
.vector("rotation", FloatRepr.FLOAT, 4)
@ -47,8 +48,7 @@ public final class InstanceTypes {
MemoryUtil.memPutByte(ptr + 2, instance.b);
MemoryUtil.memPutByte(ptr + 3, instance.a);
MemoryUtil.memPutInt(ptr + 4, instance.overlay);
MemoryUtil.memPutShort(ptr + 8, instance.blockLight);
MemoryUtil.memPutShort(ptr + 10, instance.skyLight);
MemoryUtil.memPutInt(ptr + 8, (int) instance.blockLight | (int) instance.skyLight << 16);
MemoryUtil.memPutFloat(ptr + 12, instance.posX);
MemoryUtil.memPutFloat(ptr + 16, instance.posY);
MemoryUtil.memPutFloat(ptr + 20, instance.posZ);

View file

@ -4,6 +4,6 @@ void flw_instanceVertex(in FlwInstance i) {
flw_vertexPos = vec4(rotateByQuaternion(flw_vertexPos.xyz - i.pivot, i.rotation) + i.pivot + i.position, 1.0);
flw_vertexNormal = rotateByQuaternion(flw_vertexNormal, i.rotation);
flw_vertexColor = i.color;
flw_vertexOverlay = i.overlay_light.xy;
flw_vertexLight = i.overlay_light.zw / 15.0;
flw_vertexOverlay = i.overlay;
flw_vertexLight = i.light / 15.;
}

View file

@ -2,6 +2,6 @@ void flw_instanceVertex(in FlwInstance i) {
flw_vertexPos = i.pose * flw_vertexPos;
flw_vertexNormal = i.normal * flw_vertexNormal;
flw_vertexColor = i.color;
flw_vertexOverlay = i.overlay_light.xy;
flw_vertexLight = i.overlay_light.zw / 15.0;
flw_vertexOverlay = i.overlay;
flw_vertexLight = i.light / 15.;
}

View file

@ -12,6 +12,8 @@ uniform sampler2D _flw_lightTex;
out vec4 _flw_outputColor;
in vec4 _flw_debugColor;
void _flw_main() {
flw_sampleColor = texture(_flw_diffuseTex, flw_vertexTexCoord);
flw_fragColor = flw_vertexColor * flw_sampleColor;
@ -35,7 +37,14 @@ void _flw_main() {
}
if (flw_material.useOverlay) {
vec4 overlayColor = texelFetch(_flw_overlayTex, flw_fragOverlay, 0);
// Need to clamp the overlay texture coords to sane coordinates because integer vertex attributes explode on
// some drivers for some draw calls.
// This can be removed once instancing uses sampler buffers, though
// we may need a solution for the internal vertex format. Perhaps
// pass as floats and convert to integers in the shader?
ivec2 actualCoord = clamp(flw_fragOverlay, ivec2(3), ivec2(10));
vec4 overlayColor = texelFetch(_flw_overlayTex, actualCoord, 0);
color.rgb = mix(overlayColor.rgb, color.rgb, overlayColor.a);
}
@ -48,5 +57,14 @@ void _flw_main() {
discard;
}
switch (_flw_debugOverlay) {
case 1u:
color *= _flw_debugColor;
break;
case 2u:
color = _flw_debugColor;
break;
}
_flw_outputColor = flw_fogFilter(color);
}

View file

@ -1,6 +1,29 @@
#include "flywheel:internal/fog_distance.glsl"
void _flw_main(in FlwInstance instance) {
// https://stackoverflow.com/a/17479300
uint _flw_hash(in uint x) {
x += (x << 10u);
x ^= (x >> 6u);
x += (x << 3u);
x ^= (x >> 11u);
x += (x << 15u);
return x;
}
vec4 _flw_id2Color(in uint id) {
uint x = _flw_hash(id);
return vec4(
float(x & 0xFFu) / 255.0,
float((x >> 8u) & 0xFFu) / 255.0,
float((x >> 16u) & 0xFFu) / 255.0,
1.
);
}
out vec4 _flw_debugColor;
void _flw_main(in FlwInstance instance, in uint stableInstanceID) {
_flw_layoutVertex();
flw_beginVertex();
flw_instanceVertex(instance);
@ -12,4 +35,19 @@ void _flw_main(in FlwInstance instance) {
flw_distance = fogDistance(flw_vertexPos.xyz, flw_cameraPos, flw_fogShape);
gl_Position = flw_viewProjection * flw_vertexPos;
switch (_flw_debugMode) {
case 0u:
_flw_debugColor = vec4(1.);
break;
case 1u:
_flw_debugColor = vec4(flw_vertexNormal * .5 + .5, 1.);
break;
case 2u:
_flw_debugColor = _flw_id2Color(stableInstanceID);
break;
case 3u:
_flw_debugColor = vec4(vec2((flw_vertexLight * 15.0 + 0.5) / 16.), 0., 1.);
break;
}
}

View file

@ -32,5 +32,5 @@ void main() {
uint objectIndex = objectIndices[gl_BaseInstance + gl_InstanceID];
FlwInstance instance = _flw_unpackInstance(objects[objectIndex].instance);
_flw_main(instance);
_flw_main(instance, objectIndex);
}

View file

@ -9,5 +9,5 @@ void main() {
FlwInstance instance = _flw_unpackInstance();
_flw_main(instance);
_flw_main(instance, uint(gl_InstanceID));
}

View file

@ -29,6 +29,9 @@ layout(std140) uniform _FlwFrameUniforms {
float flw_renderTicks;
float flw_renderSeconds;
uint _flw_debugMode;
uint _flw_debugOverlay;
};
#define flw_cameraPos _flw_cameraPos.xyz