mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2025-01-15 23:55:53 +01:00
Compare commits
5 commits
483eb199fa
...
68daac8659
Author | SHA1 | Date | |
---|---|---|---|
|
68daac8659 | ||
|
df83277692 | ||
|
0e00c7019d | ||
|
83119040d2 | ||
|
dd23e1d4f8 |
23 changed files with 311 additions and 260 deletions
|
@ -4,9 +4,9 @@ import java.util.List;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.Flywheel;
|
import com.jozufozu.flywheel.Flywheel;
|
||||||
import com.jozufozu.flywheel.api.layout.FloatRepr;
|
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.Layout;
|
||||||
import com.jozufozu.flywheel.api.layout.LayoutBuilder;
|
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.api.vertex.VertexView;
|
||||||
import com.jozufozu.flywheel.backend.engine.LayoutAttributes;
|
import com.jozufozu.flywheel.backend.engine.LayoutAttributes;
|
||||||
import com.jozufozu.flywheel.backend.gl.array.VertexAttribute;
|
import com.jozufozu.flywheel.backend.gl.array.VertexAttribute;
|
||||||
|
@ -19,7 +19,7 @@ public final class InternalVertex {
|
||||||
.vector("position", FloatRepr.FLOAT, 3)
|
.vector("position", FloatRepr.FLOAT, 3)
|
||||||
.vector("color", FloatRepr.NORMALIZED_UNSIGNED_BYTE, 4)
|
.vector("color", FloatRepr.NORMALIZED_UNSIGNED_BYTE, 4)
|
||||||
.vector("tex", FloatRepr.FLOAT, 2)
|
.vector("tex", FloatRepr.FLOAT, 2)
|
||||||
.vector("overlay_light", UnsignedIntegerRepr.UNSIGNED_SHORT, 4)
|
.vector("overlay_light", IntegerRepr.SHORT, 4)
|
||||||
.vector("normal", FloatRepr.NORMALIZED_BYTE, 3)
|
.vector("normal", FloatRepr.NORMALIZED_BYTE, 3)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,27 +9,24 @@ import java.util.Set;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.lwjgl.opengl.GL32;
|
import org.lwjgl.opengl.GL32;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.api.model.IndexSequence;
|
|
||||||
import com.jozufozu.flywheel.api.model.Mesh;
|
import com.jozufozu.flywheel.api.model.Mesh;
|
||||||
import com.jozufozu.flywheel.api.vertex.VertexView;
|
import com.jozufozu.flywheel.api.vertex.VertexView;
|
||||||
import com.jozufozu.flywheel.backend.InternalVertex;
|
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.GlPrimitive;
|
||||||
import com.jozufozu.flywheel.backend.gl.array.GlVertexArray;
|
import com.jozufozu.flywheel.backend.gl.array.GlVertexArray;
|
||||||
import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer;
|
import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer;
|
||||||
import com.jozufozu.flywheel.lib.memory.MemoryBlock;
|
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;
|
import it.unimi.dsi.fastutil.objects.ReferenceArraySet;
|
||||||
|
|
||||||
public class MeshPool {
|
public class MeshPool {
|
||||||
private final VertexView vertexView;
|
private final VertexView vertexView;
|
||||||
private final Map<Mesh, BufferedMesh> meshes = new HashMap<>();
|
private final Map<Mesh, BufferedMesh> meshes = new HashMap<>();
|
||||||
private final List<BufferedMesh> meshList = new ArrayList<>();
|
private final List<BufferedMesh> meshList = new ArrayList<>();
|
||||||
|
private final List<BufferedMesh> recentlyAllocated = new ArrayList<>();
|
||||||
|
|
||||||
private final GlBuffer vbo;
|
private final GlBuffer vbo;
|
||||||
private final GlBuffer ebo;
|
private final IndexPool indexPool;
|
||||||
|
|
||||||
private boolean dirty;
|
private boolean dirty;
|
||||||
private boolean anyToRemove;
|
private boolean anyToRemove;
|
||||||
|
@ -40,7 +37,7 @@ public class MeshPool {
|
||||||
public MeshPool() {
|
public MeshPool() {
|
||||||
vertexView = InternalVertex.createVertexView();
|
vertexView = InternalVertex.createVertexView();
|
||||||
vbo = new GlBuffer();
|
vbo = new GlBuffer();
|
||||||
ebo = new GlBuffer();
|
indexPool = new IndexPool();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -56,6 +53,7 @@ public class MeshPool {
|
||||||
private BufferedMesh _alloc(Mesh m) {
|
private BufferedMesh _alloc(Mesh m) {
|
||||||
BufferedMesh bufferedModel = new BufferedMesh(m);
|
BufferedMesh bufferedModel = new BufferedMesh(m);
|
||||||
meshList.add(bufferedModel);
|
meshList.add(bufferedModel);
|
||||||
|
recentlyAllocated.add(bufferedModel);
|
||||||
|
|
||||||
dirty = true;
|
dirty = true;
|
||||||
return bufferedModel;
|
return bufferedModel;
|
||||||
|
@ -74,9 +72,23 @@ public class MeshPool {
|
||||||
if (anyToRemove) {
|
if (anyToRemove) {
|
||||||
anyToRemove = false;
|
anyToRemove = false;
|
||||||
processDeletions();
|
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;
|
dirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,41 +105,8 @@ public class MeshPool {
|
||||||
|
|
||||||
private void uploadAll() {
|
private void uploadAll() {
|
||||||
long neededSize = 0;
|
long neededSize = 0;
|
||||||
Reference2IntMap<IndexSequence> indexCounts = new Reference2IntOpenHashMap<>();
|
|
||||||
indexCounts.defaultReturnValue(0);
|
|
||||||
|
|
||||||
for (BufferedMesh mesh : meshList) {
|
for (BufferedMesh mesh : meshList) {
|
||||||
neededSize += mesh.byteSize();
|
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);
|
final var vertexBlock = MemoryBlock.malloc(neededSize);
|
||||||
|
@ -144,25 +123,25 @@ public class MeshPool {
|
||||||
byteIndex += mesh.byteSize();
|
byteIndex += mesh.byteSize();
|
||||||
baseVertex += mesh.vertexCount();
|
baseVertex += mesh.vertexCount();
|
||||||
|
|
||||||
mesh.firstIndex = firstIndices.getInt(mesh.mesh.indexSequence());
|
mesh.firstIndex = indexPool.firstIndex(mesh.mesh.indexSequence());
|
||||||
|
|
||||||
|
mesh.boundTo.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
vbo.upload(vertexBlock);
|
vbo.upload(vertexBlock);
|
||||||
ebo.upload(indexBlock);
|
|
||||||
|
|
||||||
vertexBlock.free();
|
vertexBlock.free();
|
||||||
indexBlock.free();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void bind(GlVertexArray vertexArray) {
|
public void bind(GlVertexArray vertexArray) {
|
||||||
vertexArray.setElementBuffer(ebo.handle());
|
indexPool.bind(vertexArray);
|
||||||
vertexArray.bindVertexBuffer(0, vbo.handle(), 0, InternalVertex.STRIDE);
|
vertexArray.bindVertexBuffer(0, vbo.handle(), 0, InternalVertex.STRIDE);
|
||||||
vertexArray.bindAttributes(0, 0, InternalVertex.ATTRIBUTES);
|
vertexArray.bindAttributes(0, 0, InternalVertex.ATTRIBUTES);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void delete() {
|
public void delete() {
|
||||||
vbo.delete();
|
vbo.delete();
|
||||||
ebo.delete();
|
indexPool.delete();
|
||||||
meshes.clear();
|
meshes.clear();
|
||||||
meshList.clear();
|
meshList.clear();
|
||||||
}
|
}
|
||||||
|
@ -228,12 +207,13 @@ public class MeshPool {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setup(GlVertexArray vao) {
|
public void setup(GlVertexArray vao) {
|
||||||
if (boundTo.add(vao)) {
|
if (!boundTo.add(vao)) {
|
||||||
vao.setElementBuffer(MeshPool.this.ebo.handle());
|
return;
|
||||||
vao.bindVertexBuffer(0, MeshPool.this.vbo.handle(), byteIndex, InternalVertex.STRIDE);
|
}
|
||||||
vao.bindAttributes(0, 0, InternalVertex.ATTRIBUTES);
|
MeshPool.this.indexPool.bind(vao);
|
||||||
}
|
vao.bindVertexBuffer(0, MeshPool.this.vbo.handle(), byteIndex, InternalVertex.STRIDE);
|
||||||
}
|
vao.bindAttributes(0, 0, InternalVertex.ATTRIBUTES);
|
||||||
|
}
|
||||||
|
|
||||||
public void acquire() {
|
public void acquire() {
|
||||||
referenceCount++;
|
referenceCount++;
|
||||||
|
|
|
@ -7,7 +7,6 @@ import java.util.Set;
|
||||||
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.Flywheel;
|
|
||||||
import com.jozufozu.flywheel.api.context.Context;
|
import com.jozufozu.flywheel.api.context.Context;
|
||||||
import com.jozufozu.flywheel.api.instance.Instance;
|
import com.jozufozu.flywheel.api.instance.Instance;
|
||||||
import com.jozufozu.flywheel.api.instance.InstanceType;
|
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.array.VertexAttribute;
|
||||||
import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer;
|
import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer;
|
||||||
import com.jozufozu.flywheel.backend.gl.buffer.GlBufferUsage;
|
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> {
|
public class InstancedInstancer<I extends Instance> extends AbstractInstancer<I> {
|
||||||
private final List<VertexAttribute> instanceAttributes;
|
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 = new GlBuffer(GlBufferUsage.DYNAMIC_DRAW);
|
||||||
vbo.growthFunction(l -> Math.max(l + (long) instanceStride * 16, (long) (l * 1.6)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void update() {
|
public void update() {
|
||||||
|
@ -59,28 +57,61 @@ public class InstancedInstancer<I extends Instance> extends AbstractInstancer<I>
|
||||||
}
|
}
|
||||||
|
|
||||||
int byteSize = instanceStride * instances.size();
|
int byteSize = instanceStride * instances.size();
|
||||||
if (vbo.ensureCapacity(byteSize)) {
|
if (needsToGrow(byteSize)) {
|
||||||
// The vbo has moved, so we need to re-bind attributes
|
// TODO: Should this memory block be persistent?
|
||||||
boundTo.clear();
|
var temp = MemoryBlock.malloc(increaseSize(byteSize));
|
||||||
|
|
||||||
|
writeAll(temp.ptr());
|
||||||
|
|
||||||
|
vbo.upload(temp);
|
||||||
|
|
||||||
|
temp.free();
|
||||||
|
} else {
|
||||||
|
writeChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
try (MappedBuffer buf = vbo.map()) {
|
changed.clear();
|
||||||
writeChanged(buf.ptr());
|
|
||||||
|
|
||||||
changed.clear();
|
|
||||||
} catch (Exception e) {
|
|
||||||
Flywheel.LOGGER.error("Error updating InstancedInstancer:", e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeChanged(long ptr) {
|
private void writeChanged() {
|
||||||
changed.forEachSetSpan((startInclusive, endInclusive) -> {
|
changed.forEachSetSpan((startInclusive, endInclusive) -> {
|
||||||
|
var temp = MemoryBlock.malloc((long) instanceStride * (endInclusive - startInclusive + 1));
|
||||||
|
long ptr = temp.ptr();
|
||||||
for (int i = startInclusive; i <= endInclusive; i++) {
|
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.
|
* Bind this instancer's vbo to the given vao if it hasn't already been bound.
|
||||||
* @param vao The vao to bind to.
|
* @param vao The vao to bind to.
|
||||||
|
|
|
@ -64,6 +64,7 @@ public class InstancingEngine extends AbstractEngine {
|
||||||
}
|
}
|
||||||
|
|
||||||
try (var state = GlStateTracker.getRestoreState()) {
|
try (var state = GlStateTracker.getRestoreState()) {
|
||||||
|
Uniforms.bindForDraw();
|
||||||
render(drawSet);
|
render(drawSet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -104,7 +105,6 @@ public class InstancingEngine extends AbstractEngine {
|
||||||
var program = programs.get(shader.instanceType(), context.contextShader());
|
var program = programs.get(shader.instanceType(), context.contextShader());
|
||||||
program.bind();
|
program.bind();
|
||||||
|
|
||||||
Uniforms.bindForDraw();
|
|
||||||
uploadMaterialUniform(program, material);
|
uploadMaterialUniform(program, material);
|
||||||
|
|
||||||
context.prepare(material, program, textures);
|
context.prepare(material, program, textures);
|
||||||
|
|
|
@ -48,14 +48,15 @@ public class TextureBinder {
|
||||||
|
|
||||||
public static void bindLightAndOverlay() {
|
public static void bindLightAndOverlay() {
|
||||||
var gameRenderer = Minecraft.getInstance().gameRenderer;
|
var gameRenderer = Minecraft.getInstance().gameRenderer;
|
||||||
gameRenderer.overlayTexture()
|
|
||||||
.setupOverlayColor();
|
|
||||||
gameRenderer.lightTexture()
|
|
||||||
.turnOnLightLayer();
|
|
||||||
|
|
||||||
GlTextureUnit.T1.makeActive();
|
GlTextureUnit.T1.makeActive();
|
||||||
|
gameRenderer.overlayTexture()
|
||||||
|
.setupOverlayColor();
|
||||||
RenderSystem.bindTexture(RenderSystem.getShaderTexture(1));
|
RenderSystem.bindTexture(RenderSystem.getShaderTexture(1));
|
||||||
|
|
||||||
GlTextureUnit.T2.makeActive();
|
GlTextureUnit.T2.makeActive();
|
||||||
|
gameRenderer.lightTexture()
|
||||||
|
.turnOnLightLayer();
|
||||||
RenderSystem.bindTexture(RenderSystem.getShaderTexture(2));
|
RenderSystem.bindTexture(RenderSystem.getShaderTexture(2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,8 +15,10 @@ import net.minecraft.world.phys.Vec3;
|
||||||
|
|
||||||
public class FrameUniforms implements UniformProvider {
|
public class FrameUniforms implements UniformProvider {
|
||||||
public static final int SIZE = 304;
|
public static final int SIZE = 304;
|
||||||
|
public int debugMode;
|
||||||
|
public int debugOverlay;
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private RenderContext context;
|
private RenderContext context;
|
||||||
|
|
||||||
private final Matrix4f viewProjection = new Matrix4f();
|
private final Matrix4f viewProjection = new Matrix4f();
|
||||||
|
@ -70,7 +72,10 @@ public class FrameUniforms implements UniformProvider {
|
||||||
MemoryUtil.memPutInt(ptr, getConstantAmbientLightFlag(context));
|
MemoryUtil.memPutInt(ptr, getConstantAmbientLightFlag(context));
|
||||||
ptr += 4;
|
ptr += 4;
|
||||||
|
|
||||||
writeTime(ptr);
|
ptr = writeTime(ptr);
|
||||||
|
|
||||||
|
MemoryUtil.memPutInt(ptr, debugMode);
|
||||||
|
MemoryUtil.memPutInt(ptr + 4, debugOverlay);
|
||||||
}
|
}
|
||||||
|
|
||||||
private long writeMatrices(long ptr) {
|
private long writeMatrices(long ptr) {
|
||||||
|
|
|
@ -3,6 +3,8 @@ package com.jozufozu.flywheel.backend.engine.uniform;
|
||||||
import com.jozufozu.flywheel.api.event.ReloadLevelRendererEvent;
|
import com.jozufozu.flywheel.api.event.ReloadLevelRendererEvent;
|
||||||
import com.jozufozu.flywheel.api.event.RenderContext;
|
import com.jozufozu.flywheel.api.event.RenderContext;
|
||||||
import com.jozufozu.flywheel.backend.gl.GlStateTracker;
|
import com.jozufozu.flywheel.backend.gl.GlStateTracker;
|
||||||
|
import com.jozufozu.flywheel.config.DebugMode;
|
||||||
|
import com.jozufozu.flywheel.config.DebugOverlay;
|
||||||
|
|
||||||
public class Uniforms {
|
public class Uniforms {
|
||||||
public static boolean frustumPaused = false;
|
public static boolean frustumPaused = false;
|
||||||
|
@ -53,6 +55,11 @@ public class Uniforms {
|
||||||
ubo.update();
|
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) {
|
public static void onReloadLevelRenderer(ReloadLevelRendererEvent event) {
|
||||||
if (frame != null) {
|
if (frame != null) {
|
||||||
frame.delete();
|
frame.delete();
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
package com.jozufozu.flywheel.backend.gl.buffer;
|
package com.jozufozu.flywheel.backend.gl.buffer;
|
||||||
|
|
||||||
import org.lwjgl.opengl.GL15;
|
import org.lwjgl.opengl.GL15;
|
||||||
import org.lwjgl.opengl.GL30;
|
|
||||||
import org.lwjgl.opengl.GL31;
|
|
||||||
import org.lwjgl.opengl.GL45C;
|
import org.lwjgl.opengl.GL45C;
|
||||||
import org.lwjgl.system.Checks;
|
import org.lwjgl.system.Checks;
|
||||||
|
|
||||||
|
@ -15,11 +13,7 @@ public interface Buffer {
|
||||||
|
|
||||||
void data(int vbo, long size, long ptr, int glEnum);
|
void data(int vbo, long size, long ptr, int glEnum);
|
||||||
|
|
||||||
void copyData(int src, int dst, long srcOffset, long dstOffset, long size);
|
void subData(int vbo, long offset, long size, long ptr);
|
||||||
|
|
||||||
long mapRange(int handle, int offset, long size, int access);
|
|
||||||
|
|
||||||
void unmap(int handle);
|
|
||||||
|
|
||||||
class DSA implements Buffer {
|
class DSA implements Buffer {
|
||||||
@Override
|
@Override
|
||||||
|
@ -33,18 +27,8 @@ public interface Buffer {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void copyData(int src, int dst, long srcOffset, long dstOffset, long size) {
|
public void subData(int vbo, long offset, long size, long ptr) {
|
||||||
GL45C.glCopyNamedBufferSubData(src, dst, srcOffset, dstOffset, size);
|
GL45C.nglNamedBufferSubData(vbo, offset, size, ptr);
|
||||||
}
|
|
||||||
|
|
||||||
@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 Buffer fallback() {
|
public Buffer fallback() {
|
||||||
|
@ -73,23 +57,9 @@ public interface Buffer {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void copyData(int src, int dst, long size, long srcOffset, long dstOffset) {
|
public void subData(int vbo, long offset, long size, long ptr) {
|
||||||
GlBufferType.COPY_READ_BUFFER.bind(src);
|
GlBufferType.COPY_WRITE_BUFFER.bind(vbo);
|
||||||
GlBufferType.COPY_WRITE_BUFFER.bind(dst);
|
GL15.nglBufferSubData(GlBufferType.COPY_WRITE_BUFFER.glEnum, offset, size, ptr);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,24 +1,16 @@
|
||||||
package com.jozufozu.flywheel.backend.gl.buffer;
|
package com.jozufozu.flywheel.backend.gl.buffer;
|
||||||
|
|
||||||
import org.lwjgl.system.MemoryUtil;
|
|
||||||
|
|
||||||
import com.jozufozu.flywheel.backend.gl.GlObject;
|
import com.jozufozu.flywheel.backend.gl.GlObject;
|
||||||
import com.jozufozu.flywheel.lib.memory.FlwMemoryTracker;
|
import com.jozufozu.flywheel.lib.memory.FlwMemoryTracker;
|
||||||
import com.jozufozu.flywheel.lib.memory.MemoryBlock;
|
import com.jozufozu.flywheel.lib.memory.MemoryBlock;
|
||||||
import com.mojang.blaze3d.platform.GlStateManager;
|
import com.mojang.blaze3d.platform.GlStateManager;
|
||||||
|
|
||||||
import it.unimi.dsi.fastutil.longs.LongUnaryOperator;
|
|
||||||
|
|
||||||
public class GlBuffer extends GlObject {
|
public class GlBuffer extends GlObject {
|
||||||
protected final GlBufferUsage usage;
|
protected final GlBufferUsage usage;
|
||||||
/**
|
/**
|
||||||
* The size (in bytes) of the buffer on the GPU.
|
* The size (in bytes) of the buffer on the GPU.
|
||||||
*/
|
*/
|
||||||
protected long size;
|
protected long size;
|
||||||
/**
|
|
||||||
* A mapping to adjust the size of the buffer when allocating.
|
|
||||||
*/
|
|
||||||
protected LongUnaryOperator growthFunction = LongUnaryOperator.identity();
|
|
||||||
|
|
||||||
public GlBuffer() {
|
public GlBuffer() {
|
||||||
this(GlBufferUsage.STATIC_DRAW);
|
this(GlBufferUsage.STATIC_DRAW);
|
||||||
|
@ -29,63 +21,9 @@ public class GlBuffer extends GlObject {
|
||||||
this.usage = usage;
|
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) {
|
public void upload(MemoryBlock memoryBlock) {
|
||||||
upload(memoryBlock.ptr(), memoryBlock.size());
|
upload(memoryBlock.ptr(), memoryBlock.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void upload(long ptr, long size) {
|
public void upload(long ptr, long size) {
|
||||||
FlwMemoryTracker._freeGPUMemory(this.size);
|
FlwMemoryTracker._freeGPUMemory(this.size);
|
||||||
Buffer.IMPL.data(handle(), size, ptr, usage.glEnum);
|
Buffer.IMPL.data(handle(), size, ptr, usage.glEnum);
|
||||||
|
@ -93,12 +31,12 @@ public class GlBuffer extends GlObject {
|
||||||
FlwMemoryTracker._allocGPUMemory(this.size);
|
FlwMemoryTracker._allocGPUMemory(this.size);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MappedBuffer map() {
|
public void uploadSpan(long offset, MemoryBlock memoryBlock) {
|
||||||
return new MappedBuffer(handle(), size);
|
uploadSpan(offset, memoryBlock.ptr(), memoryBlock.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void growthFunction(LongUnaryOperator growthFunction) {
|
public void uploadSpan(long offset, long ptr, long size) {
|
||||||
this.growthFunction = growthFunction;
|
Buffer.IMPL.subData(handle(), offset, size, ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
public long size() {
|
public long size() {
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
package com.jozufozu.flywheel.config;
|
||||||
|
|
||||||
|
public enum DebugMode {
|
||||||
|
NONE,
|
||||||
|
NORMALS,
|
||||||
|
INSTANCE_ID,
|
||||||
|
LIGHT,
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
package com.jozufozu.flywheel.config;
|
||||||
|
|
||||||
|
public enum DebugOverlay {
|
||||||
|
NONE,
|
||||||
|
MUL,
|
||||||
|
OVERRIDE,
|
||||||
|
}
|
|
@ -23,6 +23,7 @@ import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraftforge.client.event.RegisterClientCommandsEvent;
|
import net.minecraftforge.client.event.RegisterClientCommandsEvent;
|
||||||
import net.minecraftforge.common.ForgeConfigSpec.ConfigValue;
|
import net.minecraftforge.common.ForgeConfigSpec.ConfigValue;
|
||||||
|
import net.minecraftforge.server.command.EnumArgument;
|
||||||
|
|
||||||
public class FlwCommands {
|
public class FlwCommands {
|
||||||
public static void registerClientCommands(RegisterClientCommandsEvent event) {
|
public static void registerClientCommands(RegisterClientCommandsEvent event) {
|
||||||
|
@ -101,18 +102,32 @@ public class FlwCommands {
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
|
|
||||||
// TODO
|
command.then(Commands.literal("debug")
|
||||||
command.then(Commands.literal("debugNormals"))
|
.then(Commands.argument("mode", EnumArgument.enumArgument(DebugMode.class))
|
||||||
.executes(context -> {
|
.executes(context -> {
|
||||||
LocalPlayer player = Minecraft.getInstance().player;
|
LocalPlayer player = Minecraft.getInstance().player;
|
||||||
if (player == null) return 0;
|
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("pos", BlockPosArgument.blockPos())
|
||||||
.then(Commands.argument("stage", IntegerArgumentType.integer(0, 9))
|
.then(Commands.argument("stage", IntegerArgumentType.integer(0, 9))
|
||||||
.executes(context -> {
|
.executes(context -> {
|
||||||
|
@ -132,12 +147,7 @@ public class FlwCommands {
|
||||||
return Command.SINGLE_SUCCESS;
|
return Command.SINGLE_SUCCESS;
|
||||||
}))));
|
}))));
|
||||||
|
|
||||||
command.then(Commands.literal("debugFrustum")
|
command.then(Commands.literal("frustum")
|
||||||
.then(Commands.literal("pause")
|
|
||||||
.executes(context -> {
|
|
||||||
Uniforms.frustumPaused = true;
|
|
||||||
return 1;
|
|
||||||
}))
|
|
||||||
.then(Commands.literal("unpause")
|
.then(Commands.literal("unpause")
|
||||||
.executes(context -> {
|
.executes(context -> {
|
||||||
Uniforms.frustumPaused = false;
|
Uniforms.frustumPaused = false;
|
||||||
|
|
|
@ -14,7 +14,8 @@ public final class InstanceTypes {
|
||||||
public static final InstanceType<TransformedInstance> TRANSFORMED = SimpleInstanceType.builder(TransformedInstance::new)
|
public static final InstanceType<TransformedInstance> TRANSFORMED = SimpleInstanceType.builder(TransformedInstance::new)
|
||||||
.layout(LayoutBuilder.create()
|
.layout(LayoutBuilder.create()
|
||||||
.vector("color", FloatRepr.NORMALIZED_UNSIGNED_BYTE, 4)
|
.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("pose", FloatRepr.FLOAT, 4)
|
||||||
.matrix("normal", FloatRepr.FLOAT, 3)
|
.matrix("normal", FloatRepr.FLOAT, 3)
|
||||||
.build())
|
.build())
|
||||||
|
@ -24,8 +25,7 @@ public final class InstanceTypes {
|
||||||
MemoryUtil.memPutByte(ptr + 2, instance.b);
|
MemoryUtil.memPutByte(ptr + 2, instance.b);
|
||||||
MemoryUtil.memPutByte(ptr + 3, instance.a);
|
MemoryUtil.memPutByte(ptr + 3, instance.a);
|
||||||
MemoryUtil.memPutInt(ptr + 4, instance.overlay);
|
MemoryUtil.memPutInt(ptr + 4, instance.overlay);
|
||||||
MemoryUtil.memPutShort(ptr + 8, instance.blockLight);
|
MemoryUtil.memPutInt(ptr + 8, (int) instance.blockLight | (int) instance.skyLight << 16);
|
||||||
MemoryUtil.memPutShort(ptr + 10, instance.skyLight);
|
|
||||||
MatrixMath.writeUnsafe(instance.model, ptr + 12);
|
MatrixMath.writeUnsafe(instance.model, ptr + 12);
|
||||||
MatrixMath.writeUnsafe(instance.normal, ptr + 76);
|
MatrixMath.writeUnsafe(instance.normal, ptr + 76);
|
||||||
})
|
})
|
||||||
|
@ -36,7 +36,8 @@ public final class InstanceTypes {
|
||||||
public static final InstanceType<OrientedInstance> ORIENTED = SimpleInstanceType.builder(OrientedInstance::new)
|
public static final InstanceType<OrientedInstance> ORIENTED = SimpleInstanceType.builder(OrientedInstance::new)
|
||||||
.layout(LayoutBuilder.create()
|
.layout(LayoutBuilder.create()
|
||||||
.vector("color", FloatRepr.NORMALIZED_UNSIGNED_BYTE, 4)
|
.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("position", FloatRepr.FLOAT, 3)
|
||||||
.vector("pivot", FloatRepr.FLOAT, 3)
|
.vector("pivot", FloatRepr.FLOAT, 3)
|
||||||
.vector("rotation", FloatRepr.FLOAT, 4)
|
.vector("rotation", FloatRepr.FLOAT, 4)
|
||||||
|
@ -47,8 +48,7 @@ public final class InstanceTypes {
|
||||||
MemoryUtil.memPutByte(ptr + 2, instance.b);
|
MemoryUtil.memPutByte(ptr + 2, instance.b);
|
||||||
MemoryUtil.memPutByte(ptr + 3, instance.a);
|
MemoryUtil.memPutByte(ptr + 3, instance.a);
|
||||||
MemoryUtil.memPutInt(ptr + 4, instance.overlay);
|
MemoryUtil.memPutInt(ptr + 4, instance.overlay);
|
||||||
MemoryUtil.memPutShort(ptr + 8, instance.blockLight);
|
MemoryUtil.memPutInt(ptr + 8, (int) instance.blockLight | (int) instance.skyLight << 16);
|
||||||
MemoryUtil.memPutShort(ptr + 10, instance.skyLight);
|
|
||||||
MemoryUtil.memPutFloat(ptr + 12, instance.posX);
|
MemoryUtil.memPutFloat(ptr + 12, instance.posX);
|
||||||
MemoryUtil.memPutFloat(ptr + 16, instance.posY);
|
MemoryUtil.memPutFloat(ptr + 16, instance.posY);
|
||||||
MemoryUtil.memPutFloat(ptr + 20, instance.posZ);
|
MemoryUtil.memPutFloat(ptr + 20, instance.posZ);
|
||||||
|
|
|
@ -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_vertexPos = vec4(rotateByQuaternion(flw_vertexPos.xyz - i.pivot, i.rotation) + i.pivot + i.position, 1.0);
|
||||||
flw_vertexNormal = rotateByQuaternion(flw_vertexNormal, i.rotation);
|
flw_vertexNormal = rotateByQuaternion(flw_vertexNormal, i.rotation);
|
||||||
flw_vertexColor = i.color;
|
flw_vertexColor = i.color;
|
||||||
flw_vertexOverlay = i.overlay_light.xy;
|
flw_vertexOverlay = i.overlay;
|
||||||
flw_vertexLight = i.overlay_light.zw / 15.0;
|
flw_vertexLight = i.light / 15.;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,6 @@ void flw_instanceVertex(in FlwInstance i) {
|
||||||
flw_vertexPos = i.pose * flw_vertexPos;
|
flw_vertexPos = i.pose * flw_vertexPos;
|
||||||
flw_vertexNormal = i.normal * flw_vertexNormal;
|
flw_vertexNormal = i.normal * flw_vertexNormal;
|
||||||
flw_vertexColor = i.color;
|
flw_vertexColor = i.color;
|
||||||
flw_vertexOverlay = i.overlay_light.xy;
|
flw_vertexOverlay = i.overlay;
|
||||||
flw_vertexLight = i.overlay_light.zw / 15.0;
|
flw_vertexLight = i.light / 15.;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,8 @@ uniform sampler2D _flw_lightTex;
|
||||||
|
|
||||||
out vec4 _flw_outputColor;
|
out vec4 _flw_outputColor;
|
||||||
|
|
||||||
|
in vec4 _flw_debugColor;
|
||||||
|
|
||||||
void _flw_main() {
|
void _flw_main() {
|
||||||
flw_sampleColor = texture(_flw_diffuseTex, flw_vertexTexCoord);
|
flw_sampleColor = texture(_flw_diffuseTex, flw_vertexTexCoord);
|
||||||
flw_fragColor = flw_vertexColor * flw_sampleColor;
|
flw_fragColor = flw_vertexColor * flw_sampleColor;
|
||||||
|
@ -35,7 +37,14 @@ void _flw_main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flw_material.useOverlay) {
|
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);
|
color.rgb = mix(overlayColor.rgb, color.rgb, overlayColor.a);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,5 +57,14 @@ void _flw_main() {
|
||||||
discard;
|
discard;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch (_flw_debugOverlay) {
|
||||||
|
case 1u:
|
||||||
|
color *= _flw_debugColor;
|
||||||
|
break;
|
||||||
|
case 2u:
|
||||||
|
color = _flw_debugColor;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
_flw_outputColor = flw_fogFilter(color);
|
_flw_outputColor = flw_fogFilter(color);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,29 @@
|
||||||
#include "flywheel:internal/fog_distance.glsl"
|
#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_layoutVertex();
|
||||||
flw_beginVertex();
|
flw_beginVertex();
|
||||||
flw_instanceVertex(instance);
|
flw_instanceVertex(instance);
|
||||||
|
@ -12,4 +35,19 @@ void _flw_main(in FlwInstance instance) {
|
||||||
flw_distance = fogDistance(flw_vertexPos.xyz, flw_cameraPos, flw_fogShape);
|
flw_distance = fogDistance(flw_vertexPos.xyz, flw_cameraPos, flw_fogShape);
|
||||||
|
|
||||||
gl_Position = flw_viewProjection * flw_vertexPos;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,5 +32,5 @@ void main() {
|
||||||
uint objectIndex = objectIndices[gl_BaseInstance + gl_InstanceID];
|
uint objectIndex = objectIndices[gl_BaseInstance + gl_InstanceID];
|
||||||
FlwInstance instance = _flw_unpackInstance(objects[objectIndex].instance);
|
FlwInstance instance = _flw_unpackInstance(objects[objectIndex].instance);
|
||||||
|
|
||||||
_flw_main(instance);
|
_flw_main(instance, objectIndex);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,5 +9,5 @@ void main() {
|
||||||
|
|
||||||
FlwInstance instance = _flw_unpackInstance();
|
FlwInstance instance = _flw_unpackInstance();
|
||||||
|
|
||||||
_flw_main(instance);
|
_flw_main(instance, uint(gl_InstanceID));
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,9 @@ layout(std140) uniform _FlwFrameUniforms {
|
||||||
|
|
||||||
float flw_renderTicks;
|
float flw_renderTicks;
|
||||||
float flw_renderSeconds;
|
float flw_renderSeconds;
|
||||||
|
|
||||||
|
uint _flw_debugMode;
|
||||||
|
uint _flw_debugOverlay;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define flw_cameraPos _flw_cameraPos.xyz
|
#define flw_cameraPos _flw_cameraPos.xyz
|
||||||
|
|
Loading…
Reference in a new issue