mirror of
https://github.com/GTNewHorizons/Angelica.git
synced 2026-10-25 20:22:22 +00:00
1 parent
0dfffca88e
commit
ffc324bab6
38 files changed
+1920
-166
No files matched your search
@@ -846,7 +846,12 @@ public class DisplayListManager {
|
||||
if (hasCommands) {
|
||||
DisplayListVBO compiledBuffers = null;
|
||||
try {
|
||||
compiledBuffers = new DisplayListVBOBuilder().addDraws(accumulatedDraws).build();
|
||||
final CommandRecorder pausedVbo = pauseRecording();
|
||||
try {
|
||||
compiledBuffers = new DisplayListVBOBuilder().addDraws(accumulatedDraws).build();
|
||||
} finally {
|
||||
resumeRecording(pausedVbo);
|
||||
}
|
||||
final IndexedDrawBatchBuilder indexedBuilder = commandBuffer.getIndexedDraws();
|
||||
final List<IndexedDrawBatch> indexedBatches;
|
||||
if (indexedBuilder.isEmpty()) {
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
package com.gtnewhorizons.angelica.glsm;
|
||||
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.stacks.IStateStack;
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||
import com.gtnewhorizons.angelica.glsm.stacks.AlphaStateStack;
|
||||
import com.gtnewhorizons.angelica.glsm.stacks.BlendStateStack;
|
||||
import com.gtnewhorizons.angelica.glsm.stacks.BooleanStateStack;
|
||||
@@ -180,6 +184,10 @@ class GLContextState {
|
||||
public int boundVAO;
|
||||
public int boundPixelUnpackBuffer;
|
||||
public int boundPixelPackBuffer;
|
||||
public int boundCopyReadBuffer;
|
||||
public int boundCopyWriteBuffer;
|
||||
public final Int2IntMap boundOtherBuffers = new Int2IntOpenHashMap();
|
||||
public final IntSet writeMappedBuffers = new IntOpenHashSet();
|
||||
public PixelUnpackState pixelUnpackState = PixelUnpackState.DEFAULT;
|
||||
public final int[] clientAttribSavedTextureUnit = new int[GLStateManager.CLIENT_ATTRIB_STACK_DEPTH];
|
||||
public final int[] clientAttribSavedVertexFlags = new int[GLStateManager.CLIENT_ATTRIB_STACK_DEPTH];
|
||||
|
||||
@@ -11,6 +11,7 @@ import com.gtnewhorizons.angelica.glsm.DisplayListManager.RecordMode;
|
||||
import com.gtnewhorizons.angelica.glsm.backend.BackendManager;
|
||||
import com.gtnewhorizons.angelica.glsm.backend.GLDebugMessageListener;
|
||||
import com.gtnewhorizons.angelica.glsm.backend.VSyncMode;
|
||||
import com.gtnewhorizons.angelica.glsm.ffp.FfpExtendedAttribs;
|
||||
import com.gtnewhorizons.angelica.glsm.profiling.Tracy;
|
||||
import com.gtnewhorizons.angelica.glsm.ffp.ShaderManager;
|
||||
import com.gtnewhorizons.angelica.glsm.ffp.VAOManager;
|
||||
@@ -56,6 +57,7 @@ import com.gtnewhorizons.angelica.glsm.states.TextureBinding;
|
||||
import com.gtnewhorizons.angelica.glsm.states.TextureUnitArray;
|
||||
import com.gtnewhorizons.angelica.glsm.texture.TextureInfo;
|
||||
import com.gtnewhorizons.angelica.glsm.texture.TextureInfoCache;
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntMap;
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.ints.IntStack;
|
||||
@@ -2577,12 +2579,17 @@ public class GLStateManager {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
if (mode == GL11.GL_QUADS) {
|
||||
QuadConverter.drawQuadElementsAsTriangles(indices_count, type, indices_buffer_offset);
|
||||
return;
|
||||
final boolean ffpExt = FfpExtendedAttribs.maybeBindIndexed(mode, indices_count, type, indices_buffer_offset);
|
||||
try {
|
||||
if (mode == GL11.GL_QUADS) {
|
||||
QuadConverter.drawQuadElementsAsTriangles(indices_count, type, indices_buffer_offset);
|
||||
return;
|
||||
}
|
||||
preDraw(mode);
|
||||
RENDER_BACKEND.drawElements(mode, indices_count, type, indices_buffer_offset);
|
||||
} finally {
|
||||
if (ffpExt) FfpExtendedAttribs.unbind();
|
||||
}
|
||||
preDraw(mode);
|
||||
RENDER_BACKEND.drawElements(mode, indices_count, type, indices_buffer_offset);
|
||||
} finally {
|
||||
if (savedRecorder != null) DisplayListManager.resumeRecording(savedRecorder);
|
||||
}
|
||||
@@ -2692,19 +2699,24 @@ public class GLStateManager {
|
||||
FeedbackManager.processDrawArrays(mode, first, count);
|
||||
return;
|
||||
}
|
||||
if (mode == GL11.GL_QUADS) {
|
||||
QuadConverter.drawQuadsAsTriangles(first, count);
|
||||
} else if (mode == GL11.GL_QUAD_STRIP) {
|
||||
preDraw();
|
||||
RENDER_BACKEND.drawArrays(GL11.GL_TRIANGLE_STRIP, first, count & ~1);
|
||||
} else if (mode == GL11.GL_POLYGON) {
|
||||
preDraw();
|
||||
RENDER_BACKEND.drawArrays(GL11.GL_TRIANGLE_FAN, first, count);
|
||||
} else {
|
||||
preDraw(mode);
|
||||
RENDER_BACKEND.drawArrays(mode, first, count);
|
||||
final boolean ffpExt = FfpExtendedAttribs.maybeBind(mode, first, count);
|
||||
try {
|
||||
if (mode == GL11.GL_QUADS) {
|
||||
QuadConverter.drawQuadsAsTriangles(first, count);
|
||||
} else if (mode == GL11.GL_QUAD_STRIP) {
|
||||
preDraw();
|
||||
RENDER_BACKEND.drawArrays(GL11.GL_TRIANGLE_STRIP, first, count & ~1);
|
||||
} else if (mode == GL11.GL_POLYGON) {
|
||||
preDraw();
|
||||
RENDER_BACKEND.drawArrays(GL11.GL_TRIANGLE_FAN, first, count);
|
||||
} else {
|
||||
preDraw(mode);
|
||||
RENDER_BACKEND.drawArrays(mode, first, count);
|
||||
}
|
||||
} finally {
|
||||
if (ffpExt) FfpExtendedAttribs.unbind();
|
||||
if (savedRecorder != null) DisplayListManager.resumeRecording(savedRecorder);
|
||||
}
|
||||
if (savedRecorder != null) DisplayListManager.resumeRecording(savedRecorder);
|
||||
}
|
||||
|
||||
private static void ffpClientArrayPointer(int index, int size, int type, boolean normalized, int stride, long offset) {
|
||||
@@ -5886,10 +5898,19 @@ public class GLStateManager {
|
||||
if (buffer == 0) return;
|
||||
final boolean locked = acquireDrawLock();
|
||||
try {
|
||||
FfpExtendedAttribs.onDeleteBuffer(buffer);
|
||||
if (glCtx.boundVBO == buffer) glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
|
||||
if (VAOManager.boundEBO == buffer) glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
if (glCtx.boundPixelUnpackBuffer == buffer) glBindBuffer(GL21.GL_PIXEL_UNPACK_BUFFER, 0);
|
||||
if (glCtx.boundPixelPackBuffer == buffer) glBindBuffer(GL21.GL_PIXEL_PACK_BUFFER, 0);
|
||||
if (glCtx.boundCopyReadBuffer == buffer) glBindBuffer(GL31.GL_COPY_READ_BUFFER, 0);
|
||||
if (glCtx.boundCopyWriteBuffer == buffer) glBindBuffer(GL31.GL_COPY_WRITE_BUFFER, 0);
|
||||
for (Int2IntMap.Entry e : glCtx.boundOtherBuffers.int2IntEntrySet()) {
|
||||
if (e.getIntValue() != buffer) continue;
|
||||
e.setValue(0);
|
||||
RENDER_BACKEND.bindBuffer(e.getIntKey(), 0);
|
||||
}
|
||||
glCtx.writeMappedBuffers.remove(buffer);
|
||||
|
||||
VAOManager.onDeleteBuffer(buffer);
|
||||
} finally {
|
||||
@@ -5897,20 +5918,30 @@ public class GLStateManager {
|
||||
}
|
||||
}
|
||||
|
||||
/** glBindBufferBase/Range also set the generic binding point, so they share this. */
|
||||
private static void trackBufferBinding(GLContextState glCtx, int target, int buffer) {
|
||||
if (target == GL15.GL_ARRAY_BUFFER) {
|
||||
// if (boundVBO == buffer) return; TODO figure out why this breaks switching async occlusion mode
|
||||
glCtx.boundVBO = buffer;
|
||||
} else if (target == GL15.GL_ELEMENT_ARRAY_BUFFER) {
|
||||
VAOManager.onBindEBO(buffer);
|
||||
} else if (target == GL21.GL_PIXEL_UNPACK_BUFFER) {
|
||||
glCtx.boundPixelUnpackBuffer = buffer;
|
||||
} else if (target == GL21.GL_PIXEL_PACK_BUFFER) {
|
||||
glCtx.boundPixelPackBuffer = buffer;
|
||||
} else if (target == GL31.GL_COPY_READ_BUFFER) {
|
||||
glCtx.boundCopyReadBuffer = buffer;
|
||||
} else if (target == GL31.GL_COPY_WRITE_BUFFER) {
|
||||
glCtx.boundCopyWriteBuffer = buffer;
|
||||
} else {
|
||||
glCtx.boundOtherBuffers.put(target, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
public static void glBindBuffer(int target, int buffer) {
|
||||
final GLContextState glCtx = ctx();
|
||||
final boolean locked = acquireDrawLock();
|
||||
try {
|
||||
if (target == GL15.GL_ARRAY_BUFFER) {
|
||||
// if (boundVBO == buffer) return; TODO figure out why this breaks switching async occlusion mode
|
||||
glCtx.boundVBO = buffer;
|
||||
} else if (target == GL15.GL_ELEMENT_ARRAY_BUFFER) {
|
||||
VAOManager.onBindEBO(buffer);
|
||||
} else if (target == GL21.GL_PIXEL_UNPACK_BUFFER) {
|
||||
glCtx.boundPixelUnpackBuffer = buffer;
|
||||
} else if (target == GL21.GL_PIXEL_PACK_BUFFER) {
|
||||
glCtx.boundPixelPackBuffer = buffer;
|
||||
}
|
||||
trackBufferBinding(ctx(), target, buffer);
|
||||
RENDER_BACKEND.bindBuffer(target, buffer);
|
||||
} finally {
|
||||
if (locked) releaseDrawLock();
|
||||
@@ -5989,15 +6020,78 @@ public class GLStateManager {
|
||||
for (int i = 0; i < buffers.length; i++) buffers[i] = RENDER_BACKEND.createBuffers();
|
||||
}
|
||||
|
||||
public static void glBufferData(int target, long size, int usage) { RENDER_BACKEND.bufferData(target, size, usage); }
|
||||
public static void glBufferData(int target, ByteBuffer data, int usage) { RENDER_BACKEND.bufferData(target, data, usage); }
|
||||
public static void glBufferData(int target, ShortBuffer data, int usage) { RENDER_BACKEND.bufferData(target, data, usage); }
|
||||
public static void glBufferData(int target, IntBuffer data, int usage) { RENDER_BACKEND.bufferData(target, data, usage); }
|
||||
public static void glBufferData(int target, FloatBuffer data, int usage) { RENDER_BACKEND.bufferData(target, data, usage); }
|
||||
public static void glBufferData(int target, DoubleBuffer data, int usage) { RENDER_BACKEND.bufferData(target, data, usage); }
|
||||
private static final int MAP_PERSISTENT_BIT = 0x40;
|
||||
|
||||
private static int bufferForTarget(int target) {
|
||||
final GLContextState glCtx = ctx();
|
||||
if (target == GL15.GL_ARRAY_BUFFER) return glCtx.boundVBO;
|
||||
if (target == GL15.GL_ELEMENT_ARRAY_BUFFER) return VAOManager.boundEBO;
|
||||
if (target == GL31.GL_COPY_READ_BUFFER) return glCtx.boundCopyReadBuffer;
|
||||
if (target == GL31.GL_COPY_WRITE_BUFFER) return glCtx.boundCopyWriteBuffer;
|
||||
if (target == GL21.GL_PIXEL_UNPACK_BUFFER) return glCtx.boundPixelUnpackBuffer;
|
||||
if (target == GL21.GL_PIXEL_PACK_BUFFER) return glCtx.boundPixelPackBuffer;
|
||||
return glCtx.boundOtherBuffers.get(target);
|
||||
}
|
||||
|
||||
private static void onBufferRespec(int target) {
|
||||
if (FfpExtendedAttribs.isEmpty()) return;
|
||||
final int buffer = bufferForTarget(target);
|
||||
if (buffer != 0) FfpExtendedAttribs.onBufferRespecified(buffer);
|
||||
}
|
||||
|
||||
private static void onBufferMap(int target, int access) {
|
||||
if (access == GL15.GL_READ_ONLY) return;
|
||||
markWriteMapped(target);
|
||||
onBufferRespec(target);
|
||||
}
|
||||
|
||||
private static void onBufferMapRange(int target, int access) {
|
||||
if ((access & GL30.GL_MAP_WRITE_BIT) == 0) return;
|
||||
if ((access & MAP_PERSISTENT_BIT) != 0) {
|
||||
markPersistentlyMapped(target);
|
||||
return;
|
||||
}
|
||||
markWriteMapped(target);
|
||||
onBufferRespec(target);
|
||||
}
|
||||
|
||||
private static void markWriteMapped(int target) {
|
||||
final int buffer = bufferForTarget(target);
|
||||
if (buffer != 0) ctx().writeMappedBuffers.add(buffer);
|
||||
}
|
||||
|
||||
private static void onBufferUnmap(int target) {
|
||||
final int buffer = bufferForTarget(target);
|
||||
if (buffer == 0 || !ctx().writeMappedBuffers.remove(buffer)) return;
|
||||
onBufferRespec(target);
|
||||
}
|
||||
|
||||
private static void onBufferStorage(int target, int flags) {
|
||||
if ((flags & MAP_PERSISTENT_BIT) != 0) {
|
||||
markPersistentlyMapped(target);
|
||||
return;
|
||||
}
|
||||
onBufferRespec(target);
|
||||
}
|
||||
|
||||
private static void markPersistentlyMapped(int target) {
|
||||
FfpExtendedAttribs.markPersistent(bufferForTarget(target));
|
||||
}
|
||||
|
||||
private static void onNamedBufferRespec(int buffer) {
|
||||
if (FfpExtendedAttribs.isEmpty()) return;
|
||||
FfpExtendedAttribs.onBufferRespecified(buffer);
|
||||
}
|
||||
|
||||
public static void glBufferData(int target, long size, int usage) { onBufferRespec(target); RENDER_BACKEND.bufferData(target, size, usage); }
|
||||
public static void glBufferData(int target, ByteBuffer data, int usage) { onBufferRespec(target); RENDER_BACKEND.bufferData(target, data, usage); }
|
||||
public static void glBufferData(int target, ShortBuffer data, int usage) { onBufferRespec(target); RENDER_BACKEND.bufferData(target, data, usage); }
|
||||
public static void glBufferData(int target, IntBuffer data, int usage) { onBufferRespec(target); RENDER_BACKEND.bufferData(target, data, usage); }
|
||||
public static void glBufferData(int target, FloatBuffer data, int usage) { onBufferRespec(target); RENDER_BACKEND.bufferData(target, data, usage); }
|
||||
public static void glBufferData(int target, DoubleBuffer data, int usage) { onBufferRespec(target); RENDER_BACKEND.bufferData(target, data, usage); }
|
||||
public static void glBufferData(int target, LongBuffer data, int usage) { glBufferData(target, MemoryUtilities.memByteBuffer(data), usage); }
|
||||
public static void glBufferData(int target, int[] data, int usage) { RENDER_BACKEND.bufferData(target, data, usage); }
|
||||
public static void glBufferData(int target, float[] data, int usage) { RENDER_BACKEND.bufferData(target, data, usage); }
|
||||
public static void glBufferData(int target, int[] data, int usage) { onBufferRespec(target); RENDER_BACKEND.bufferData(target, data, usage); }
|
||||
public static void glBufferData(int target, float[] data, int usage) { onBufferRespec(target); RENDER_BACKEND.bufferData(target, data, usage); }
|
||||
public static void glBufferData(int target, short[] data, int usage) {
|
||||
final ByteBuffer copy = copyOf(data);
|
||||
glBufferData(target, copy, usage);
|
||||
@@ -6022,11 +6116,11 @@ public class GLStateManager {
|
||||
glBufferData(target, MemoryUtilities.memByteBuffer(data, checkedSize(size)), usage);
|
||||
}
|
||||
|
||||
public static void glBufferSubData(int target, long offset, ByteBuffer data) { RENDER_BACKEND.bufferSubData(target, offset, data); }
|
||||
public static void glBufferSubData(int target, long offset, ShortBuffer data) { RENDER_BACKEND.bufferSubData(target, offset, data); }
|
||||
public static void glBufferSubData(int target, long offset, IntBuffer data) { RENDER_BACKEND.bufferSubData(target, offset, data); }
|
||||
public static void glBufferSubData(int target, long offset, FloatBuffer data) { RENDER_BACKEND.bufferSubData(target, offset, data); }
|
||||
public static void glBufferSubData(int target, long offset, DoubleBuffer data) { RENDER_BACKEND.bufferSubData(target, offset, data); }
|
||||
public static void glBufferSubData(int target, long offset, ByteBuffer data) { onBufferRespec(target); RENDER_BACKEND.bufferSubData(target, offset, data); }
|
||||
public static void glBufferSubData(int target, long offset, ShortBuffer data) { onBufferRespec(target); RENDER_BACKEND.bufferSubData(target, offset, data); }
|
||||
public static void glBufferSubData(int target, long offset, IntBuffer data) { onBufferRespec(target); RENDER_BACKEND.bufferSubData(target, offset, data); }
|
||||
public static void glBufferSubData(int target, long offset, FloatBuffer data) { onBufferRespec(target); RENDER_BACKEND.bufferSubData(target, offset, data); }
|
||||
public static void glBufferSubData(int target, long offset, DoubleBuffer data) { onBufferRespec(target); RENDER_BACKEND.bufferSubData(target, offset, data); }
|
||||
public static void glBufferSubData(int target, long offset, LongBuffer data) { glBufferSubData(target, offset, MemoryUtilities.memByteBuffer(data)); }
|
||||
public static void glBufferSubData(int target, long offset, short[] data) {
|
||||
final ByteBuffer copy = copyOf(data);
|
||||
@@ -6056,13 +6150,13 @@ public class GLStateManager {
|
||||
|
||||
public static void nglBufferSubData(int target, long offset, long size, long data) { glBufferSubData(target, offset, MemoryUtilities.memByteBuffer(data, checkedSize(size))); }
|
||||
|
||||
public static ByteBuffer glMapBuffer(int target, int access) { return RENDER_BACKEND.mapBuffer(target, access); }
|
||||
public static ByteBuffer glMapBuffer(int target, int access) { onBufferMap(target, access); return RENDER_BACKEND.mapBuffer(target, access); }
|
||||
public static ByteBuffer glMapBuffer(int target, int access, ByteBuffer old_buffer) { return glMapBuffer(target, access); }
|
||||
public static ByteBuffer glMapBuffer(int target, int access, long length, ByteBuffer old_buffer) { return RENDER_BACKEND.mapBuffer(target, access, length, old_buffer); }
|
||||
public static ByteBuffer glMapBufferRange(int target, long offset, long length, int access) { return RENDER_BACKEND.mapBufferRange(target, offset, length, access); }
|
||||
public static ByteBuffer glMapBuffer(int target, int access, long length, ByteBuffer old_buffer) { onBufferMap(target, access); return RENDER_BACKEND.mapBuffer(target, access, length, old_buffer); }
|
||||
public static ByteBuffer glMapBufferRange(int target, long offset, long length, int access) { onBufferMapRange(target, access); return RENDER_BACKEND.mapBufferRange(target, offset, length, access); }
|
||||
public static ByteBuffer glMapBufferRange(int target, long offset, long length, int access, ByteBuffer old_buffer) { return glMapBufferRange(target, offset, length, access); }
|
||||
public static void glFlushMappedBufferRange(int target, long offset, long length) { RENDER_BACKEND.flushMappedBufferRange(target, offset, length); }
|
||||
public static boolean glUnmapBuffer(int target) { return RENDER_BACKEND.unmapBuffer(target); }
|
||||
public static boolean glUnmapBuffer(int target) { onBufferUnmap(target); return RENDER_BACKEND.unmapBuffer(target); }
|
||||
|
||||
public static void glGetBufferSubData(int target, long offset, ByteBuffer data) { RENDER_BACKEND.getBufferSubData(target, offset, data); }
|
||||
public static void glGetBufferSubData(int target, long offset, ShortBuffer data) { RENDER_BACKEND.getBufferSubData(target, offset, data); }
|
||||
@@ -6109,8 +6203,8 @@ public class GLStateManager {
|
||||
public static void glGetBufferParameteriv(int target, int pname, IntBuffer params) { params.put(params.position(), glGetBufferParameteri(target, pname)); }
|
||||
public static void glGetBufferParameteriv(int target, int pname, int[] params) { params[0] = glGetBufferParameteri(target, pname); }
|
||||
|
||||
public static void glBufferStorage(int target, long size, int flags) { RENDER_BACKEND.bufferStorage(target, size, flags); }
|
||||
public static void glBufferStorage(int target, ByteBuffer data, int flags) { RENDER_BACKEND.bufferStorage(target, data, flags); }
|
||||
public static void glBufferStorage(int target, long size, int flags) { onBufferStorage(target, flags); RENDER_BACKEND.bufferStorage(target, size, flags); }
|
||||
public static void glBufferStorage(int target, ByteBuffer data, int flags) { onBufferStorage(target, flags); RENDER_BACKEND.bufferStorage(target, data, flags); }
|
||||
public static void glBufferStorage(int target, ShortBuffer data, int flags) { glBufferStorage(target, MemoryUtilities.memByteBuffer(data), flags); }
|
||||
public static void glBufferStorage(int target, IntBuffer data, int flags) { glBufferStorage(target, MemoryUtilities.memByteBuffer(data), flags); }
|
||||
public static void glBufferStorage(int target, FloatBuffer data, int flags) { glBufferStorage(target, MemoryUtilities.memByteBuffer(data), flags); }
|
||||
@@ -6136,9 +6230,9 @@ public class GLStateManager {
|
||||
MemoryUtilities.memFree(copy);
|
||||
}
|
||||
|
||||
public static void glNamedBufferData(int buffer, long size, int usage) { RENDER_BACKEND.namedBufferData(buffer, size, usage); }
|
||||
public static void glNamedBufferData(int buffer, ByteBuffer data, int usage) { RENDER_BACKEND.namedBufferData(buffer, data, usage); }
|
||||
public static void glNamedBufferData(int buffer, FloatBuffer data, int usage) { RENDER_BACKEND.namedBufferData(buffer, data, usage); }
|
||||
public static void glNamedBufferData(int buffer, long size, int usage) { onNamedBufferRespec(buffer); RENDER_BACKEND.namedBufferData(buffer, size, usage); }
|
||||
public static void glNamedBufferData(int buffer, ByteBuffer data, int usage) { onNamedBufferRespec(buffer); RENDER_BACKEND.namedBufferData(buffer, data, usage); }
|
||||
public static void glNamedBufferData(int buffer, FloatBuffer data, int usage) { onNamedBufferRespec(buffer); RENDER_BACKEND.namedBufferData(buffer, data, usage); }
|
||||
public static void glNamedBufferData(int buffer, ShortBuffer data, int usage) { glNamedBufferData(buffer, MemoryUtilities.memByteBuffer(data), usage); }
|
||||
public static void glNamedBufferData(int buffer, IntBuffer data, int usage) { glNamedBufferData(buffer, MemoryUtilities.memByteBuffer(data), usage); }
|
||||
public static void glNamedBufferData(int buffer, LongBuffer data, int usage) { glNamedBufferData(buffer, MemoryUtilities.memByteBuffer(data), usage); }
|
||||
@@ -6169,7 +6263,7 @@ public class GLStateManager {
|
||||
MemoryUtilities.memFree(copy);
|
||||
}
|
||||
|
||||
public static void glNamedBufferSubData(int buffer, long offset, ByteBuffer data) { RENDER_BACKEND.namedBufferSubData(buffer, offset, data); }
|
||||
public static void glNamedBufferSubData(int buffer, long offset, ByteBuffer data) { onNamedBufferRespec(buffer); RENDER_BACKEND.namedBufferSubData(buffer, offset, data); }
|
||||
public static void glNamedBufferSubData(int buffer, long offset, ShortBuffer data) { glNamedBufferSubData(buffer, offset, MemoryUtilities.memByteBuffer(data)); }
|
||||
public static void glNamedBufferSubData(int buffer, long offset, IntBuffer data) { glNamedBufferSubData(buffer, offset, MemoryUtilities.memByteBuffer(data)); }
|
||||
public static void glNamedBufferSubData(int buffer, long offset, LongBuffer data) { glNamedBufferSubData(buffer, offset, MemoryUtilities.memByteBuffer(data)); }
|
||||
@@ -6201,15 +6295,15 @@ public class GLStateManager {
|
||||
MemoryUtilities.memFree(copy);
|
||||
}
|
||||
|
||||
public static void glClearBufferSubData(int target, int internalFormat, long offset, long size, int format, int type, ByteBuffer data) { RENDER_BACKEND.clearBufferSubData(target, internalFormat, offset, size, format, type, data); }
|
||||
public static void glClearBufferData(int target, int internalformat, int format, int type, ByteBuffer data) { RENDER_BACKEND.clearBufferData(target, internalformat, format, type, data); }
|
||||
public static void glClearBufferSubData(int target, int internalFormat, long offset, long size, int format, int type, ByteBuffer data) { onBufferRespec(target); RENDER_BACKEND.clearBufferSubData(target, internalFormat, offset, size, format, type, data); }
|
||||
public static void glClearBufferData(int target, int internalformat, int format, int type, ByteBuffer data) { onBufferRespec(target); RENDER_BACKEND.clearBufferData(target, internalformat, format, type, data); }
|
||||
public static boolean glIsBuffer(int buffer) { return RENDER_BACKEND.isBuffer(buffer); }
|
||||
public static boolean glIsTexture(int texture) { return RENDER_BACKEND.isTexture(texture); }
|
||||
public static boolean glIsFramebuffer(int framebuffer) { return RENDER_BACKEND.isFramebuffer(framebuffer); }
|
||||
public static boolean glIsRenderbuffer(int renderbuffer) { return RENDER_BACKEND.isRenderbuffer(renderbuffer); }
|
||||
public static boolean glIsSampler(int sampler) { return RENDER_BACKEND.isSampler(sampler); }
|
||||
public static boolean glIsQuery(int query) { return RENDER_BACKEND.isQuery(query); }
|
||||
public static void glCopyBufferSubData(int readTarget, int writeTarget, long readOffset, long writeOffset, long size) { RENDER_BACKEND.copyBufferSubData(readTarget, writeTarget, readOffset, writeOffset, size); }
|
||||
public static void glCopyBufferSubData(int readTarget, int writeTarget, long readOffset, long writeOffset, long size) { onBufferRespec(writeTarget); RENDER_BACKEND.copyBufferSubData(readTarget, writeTarget, readOffset, writeOffset, size); }
|
||||
|
||||
private static int checkedSize(long size) {
|
||||
if (size < 0 || size > Integer.MAX_VALUE) {
|
||||
@@ -6373,7 +6467,26 @@ public class GLStateManager {
|
||||
public static void glGetQueryObjectui(int id, int pname, IntBuffer params) { RENDER_BACKEND.getQueryObjectui(id, pname, params); }
|
||||
public static int glGetQueryObjecti(int id, int pname) { return RENDER_BACKEND.getQueryObjecti(id, pname); }
|
||||
|
||||
public static void glBindBufferBase(int target, int index, int buffer) { RENDER_BACKEND.bindBufferBase(target, index, buffer); }
|
||||
public static void glBindBufferBase(int target, int index, int buffer) {
|
||||
final boolean locked = acquireDrawLock();
|
||||
try {
|
||||
trackBufferBinding(ctx(), target, buffer);
|
||||
RENDER_BACKEND.bindBufferBase(target, index, buffer);
|
||||
} finally {
|
||||
if (locked) releaseDrawLock();
|
||||
}
|
||||
}
|
||||
|
||||
public static void glBindBufferRange(int target, int index, int buffer, long offset, long size) {
|
||||
final boolean locked = acquireDrawLock();
|
||||
try {
|
||||
trackBufferBinding(ctx(), target, buffer);
|
||||
RENDER_BACKEND.bindBufferRange(target, index, buffer, offset, size);
|
||||
} finally {
|
||||
if (locked) releaseDrawLock();
|
||||
}
|
||||
}
|
||||
|
||||
public static int glGetUniformBlockIndex(int program, CharSequence name) { return RENDER_BACKEND.getUniformBlockIndex(program, name); }
|
||||
public static void glUniformBlockBinding(int program, int blockIndex, int binding) { RENDER_BACKEND.uniformBlockBinding(program, blockIndex, binding); }
|
||||
public static void glBindFragDataLocation(int program, int colorNumber, CharSequence name) { RENDER_BACKEND.bindFragDataLocation(program, colorNumber, name); }
|
||||
@@ -6411,6 +6524,7 @@ public class GLStateManager {
|
||||
}
|
||||
}
|
||||
public static long nglMapBuffer(int target, int access) {
|
||||
onBufferMap(target, access);
|
||||
final ByteBuffer buf = RENDER_BACKEND.mapBuffer(target, access);
|
||||
return buf == null ? 0L : MemoryUtilities.memAddress0(buf);
|
||||
}
|
||||
@@ -7728,6 +7842,14 @@ public class GLStateManager {
|
||||
return ctx().boundVBO;
|
||||
}
|
||||
|
||||
public static int getBoundCopyReadBuffer() {
|
||||
return ctx().boundCopyReadBuffer;
|
||||
}
|
||||
|
||||
public static int getBoundCopyWriteBuffer() {
|
||||
return ctx().boundCopyWriteBuffer;
|
||||
}
|
||||
|
||||
public static int getBoundVAO() {
|
||||
return ctx().boundVAO;
|
||||
}
|
||||
|
||||
@@ -559,7 +559,7 @@ public class RenderSystem {
|
||||
}
|
||||
|
||||
public static void bindBufferBase(int target, int index, int buffer) {
|
||||
RENDER_BACKEND.bindBufferBase(target, index, buffer);
|
||||
GLStateManager.glBindBufferBase(target, index, buffer);
|
||||
}
|
||||
|
||||
public static void bufferStorage(int target, long size, int flags) {
|
||||
|
||||
@@ -0,0 +1,583 @@
|
||||
package com.gtnewhorizons.angelica.glsm.ffp;
|
||||
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.cel.api.util.NormI8;
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.vertex.VertexFormatElement.Usage;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.GLSMHooks;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.ImmediateExtendedAttribHandler;
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectSet;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL15;
|
||||
import org.lwjgl.opengl.GL31;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.HashMap;
|
||||
|
||||
import static com.gtnewhorizon.gtnhlib.bytebuf.MemoryUtilities.memAddress0;
|
||||
import static com.gtnewhorizon.gtnhlib.bytebuf.MemoryUtilities.memAlloc;
|
||||
import static com.gtnewhorizon.gtnhlib.bytebuf.MemoryUtilities.memCalloc;
|
||||
import static com.gtnewhorizon.gtnhlib.bytebuf.MemoryUtilities.memFree;
|
||||
import static com.gtnewhorizon.gtnhlib.bytebuf.MemoryUtilities.memGetByte;
|
||||
import static com.gtnewhorizon.gtnhlib.bytebuf.MemoryUtilities.memGetInt;
|
||||
import static com.gtnewhorizon.gtnhlib.bytebuf.MemoryUtilities.memGetShort;
|
||||
import static com.gtnewhorizons.angelica.glsm.backend.BackendManager.RENDER_BACKEND;
|
||||
|
||||
/**
|
||||
* Supplies {@code mc_midTexCoord}/{@code at_tangent} for mod geometry drawn through the FFPclient-array path
|
||||
* ({@code glVertexPointer}/{@code glTexCoordPointer} + {@code glDrawArrays}) out of a VBO, which bypasses the
|
||||
* Tessellator and display-list ext-injection paths.
|
||||
*
|
||||
* <p>Tangents are reconstructed from the flat face normal (handler's {@code normalOffset < 0} path).
|
||||
*/
|
||||
public final class FfpExtendedAttribs {
|
||||
|
||||
private FfpExtendedAttribs() {}
|
||||
|
||||
private static final int POSITION_LOC = Usage.POSITION.getAttributeLocation();
|
||||
private static final int UV_LOC = Usage.PRIMARY_UV.getAttributeLocation();
|
||||
private static final int NORMAL_LOC = Usage.NORMAL.getAttributeLocation();
|
||||
private static final int SRC_TEX_OFFSET = 12;
|
||||
private static final int SRC_NORMAL_OFFSET = 20;
|
||||
private static final int SRC_STRIDE_FLAT = 20;
|
||||
private static final int SRC_STRIDE_SMOOTH = 24;
|
||||
private static final int MAX_CACHE = 1024;
|
||||
private static final int MAX_EXT_VERTS = 1 << 20;
|
||||
private static final int MAX_RESPECS = 8;
|
||||
private static final int RESPEC_DECAY_FRAMES = 2;
|
||||
private static final int MIN_STREAM_SPAN_FRAMES = 4;
|
||||
private static final int STREAM_EXPIRE_FRAMES = 60;
|
||||
|
||||
private static final HashMap<Key, ExtBuffer> cache = new HashMap<>();
|
||||
private static final Key lookup = new Key();
|
||||
private static int internalGlDepth = 0;
|
||||
|
||||
private static final HashMap<EboKey, Boolean> eboPatternCache = new HashMap<>();
|
||||
private static final EboKey eboLookup = new EboKey();
|
||||
|
||||
private static final Int2ObjectMap<ObjectSet<Key>> keysBySource = new Int2ObjectOpenHashMap<>();
|
||||
private static final Int2ObjectMap<ObjectSet<EboKey>> eboKeysBySource = new Int2ObjectOpenHashMap<>();
|
||||
private static final Int2IntMap respecCounts = new Int2IntOpenHashMap();
|
||||
private static final Int2IntMap respecFrames = new Int2IntOpenHashMap();
|
||||
private static final Int2IntMap respecRunStart = new Int2IntOpenHashMap();
|
||||
private static final IntSet streamingSources = new IntOpenHashSet();
|
||||
private static final IntSet persistentSources = new IntOpenHashSet();
|
||||
private static int frame;
|
||||
|
||||
public static void endFrame() { frame++; }
|
||||
|
||||
public static boolean isEmpty() {
|
||||
return cache.isEmpty() && eboPatternCache.isEmpty();
|
||||
}
|
||||
|
||||
private static int internalDrawDepth = 0;
|
||||
|
||||
public static void beginInternalDraw() { internalDrawDepth++; }
|
||||
|
||||
public static void endInternalDraw() { if (internalDrawDepth > 0) internalDrawDepth--; }
|
||||
|
||||
private static void beginInternalGl() { internalGlDepth++; }
|
||||
|
||||
private static void endInternalGl() { if (internalGlDepth > 0) internalGlDepth--; }
|
||||
|
||||
private static boolean isNotConventionalTexturedArray(VAOManager.Attrib a) {
|
||||
return a == null || !a.enabled || a.genericPointer || a.vboId == 0 || a.size < 2;
|
||||
}
|
||||
|
||||
private static boolean isStreaming(int vboId) {
|
||||
if (vboId == 0 || !streamingSources.contains(vboId)) return false;
|
||||
if (persistentSources.contains(vboId)) return true;
|
||||
if (frame - respecFrames.get(vboId) > STREAM_EXPIRE_FRAMES) {
|
||||
streamingSources.remove(vboId);
|
||||
respecFrames.remove(vboId);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean maybeBind(int mode, int first, int count) {
|
||||
final ImmediateExtendedAttribHandler h = GLSMHooks.immediateExtendedHandler;
|
||||
if (h == null) return false;
|
||||
if (internalDrawDepth > 0) return false;
|
||||
final int extPrim = ImmediateExtendedAttribHandler.extPrimVerts(mode, count);
|
||||
if (extPrim == 0 || first < 0) return false;
|
||||
if (!h.wantsExtended()) return false;
|
||||
|
||||
final VAOManager.Attrib pos = VAOManager.get(POSITION_LOC);
|
||||
final VAOManager.Attrib uv = VAOManager.get(UV_LOC);
|
||||
if (isNotConventionalTexturedArray(pos) || isNotConventionalTexturedArray(uv)) return false;
|
||||
if (isStreaming(pos.vboId) || isStreaming(uv.vboId)) return false;
|
||||
|
||||
VAOManager.Attrib normal = extPrim == 3 ? VAOManager.get(NORMAL_LOC) : null;
|
||||
if (normal != null && (!normal.enabled || normal.genericPointer || normal.vboId == 0 || normal.size < 3
|
||||
|| isStreaming(normal.vboId))) {
|
||||
normal = null;
|
||||
}
|
||||
|
||||
return bindExt(h, mode, first, count, extPrim, pos, uv, normal);
|
||||
}
|
||||
|
||||
public static boolean maybeBindIndexed(int mode, int indexCount, int indexType, long indicesOffset) {
|
||||
final ImmediateExtendedAttribHandler h = GLSMHooks.immediateExtendedHandler;
|
||||
if (h == null) return false;
|
||||
if (internalDrawDepth > 0) return false;
|
||||
if (mode != GL11.GL_TRIANGLES || indexCount <= 0 || indexCount % 6 != 0) return false;
|
||||
if (!h.wantsExtended()) return false;
|
||||
|
||||
final VAOManager.Attrib pos = VAOManager.get(POSITION_LOC);
|
||||
final VAOManager.Attrib uv = VAOManager.get(UV_LOC);
|
||||
if (isNotConventionalTexturedArray(pos) || isNotConventionalTexturedArray(uv)) return false;
|
||||
if (isStreaming(pos.vboId) || isStreaming(uv.vboId) || isStreaming(VAOManager.boundEBO)) return false;
|
||||
|
||||
final int indexSize = indexTypeBytes(indexType);
|
||||
if (indexSize == 0) return false;
|
||||
if (indicesOffset % (6L * indexSize) != 0) return false;
|
||||
final int first = (int) (indicesOffset / indexSize) / 6 * 4;
|
||||
final int count = indexCount / 6 * 4;
|
||||
|
||||
if (!isQuadPatternEbo(VAOManager.boundEBO, indicesOffset, indexCount, indexType, indexSize, first)) return false;
|
||||
|
||||
// Build/bind as GL_QUADS (the real primitive): face-normal tangents, 4-vertex tiles, no per-vertex normal.
|
||||
return bindExt(h, GL11.GL_QUADS, first, count, 4, pos, uv, null);
|
||||
}
|
||||
|
||||
private static boolean isQuadPatternEbo(int ebo, long offset, int indexCount, int indexType, int indexSize, int firstVertex) {
|
||||
if (ebo == 0) return false;
|
||||
eboLookup.set(ebo, offset, indexCount, indexType);
|
||||
final Boolean cached = eboPatternCache.get(eboLookup);
|
||||
if (cached != null) return cached;
|
||||
if (eboPatternCache.size() >= MAX_CACHE) {
|
||||
eboPatternCache.clear();
|
||||
eboKeysBySource.clear();
|
||||
}
|
||||
|
||||
final ByteBuffer buf = memCalloc(indexCount, indexSize);
|
||||
RENDER_BACKEND.getBufferSubData(GL15.GL_ELEMENT_ARRAY_BUFFER, offset, buf);
|
||||
final long addr = memAddress0(buf);
|
||||
boolean match = true;
|
||||
for (int q = 0, quadCount = indexCount / 6; q < quadCount; q++) {
|
||||
final int base = firstVertex + q * 4;
|
||||
final long p = addr + (long) q * 6 * indexSize;
|
||||
if (readIndex(p, 0, indexSize) != base
|
||||
|| readIndex(p, 1, indexSize) != base + 1
|
||||
|| readIndex(p, 2, indexSize) != base + 2
|
||||
|| readIndex(p, 3, indexSize) != base + 2
|
||||
|| readIndex(p, 4, indexSize) != base + 3
|
||||
|| readIndex(p, 5, indexSize) != base) {
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
memFree(buf);
|
||||
final EboKey stored = eboLookup.copy();
|
||||
eboPatternCache.put(stored, match);
|
||||
ObjectSet<EboKey> ebos = eboKeysBySource.get(stored.ebo);
|
||||
if (ebos == null) eboKeysBySource.put(stored.ebo, ebos = new ObjectOpenHashSet<>());
|
||||
ebos.add(stored);
|
||||
return match;
|
||||
}
|
||||
|
||||
private static long readIndex(long base, int i, int indexSize) {
|
||||
return switch (indexSize) {
|
||||
case 1 -> memGetByte(base + i) & 0xFFL;
|
||||
case 2 -> memGetShort(base + (long) i * 2) & 0xFFFFL;
|
||||
default -> memGetInt(base + (long) i * 4) & 0xFFFFFFFFL;
|
||||
};
|
||||
}
|
||||
|
||||
private static int indexTypeBytes(int indexType) {
|
||||
return switch (indexType) {
|
||||
case GL11.GL_UNSIGNED_BYTE -> 1;
|
||||
case GL11.GL_UNSIGNED_SHORT -> 2;
|
||||
case GL11.GL_UNSIGNED_INT -> 4;
|
||||
default -> 0;
|
||||
};
|
||||
}
|
||||
|
||||
private static boolean bindExt(ImmediateExtendedAttribHandler h, int mode, int first, int count, int extPrim,
|
||||
VAOManager.Attrib pos, VAOManager.Attrib uv, VAOManager.Attrib normal) {
|
||||
final int extVbo = getOrBuild(h, pos, uv, normal, first, count, extPrim, mode);
|
||||
if (extVbo == 0) return false;
|
||||
|
||||
final int savedVBO = GLStateManager.getBoundVBO();
|
||||
GLStateManager.glBindBuffer(GL15.GL_ARRAY_BUFFER, extVbo);
|
||||
ImmediateExtendedAttribHandler.setupExtAttribPointers(0L, ImmediateExtendedAttribHandler.EXT_STRIDE);
|
||||
GLStateManager.glBindBuffer(GL15.GL_ARRAY_BUFFER, savedVBO);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void unbind() {
|
||||
GLStateManager.glDisableVertexAttribArray(ImmediateExtendedAttribHandler.LOC_MID_TEX);
|
||||
GLStateManager.glDisableVertexAttribArray(ImmediateExtendedAttribHandler.LOC_TANGENT);
|
||||
setNeutralCurrentValues();
|
||||
}
|
||||
|
||||
public static void setNeutralCurrentValues() {
|
||||
GLStateManager.glVertexAttrib2f(ImmediateExtendedAttribHandler.LOC_MID_TEX, 0.5f, 0.5f);
|
||||
GLStateManager.glVertexAttrib4f(ImmediateExtendedAttribHandler.LOC_TANGENT, 1.0f, 0.0f, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
public static void onDeleteBuffer(int vboId) {
|
||||
if (internalGlDepth > 0 || vboId == 0) return;
|
||||
dropDerivedFrom(vboId);
|
||||
respecCounts.remove(vboId);
|
||||
respecFrames.remove(vboId);
|
||||
respecRunStart.remove(vboId);
|
||||
streamingSources.remove(vboId);
|
||||
persistentSources.remove(vboId);
|
||||
}
|
||||
|
||||
public static void onBufferRespecified(int vboId) {
|
||||
if (internalGlDepth > 0 || vboId == 0) return;
|
||||
if (streamingSources.contains(vboId)) {
|
||||
respecFrames.put(vboId, frame);
|
||||
return;
|
||||
}
|
||||
if (!dropDerivedFrom(vboId)) return;
|
||||
final boolean sameRun = respecCounts.containsKey(vboId) && frame - respecFrames.get(vboId) <= RESPEC_DECAY_FRAMES;
|
||||
if (!sameRun) {
|
||||
startRespecRun(vboId);
|
||||
return;
|
||||
}
|
||||
final int respecs = respecCounts.get(vboId) + 1;
|
||||
final int span = frame - respecRunStart.get(vboId);
|
||||
if (respecs >= MAX_RESPECS && span >= MIN_STREAM_SPAN_FRAMES && span <= respecs) {
|
||||
markStreaming(vboId);
|
||||
return;
|
||||
}
|
||||
if (span > respecs) {
|
||||
startRespecRun(vboId);
|
||||
return;
|
||||
}
|
||||
respecCounts.put(vboId, respecs);
|
||||
respecFrames.put(vboId, frame);
|
||||
}
|
||||
|
||||
private static void startRespecRun(int vboId) {
|
||||
respecCounts.put(vboId, 1);
|
||||
respecRunStart.put(vboId, frame);
|
||||
respecFrames.put(vboId, frame);
|
||||
}
|
||||
|
||||
public static void markStreaming(int vboId) {
|
||||
if (internalGlDepth > 0 || vboId == 0) return;
|
||||
respecCounts.remove(vboId);
|
||||
respecRunStart.remove(vboId);
|
||||
respecFrames.put(vboId, frame);
|
||||
if (streamingSources.add(vboId)) dropDerivedFrom(vboId);
|
||||
}
|
||||
|
||||
public static void markPersistent(int vboId) {
|
||||
if (internalGlDepth > 0 || vboId == 0) return;
|
||||
markStreaming(vboId);
|
||||
persistentSources.add(vboId);
|
||||
}
|
||||
|
||||
public static void reset() {
|
||||
invalidateAll();
|
||||
respecCounts.clear();
|
||||
respecFrames.clear();
|
||||
respecRunStart.clear();
|
||||
streamingSources.clear();
|
||||
persistentSources.clear();
|
||||
}
|
||||
|
||||
private static boolean dropDerivedFrom(int srcId) {
|
||||
final ObjectSet<EboKey> ebos = eboKeysBySource.remove(srcId);
|
||||
if (ebos != null) {
|
||||
for (EboKey k : ebos) eboPatternCache.remove(k);
|
||||
}
|
||||
final ObjectSet<Key> keys = keysBySource.get(srcId);
|
||||
if (keys == null || keys.isEmpty()) return ebos != null;
|
||||
IntArrayList toFree = null;
|
||||
for (Key k : keys.toArray(new Key[0])) {
|
||||
final ExtBuffer buf = cache.remove(k);
|
||||
if (buf != null && buf.vbo != 0) {
|
||||
if (toFree == null) toFree = new IntArrayList();
|
||||
toFree.add(buf.vbo);
|
||||
}
|
||||
unindexKey(k);
|
||||
}
|
||||
freeExtVbos(toFree);
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void indexKey(Key k) {
|
||||
addToBucket(k.posVBO, k);
|
||||
if (k.uvVBO != k.posVBO) addToBucket(k.uvVBO, k);
|
||||
if (k.normalVBO != k.posVBO && k.normalVBO != k.uvVBO) addToBucket(k.normalVBO, k);
|
||||
}
|
||||
|
||||
private static void unindexKey(Key k) {
|
||||
removeFromBucket(k.posVBO, k);
|
||||
if (k.uvVBO != k.posVBO) removeFromBucket(k.uvVBO, k);
|
||||
if (k.normalVBO != k.posVBO && k.normalVBO != k.uvVBO) removeFromBucket(k.normalVBO, k);
|
||||
}
|
||||
|
||||
private static void addToBucket(int src, Key k) {
|
||||
if (src == 0) return;
|
||||
ObjectSet<Key> set = keysBySource.get(src);
|
||||
if (set == null) keysBySource.put(src, set = new ObjectOpenHashSet<>());
|
||||
set.add(k);
|
||||
}
|
||||
|
||||
private static void removeFromBucket(int src, Key k) {
|
||||
if (src == 0) return;
|
||||
final ObjectSet<Key> set = keysBySource.get(src);
|
||||
if (set != null && set.remove(k) && set.isEmpty()) keysBySource.remove(src);
|
||||
}
|
||||
|
||||
private static int getOrBuild(ImmediateExtendedAttribHandler h, VAOManager.Attrib pos, VAOManager.Attrib uv,
|
||||
VAOManager.Attrib normal, int first, int count, int extPrim, int mode) {
|
||||
if (first + count > MAX_EXT_VERTS) return 0;
|
||||
lookup.set(pos, uv, normal, mode, first % extPrim);
|
||||
ExtBuffer buf = cache.get(lookup);
|
||||
if (buf == null) {
|
||||
if (cache.size() >= MAX_CACHE) invalidateExtBuffers();
|
||||
buf = new ExtBuffer();
|
||||
final Key stored = lookup.copy();
|
||||
cache.put(stored, buf);
|
||||
indexKey(stored);
|
||||
}
|
||||
|
||||
final long range = (long) first << 32 | (count & 0xFFFFFFFFL);
|
||||
if (buf.vbo != 0 && buf.builtRanges.contains(range)) return buf.vbo;
|
||||
if (!ensureCapacity(buf, first + count)) return 0;
|
||||
buildRange(h, buf.vbo, pos, uv, normal, first, count, extPrim);
|
||||
buf.builtRanges.add(range);
|
||||
return buf.vbo;
|
||||
}
|
||||
|
||||
private static boolean ensureCapacity(ExtBuffer buf, int neededVerts) {
|
||||
if (buf.vbo != 0 && buf.capacityVerts >= neededVerts) return true;
|
||||
final int extStride = ImmediateExtendedAttribHandler.EXT_STRIDE;
|
||||
final int newCap = Math.min(MAX_EXT_VERTS, Math.max(neededVerts, buf.capacityVerts * 2));
|
||||
beginInternalGl();
|
||||
try {
|
||||
final int vbo = GLStateManager.glGenBuffers();
|
||||
if (vbo == 0) return false;
|
||||
final int savedVBO = GLStateManager.getBoundVBO();
|
||||
GLStateManager.glBindBuffer(GL15.GL_ARRAY_BUFFER, vbo);
|
||||
GLStateManager.glBufferData(GL15.GL_ARRAY_BUFFER, (long) newCap * extStride, GL15.GL_STATIC_DRAW);
|
||||
GLStateManager.glBindBuffer(GL15.GL_ARRAY_BUFFER, savedVBO);
|
||||
if (buf.vbo != 0) {
|
||||
final int savedRead = GLStateManager.getBoundCopyReadBuffer();
|
||||
final int savedWrite = GLStateManager.getBoundCopyWriteBuffer();
|
||||
GLStateManager.glBindBuffer(GL31.GL_COPY_READ_BUFFER, buf.vbo);
|
||||
GLStateManager.glBindBuffer(GL31.GL_COPY_WRITE_BUFFER, vbo);
|
||||
GLStateManager.glCopyBufferSubData(GL31.GL_COPY_READ_BUFFER, GL31.GL_COPY_WRITE_BUFFER, 0L, 0L,
|
||||
(long) buf.capacityVerts * extStride);
|
||||
GLStateManager.glBindBuffer(GL31.GL_COPY_READ_BUFFER, savedRead);
|
||||
GLStateManager.glBindBuffer(GL31.GL_COPY_WRITE_BUFFER, savedWrite);
|
||||
GLStateManager.glDeleteBuffers(buf.vbo);
|
||||
}
|
||||
buf.vbo = vbo;
|
||||
buf.capacityVerts = newCap;
|
||||
return true;
|
||||
} finally {
|
||||
endInternalGl();
|
||||
}
|
||||
}
|
||||
|
||||
private static void buildRange(ImmediateExtendedAttribHandler h, int extVbo, VAOManager.Attrib pos,
|
||||
VAOManager.Attrib uv, VAOManager.Attrib normal, int first, int count, int extPrim) {
|
||||
final int posStride = pos.effectiveStride();
|
||||
final int uvStride = uv.effectiveStride();
|
||||
final boolean smooth = normal != null;
|
||||
final int normalStride = smooth ? normal.effectiveStride() : 0;
|
||||
final int srcStride = smooth ? SRC_STRIDE_SMOOTH : SRC_STRIDE_FLAT;
|
||||
final int srcNormalOffset = smooth ? SRC_NORMAL_OFFSET : -1;
|
||||
|
||||
final ByteBuffer posBuf = readRange(pos, first, count, posStride);
|
||||
final ByteBuffer uvBuf = readRange(uv, first, count, uvStride);
|
||||
final ByteBuffer normalBuf = smooth ? readRange(normal, first, count, normalStride) : null;
|
||||
|
||||
final ByteBuffer src = memAlloc(count * srcStride).order(ByteOrder.nativeOrder());
|
||||
for (int i = 0; i < count; i++) {
|
||||
final int pb = i * posStride, ub = i * uvStride, d = i * srcStride;
|
||||
src.putFloat(d, pos.readComponent(posBuf, pb, 0));
|
||||
src.putFloat(d + 4, pos.readComponent(posBuf, pb, 1));
|
||||
src.putFloat(d + 8, pos.size >= 3 ? pos.readComponent(posBuf, pb, 2) : 0f);
|
||||
src.putFloat(d + SRC_TEX_OFFSET, uv.readComponent(uvBuf, ub, 0));
|
||||
src.putFloat(d + SRC_TEX_OFFSET + 4, uv.readComponent(uvBuf, ub, 1));
|
||||
if (smooth) {
|
||||
final int nb = i * normalStride;
|
||||
src.putInt(d + SRC_NORMAL_OFFSET, NormI8.pack(
|
||||
normal.readComponent(normalBuf, nb, 0),
|
||||
normal.readComponent(normalBuf, nb, 1),
|
||||
normal.readComponent(normalBuf, nb, 2)));
|
||||
}
|
||||
}
|
||||
|
||||
final int extStride = ImmediateExtendedAttribHandler.EXT_STRIDE;
|
||||
final ByteBuffer ext = memCalloc(count, extStride);
|
||||
h.buildPacked(memAddress0(src), srcStride, 0, SRC_TEX_OFFSET, srcNormalOffset, count, extPrim, memAddress0(ext), extStride);
|
||||
|
||||
beginInternalGl();
|
||||
try {
|
||||
final int savedVBO = GLStateManager.getBoundVBO();
|
||||
GLStateManager.glBindBuffer(GL15.GL_ARRAY_BUFFER, extVbo);
|
||||
ext.position(0).limit(count * extStride);
|
||||
GLStateManager.glBufferSubData(GL15.GL_ARRAY_BUFFER, (long) first * extStride, ext);
|
||||
GLStateManager.glBindBuffer(GL15.GL_ARRAY_BUFFER, savedVBO);
|
||||
} finally {
|
||||
endInternalGl();
|
||||
}
|
||||
|
||||
memFree(posBuf);
|
||||
memFree(uvBuf);
|
||||
if (normalBuf != null) memFree(normalBuf);
|
||||
memFree(src);
|
||||
memFree(ext);
|
||||
}
|
||||
|
||||
private static ByteBuffer readRange(VAOManager.Attrib a, int first, int count, int stride) {
|
||||
final int elementBytes = a.size * a.typeSizeBytes();
|
||||
final int bytes = (count - 1) * stride + elementBytes;
|
||||
final ByteBuffer dst = memAlloc(bytes).order(ByteOrder.nativeOrder());
|
||||
dst.position(0).limit(bytes);
|
||||
final int savedVBO = GLStateManager.getBoundVBO();
|
||||
GLStateManager.glBindBuffer(GL15.GL_ARRAY_BUFFER, a.vboId);
|
||||
RENDER_BACKEND.getBufferSubData(GL15.GL_ARRAY_BUFFER, a.offset + (long) first * stride, dst);
|
||||
GLStateManager.glBindBuffer(GL15.GL_ARRAY_BUFFER, savedVBO);
|
||||
dst.position(0).limit(bytes);
|
||||
return dst;
|
||||
}
|
||||
|
||||
private static void invalidateAll() {
|
||||
eboPatternCache.clear();
|
||||
eboKeysBySource.clear();
|
||||
invalidateExtBuffers();
|
||||
}
|
||||
|
||||
private static void invalidateExtBuffers() {
|
||||
if (cache.isEmpty()) return;
|
||||
final IntArrayList toFree = new IntArrayList(cache.size());
|
||||
for (ExtBuffer buf : cache.values()) {
|
||||
if (buf.vbo != 0) toFree.add(buf.vbo);
|
||||
}
|
||||
cache.clear();
|
||||
keysBySource.clear();
|
||||
freeExtVbos(toFree);
|
||||
}
|
||||
|
||||
private static void freeExtVbos(IntArrayList vbos) {
|
||||
if (vbos == null || vbos.isEmpty()) return;
|
||||
beginInternalGl();
|
||||
try {
|
||||
for (int i = 0; i < vbos.size(); i++) {
|
||||
GLStateManager.glDeleteBuffers(vbos.getInt(i));
|
||||
}
|
||||
} finally {
|
||||
endInternalGl();
|
||||
}
|
||||
}
|
||||
|
||||
private static final class ExtBuffer {
|
||||
int vbo;
|
||||
int capacityVerts;
|
||||
final LongOpenHashSet builtRanges = new LongOpenHashSet();
|
||||
}
|
||||
|
||||
private static final class EboKey {
|
||||
int ebo, count, type;
|
||||
long offset;
|
||||
|
||||
void set(int ebo, long offset, int count, int type) {
|
||||
this.ebo = ebo;
|
||||
this.offset = offset;
|
||||
this.count = count;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
EboKey copy() {
|
||||
final EboKey k = new EboKey();
|
||||
k.set(ebo, offset, count, type);
|
||||
return k;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof EboKey k)) return false;
|
||||
return ebo == k.ebo && count == k.count && type == k.type && offset == k.offset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int h = ebo;
|
||||
h = h * 31 + count;
|
||||
h = h * 31 + type;
|
||||
h = h * 31 + Long.hashCode(offset);
|
||||
return h;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class Key {
|
||||
int posVBO, uvVBO, normalVBO, posStride, uvStride, normalStride, posFmt, uvFmt, normalFmt, mode, phase;
|
||||
long posOffset, uvOffset, normalOffset;
|
||||
|
||||
void set(VAOManager.Attrib pos, VAOManager.Attrib uv, VAOManager.Attrib normal, int mode, int phase) {
|
||||
posVBO = pos.vboId; posOffset = pos.offset; posStride = pos.effectiveStride(); posFmt = fmt(pos);
|
||||
uvVBO = uv.vboId; uvOffset = uv.offset; uvStride = uv.effectiveStride(); uvFmt = fmt(uv);
|
||||
if (normal != null) {
|
||||
normalVBO = normal.vboId; normalOffset = normal.offset;
|
||||
normalStride = normal.effectiveStride(); normalFmt = fmt(normal);
|
||||
} else {
|
||||
normalVBO = 0; normalOffset = 0; normalStride = 0; normalFmt = 0;
|
||||
}
|
||||
this.mode = mode;
|
||||
this.phase = phase;
|
||||
}
|
||||
|
||||
private static int fmt(VAOManager.Attrib a) {
|
||||
return (a.size & 0x7F) | (a.normalized ? 0x80 : 0) | (a.type << 8);
|
||||
}
|
||||
|
||||
Key copy() {
|
||||
final Key k = new Key();
|
||||
k.posVBO = posVBO; k.posOffset = posOffset; k.posStride = posStride; k.posFmt = posFmt;
|
||||
k.uvVBO = uvVBO; k.uvOffset = uvOffset; k.uvStride = uvStride; k.uvFmt = uvFmt;
|
||||
k.normalVBO = normalVBO; k.normalOffset = normalOffset; k.normalStride = normalStride; k.normalFmt = normalFmt;
|
||||
k.mode = mode; k.phase = phase;
|
||||
return k;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof Key k)) return false;
|
||||
return posVBO == k.posVBO && uvVBO == k.uvVBO && normalVBO == k.normalVBO
|
||||
&& posStride == k.posStride && uvStride == k.uvStride && normalStride == k.normalStride
|
||||
&& posFmt == k.posFmt && uvFmt == k.uvFmt && normalFmt == k.normalFmt
|
||||
&& mode == k.mode && phase == k.phase
|
||||
&& posOffset == k.posOffset && uvOffset == k.uvOffset && normalOffset == k.normalOffset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int h = posVBO;
|
||||
h = h * 31 + uvVBO;
|
||||
h = h * 31 + normalVBO;
|
||||
h = h * 31 + posStride;
|
||||
h = h * 31 + uvStride;
|
||||
h = h * 31 + normalStride;
|
||||
h = h * 31 + posFmt;
|
||||
h = h * 31 + uvFmt;
|
||||
h = h * 31 + normalFmt;
|
||||
h = h * 31 + mode;
|
||||
h = h * 31 + phase;
|
||||
h = h * 31 + Long.hashCode(posOffset);
|
||||
h = h * 31 + Long.hashCode(uvOffset);
|
||||
h = h * 31 + Long.hashCode(normalOffset);
|
||||
return h;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,12 +2,12 @@ package com.gtnewhorizons.angelica.glsm.ffp;
|
||||
|
||||
public final class InstancedAttribs {
|
||||
|
||||
public static final int LOC_MATRIX_COL0 = 7;
|
||||
public static final int LOC_MATRIX_COL1 = 8;
|
||||
public static final int LOC_MATRIX_COL2 = 9;
|
||||
public static final int LOC_MATRIX_COL3 = 10;
|
||||
public static final int LOC_COLOR = 11;
|
||||
public static final int LOC_LIGHTMAP = 12;
|
||||
public static final int LOC_MATRIX_COL0 = 5;
|
||||
public static final int LOC_MATRIX_COL1 = 6;
|
||||
public static final int LOC_MATRIX_COL2 = 7;
|
||||
public static final int LOC_MATRIX_COL3 = 8;
|
||||
public static final int LOC_COLOR = 9;
|
||||
public static final int LOC_LIGHTMAP = 10;
|
||||
|
||||
public static final int OFFSET_MATRIX = 0;
|
||||
public static final int OFFSET_COLOR = 64;
|
||||
|
||||
@@ -179,6 +179,7 @@ public final class ShaderManager {
|
||||
sm.lastFramePreDrawCalls = sm.preDrawCalls;
|
||||
sm.preDrawCalls = 0;
|
||||
sm.uniforms.endFrame();
|
||||
FfpExtendedAttribs.endFrame();
|
||||
}
|
||||
|
||||
public static void setCurrentNormal(float x, float y, float z) {
|
||||
|
||||
@@ -27,7 +27,6 @@ import static com.gtnewhorizon.gtnhlib.bytebuf.MemoryUtilities.memCalloc;
|
||||
import static com.gtnewhorizon.gtnhlib.bytebuf.MemoryUtilities.memFree;
|
||||
import static com.gtnewhorizon.gtnhlib.bytebuf.MemoryUtilities.memGetInt;
|
||||
import static com.gtnewhorizon.gtnhlib.bytebuf.MemoryUtilities.memPutInt;
|
||||
import static com.gtnewhorizons.angelica.glsm.backend.BackendManager.RENDER_BACKEND;
|
||||
|
||||
/**
|
||||
* Maintains the shared {@link FFPUniformBlock} image from GLSM cached state and streams it to the UBO ring.
|
||||
@@ -209,7 +208,7 @@ public class Uniforms {
|
||||
ring = new UniformRingBuffer(RING_CAPACITY, FFPUniformBlock.SIZE);
|
||||
}
|
||||
final int offset = ring.writeBlock(staging);
|
||||
RENDER_BACKEND.bindBufferRange(GL31.GL_UNIFORM_BUFFER, FFPUniformBlock.BINDING_POINT,
|
||||
GLStateManager.glBindBufferRange(GL31.GL_UNIFORM_BUFFER, FFPUniformBlock.BINDING_POINT,
|
||||
ring.getBufferId(), offset, FFPUniformBlock.SIZE);
|
||||
bound = true;
|
||||
blockWrites++;
|
||||
|
||||
@@ -16,6 +16,7 @@ public final class GLSMConfig {
|
||||
|
||||
public static boolean hudCacheOverride;
|
||||
|
||||
public static boolean extendedAttribsExpected;
|
||||
public static volatile boolean expandVertexFormats;
|
||||
|
||||
private GLSMConfig() {}
|
||||
|
||||
@@ -9,6 +9,7 @@ public final class GLSMHooks {
|
||||
public static DeferredAlphaHandler alphaHandler;
|
||||
public static DeferredDepthColorHandler depthColorHandler;
|
||||
public static GlintColorHandler glintColorHandler;
|
||||
public static ImmediateExtendedAttribHandler immediateExtendedHandler;
|
||||
public static ShaderWorkSubmitter shaderWorkSubmitter;
|
||||
public static ShaderTransformPostProcessor postTransformProcessor;
|
||||
public static PerFrameUniformBlock perFrameUniformBlock;
|
||||
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
package com.gtnewhorizons.angelica.glsm.hooks;
|
||||
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.vertex.VertexFormat;
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.vertex.VertexFormatElement;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
public interface ImmediateExtendedAttribHandler {
|
||||
|
||||
int EXT_STRIDE = 12;
|
||||
int LOC_MC_ENTITY = 11;
|
||||
int LOC_MID_TEX = 12;
|
||||
int LOC_TANGENT = 13;
|
||||
int LOC_MIDBLOCK = 14;
|
||||
|
||||
int RAW_NORMAL_INDEX = 6;
|
||||
|
||||
boolean wantsExtended();
|
||||
|
||||
boolean wantsTangent();
|
||||
|
||||
boolean wantsExtendedCapture();
|
||||
|
||||
void build(int[] rawBuffer, int vertexCount, int vertsPerPrim, int normalIntIndex, long dstAddr, int dstStride);
|
||||
|
||||
void buildPacked(long srcBase, int stride, int posOffset, int texOffset, int normalOffset,
|
||||
int vertexCount, int vertsPerPrim, long dstAddr, int dstStride);
|
||||
|
||||
static int extPrimVerts(int drawMode) {
|
||||
if (drawMode == GL11.GL_QUADS) return 4;
|
||||
if (drawMode == GL11.GL_TRIANGLES) return 3;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int extPrimVerts(int drawMode, int vertexCount) {
|
||||
final int p = extPrimVerts(drawMode);
|
||||
return (p != 0 && vertexCount > 0 && vertexCount % p == 0) ? p : 0;
|
||||
}
|
||||
|
||||
static int texOffset(VertexFormat format) {
|
||||
int offset = 0;
|
||||
for (VertexFormatElement element : format.elementsArray) {
|
||||
if (element.getUsage() == VertexFormatElement.Usage.PRIMARY_UV) return offset;
|
||||
offset += element.getByteSize();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int normalOffset(VertexFormat format) {
|
||||
int offset = 0;
|
||||
for (VertexFormatElement element : format.elementsArray) {
|
||||
if (element.getUsage() == VertexFormatElement.Usage.NORMAL) return offset;
|
||||
offset += element.getByteSize();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void setupExtAttribPointers(long baseOffset, int stride) {
|
||||
GLStateManager.glEnableVertexAttribArray(LOC_MID_TEX);
|
||||
GLStateManager.glVertexAttribPointer(LOC_MID_TEX, 2, GL11.GL_FLOAT, false, stride, baseOffset);
|
||||
GLStateManager.glEnableVertexAttribArray(LOC_TANGENT);
|
||||
GLStateManager.glVertexAttribPointer(LOC_TANGENT, 4, GL11.GL_BYTE, true, stride, baseOffset + 8);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,10 @@
|
||||
package com.gtnewhorizons.angelica.glsm.recording;
|
||||
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.vao.IVertexArrayObject;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.ImmediateExtendedAttribHandler;
|
||||
import org.lwjgl.opengl.GL15;
|
||||
import com.gtnewhorizons.angelica.glsm.ffp.FfpExtendedAttribs;
|
||||
import com.gtnewhorizons.angelica.glsm.ffp.VAOManager;
|
||||
|
||||
/**
|
||||
@@ -9,15 +13,26 @@ import com.gtnewhorizons.angelica.glsm.ffp.VAOManager;
|
||||
public final class DisplayListVBO {
|
||||
|
||||
private final SubVBO[] vbos;
|
||||
private final int[] extVbos;
|
||||
|
||||
DisplayListVBO(SubVBO[] vbos) {
|
||||
this(vbos, null);
|
||||
}
|
||||
|
||||
DisplayListVBO(SubVBO[] vbos, int[] extVbos) {
|
||||
this.vbos = vbos;
|
||||
this.extVbos = extVbos;
|
||||
}
|
||||
|
||||
public void delete() {
|
||||
for (SubVBO vbo : vbos) {
|
||||
vbo.delete();
|
||||
}
|
||||
if (extVbos != null) {
|
||||
for (int extVbo : extVbos) {
|
||||
if (extVbo != 0) GLStateManager.glDeleteBuffers(extVbo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public SubVBO[] getVBOs() {
|
||||
@@ -39,6 +54,9 @@ public final class DisplayListVBO {
|
||||
private final int start;
|
||||
private final int count;
|
||||
private final int vertexFlags;
|
||||
private int pendingExtVbo = 0;
|
||||
|
||||
void setPendingExtVbo(int extVbo) { this.pendingExtVbo = extVbo; }
|
||||
|
||||
public SubVBO(IVertexArrayObject vao, int drawMode, int start, int count, int vertexFlags) {
|
||||
this.vao = vao;
|
||||
@@ -67,9 +85,20 @@ public final class DisplayListVBO {
|
||||
public void render() {
|
||||
if (vao == null) return;
|
||||
vao.bind();
|
||||
if (pendingExtVbo != 0) {
|
||||
GLStateManager.glBindBuffer(GL15.GL_ARRAY_BUFFER, pendingExtVbo);
|
||||
ImmediateExtendedAttribHandler.setupExtAttribPointers(0L, ImmediateExtendedAttribHandler.EXT_STRIDE);
|
||||
GLStateManager.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
|
||||
pendingExtVbo = 0;
|
||||
}
|
||||
if (count <= 0) { vao.unbind(); return; }
|
||||
VAOManager.setCurrentVertexFlags(vertexFlags);
|
||||
vao.draw(drawMode, start, count);
|
||||
FfpExtendedAttribs.beginInternalDraw();
|
||||
try {
|
||||
vao.draw(drawMode, start, count);
|
||||
} finally {
|
||||
FfpExtendedAttribs.endInternalDraw();
|
||||
}
|
||||
vao.unbind();
|
||||
}
|
||||
|
||||
|
||||
+84
-1
@@ -1,5 +1,6 @@
|
||||
package com.gtnewhorizons.angelica.glsm.recording;
|
||||
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.vao.BaseVAO;
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.vao.IVertexArrayObject;
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.vao.IndexBuffer;
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.vao.IndexedVAO;
|
||||
@@ -8,7 +9,13 @@ import com.gtnewhorizon.gtnhlib.client.renderer.vbo.IVertexBuffer;
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.vertex.DefaultVertexFormat;
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.vertex.VertexFlags;
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.vertex.VertexFormat;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.GLSMConfig;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.GLSMHooks;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.ImmediateExtendedAttribHandler;
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL15;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
@@ -16,6 +23,7 @@ import java.util.List;
|
||||
|
||||
import static com.gtnewhorizon.gtnhlib.bytebuf.MemoryUtilities.memAddress0;
|
||||
import static com.gtnewhorizon.gtnhlib.bytebuf.MemoryUtilities.memAlloc;
|
||||
import static com.gtnewhorizon.gtnhlib.bytebuf.MemoryUtilities.memCalloc;
|
||||
import static com.gtnewhorizon.gtnhlib.bytebuf.MemoryUtilities.memCopy;
|
||||
import static com.gtnewhorizon.gtnhlib.bytebuf.MemoryUtilities.memFree;
|
||||
import static com.gtnewhorizon.gtnhlib.bytebuf.MemoryUtilities.nmemFree;
|
||||
@@ -48,15 +56,29 @@ public final class DisplayListVBOBuilder {
|
||||
}
|
||||
|
||||
public DisplayListVBO build() {
|
||||
final ImmediateExtendedAttribHandler extHandler = GLSMHooks.immediateExtendedHandler;
|
||||
final DisplayListVBO.SubVBO[] vbos = new DisplayListVBO.SubVBO[count];
|
||||
final ArrayList<ByteBuffer> allBuffers = new ArrayList<>();
|
||||
final IntArrayList extVbos = new IntArrayList();
|
||||
for (int i = 0; i < VertexFlags.BITSET_SIZE; i++) {
|
||||
List<FormatData> formatData = formats[i];
|
||||
if (formatData == null) continue;
|
||||
final VertexFormat format = DefaultVertexFormat.ALL_FORMATS[i];
|
||||
final boolean wantExt = extHandler != null && format.hasTexture();
|
||||
if (extHandler == null && GLSMConfig.extendedAttribsExpected && format.hasTexture()) {
|
||||
GLStateManager.warnOnce("dl-ext-no-handler",
|
||||
"Textured display list compiled before the immediate ext-attribute handler was installed! POM data will be missing for this geometry.");
|
||||
}
|
||||
int start = 0;
|
||||
final IVertexArrayObject vao = VAOManager.createStorageVAO(format, -1, 0); // drawMode will be ignored
|
||||
final IVertexBuffer vbo = vao.getVBO();
|
||||
|
||||
// SubVBO slots that need the ext attributes attached on their first draw.
|
||||
final IntArrayList extDrawIndexes = wantExt ? new IntArrayList() : null;
|
||||
final IntArrayList extStarts = wantExt ? new IntArrayList() : null;
|
||||
final IntArrayList extCounts = wantExt ? new IntArrayList() : null;
|
||||
final IntArrayList extPrims = wantExt ? new IntArrayList() : null;
|
||||
|
||||
for (FormatData data : formatData) {
|
||||
int vertexCount;
|
||||
final List<ByteBuffer> drawBuffers = data.buffers;
|
||||
@@ -76,6 +98,23 @@ public final class DisplayListVBOBuilder {
|
||||
if (data.drawMode == GL11.GL_QUADS) {
|
||||
final IVertexArrayObject indexedVAO = new IndexedVAO(vbo, IndexBuffer.convertQuadsToTrigs(start, start + vertexCount));
|
||||
vbos[data.drawIndex] = new DisplayListVBO.SubVBO(indexedVAO, GL11.GL_TRIANGLES, 0, vertexCount / 4 * 6, flags);
|
||||
if (wantExt) {
|
||||
extDrawIndexes.add(data.drawIndex);
|
||||
extStarts.add(start);
|
||||
extCounts.add(vertexCount);
|
||||
extPrims.add(4);
|
||||
}
|
||||
} else if (data.drawMode == GL11.GL_TRIANGLES) {
|
||||
if (wantExt) {
|
||||
final IVertexArrayObject triVao = new BaseVAO(vbo);
|
||||
vbos[data.drawIndex] = new DisplayListVBO.SubVBO(triVao, GL11.GL_TRIANGLES, start, vertexCount, flags);
|
||||
extDrawIndexes.add(data.drawIndex);
|
||||
extStarts.add(start);
|
||||
extCounts.add(vertexCount);
|
||||
extPrims.add(3);
|
||||
} else {
|
||||
vbos[data.drawIndex] = new DisplayListVBO.SubVBO(vao, GL11.GL_TRIANGLES, start, vertexCount, flags);
|
||||
}
|
||||
} else if (data.drawMode == GL11.GL_QUAD_STRIP) {
|
||||
// GL_QUAD_STRIP is removed in core profile; an even-length GL_TRIANGLE_STRIP produces the same quads
|
||||
vbos[data.drawIndex] = new DisplayListVBO.SubVBO(vao, GL11.GL_TRIANGLE_STRIP, start, vertexCount & ~1, flags);
|
||||
@@ -91,11 +130,55 @@ public final class DisplayListVBOBuilder {
|
||||
}
|
||||
ByteBuffer bigBuffer = mergeAndDelete(allBuffers);
|
||||
vbo.allocate(bigBuffer, start);
|
||||
|
||||
if (wantExt && !extDrawIndexes.isEmpty()) {
|
||||
final int extVbo = buildExt(extHandler, format, bigBuffer, extStarts, extCounts, extPrims);
|
||||
if (extVbo != 0) {
|
||||
extVbos.add(extVbo);
|
||||
for (int e = 0; e < extDrawIndexes.size(); e++) {
|
||||
vbos[extDrawIndexes.getInt(e)].setPendingExtVbo(extVbo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
memFree(bigBuffer);
|
||||
|
||||
allBuffers.clear();
|
||||
}
|
||||
return new DisplayListVBO(vbos);
|
||||
return new DisplayListVBO(vbos, extVbos.toIntArray());
|
||||
}
|
||||
|
||||
private static int buildExt(ImmediateExtendedAttribHandler handler, VertexFormat format, ByteBuffer bigBuffer,
|
||||
IntArrayList extStarts, IntArrayList extCounts, IntArrayList extPrims) {
|
||||
final int extStride = ImmediateExtendedAttribHandler.EXT_STRIDE;
|
||||
final int stride = format.getVertexSize();
|
||||
final int posOffset = 0;
|
||||
final int texOffset = ImmediateExtendedAttribHandler.texOffset(format);
|
||||
final int normalOffset = ImmediateExtendedAttribHandler.normalOffset(format);
|
||||
|
||||
int extVerts = 0;
|
||||
for (int q = 0; q < extStarts.size(); q++) {
|
||||
extVerts = Math.max(extVerts, extStarts.getInt(q) + extCounts.getInt(q));
|
||||
}
|
||||
|
||||
final ByteBuffer ext = memCalloc(extVerts, extStride);
|
||||
final long extAddr = memAddress0(ext);
|
||||
final long srcBase = memAddress0(bigBuffer);
|
||||
for (int q = 0; q < extStarts.size(); q++) {
|
||||
final int rStart = extStarts.getInt(q);
|
||||
final int rCount = extCounts.getInt(q);
|
||||
final int rPrim = extPrims.getInt(q);
|
||||
handler.buildPacked(srcBase + (long) rStart * stride, stride, posOffset, texOffset, normalOffset, rCount, rPrim,
|
||||
extAddr + (long) rStart * extStride, extStride);
|
||||
}
|
||||
|
||||
final int extVbo = GLStateManager.glGenBuffers();
|
||||
GLStateManager.glBindBuffer(GL15.GL_ARRAY_BUFFER, extVbo);
|
||||
ext.position(0).limit(extVerts * extStride);
|
||||
GLStateManager.glBufferData(GL15.GL_ARRAY_BUFFER, ext, GL15.GL_STATIC_DRAW);
|
||||
GLStateManager.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
|
||||
memFree(ext);
|
||||
return extVbo;
|
||||
}
|
||||
|
||||
private static ByteBuffer mergeAndDelete(List<ByteBuffer> buffers) {
|
||||
|
||||
@@ -517,7 +517,8 @@ public class GLSMRedirector {
|
||||
.add("glFramebufferRenderbuffer")
|
||||
.add("glIsFramebuffer")
|
||||
.add("glIsRenderbuffer")
|
||||
.add("glBindBufferBase");
|
||||
.add("glBindBufferBase")
|
||||
.add("glBindBufferRange");
|
||||
final var gl31 = RedirectMap.newMap()
|
||||
.add("glDrawElementsInstanced")
|
||||
.add("glDrawArraysInstanced")
|
||||
@@ -722,6 +723,7 @@ public class GLSMRedirector {
|
||||
);
|
||||
final var uniformBufferObject = RedirectMap.newMap()
|
||||
.add("glBindBufferBase")
|
||||
.add("glBindBufferRange")
|
||||
.add("glGetUniformBlockIndex")
|
||||
.add("glUniformBlockBinding");
|
||||
methodRedirects.put(ARBUniformBufferObject, uniformBufferObject);
|
||||
|
||||
+150
-4
@@ -4,12 +4,16 @@ import com.gtnewhorizon.gtnhlib.client.renderer.DirectTessellator;
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.vertex.DefaultVertexFormat;
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.vertex.VertexFlags;
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.vertex.VertexFormat;
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.vertex.VertexFormatElement;
|
||||
import com.gtnewhorizons.angelica.config.SystemProperties;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.QuadConverter;
|
||||
import com.gtnewhorizons.angelica.glsm.RenderSystem;
|
||||
import com.gtnewhorizons.angelica.glsm.ffp.FfpExtendedAttribs;
|
||||
import com.gtnewhorizons.angelica.glsm.ffp.ShaderManager;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.GLSMConfig;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.GLSMHooks;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.ImmediateExtendedAttribHandler;
|
||||
import com.gtnewhorizons.angelica.glsm.profiling.Tracy;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
@@ -22,6 +26,7 @@ import java.nio.ByteBuffer;
|
||||
import static com.gtnewhorizon.gtnhlib.bytebuf.MemoryUtilities.memAddress0;
|
||||
import static org.joml.Math.clamp;
|
||||
import static com.gtnewhorizon.gtnhlib.bytebuf.MemoryUtilities.memAlloc;
|
||||
import static com.gtnewhorizon.gtnhlib.bytebuf.MemoryUtilities.memCopy;
|
||||
import static com.gtnewhorizon.gtnhlib.bytebuf.MemoryUtilities.memFree;
|
||||
|
||||
/**
|
||||
@@ -36,6 +41,7 @@ public class TessellatorStreamingDrawer {
|
||||
private static final Tracy.ZoneId Z_SDL_STREAM_DRAW = Tracy.zoneId("sdlStreamDraw", Tracy.COLOR_FFP);
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger("TessellatorStreamingDrawer");
|
||||
|
||||
private static final int FORMAT_COUNT = VertexFlags.BITSET_SIZE; // 16
|
||||
|
||||
private static PersistentStreamingBuffer persistentBuffer;
|
||||
@@ -44,6 +50,12 @@ public class TessellatorStreamingDrawer {
|
||||
private static final int[] persistentVAOs = new int[FORMAT_COUNT];
|
||||
private static final int[] orphanVAOs = new int[FORMAT_COUNT];
|
||||
|
||||
private static final int[] extendedPersistentVAOs = new int[FORMAT_COUNT];
|
||||
private static final int[] extendedOrphanVAOs = new int[FORMAT_COUNT];
|
||||
private static ByteBuffer extScratch;
|
||||
private static long extScratchAddress;
|
||||
private static int extScratchCapacity;
|
||||
|
||||
private static ByteBuffer repackBuffer;
|
||||
private static long repackAddress;
|
||||
private static int repackCapacity;
|
||||
@@ -153,7 +165,25 @@ public class TessellatorStreamingDrawer {
|
||||
repackBuffer.position(0);
|
||||
repackBuffer.limit((int)(writePtr - repackAddress));
|
||||
|
||||
uploadAndDraw(repackBuffer, effectiveFlags, format, vertexSize, tess.drawMode, vertexCount);
|
||||
final ImmediateExtendedAttribHandler extHandler = GLSMHooks.immediateExtendedHandler;
|
||||
final int extPrim = extHandler == null ? 0 : ImmediateExtendedAttribHandler.extPrimVerts(tess.drawMode, vertexCount);
|
||||
final boolean wantsExt = extHandler != null && extHandler.wantsExtended();
|
||||
final boolean doExt = extPrim != 0 && tess.hasTexture && wantsExt;
|
||||
if (doExt) {
|
||||
final int combinedStride = vertexSize + ImmediateExtendedAttribHandler.EXT_STRIDE;
|
||||
final int combinedBytes = vertexCount * combinedStride;
|
||||
ensureExtScratch(combinedBytes);
|
||||
interleaveBase(repackAddress, extScratchAddress, vertexCount, vertexSize, combinedStride);
|
||||
// format expansion backfills a normal into rawBuffer, so trust effectiveFlags rather than tess.hasNormals
|
||||
final int normalIndex = (effectiveFlags & VertexFlags.NORMAL_BIT) != 0 ? ImmediateExtendedAttribHandler.RAW_NORMAL_INDEX : -1;
|
||||
extHandler.build(tess.rawBuffer, vertexCount, extPrim, normalIndex, extScratchAddress + vertexSize, combinedStride);
|
||||
extScratch.position(0);
|
||||
extScratch.limit(combinedBytes);
|
||||
uploadAndDrawExtended(extScratch, effectiveFlags, format, combinedStride, tess.drawMode, vertexCount);
|
||||
shrinkExtScratchIfOversized(combinedBytes);
|
||||
} else {
|
||||
uploadAndDraw(repackBuffer, effectiveFlags, format, vertexSize, tess.drawMode, vertexCount);
|
||||
}
|
||||
} finally {
|
||||
if (locked) GLStateManager.releaseDrawLock();
|
||||
}
|
||||
@@ -184,6 +214,7 @@ public class TessellatorStreamingDrawer {
|
||||
final ByteBuffer buffer = dt.getWriteBuffer();
|
||||
final int vertexSize = format.getVertexSize();
|
||||
|
||||
if (tryExtendedPacked(buffer, flags, format, vertexSize, drawMode, vertexCount)) return;
|
||||
uploadAndDraw(buffer, flags, format, vertexSize, drawMode, vertexCount);
|
||||
}
|
||||
|
||||
@@ -197,9 +228,37 @@ public class TessellatorStreamingDrawer {
|
||||
public static void drawPacked(ByteBuffer packedData, int drawMode, int flags, int vertexCount) {
|
||||
final VertexFormat format = DefaultVertexFormat.ALL_FORMATS[flags];
|
||||
final int vertexSize = format.getVertexSize();
|
||||
if (tryExtendedPacked(packedData, flags, format, vertexSize, drawMode, vertexCount)) return;
|
||||
uploadAndDraw(packedData, flags, format, vertexSize, drawMode, vertexCount);
|
||||
}
|
||||
|
||||
private static boolean tryExtendedPacked(ByteBuffer packed, int flags, VertexFormat format, int vertexSize, int drawMode, int vertexCount) {
|
||||
final ImmediateExtendedAttribHandler extHandler = GLSMHooks.immediateExtendedHandler;
|
||||
if (extHandler == null || !extHandler.wantsExtended()) return false;
|
||||
final int extPrim = ImmediateExtendedAttribHandler.extPrimVerts(drawMode, vertexCount);
|
||||
if (extPrim == 0 || !format.hasTexture()) return false;
|
||||
|
||||
final long srcBase = memAddress0(packed) + packed.position();
|
||||
final int texOffset = ImmediateExtendedAttribHandler.texOffset(format);
|
||||
final int normalOffset = ImmediateExtendedAttribHandler.normalOffset(format);
|
||||
final int combinedStride = vertexSize + ImmediateExtendedAttribHandler.EXT_STRIDE;
|
||||
final int combinedBytes = vertexCount * combinedStride;
|
||||
ensureExtScratch(combinedBytes);
|
||||
interleaveBase(srcBase, extScratchAddress, vertexCount, vertexSize, combinedStride);
|
||||
extHandler.buildPacked(srcBase, vertexSize, 0, texOffset, normalOffset, vertexCount, extPrim, extScratchAddress + vertexSize, combinedStride);
|
||||
extScratch.position(0);
|
||||
extScratch.limit(combinedBytes);
|
||||
uploadAndDrawExtended(extScratch, flags, format, combinedStride, drawMode, vertexCount);
|
||||
shrinkExtScratchIfOversized(combinedBytes);
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void interleaveBase(long src, long dst, int vertexCount, int vertexSize, int combinedStride) {
|
||||
for (int i = 0; i < vertexCount; i++) {
|
||||
memCopy(src + (long) i * vertexSize, dst + (long) i * combinedStride, vertexSize);
|
||||
}
|
||||
}
|
||||
|
||||
private static String cachedDebugInfo = "Stream: not initialized";
|
||||
private static long lastDebugUpdateNanos;
|
||||
private static final long DEBUG_UPDATE_INTERVAL_NS = 500_000_000L; // 500ms
|
||||
@@ -294,10 +353,89 @@ public class TessellatorStreamingDrawer {
|
||||
}
|
||||
|
||||
private static void drawWithQuadConversion(int drawMode, int firstVertex, int vertexCount) {
|
||||
if (drawMode == GL11.GL_QUADS) {
|
||||
QuadConverter.drawQuadsAsTriangles(firstVertex, vertexCount);
|
||||
FfpExtendedAttribs.beginInternalDraw();
|
||||
try {
|
||||
if (drawMode == GL11.GL_QUADS) {
|
||||
QuadConverter.drawQuadsAsTriangles(firstVertex, vertexCount);
|
||||
} else {
|
||||
GLStateManager.glDrawArrays(drawMode, firstVertex, vertexCount);
|
||||
}
|
||||
} finally {
|
||||
FfpExtendedAttribs.endInternalDraw();
|
||||
}
|
||||
}
|
||||
|
||||
private static void uploadAndDrawExtended(ByteBuffer combined, int flags, VertexFormat format, int combinedStride, int drawMode, int vertexCount) {
|
||||
ensureVAO(flags, format);
|
||||
ensureExtendedVAOs(flags, format);
|
||||
|
||||
int firstVertex = -1;
|
||||
|
||||
if (persistentBuffer != null) {
|
||||
firstVertex = persistentBuffer.upload(combined, combinedStride);
|
||||
}
|
||||
|
||||
if (firstVertex >= 0) {
|
||||
GLStateManager.glBindVertexArray(extendedPersistentVAOs[flags]);
|
||||
} else {
|
||||
GLStateManager.glDrawArrays(drawMode, firstVertex, vertexCount);
|
||||
GLStateManager.glBindVertexArray(extendedOrphanVAOs[flags]);
|
||||
orphanBuffers[flags].upload(combined);
|
||||
firstVertex = 0;
|
||||
}
|
||||
|
||||
drawWithQuadConversion(drawMode, firstVertex, vertexCount);
|
||||
GLStateManager.glBindVertexArray(0);
|
||||
}
|
||||
|
||||
private static void ensureExtendedVAOs(int flags, VertexFormat format) {
|
||||
if (extendedOrphanVAOs[flags] == 0) {
|
||||
extendedOrphanVAOs[flags] = GLStateManager.glGenVertexArrays();
|
||||
GLStateManager.glBindVertexArray(extendedOrphanVAOs[flags]);
|
||||
GLStateManager.glBindBuffer(GL15.GL_ARRAY_BUFFER, orphanBuffers[flags].getBufferId());
|
||||
setupExtendedBufferState(format);
|
||||
GLStateManager.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
|
||||
GLStateManager.glBindVertexArray(0);
|
||||
}
|
||||
|
||||
if (persistentBuffer != null && extendedPersistentVAOs[flags] == 0) {
|
||||
extendedPersistentVAOs[flags] = GLStateManager.glGenVertexArrays();
|
||||
GLStateManager.glBindVertexArray(extendedPersistentVAOs[flags]);
|
||||
GLStateManager.glBindBuffer(GL15.GL_ARRAY_BUFFER, persistentBuffer.getBufferId());
|
||||
setupExtendedBufferState(format);
|
||||
GLStateManager.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
|
||||
GLStateManager.glBindVertexArray(0);
|
||||
}
|
||||
}
|
||||
|
||||
private static void setupExtendedBufferState(VertexFormat format) {
|
||||
final int combinedStride = format.getVertexSize() + ImmediateExtendedAttribHandler.EXT_STRIDE;
|
||||
long offset = 0;
|
||||
for (final VertexFormatElement element : format.elementsArray) {
|
||||
element.setupBufferState(offset, combinedStride);
|
||||
offset += element.getByteSize();
|
||||
}
|
||||
ImmediateExtendedAttribHandler.setupExtAttribPointers(offset, combinedStride);
|
||||
}
|
||||
|
||||
private static void ensureExtScratch(int requiredBytes) {
|
||||
if (extScratch != null && requiredBytes <= extScratchCapacity) return;
|
||||
|
||||
int newCapacity = Math.max(0x4000, extScratchCapacity);
|
||||
while (newCapacity < requiredBytes) {
|
||||
newCapacity *= 2;
|
||||
}
|
||||
if (extScratch != null) memFree(extScratch);
|
||||
extScratch = memAlloc(newCapacity);
|
||||
extScratchAddress = memAddress0(extScratch);
|
||||
extScratchCapacity = newCapacity;
|
||||
}
|
||||
|
||||
private static void shrinkExtScratchIfOversized(int lastRequiredBytes) {
|
||||
if (extScratchCapacity > 0x20000 && lastRequiredBytes < (extScratchCapacity >> 3)) {
|
||||
memFree(extScratch);
|
||||
extScratchCapacity = 0x4000;
|
||||
extScratch = memAlloc(extScratchCapacity);
|
||||
extScratchAddress = memAddress0(extScratch);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -358,8 +496,16 @@ public class TessellatorStreamingDrawer {
|
||||
for (int i = 0; i < FORMAT_COUNT; i++) {
|
||||
if (persistentVAOs[i] != 0) { GLStateManager.glDeleteVertexArrays(persistentVAOs[i]); persistentVAOs[i] = 0; }
|
||||
if (orphanVAOs[i] != 0) { GLStateManager.glDeleteVertexArrays(orphanVAOs[i]); orphanVAOs[i] = 0; }
|
||||
if (extendedPersistentVAOs[i] != 0) { GLStateManager.glDeleteVertexArrays(extendedPersistentVAOs[i]); extendedPersistentVAOs[i] = 0; }
|
||||
if (extendedOrphanVAOs[i] != 0) { GLStateManager.glDeleteVertexArrays(extendedOrphanVAOs[i]); extendedOrphanVAOs[i] = 0; }
|
||||
if (orphanBuffers[i] != null) { orphanBuffers[i].destroy(); orphanBuffers[i] = null; }
|
||||
}
|
||||
if (extScratch != null) {
|
||||
memFree(extScratch);
|
||||
extScratch = null;
|
||||
extScratchAddress = 0;
|
||||
extScratchCapacity = 0;
|
||||
}
|
||||
if (persistentBuffer != null) {
|
||||
persistentBuffer.destroy();
|
||||
persistentBuffer = null;
|
||||
|
||||
@@ -61,13 +61,17 @@ public class NativeImage extends BufferedImage {
|
||||
// final int width = GL11.glGetTexLevelParameteri(GL11.GL_TEXTURE_2D, level, GL11.GL_TEXTURE_WIDTH);
|
||||
// final int height = GL11.glGetTexLevelParameteri(GL11.GL_TEXTURE_2D, level, GL11.GL_TEXTURE_HEIGHT);
|
||||
|
||||
final IntBuffer buffer = MemoryUtilities.memAllocInt(size);
|
||||
final int pixels = width * height;
|
||||
final IntBuffer buffer = MemoryUtilities.memAllocInt(pixels);
|
||||
|
||||
try {
|
||||
GLStateManager.glGetTexImage(GL11.GL_TEXTURE_2D, level, format.glFormat, GL12.GL_UNSIGNED_INT_8_8_8_8_REV, buffer);
|
||||
|
||||
int[] data = new int[size];
|
||||
buffer.get(data);
|
||||
int[] data = new int[pixels];
|
||||
buffer.get(data, 0, pixels);
|
||||
for (int i = 0; i < pixels; i++) {
|
||||
data[i] = swapRedBlue(data[i]);
|
||||
}
|
||||
setRGB(0, 0, width, height, data, 0, width);
|
||||
} finally {
|
||||
MemoryUtilities.memFree(buffer);
|
||||
@@ -90,7 +94,7 @@ public class NativeImage extends BufferedImage {
|
||||
}
|
||||
|
||||
public static int getR(int i) {
|
||||
return i >> 0 & 255;
|
||||
return i & 255;
|
||||
}
|
||||
|
||||
public static int getG(int i) {
|
||||
@@ -102,11 +106,15 @@ public class NativeImage extends BufferedImage {
|
||||
}
|
||||
|
||||
public int getPixelRGBA(int x, int y) {
|
||||
return getRGB(x, y);
|
||||
return swapRedBlue(getRGB(x, y));
|
||||
}
|
||||
|
||||
public void setPixelRGBA(int x, int y, int rgb) {
|
||||
setRGB(x, y, rgb);
|
||||
setRGB(x, y, swapRedBlue(rgb));
|
||||
}
|
||||
|
||||
private static int swapRedBlue(int c) {
|
||||
return (c & 0xFF00FF00) | ((c >>> 16) & 0xFF) | ((c & 0xFF) << 16);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,315 @@
|
||||
package com.gtnewhorizons.angelica.iris;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.ffp.FfpExtendedAttribs;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.ImmediateExtendedAttribHandler;
|
||||
import com.gtnewhorizons.angelica.rendering.items.ItemRenderListManager;
|
||||
import com.gtnewhorizons.angelica.rendering.tesr.TesrBatchRenderer;
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
|
||||
import net.coderbot.iris.Iris;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.texture.ITextureObject;
|
||||
import net.minecraft.client.renderer.texture.TextureMap;
|
||||
import net.coderbot.iris.vertices.IrisQuadView;
|
||||
import net.coderbot.iris.vertices.NormI8;
|
||||
import net.coderbot.iris.vertices.NormalHelper;
|
||||
import org.joml.Vector3f;
|
||||
|
||||
import static com.gtnewhorizon.gtnhlib.bytebuf.MemoryUtilities.memGetFloat;
|
||||
import static com.gtnewhorizon.gtnhlib.bytebuf.MemoryUtilities.memGetInt;
|
||||
import static com.gtnewhorizon.gtnhlib.bytebuf.MemoryUtilities.memPutFloat;
|
||||
import static com.gtnewhorizon.gtnhlib.bytebuf.MemoryUtilities.memPutInt;
|
||||
|
||||
/**
|
||||
* Supplies per-quad {@code mc_midTexCoord} + {@code at_tangent} for immediate-mode draws so parallax/POM shader packs
|
||||
* reconstruct sprite bounds correctly.
|
||||
*/
|
||||
public final class ImmediateExtendedAttribs implements ImmediateExtendedAttribHandler {
|
||||
|
||||
private static final int VERTEX_SIZE = 8;
|
||||
private static final int X = 0, Y = 1, Z = 2, U = 3, V = 4;
|
||||
|
||||
private static final float UV_EPS = 1.0e-5f;
|
||||
private static final float POM_SUPPRESS_EPS = 1.0e-4f;
|
||||
|
||||
private static final float POM_MAX_TILE_EXTENT = 0.125f;
|
||||
|
||||
private static final int WANTS_MID = 1;
|
||||
private static final int WANTS_TANGENT = 2;
|
||||
|
||||
private static final int NEUTRAL_TANGENT = NormI8.pack(1.0f, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
private static volatile int currentProgramWants = 0;
|
||||
|
||||
private static final Int2IntOpenHashMap programWantsExtCache = new Int2IntOpenHashMap();
|
||||
|
||||
public static void onProgramBound(int program) {
|
||||
if (program == 0) {
|
||||
currentProgramWants = 0;
|
||||
return;
|
||||
}
|
||||
int wants;
|
||||
if (programWantsExtCache.containsKey(program)) {
|
||||
wants = programWantsExtCache.get(program);
|
||||
} else {
|
||||
wants = 0;
|
||||
if (GLStateManager.glGetAttribLocation(program, "mc_midTexCoord") >= 0) wants |= WANTS_MID;
|
||||
if (GLStateManager.glGetAttribLocation(program, "at_tangent") >= 0) wants |= WANTS_TANGENT;
|
||||
programWantsExtCache.put(program, wants);
|
||||
}
|
||||
currentProgramWants = wants;
|
||||
}
|
||||
|
||||
public static void onProgramDeleted(int program) {
|
||||
programWantsExtCache.remove(program);
|
||||
}
|
||||
|
||||
public static void onShaderPackChanged() {
|
||||
currentProgramWants = 0;
|
||||
programWantsExtCache.clear();
|
||||
ItemRenderListManager.clearCache();
|
||||
FfpExtendedAttribs.reset();
|
||||
TesrBatchRenderer.INSTANCE.clearRetained();
|
||||
}
|
||||
|
||||
private final Vector3f normal = new Vector3f();
|
||||
private final QuadView quad = new QuadView();
|
||||
private final PackedQuadView packedQuad = new PackedQuadView();
|
||||
|
||||
private boolean limitTileExtent = true;
|
||||
private boolean needTangent = true;
|
||||
|
||||
@Override
|
||||
public boolean wantsExtended() {
|
||||
return Iris.enabled && currentProgramWants != 0 && GLStateManager.getActiveProgram() != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean wantsTangent() {
|
||||
return (currentProgramWants & WANTS_TANGENT) != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean wantsExtendedCapture() {
|
||||
return Iris.enabled && Iris.getCurrentPack().isPresent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void build(int[] rawBuffer, int vertexCount, int vertsPerPrim, int normalIntIndex, long dstAddr, int dstStride) {
|
||||
final boolean smooth = normalIntIndex >= 0;
|
||||
limitTileExtent = isAtlasNotBound();
|
||||
needTangent = wantsTangent();
|
||||
long ptr = dstAddr;
|
||||
for (int v = 0; v < vertexCount; v += vertsPerPrim) {
|
||||
quad.setup(rawBuffer, v, normalIntIndex);
|
||||
if (vertsPerPrim == 4) {
|
||||
writeQuadExt(quad, ptr, dstStride);
|
||||
} else {
|
||||
writeTriExt(quad, smooth, ptr, dstStride);
|
||||
}
|
||||
ptr += (long) dstStride * vertsPerPrim;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void buildPacked(long srcBase, int stride, int posOffset, int texOffset, int normalOffset,
|
||||
int vertexCount, int vertsPerPrim, long dstAddr, int dstStride) {
|
||||
final boolean smooth = normalOffset >= 0;
|
||||
limitTileExtent = isAtlasNotBound();
|
||||
needTangent = wantsTangent();
|
||||
long ptr = dstAddr;
|
||||
for (int v = 0; v < vertexCount; v += vertsPerPrim) {
|
||||
packedQuad.setup(srcBase + (long) v * stride, stride, posOffset, texOffset, normalOffset);
|
||||
if (vertsPerPrim == 4) {
|
||||
writeQuadExt(packedQuad, ptr, dstStride);
|
||||
} else {
|
||||
writeTriExt(packedQuad, smooth, ptr, dstStride);
|
||||
}
|
||||
ptr += (long) dstStride * vertsPerPrim;
|
||||
}
|
||||
}
|
||||
|
||||
private void writeQuadExt(IrisQuadView quad, long dstAddr, int dstStride) {
|
||||
final float u0 = quad.u(0), u1 = quad.u(1), u2 = quad.u(2), u3 = quad.u(3);
|
||||
final float v0 = quad.v(0), v1 = quad.v(1), v2 = quad.v(2), v3 = quad.v(3);
|
||||
|
||||
final float umin = min4(u0, u1, u2, u3), umax = max4(u0, u1, u2, u3);
|
||||
final float vmin = min4(v0, v1, v2, v3), vmax = max4(v0, v1, v2, v3);
|
||||
|
||||
final boolean tileable = formsRectAxisQuad(u0, u1, u2, u3) && formsRectAxisQuad(v0, v1, v2, v3)
|
||||
&& (!limitTileExtent || ((umax - umin) <= POM_MAX_TILE_EXTENT && (vmax - vmin) <= POM_MAX_TILE_EXTENT));
|
||||
|
||||
final int tangent;
|
||||
if (needTangent) {
|
||||
NormalHelper.computeFaceNormal(normal, quad);
|
||||
tangent = NormalHelper.computeTangent(normal.x, normal.y, normal.z, quad);
|
||||
} else {
|
||||
tangent = NEUTRAL_TANGENT;
|
||||
}
|
||||
|
||||
long ptr = dstAddr;
|
||||
if (!tileable) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
memPutFloat(ptr, quad.u(i) + POM_SUPPRESS_EPS);
|
||||
memPutFloat(ptr + 4, quad.v(i) + POM_SUPPRESS_EPS);
|
||||
memPutInt(ptr + 8, tangent);
|
||||
ptr += dstStride;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
final float midU = (umin + umax) * 0.5f;
|
||||
final float midV = (vmin + vmax) * 0.5f;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
memPutFloat(ptr, midU);
|
||||
memPutFloat(ptr + 4, midV);
|
||||
memPutInt(ptr + 8, tangent);
|
||||
ptr += dstStride;
|
||||
}
|
||||
}
|
||||
|
||||
private void writeTriExt(NormalSource view, boolean smooth, long dstAddr, int dstStride) {
|
||||
final float u0 = view.u(0), u1 = view.u(1), u2 = view.u(2);
|
||||
final float v0 = view.v(0), v1 = view.v(1), v2 = view.v(2);
|
||||
|
||||
final float umin = Math.min(u0, Math.min(u1, u2)), umax = Math.max(u0, Math.max(u1, u2));
|
||||
final float vmin = Math.min(v0, Math.min(v1, v2)), vmax = Math.max(v0, Math.max(v1, v2));
|
||||
|
||||
final boolean tileable = formsRectAxis(u0, u1, u2) && formsRectAxis(v0, v1, v2)
|
||||
&& (!limitTileExtent || ((umax - umin) <= POM_MAX_TILE_EXTENT && (vmax - vmin) <= POM_MAX_TILE_EXTENT));
|
||||
if (!tileable) {
|
||||
writeTriSuppressed(view, dstAddr, dstStride);
|
||||
return;
|
||||
}
|
||||
|
||||
final float midU = (umin + umax) * 0.5f;
|
||||
final float midV = (vmin + vmax) * 0.5f;
|
||||
|
||||
long ptr = dstAddr;
|
||||
if (smooth) {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
final int n = view.packedNormal(i);
|
||||
final int tangent = needTangent
|
||||
? NormalHelper.computeTangentSmooth(NormI8.unpackX(n), NormI8.unpackY(n), NormI8.unpackZ(n), view)
|
||||
: NEUTRAL_TANGENT;
|
||||
memPutFloat(ptr, midU);
|
||||
memPutFloat(ptr + 4, midV);
|
||||
memPutInt(ptr + 8, tangent);
|
||||
ptr += dstStride;
|
||||
}
|
||||
} else {
|
||||
final int tangent;
|
||||
if (needTangent) {
|
||||
NormalHelper.computeFaceNormalTri(normal, view);
|
||||
tangent = NormalHelper.computeTangent(normal.x, normal.y, normal.z, view);
|
||||
} else {
|
||||
tangent = NEUTRAL_TANGENT;
|
||||
}
|
||||
for (int i = 0; i < 3; i++) {
|
||||
memPutFloat(ptr, midU);
|
||||
memPutFloat(ptr + 4, midV);
|
||||
memPutInt(ptr + 8, tangent);
|
||||
ptr += dstStride;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void writeTriSuppressed(NormalSource view, long dstAddr, int dstStride) {
|
||||
final int tangent;
|
||||
if (needTangent) {
|
||||
NormalHelper.computeFaceNormalTri(normal, view);
|
||||
tangent = NormalHelper.computeTangent(normal.x, normal.y, normal.z, view);
|
||||
} else {
|
||||
tangent = NEUTRAL_TANGENT;
|
||||
}
|
||||
long ptr = dstAddr;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
memPutFloat(ptr, view.u(i) + POM_SUPPRESS_EPS);
|
||||
memPutFloat(ptr + 4, view.v(i) + POM_SUPPRESS_EPS);
|
||||
memPutInt(ptr + 8, tangent);
|
||||
ptr += dstStride;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean formsRectAxis(float a, float b, float c) {
|
||||
final boolean ab = Math.abs(a - b) <= UV_EPS;
|
||||
final boolean ac = Math.abs(a - c) <= UV_EPS;
|
||||
final boolean bc = Math.abs(b - c) <= UV_EPS;
|
||||
return (ab || ac || bc) && !(ab && ac && bc);
|
||||
}
|
||||
|
||||
private static boolean formsRectAxisQuad(float a, float b, float c, float d) {
|
||||
final float lo = min4(a, b, c, d), hi = max4(a, b, c, d);
|
||||
if (hi - lo <= UV_EPS) return false;
|
||||
return atEdge(a, lo, hi) && atEdge(b, lo, hi) && atEdge(c, lo, hi) && atEdge(d, lo, hi);
|
||||
}
|
||||
|
||||
private static boolean atEdge(float x, float lo, float hi) {
|
||||
return Math.abs(x - lo) <= UV_EPS || Math.abs(x - hi) <= UV_EPS;
|
||||
}
|
||||
|
||||
private static boolean isAtlasNotBound() {
|
||||
final int tex = GLStateManager.getBoundTextureForServerState(0);
|
||||
if (tex <= 0) return true;
|
||||
final Minecraft mc = Minecraft.getMinecraft();
|
||||
if (mc == null || mc.getTextureManager() == null) return true;
|
||||
final ITextureObject blocks = mc.getTextureManager().getTexture(TextureMap.locationBlocksTexture);
|
||||
if (blocks != null && blocks.getGlTextureId() == tex) return false;
|
||||
final ITextureObject items = mc.getTextureManager().getTexture(TextureMap.locationItemsTexture);
|
||||
return items == null || items.getGlTextureId() != tex;
|
||||
}
|
||||
|
||||
private static float min4(float a, float b, float c, float d) {
|
||||
return Math.min(Math.min(a, b), Math.min(c, d));
|
||||
}
|
||||
|
||||
private static float max4(float a, float b, float c, float d) {
|
||||
return Math.max(Math.max(a, b), Math.max(c, d));
|
||||
}
|
||||
|
||||
private interface NormalSource extends IrisQuadView {
|
||||
int packedNormal(int i);
|
||||
}
|
||||
|
||||
private static final class QuadView implements NormalSource {
|
||||
private int[] raw;
|
||||
private int base;
|
||||
private int normalIndex;
|
||||
|
||||
void setup(int[] raw, int firstVertex, int normalIndex) {
|
||||
this.raw = raw;
|
||||
this.base = firstVertex;
|
||||
this.normalIndex = normalIndex;
|
||||
}
|
||||
|
||||
@Override public float x(int i) { return Float.intBitsToFloat(raw[(base + i) * VERTEX_SIZE + X]); }
|
||||
@Override public float y(int i) { return Float.intBitsToFloat(raw[(base + i) * VERTEX_SIZE + Y]); }
|
||||
@Override public float z(int i) { return Float.intBitsToFloat(raw[(base + i) * VERTEX_SIZE + Z]); }
|
||||
@Override public float u(int i) { return Float.intBitsToFloat(raw[(base + i) * VERTEX_SIZE + U]); }
|
||||
@Override public float v(int i) { return Float.intBitsToFloat(raw[(base + i) * VERTEX_SIZE + V]); }
|
||||
@Override public int packedNormal(int i) { return raw[(base + i) * VERTEX_SIZE + normalIndex]; }
|
||||
}
|
||||
|
||||
private static final class PackedQuadView implements NormalSource {
|
||||
private long base;
|
||||
private int stride;
|
||||
private int posOffset;
|
||||
private int texOffset;
|
||||
private int normalOffset;
|
||||
|
||||
void setup(long base, int stride, int posOffset, int texOffset, int normalOffset) {
|
||||
this.base = base;
|
||||
this.stride = stride;
|
||||
this.posOffset = posOffset;
|
||||
this.texOffset = texOffset;
|
||||
this.normalOffset = normalOffset;
|
||||
}
|
||||
|
||||
@Override public float x(int i) { return memGetFloat(base + (long) i * stride + posOffset); }
|
||||
@Override public float y(int i) { return memGetFloat(base + (long) i * stride + posOffset + 4); }
|
||||
@Override public float z(int i) { return memGetFloat(base + (long) i * stride + posOffset + 8); }
|
||||
@Override public float u(int i) { return memGetFloat(base + (long) i * stride + texOffset); }
|
||||
@Override public float v(int i) { return memGetFloat(base + (long) i * stride + texOffset + 4); }
|
||||
@Override public int packedNormal(int i) { return memGetInt(base + (long) i * stride + normalOffset); }
|
||||
}
|
||||
}
|
||||
@@ -67,6 +67,10 @@ public class IrisGLSMBridge {
|
||||
StateUpdateNotifiers.colorModulatorNotifier = listener -> colorModulatorListener = listener;
|
||||
}
|
||||
|
||||
public static void installImmediateExtendedHandler() {
|
||||
GLSMHooks.immediateExtendedHandler = new ImmediateExtendedAttribs();
|
||||
}
|
||||
|
||||
public static void installPostTransformHook() {
|
||||
if (GLSMHooks.postTransformProcessor != null) return;
|
||||
GLSMHooks.postTransformProcessor = new ShaderTransformPostProcessor() {
|
||||
@@ -298,6 +302,14 @@ public class IrisGLSMBridge {
|
||||
}
|
||||
});
|
||||
|
||||
GLSMHooks.PROGRAM_CHANGE.addListener(event -> {
|
||||
if (Iris.enabled && event.postBind) {
|
||||
ImmediateExtendedAttribs.onProgramBound(event.newProgram);
|
||||
}
|
||||
});
|
||||
|
||||
GLSMHooks.PROGRAM_DELETE.addListener(event -> ImmediateExtendedAttribs.onProgramDeleted(event.program));
|
||||
|
||||
GLSMHooks.PROGRAM_CHANGE.addListener(event -> {
|
||||
if (!Iris.enabled) return;
|
||||
if (event.postBind) return;
|
||||
|
||||
@@ -97,6 +97,12 @@ import net.coderbot.iris.client.IrisDebugScreenHandler;
|
||||
|
||||
public final class ClientProxy extends CommonProxy {
|
||||
|
||||
/**
|
||||
* So you don't need to be in a dev env to have access to the commands.
|
||||
* Do not commit with this set to true.
|
||||
*/
|
||||
private static final boolean FORCE_DEBUG_MODE = false;
|
||||
|
||||
public static BlockError blockError;
|
||||
public static final ManagedEnum<AnimationMode> animationsMode = new ManagedEnum<>(AnimationMode.VISIBLE_ONLY);
|
||||
private static final Logger LOGGER = LogManager.getLogger("Angelica");
|
||||
@@ -136,6 +142,7 @@ public final class ClientProxy extends CommonProxy {
|
||||
ModelRegistry.registerModid(MOD_ID);
|
||||
blockError = new BlockError();
|
||||
if (AngelicaConfig.enableIris) {
|
||||
IrisGLSMBridge.installImmediateExtendedHandler();
|
||||
Iris.warmupShaderTransforms();
|
||||
}
|
||||
}
|
||||
@@ -190,7 +197,7 @@ public final class ClientProxy extends CommonProxy {
|
||||
}
|
||||
|
||||
// Debug tooling
|
||||
if (!AngelicaClientTweaker.isObfEnv()) {
|
||||
if (FORCE_DEBUG_MODE || !AngelicaClientTweaker.isObfEnv()) {
|
||||
ClientCommandHandler.instance.registerCommand(new AngelicaCommand());
|
||||
|
||||
FMLCommonHandler.instance().bus().register(FlybyRunner.INSTANCE);
|
||||
|
||||
+2
@@ -45,6 +45,7 @@ import com.gtnewhorizons.angelica.compat.cubicchunks.CubicChunksAPI;
|
||||
import com.gtnewhorizons.angelica.dynamiclights.DynamicLights;
|
||||
import com.gtnewhorizons.angelica.dynamiclights.IDynamicLightWorldRenderer;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.ffp.FfpExtendedAttribs;
|
||||
import com.gtnewhorizons.angelica.glsm.profiling.Tracy;
|
||||
import com.gtnewhorizons.angelica.mixins.interfaces.ITileEntityBoundingBoxCache;
|
||||
import com.gtnewhorizons.angelica.mixins.interfaces.OverridesShouldRenderInPass;
|
||||
@@ -168,6 +169,7 @@ public class CeleritasWorldRenderer extends SimpleWorldRenderer<WorldClient, Ang
|
||||
TesrBatchRenderer.INSTANCE.clearRetained();
|
||||
ModelPartBatcher.INSTANCE.clear();
|
||||
GpuCulling.onWorldUnload();
|
||||
FfpExtendedAttribs.reset();
|
||||
BopFogBlend.invalidate();
|
||||
FogBiomeCache.invalidate();
|
||||
super.unloadWorld();
|
||||
|
||||
+77
-6
@@ -31,7 +31,11 @@ import com.gtnewhorizon.gtnhlib.client.renderer.vao.IVertexArrayObject;
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.vao.IndexBuffer;
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.vao.VAOManager;
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.vertex.DefaultVertexFormat;
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.vertex.VertexFormat;
|
||||
import com.gtnewhorizons.angelica.config.AngelicaConfig;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.GLSMHooks;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.ImmediateExtendedAttribHandler;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap;
|
||||
import lombok.Data;
|
||||
@@ -39,6 +43,13 @@ import lombok.NoArgsConstructor;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.resources.IReloadableResourceManager;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL15;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import static com.gtnewhorizon.gtnhlib.bytebuf.MemoryUtilities.memAddress0;
|
||||
import static com.gtnewhorizon.gtnhlib.bytebuf.MemoryUtilities.memCalloc;
|
||||
import static com.gtnewhorizon.gtnhlib.bytebuf.MemoryUtilities.memFree;
|
||||
|
||||
public class ItemRenderListManager {
|
||||
// Least used element is at position 0. This is in theory slightly faster.
|
||||
@@ -102,18 +113,21 @@ public class ItemRenderListManager {
|
||||
public static void registerReloadListener(){
|
||||
IReloadableResourceManager resourceManager = (IReloadableResourceManager) Minecraft.getMinecraft()
|
||||
.getResourceManager();
|
||||
resourceManager.registerReloadListener(_ -> {
|
||||
for (CachedVBO value : vboCache.values()) {
|
||||
value.delete();
|
||||
}
|
||||
vboCache.clear();
|
||||
});
|
||||
resourceManager.registerReloadListener(_ -> clearCache());
|
||||
}
|
||||
|
||||
public static void clearCache() {
|
||||
for (CachedVBO value : vboCache.values()) {
|
||||
value.delete();
|
||||
}
|
||||
vboCache.clear();
|
||||
}
|
||||
|
||||
public static final class CachedVBO {
|
||||
private final IVertexArrayObject vertexBuffer;
|
||||
private final IndexBuffer ebo;
|
||||
private int expiry;
|
||||
private int extVbo = 0;
|
||||
|
||||
public CachedVBO() {
|
||||
this.ebo = new IndexBuffer();
|
||||
@@ -126,6 +140,59 @@ public class ItemRenderListManager {
|
||||
|
||||
private void allocate(DirectTessellator tessellator) {
|
||||
tessellator.allocateToVBO(vertexBuffer, ebo);
|
||||
attachExtAttribs(tessellator);
|
||||
}
|
||||
|
||||
private void attachExtAttribs(DirectTessellator tessellator) {
|
||||
final ImmediateExtendedAttribHandler handler = GLSMHooks.immediateExtendedHandler;
|
||||
final VertexFormat format = tessellator.getVertexFormat();
|
||||
final int vertexCount = tessellator.getVertexCount();
|
||||
final int extPrim = handler == null ? 0 : ImmediateExtendedAttribHandler.extPrimVerts(tessellator.getDrawMode(), vertexCount);
|
||||
final boolean capture = handler != null && format != null && format.hasTexture()
|
||||
&& extPrim != 0
|
||||
&& (extVbo != 0 || handler.wantsExtendedCapture());
|
||||
if (!capture) {
|
||||
detachExtAttribs();
|
||||
return;
|
||||
}
|
||||
|
||||
final int extStride = ImmediateExtendedAttribHandler.EXT_STRIDE;
|
||||
final int stride = format.getVertexSize();
|
||||
final int texOffset = ImmediateExtendedAttribHandler.texOffset(format);
|
||||
final int normalOffset = ImmediateExtendedAttribHandler.normalOffset(format);
|
||||
final ByteBuffer packed = tessellator.getWriteBuffer();
|
||||
final long srcBase = memAddress0(packed) + packed.position();
|
||||
|
||||
final ByteBuffer ext = memCalloc(vertexCount, extStride);
|
||||
handler.buildPacked(srcBase, stride, 0, texOffset, normalOffset, vertexCount, extPrim, memAddress0(ext), extStride);
|
||||
|
||||
final boolean firstAttach = extVbo == 0;
|
||||
if (firstAttach) {
|
||||
extVbo = GLStateManager.glGenBuffers();
|
||||
}
|
||||
GLStateManager.glBindBuffer(GL15.GL_ARRAY_BUFFER, extVbo);
|
||||
ext.position(0).limit(vertexCount * extStride);
|
||||
GLStateManager.glBufferData(GL15.GL_ARRAY_BUFFER, ext, GL15.GL_STATIC_DRAW);
|
||||
GLStateManager.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
|
||||
memFree(ext);
|
||||
|
||||
if (firstAttach) {
|
||||
vertexBuffer.bind();
|
||||
GLStateManager.glBindBuffer(GL15.GL_ARRAY_BUFFER, extVbo);
|
||||
ImmediateExtendedAttribHandler.setupExtAttribPointers(0L, extStride);
|
||||
GLStateManager.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
|
||||
vertexBuffer.unbind();
|
||||
}
|
||||
}
|
||||
|
||||
private void detachExtAttribs() {
|
||||
if (extVbo == 0) return;
|
||||
vertexBuffer.bind();
|
||||
GLStateManager.glDisableVertexAttribArray(ImmediateExtendedAttribHandler.LOC_MID_TEX);
|
||||
GLStateManager.glDisableVertexAttribArray(ImmediateExtendedAttribHandler.LOC_TANGENT);
|
||||
vertexBuffer.unbind();
|
||||
GLStateManager.glDeleteBuffers(extVbo);
|
||||
extVbo = 0;
|
||||
}
|
||||
|
||||
private void render(int elapsedTicks) {
|
||||
@@ -136,6 +203,10 @@ public class ItemRenderListManager {
|
||||
private void delete() {
|
||||
vertexBuffer.delete();
|
||||
// EBO gets deleted by vertexBuffer.delete()
|
||||
if (extVbo != 0) {
|
||||
GLStateManager.glDeleteBuffers(extVbo);
|
||||
extVbo = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+37
@@ -2,6 +2,9 @@ package com.gtnewhorizons.angelica.rendering.tesr;
|
||||
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.vertex.VertexFlags;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.ImmediateExtendedAttribHandler;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.GLSMHooks;
|
||||
import com.gtnewhorizons.angelica.glsm.ffp.FfpExtendedAttribs;
|
||||
import com.gtnewhorizons.angelica.glsm.ffp.InstancedAttribs;
|
||||
import com.gtnewhorizons.angelica.glsm.ffp.VAOManager;
|
||||
import com.gtnewhorizons.angelica.glsm.streaming.OrphanStreamingBuffer;
|
||||
@@ -17,6 +20,8 @@ import org.lwjgl.opengl.GL15;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import static com.gtnewhorizon.gtnhlib.bytebuf.MemoryUtilities.memAddress0;
|
||||
import static com.gtnewhorizon.gtnhlib.bytebuf.MemoryUtilities.memCalloc;
|
||||
import static com.gtnewhorizon.gtnhlib.bytebuf.MemoryUtilities.memFree;
|
||||
import static com.gtnewhorizon.gtnhlib.client.renderer.cel.util.ModelQuadUtil.COLOR_INDEX;
|
||||
import static com.gtnewhorizon.gtnhlib.client.renderer.cel.util.ModelQuadUtil.NORMAL_INDEX;
|
||||
import static com.gtnewhorizon.gtnhlib.client.renderer.cel.util.ModelQuadUtil.TEX_X_INDEX;
|
||||
@@ -34,6 +39,7 @@ final class InstancedTemplateRenderer {
|
||||
private static final class TemplateMesh {
|
||||
int vao;
|
||||
int vbo;
|
||||
int extVbo;
|
||||
int vertexCount;
|
||||
int drawMode;
|
||||
long lastUsedMs;
|
||||
@@ -96,6 +102,10 @@ final class InstancedTemplateRenderer {
|
||||
int draws = 0;
|
||||
long recordOffset = ringBase;
|
||||
final int ringId = uploadBufferId;
|
||||
final ImmediateExtendedAttribHandler extHandler = GLSMHooks.immediateExtendedHandler;
|
||||
if (extHandler != null && extHandler.wantsExtended()) {
|
||||
FfpExtendedAttribs.setNeutralCurrentValues();
|
||||
}
|
||||
GLStateManager.instancedFfpDrawActive = true;
|
||||
for (int b = 0, n = liveBuckets.size(); b < n; b++) {
|
||||
final Bucket bucket = liveBuckets.get(b);
|
||||
@@ -179,6 +189,13 @@ final class InstancedTemplateRenderer {
|
||||
GLStateManager.glVertexAttribPointer(4, 3, GL11.GL_BYTE, true, TEMPLATE_STRIDE, NORMAL_INDEX * 4L);
|
||||
GLStateManager.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
|
||||
|
||||
mesh.extVbo = buildExt(template);
|
||||
if (mesh.extVbo != 0) {
|
||||
GLStateManager.glBindBuffer(GL15.GL_ARRAY_BUFFER, mesh.extVbo);
|
||||
ImmediateExtendedAttribHandler.setupExtAttribPointers(0L, ImmediateExtendedAttribHandler.EXT_STRIDE);
|
||||
GLStateManager.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
|
||||
}
|
||||
|
||||
for (int loc = InstancedAttribs.LOC_MATRIX_COL0; loc <= InstancedAttribs.LOC_LIGHTMAP; loc++) {
|
||||
GLStateManager.glEnableVertexAttribArray(loc);
|
||||
GLStateManager.glVertexAttribDivisor(loc, 1);
|
||||
@@ -188,6 +205,25 @@ final class InstancedTemplateRenderer {
|
||||
return mesh;
|
||||
}
|
||||
|
||||
private static int buildExt(TemplateBuffer template) {
|
||||
final ImmediateExtendedAttribHandler handler = GLSMHooks.immediateExtendedHandler;
|
||||
if (handler == null || !handler.wantsExtendedCapture()) return 0;
|
||||
final int extPrim = ImmediateExtendedAttribHandler.extPrimVerts(template.drawMode, template.vertexCount);
|
||||
if (extPrim == 0) return 0;
|
||||
|
||||
final int extStride = ImmediateExtendedAttribHandler.EXT_STRIDE;
|
||||
final ByteBuffer ext = memCalloc(template.vertexCount, extStride);
|
||||
handler.build(template.data, template.vertexCount, extPrim,
|
||||
ImmediateExtendedAttribHandler.RAW_NORMAL_INDEX, memAddress0(ext), extStride);
|
||||
|
||||
final int extVbo = GLStateManager.glGenBuffers();
|
||||
GLStateManager.glBindBuffer(GL15.GL_ARRAY_BUFFER, extVbo);
|
||||
ext.position(0).limit(template.vertexCount * extStride);
|
||||
GLStateManager.glBufferData(GL15.GL_ARRAY_BUFFER, ext, GL15.GL_STATIC_DRAW);
|
||||
memFree(ext);
|
||||
return extVbo;
|
||||
}
|
||||
|
||||
void endFrame() {
|
||||
if (ringUsedThisFrame && persistentRing != null) {
|
||||
persistentRing.postDraw();
|
||||
@@ -215,6 +251,7 @@ final class InstancedTemplateRenderer {
|
||||
|
||||
private static void delete(TemplateMesh mesh) {
|
||||
GLStateManager.glDeleteBuffers(mesh.vbo);
|
||||
if (mesh.extVbo != 0) GLStateManager.glDeleteBuffers(mesh.extVbo);
|
||||
GLStateManager.glDeleteVertexArrays(mesh.vao);
|
||||
}
|
||||
|
||||
|
||||
@@ -250,8 +250,8 @@ public class ColorizeBlock {
|
||||
}
|
||||
colorMap = wrapBlockMap(colorMap);
|
||||
for (String idString : idList.split("\\s+")) {
|
||||
BlockStateMatcher blockMatcher = BlockAPI.createMatcher(new PropertiesFile(logger, resource), idString);
|
||||
if (blockMatcher != null) {
|
||||
for (BlockStateMatcher blockMatcher : BlockAPI
|
||||
.createMatchers(new PropertiesFile(logger, resource), idString)) {
|
||||
List<BlockStateMatcher> maps = blockColorMaps
|
||||
.computeIfAbsent(blockMatcher.getBlock(), k -> new ArrayList<>());
|
||||
blockMatcher.setData(colorMap);
|
||||
|
||||
@@ -13,6 +13,7 @@ import java.util.function.Consumer;
|
||||
|
||||
import com.github.bsideup.jabel.Desugar;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.client.resources.IResourcePack;
|
||||
import net.minecraft.util.IIcon;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.world.IBlockAccess;
|
||||
@@ -25,6 +26,7 @@ import com.prupe.mcpatcher.mal.block.RenderBlocksUtils;
|
||||
import com.prupe.mcpatcher.mal.block.RenderPassAPI;
|
||||
import com.prupe.mcpatcher.mal.resource.BlendMethod;
|
||||
import com.prupe.mcpatcher.mal.resource.ResourceList;
|
||||
import com.prupe.mcpatcher.mal.resource.ResourceLocationWithSource;
|
||||
import com.prupe.mcpatcher.mal.resource.TexturePackAPI;
|
||||
import com.prupe.mcpatcher.mal.resource.TexturePackChangeHandler;
|
||||
import com.prupe.mcpatcher.mal.tile.TileLoader;
|
||||
@@ -128,8 +130,14 @@ public class CTMUtils {
|
||||
logger.info("loading CTM overrides");
|
||||
newOverrides = new Overrides();
|
||||
if (MCPatcherForgeConfig.ConnectedTextures.standard || MCPatcherForgeConfig.ConnectedTextures.nonStandard) {
|
||||
for (ResourceLocation resource : ResourceList.getInstance()
|
||||
.listResources(TexturePackAPI.MCPATCHER_SUBDIR + "ctm", ".properties", true)) {
|
||||
final List<ResourceLocation> ctmResources = new ArrayList<>();
|
||||
for (String subdir : new String[] { TexturePackAPI.MCPATCHER_SUBDIR, TexturePackAPI.OPTIFINE_SUBDIR }) {
|
||||
ctmResources.addAll(ResourceList.getInstance()
|
||||
.listResources(subdir + "ctm", ".properties", true));
|
||||
}
|
||||
final Map<String, Map<IResourcePack, Integer>> packPriority = new HashMap<>();
|
||||
ctmResources.sort((a, b) -> packPriorityOf(packPriority, b) - packPriorityOf(packPriority, a));
|
||||
for (ResourceLocation resource : ctmResources) {
|
||||
registerOverrideWithoutLock(newOverrides, TileOverride.create(resource, tileLoader));
|
||||
}
|
||||
for (Consumer<Overrides> callback : ctmRegistrationCallbacks) {
|
||||
@@ -294,9 +302,7 @@ public class CTMUtils {
|
||||
Set<String> matchingTiles = override.getMatchingTiles();
|
||||
if (!MCPatcherUtils.isNullOrEmpty(matchingTiles)) {
|
||||
for (String name : matchingTiles) {
|
||||
List<TileOverride> list = overrides.tile.computeIfAbsent(name, k -> new ArrayList<>());
|
||||
list.add(override);
|
||||
logger.fine("using %s for tile %s", override, name);
|
||||
registerTileWithoutLock(overrides, name, override);
|
||||
registered = true;
|
||||
}
|
||||
}
|
||||
@@ -306,6 +312,30 @@ public class CTMUtils {
|
||||
}
|
||||
}
|
||||
|
||||
private static void registerTileWithoutLock(Overrides overrides, String name, TileOverride override) {
|
||||
overrides.tile.computeIfAbsent(name, k -> new ArrayList<>())
|
||||
.add(override);
|
||||
logger.fine("using %s for tile %s", override, name);
|
||||
}
|
||||
|
||||
private static Map<IResourcePack, Integer> getPackPriority(String namespace) {
|
||||
final List<IResourcePack> packs = TexturePackAPI.getResourcePacks(namespace);
|
||||
final Map<IResourcePack, Integer> priority = new IdentityHashMap<>(packs.size());
|
||||
for (int i = 0; i < packs.size(); i++) {
|
||||
priority.put(packs.get(i), i);
|
||||
}
|
||||
return priority;
|
||||
}
|
||||
|
||||
|
||||
private static int packPriorityOf(Map<String, Map<IResourcePack, Integer>> byDomain, ResourceLocation resource) {
|
||||
if (!(resource instanceof ResourceLocationWithSource source)) return -1;
|
||||
final Integer rank = byDomain
|
||||
.computeIfAbsent(resource.getResourceDomain(), CTMUtils::getPackPriority)
|
||||
.get(source.getSource());
|
||||
return rank == null ? -1 : rank;
|
||||
}
|
||||
|
||||
private static void setBlankResourceWithoutLock() {
|
||||
RenderBlocksUtils.blankIcon = tileLoader.getIcon(RenderPassAPI.instance.getBlankResource());
|
||||
}
|
||||
|
||||
@@ -33,11 +33,15 @@ public abstract class TileOverride implements Comparable<TileOverride> {
|
||||
|
||||
private static final MCLogger logger = MCLogger.getLogger(MCLogger.Category.CONNECTED_TEXTURES, "CTM");
|
||||
|
||||
private static int nextRegistrationOrder;
|
||||
|
||||
public final PropertiesFile properties;
|
||||
private final String baseFilename;
|
||||
protected final TileLoader tileLoader;
|
||||
protected final int renderPass;
|
||||
private final int weight;
|
||||
private boolean lostScope;
|
||||
private final int registrationOrder = nextRegistrationOrder++;
|
||||
private final List<BlockStateMatcher> matchBlocks;
|
||||
private final Set<String> matchTiles;
|
||||
private final BlockFaceMatcher faceMatcher;
|
||||
@@ -274,19 +278,21 @@ public abstract class TileOverride implements Comparable<TileOverride> {
|
||||
// nothing
|
||||
} else if (token.matches("\\d+-\\d+")) {
|
||||
for (int id : MCPatcherUtils.parseIntegerList(token, 0, 65535)) {
|
||||
BlockStateMatcher matcher = BlockAPI.createMatcher(properties, id + defaultMetadata);
|
||||
if (matcher == null) {
|
||||
properties.warning("unknown block id %d", id);
|
||||
List<BlockStateMatcher> matchers = BlockAPI.createMatchers(properties, id + defaultMetadata);
|
||||
if (matchers.isEmpty()) {
|
||||
properties.fine("unknown block id %d", id);
|
||||
lostScope = true;
|
||||
} else {
|
||||
blocks.add(matcher);
|
||||
blocks.addAll(matchers);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
BlockStateMatcher matcher = BlockAPI.createMatcher(properties, token + defaultMetadata);
|
||||
if (matcher == null) {
|
||||
properties.warning("unknown block %s", token);
|
||||
List<BlockStateMatcher> matchers = BlockAPI.createMatchers(properties, token + defaultMetadata);
|
||||
if (matchers.isEmpty()) {
|
||||
properties.fine("unknown block %s", token);
|
||||
lostScope = true;
|
||||
} else {
|
||||
blocks.add(matcher);
|
||||
blocks.addAll(matchers);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -334,7 +340,11 @@ public abstract class TileOverride implements Comparable<TileOverride> {
|
||||
public final void registerIcons() {
|
||||
icons = new IIcon[tileNames.size()];
|
||||
for (int i = 0; i < icons.length; i++) {
|
||||
icons[i] = tileLoader.getIcon(tileNames.get(i));
|
||||
final ResourceLocation tileName = tileNames.get(i);
|
||||
icons[i] = tileLoader.getIcon(tileName);
|
||||
if (icons[i] == null && tileName != null) {
|
||||
properties.warning("tile %s did not resolve to an icon, tile %d will not render", tileName, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -368,11 +378,11 @@ public abstract class TileOverride implements Comparable<TileOverride> {
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
if (o instanceof TileOverride) {
|
||||
return baseFilename.compareTo(((TileOverride) o).baseFilename);
|
||||
} else {
|
||||
return -1;
|
||||
result = Boolean.compare(lostScope, o.lostScope);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
return Integer.compare(registrationOrder, o.registrationOrder);
|
||||
}
|
||||
|
||||
final boolean shouldConnect(RenderBlockState renderBlockState, IIcon icon, int relativeDirection) {
|
||||
|
||||
@@ -4,15 +4,20 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import net.coderbot.iris.shaderpack.materialmap.BlockEntry;
|
||||
import net.coderbot.iris.shaderpack.materialmap.FlatteningMap;
|
||||
import net.coderbot.iris.shaderpack.materialmap.NamespacedId;
|
||||
import net.minecraft.block.Block;
|
||||
|
||||
import com.prupe.mcpatcher.MCPatcherUtils;
|
||||
import com.prupe.mcpatcher.mal.resource.PropertiesFile;
|
||||
import com.prupe.mcpatcher.mal.resource.TexturePackAPI;
|
||||
|
||||
import cpw.mods.fml.common.registry.FMLControlledNamespacedRegistry;
|
||||
import cpw.mods.fml.common.registry.GameData;
|
||||
@@ -64,7 +69,7 @@ public class BlockAPI {
|
||||
return blocks;
|
||||
}
|
||||
|
||||
public static BlockStateMatcher createMatcher(PropertiesFile source, String matchString) {
|
||||
public static List<BlockStateMatcher> createMatchers(PropertiesFile source, String matchString) {
|
||||
Map<String, String> propertyMap = new HashMap<>();
|
||||
String namespace = null;
|
||||
String blockName = null;
|
||||
@@ -90,7 +95,7 @@ public class BlockAPI {
|
||||
appendThis = true;
|
||||
} else {
|
||||
source.warning("invalid token '%s' in %s", source, s, matchString);
|
||||
return null;
|
||||
return Collections.emptyList();
|
||||
}
|
||||
if (appendThis) {
|
||||
metaString.append(':');
|
||||
@@ -103,19 +108,73 @@ public class BlockAPI {
|
||||
}
|
||||
if (MCPatcherUtils.isNullOrEmpty(blockName)) {
|
||||
source.warning("cannot parse namespace/block name from %s", matchString);
|
||||
return null;
|
||||
return Collections.emptyList();
|
||||
}
|
||||
Block block = GameData.getBlockRegistry()
|
||||
.getObject(namespace + ':' + blockName);
|
||||
if (block == null) {
|
||||
source.warning("unknown block %s:%s", namespace, blockName);
|
||||
return null;
|
||||
final Block block = GameData.getBlockRegistry()
|
||||
.getRaw(namespace + ':' + blockName);
|
||||
if (block != null) {
|
||||
return Collections.singletonList(
|
||||
new BlockStateMatcher(
|
||||
metaString.toString(),
|
||||
block,
|
||||
metadata.toString()
|
||||
.trim()));
|
||||
}
|
||||
return new BlockStateMatcher(
|
||||
metaString.toString(),
|
||||
block,
|
||||
metadata.toString()
|
||||
.trim());
|
||||
if (!TexturePackAPI.DEFAULT_NAMESPACE.equals(namespace)) {
|
||||
source.fine("unknown block %s:%s", namespace, blockName);
|
||||
return Collections.emptyList();
|
||||
}
|
||||
final List<BlockEntry> entries = FlatteningMap.toLegacy(blockName, propertyMap);
|
||||
if (entries == null) {
|
||||
source.fine("unknown block %s:%s", namespace, blockName);
|
||||
return Collections.emptyList();
|
||||
}
|
||||
if (!propertyMap.isEmpty() && entries.equals(FlatteningMap.toLegacy(blockName, Collections.emptyMap()))) {
|
||||
source.fine("block %s has no 1.7.10 equivalent for %s, ignoring this match", blockName, propertyMap);
|
||||
return Collections.emptyList();
|
||||
}
|
||||
final String explicitMetadata = metadata.toString()
|
||||
.trim();
|
||||
final List<BlockStateMatcher> matchers = new ArrayList<>(entries.size());
|
||||
for (BlockEntry entry : entries) {
|
||||
final NamespacedId id = entry.id();
|
||||
final Block legacy = GameData.getBlockRegistry()
|
||||
.getRaw(id.getNamespace() + ':' + id.getName());
|
||||
final String entryMetadata = intersectMetadata(explicitMetadata, entry.metas());
|
||||
if (entryMetadata == null) {
|
||||
continue;
|
||||
}
|
||||
matchers.add(new BlockStateMatcher(metaString.toString(), legacy, entryMetadata));
|
||||
}
|
||||
if (matchers.isEmpty()) {
|
||||
source.fine("unknown block %s:%s", namespace, blockName);
|
||||
}
|
||||
return matchers;
|
||||
}
|
||||
|
||||
private static String intersectMetadata(String explicitMetadata, Set<Integer> entryMetas) {
|
||||
if (MCPatcherUtils.isNullOrEmpty(explicitMetadata)) {
|
||||
if (entryMetas.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
for (int meta : entryMetas) {
|
||||
sb.append(' ')
|
||||
.append(meta);
|
||||
}
|
||||
return sb.toString()
|
||||
.trim();
|
||||
}
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
for (int meta : MCPatcherUtils.parseIntegerList(explicitMetadata, 0, 15)) {
|
||||
if (entryMetas.isEmpty() || entryMetas.contains(meta)) {
|
||||
sb.append(' ')
|
||||
.append(meta);
|
||||
}
|
||||
}
|
||||
return sb.length() == 0 ? null
|
||||
: sb.toString()
|
||||
.trim();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -43,6 +43,7 @@ public class TexturePackAPI {
|
||||
public static final String DEFAULT_NAMESPACE = "minecraft";
|
||||
|
||||
public static final String MCPATCHER_SUBDIR = "mcpatcher/";
|
||||
public static final String OPTIFINE_SUBDIR = "optifine/";
|
||||
public static final ResourceLocation ITEMS_PNG = new ResourceLocation("textures/atlas/items.png");
|
||||
|
||||
private static final String ASSETS = "assets/";
|
||||
@@ -204,6 +205,11 @@ public class TexturePackAPI {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String subdirOf(ResourceLocation baseResource) {
|
||||
return baseResource != null && baseResource.getResourcePath()
|
||||
.startsWith(OPTIFINE_SUBDIR) ? OPTIFINE_SUBDIR : MCPATCHER_SUBDIR;
|
||||
}
|
||||
|
||||
public static ResourceLocation parseResourceLocation(ResourceLocation baseResource, String path) {
|
||||
if (MCPatcherUtils.isNullOrEmpty(path)) {
|
||||
return null;
|
||||
@@ -232,8 +238,8 @@ public class TexturePackAPI {
|
||||
ResourceLocation resource;
|
||||
if (path.startsWith("~/")) {
|
||||
// Relative to namespace mcpatcher dir:
|
||||
// ~/path -> assets/(namespace of base file)/mcpatcher/path
|
||||
resource = new ResourceLocation(baseResource.getResourceDomain(), MCPATCHER_SUBDIR + path.substring(2));
|
||||
// ~/path -> assets/(namespace of base file)/(mcpatcher|optifine)/path
|
||||
resource = new ResourceLocation(baseResource.getResourceDomain(), subdirOf(baseResource) + path.substring(2));
|
||||
} else if (path.startsWith("./")) {
|
||||
// Relative to properties file:
|
||||
// ./path -> (dir of base file)/path
|
||||
|
||||
@@ -8,6 +8,7 @@ import com.gtnewhorizons.angelica.glsm.RenderSystem;
|
||||
import com.gtnewhorizons.angelica.glsm.backend.BackendManager;
|
||||
import com.gtnewhorizons.angelica.glsm.shader.GlslVulkanPreprocess;
|
||||
import com.gtnewhorizons.angelica.glsm.shader.SpirvCompiler;
|
||||
import com.gtnewhorizons.angelica.iris.ImmediateExtendedAttribs;
|
||||
import com.gtnewhorizons.angelica.iris.IrisGLSMBridge;
|
||||
import com.gtnewhorizons.angelica.proxy.ClientProxy;
|
||||
import com.gtnewhorizons.angelica.rendering.StateAwareTessellator;
|
||||
@@ -802,6 +803,9 @@ public class Iris {
|
||||
// Load the new shaderpack
|
||||
loadShaderpack();
|
||||
|
||||
// Drop the stale program probe and cached item geometry
|
||||
ImmediateExtendedAttribs.onShaderPackChanged();
|
||||
|
||||
// Very important - we need to re-create the pipeline straight away.
|
||||
// https://github.com/IrisShaders/Iris/issues/1330
|
||||
if (Minecraft.getMinecraft().theWorld != null) {
|
||||
|
||||
@@ -5,6 +5,7 @@ package net.coderbot.iris.gl.shader;
|
||||
import com.gtnewhorizons.angelica.glsm.GLDebug;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.RenderSystem;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.ImmediateExtendedAttribHandler;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
@@ -15,10 +16,10 @@ public class ProgramCreator {
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger("ProgramCreator");
|
||||
|
||||
public static final int MC_ENTITY = 11;
|
||||
public static final int MC_MID_TEX_COORD = 12;
|
||||
public static final int AT_TANGENT = 13;
|
||||
public static final int AT_MIDBLOCK = 14;
|
||||
public static final int MC_ENTITY = ImmediateExtendedAttribHandler.LOC_MC_ENTITY;
|
||||
public static final int MC_MID_TEX_COORD = ImmediateExtendedAttribHandler.LOC_MID_TEX;
|
||||
public static final int AT_TANGENT = ImmediateExtendedAttribHandler.LOC_TANGENT;
|
||||
public static final int AT_MIDBLOCK = ImmediateExtendedAttribHandler.LOC_MIDBLOCK;
|
||||
|
||||
public static int create(String name, GlShader... shaders) {
|
||||
int program = GLStateManager.glCreateProgram();
|
||||
|
||||
@@ -4,6 +4,7 @@ import lombok.Getter;
|
||||
import net.coderbot.iris.Iris;
|
||||
import net.coderbot.iris.gbuffer_overrides.matching.SpecialCondition;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.ffp.FfpExtendedAttribs;
|
||||
import com.gtnewhorizons.angelica.glsm.states.AlphaState;
|
||||
import com.gtnewhorizons.angelica.glsm.states.BlendState;
|
||||
import net.coderbot.iris.gl.shader.ProgramCreator;
|
||||
@@ -240,8 +241,7 @@ public class GbufferPrograms {
|
||||
|
||||
public static void setBlockEntityDefaults() {
|
||||
GLStateManager.glVertexAttrib2s(ProgramCreator.MC_ENTITY, (short)-1, (short)-1);
|
||||
GLStateManager.glVertexAttrib2f(ProgramCreator.MC_MID_TEX_COORD, 0.5f, 0.5f);
|
||||
GLStateManager.glVertexAttrib4f(ProgramCreator.AT_TANGENT, 1.0f, 0.0f, 0.0f, 1.0f);
|
||||
FfpExtendedAttribs.setNeutralCurrentValues();
|
||||
GLStateManager.glVertexAttrib4f(ProgramCreator.AT_MIDBLOCK, 0.0f, 0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
|
||||
|
||||
@@ -87,7 +87,6 @@ class AttributeTransformer {
|
||||
|
||||
if (instancedVertex) {
|
||||
foldConstantAttribute(transformer, "mc_Entity", "-1.0", "vec2(-1.0, -1.0)", "vec3(-1.0, -1.0, 0.0)", "vec4(-1.0, -1.0, 0.0, 1.0)");
|
||||
foldConstantAttribute(transformer, "mc_midTexCoord", "0.5", "vec2(0.5, 0.5)", "vec3(0.5, 0.5, 0.0)", "vec4(0.5, 0.5, 0.0, 1.0)");
|
||||
|
||||
final StringBuilder init = new StringBuilder(256);
|
||||
init.append("{ iris_ModelViewMatrix = mat4(iris_InstMat0, iris_InstMat1, iris_InstMat2, iris_InstMat3);");
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package net.coderbot.iris.pipeline.transform;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.ffp.InstancedAttribs;
|
||||
import org.taumc.glsl.Transformer;
|
||||
|
||||
import java.util.HashMap;
|
||||
@@ -20,12 +21,12 @@ class CoreTransformHelper {
|
||||
|
||||
static void injectMatrixUniforms(Transformer transformer, boolean instancedVertex) {
|
||||
if (instancedVertex) {
|
||||
transformer.injectVariable("layout(location = 7) in vec4 iris_InstMat0;");
|
||||
transformer.injectVariable("layout(location = 8) in vec4 iris_InstMat1;");
|
||||
transformer.injectVariable("layout(location = 9) in vec4 iris_InstMat2;");
|
||||
transformer.injectVariable("layout(location = 10) in vec4 iris_InstMat3;");
|
||||
transformer.injectVariable("layout(location = 11) in vec4 iris_InstColor;");
|
||||
transformer.injectVariable("layout(location = 12) in vec2 iris_InstLightmap;");
|
||||
transformer.injectVariable("layout(location = " + InstancedAttribs.LOC_MATRIX_COL0 + ") in vec4 iris_InstMat0;");
|
||||
transformer.injectVariable("layout(location = " + InstancedAttribs.LOC_MATRIX_COL1 + ") in vec4 iris_InstMat1;");
|
||||
transformer.injectVariable("layout(location = " + InstancedAttribs.LOC_MATRIX_COL2 + ") in vec4 iris_InstMat2;");
|
||||
transformer.injectVariable("layout(location = " + InstancedAttribs.LOC_MATRIX_COL3 + ") in vec4 iris_InstMat3;");
|
||||
transformer.injectVariable("layout(location = " + InstancedAttribs.LOC_COLOR + ") in vec4 iris_InstColor;");
|
||||
transformer.injectVariable("layout(location = " + InstancedAttribs.LOC_LIGHTMAP + ") in vec2 iris_InstLightmap;");
|
||||
transformer.injectVariable("mat4 iris_ModelViewMatrix;");
|
||||
transformer.injectVariable("mat4 iris_ModelViewMatrixInverse;");
|
||||
transformer.injectVariable("mat3 iris_NormalMatrix;");
|
||||
|
||||
@@ -89,7 +89,7 @@ public class PBRAtlasTexture extends AutoClosableAbstractTexture {
|
||||
}
|
||||
|
||||
if (AngelicaConfig.enablePBRDebug) {
|
||||
TextureExporter.exportTextures("pbr_debug/atlas", id.getResourceDomain() + "_" + id.getResourcePath().replaceAll("/", "_"), glId, mipLevel, atlasWidth, atlasHeight);
|
||||
TextureExporter.exportTextures("pbr_debug/atlas", id.getResourceDomain() + "_" + id.getResourcePath().replace("/", "_") + ".png", glId, mipLevel, atlasWidth, atlasHeight);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,10 +2,10 @@ package net.coderbot.iris.texture.pbr.loader;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.gtnewhorizons.angelica.compat.mojang.NativeImage;
|
||||
import com.gtnewhorizons.angelica.config.AngelicaConfig;
|
||||
import com.gtnewhorizons.angelica.glsm.texture.TextureInfo;
|
||||
import com.gtnewhorizons.angelica.glsm.texture.TextureInfoCache;
|
||||
import com.gtnewhorizons.angelica.mixins.interfaces.ISpriteExt;
|
||||
import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions;
|
||||
import net.coderbot.iris.Iris;
|
||||
import net.coderbot.iris.texture.format.TextureFormat;
|
||||
import net.coderbot.iris.texture.format.TextureFormatLoader;
|
||||
@@ -17,10 +17,13 @@ import net.coderbot.iris.texture.pbr.PBRSpriteHolder;
|
||||
import net.coderbot.iris.texture.pbr.PBRType;
|
||||
import net.coderbot.iris.texture.pbr.TextureAtlasSpriteExtension;
|
||||
import net.coderbot.iris.texture.util.ImageManipulationUtil;
|
||||
import net.coderbot.iris.texture.util.TextureExporter;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.client.renderer.texture.TextureMap;
|
||||
import net.minecraft.client.renderer.texture.TextureUtil;
|
||||
import net.minecraft.client.resources.IResource;
|
||||
import net.minecraft.client.resources.IResourceManager;
|
||||
import net.minecraft.client.resources.data.AnimationFrame;
|
||||
import net.minecraft.client.resources.data.AnimationMetadataSection;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
@@ -28,7 +31,11 @@ import org.apache.commons.lang3.tuple.Pair;
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public class AtlasPBRLoader implements PBRTextureLoader<TextureMap> {
|
||||
public static final ChannelMipmapGenerator LINEAR_MIPMAP_GENERATOR = new ChannelMipmapGenerator(
|
||||
@@ -84,6 +91,45 @@ public class AtlasPBRLoader implements PBRTextureLoader<TextureMap> {
|
||||
pbrTextureConsumer.acceptSpecularTexture(specularAtlas);
|
||||
}
|
||||
}
|
||||
|
||||
if (AngelicaConfig.enablePBRDebug && (normalAtlas != null || specularAtlas != null)) {
|
||||
TextureExporter.exportTextures("pbr_debug/atlas", "base_atlas.png", texMap.getGlTextureId(), mipLevel, atlasWidth, atlasHeight);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static NativeImage padAnisotropic(NativeImage image, int frameWidth, int frameHeight) {
|
||||
final int width = image.getWidth();
|
||||
final int height = image.getHeight();
|
||||
final int frames = (frameWidth == width && frameHeight > 0) ? height / frameHeight : 0;
|
||||
if (frames < 1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final int paddedWidth = frameWidth + 16;
|
||||
final int paddedHeight = frameHeight + 16;
|
||||
final int framePixels = paddedWidth * paddedHeight;
|
||||
|
||||
final NativeImage padded = new NativeImage(paddedWidth, paddedHeight * frames, false);
|
||||
final int[] frame = new int[framePixels];
|
||||
for (int f = 0; f < frames; f++) {
|
||||
Arrays.fill(frame, 0);
|
||||
image.getRGB(0, f * frameHeight, frameWidth, frameHeight, frame, 0, frameWidth);
|
||||
TextureUtil.prepareAnisotropicData(frame, frameWidth, frameHeight, 8);
|
||||
padded.setRGB(0, f * paddedHeight, paddedWidth, paddedHeight, frame, 0, paddedWidth);
|
||||
}
|
||||
return padded;
|
||||
}
|
||||
|
||||
private static AnimationMetadataSection withFrameSize(AnimationMetadataSection src, int frameWidth, int frameHeight) {
|
||||
final List<AnimationFrame> frames = new ArrayList<>(src.getFrameCount());
|
||||
for (int f = 0; f < src.getFrameCount(); f++) {
|
||||
frames.add(new AnimationFrame(src.getFrameIndex(f), src.frameHasTime(f) ? src.getFrameTimeSingle(f) : -1));
|
||||
}
|
||||
return new AnimationMetadataSection(frames,
|
||||
src.getFrameWidth() != -1 ? frameWidth : -1,
|
||||
src.getFrameHeight() != -1 ? frameHeight : -1,
|
||||
src.getFrameTime());
|
||||
}
|
||||
|
||||
protected static int fetchAtlasMipLevel(TextureMap texMap) {
|
||||
@@ -104,18 +150,15 @@ public class AtlasPBRLoader implements PBRTextureLoader<TextureMap> {
|
||||
NativeImage nativeImage = NativeImage.read(resource.getInputStream());
|
||||
AnimationMetadataSection animationMetadata = (AnimationMetadataSection) resource.getMetadata("animation");
|
||||
if (animationMetadata == null) {
|
||||
final IResource resourceOriginal = resourceManager.getResource(imageLocation);
|
||||
animationMetadata = (AnimationMetadataSection) resourceOriginal.getMetadata("animation");
|
||||
if (animationMetadata == null) {
|
||||
animationMetadata = new AnimationMetadataSection(Lists.newArrayList(), -1, -1, -1);
|
||||
}
|
||||
animationMetadata = new AnimationMetadataSection(Lists.newArrayList(), -1, -1, -1);
|
||||
}
|
||||
|
||||
final Pair<Integer, Integer> frameSize = this.getFrameSize(nativeImage.getWidth(), nativeImage.getHeight(), animationMetadata);
|
||||
int frameWidth = frameSize.getLeft();
|
||||
int frameHeight = frameSize.getRight();
|
||||
final int targetFrameWidth = sprite.getIconWidth();
|
||||
final int targetFrameHeight = sprite.getIconHeight();
|
||||
final int spritePadding = sprite.useAnisotropicFiltering ? 16 : 0;
|
||||
final int targetFrameWidth = sprite.getIconWidth() - spritePadding;
|
||||
final int targetFrameHeight = sprite.getIconHeight() - spritePadding;
|
||||
if (frameWidth != targetFrameWidth || frameHeight != targetFrameHeight) {
|
||||
final int imageWidth = nativeImage.getWidth();
|
||||
final int imageHeight = nativeImage.getHeight();
|
||||
@@ -139,15 +182,8 @@ public class AtlasPBRLoader implements PBRTextureLoader<TextureMap> {
|
||||
frameWidth = targetFrameWidth;
|
||||
frameHeight = targetFrameHeight;
|
||||
|
||||
if (!animationMetadata.equals(new AnimationMetadataSection(Lists.newArrayList(), -1, -1, -1))) {
|
||||
final int internalFrameWidth = animationMetadata.frameHeight;
|
||||
final int internalFrameHeight = animationMetadata.frameWidth;
|
||||
if (internalFrameWidth != -1) {
|
||||
animationMetadata.frameWidth = frameWidth;
|
||||
}
|
||||
if (internalFrameHeight != -1) {
|
||||
animationMetadata.frameHeight = frameHeight;
|
||||
}
|
||||
if (animationMetadata.getFrameWidth() != -1 || animationMetadata.getFrameHeight() != -1) {
|
||||
animationMetadata = withFrameSize(animationMetadata, frameWidth, frameHeight);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,7 +192,15 @@ public class AtlasPBRLoader implements PBRTextureLoader<TextureMap> {
|
||||
|
||||
final int x = sprite.getOriginX();
|
||||
final int y = sprite.getOriginY();
|
||||
pbrSprite = new PBRTextureAtlasSprite(pbrSpriteInfo, animationMetadata, atlasWidth, atlasHeight, x, y, nativeImage, texMap, mipLevel);
|
||||
boolean padInLoadSprite = sprite.useAnisotropicFiltering;
|
||||
if (padInLoadSprite) {
|
||||
final NativeImage padded = padAnisotropic(nativeImage, frameWidth, frameHeight);
|
||||
if (padded != null) {
|
||||
nativeImage = padded;
|
||||
padInLoadSprite = false;
|
||||
}
|
||||
}
|
||||
pbrSprite = new PBRTextureAtlasSprite(pbrSpriteInfo, animationMetadata, atlasWidth, atlasHeight, x, y, nativeImage, padInLoadSprite, mipLevel);
|
||||
syncAnimation(sprite, pbrSprite);
|
||||
} catch (FileNotFoundException e) {
|
||||
//
|
||||
@@ -217,12 +261,10 @@ public class AtlasPBRLoader implements PBRTextureLoader<TextureMap> {
|
||||
|
||||
public static class PBRTextureAtlasSprite extends TextureAtlasSprite implements CustomMipmapGenerator.Provider {
|
||||
// This feels super janky
|
||||
protected PBRTextureAtlasSprite(TextureAtlasSpriteInfo info, AnimationMetadataSection animationMetaDataSection, int atlasWidth, int atlasHeight, int x, int y, NativeImage nativeImage, TextureMap texMap, int miplevel) {
|
||||
protected PBRTextureAtlasSprite(TextureAtlasSpriteInfo info, AnimationMetadataSection animationMetaDataSection, int atlasWidth, int atlasHeight, int x, int y, NativeImage nativeImage, boolean useAnisotropicFiltering, int miplevel) {
|
||||
super(info.name().toString());
|
||||
super.loadSprite(Objects.requireNonNull(getMipmapGenerator(info, atlasWidth, atlasHeight)).generateMipLevels(nativeImage, miplevel), animationMetaDataSection, useAnisotropicFiltering);
|
||||
super.initSprite(atlasWidth, atlasHeight, x, y, false);
|
||||
final boolean useAnisotropicFiltering = texMap.anisotropicFiltering > 1
|
||||
|| SodiumGameOptions.needsForcedSpritePadding();
|
||||
super.loadSprite(getMipmapGenerator(info, atlasWidth, atlasHeight).generateMipLevels(nativeImage, miplevel), animationMetaDataSection, useAnisotropicFiltering);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+3
@@ -9,6 +9,7 @@ import com.gtnewhorizons.angelica.glsm.streaming.TessellatorStreamingDrawer;
|
||||
import com.gtnewhorizons.angelica.compat.DriverCompatabilityCheck;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.backend.BackendManager;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.GLSMConfig;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.GLSMHooks;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.GLSMInitConfig;
|
||||
import com.gtnewhorizons.angelica.proxy.ClientProxy;
|
||||
@@ -51,6 +52,8 @@ public class MixinInitGLStateManager {
|
||||
.postInitCallback(SelectionBoxRenderer::init)
|
||||
.build());
|
||||
|
||||
GLSMConfig.extendedAttribsExpected = AngelicaConfig.enableIris;
|
||||
|
||||
GLSMHooks.LIGHTMAP_COORDS.addListener(event -> {
|
||||
OpenGlHelper.lastBrightnessX = event.x;
|
||||
OpenGlHelper.lastBrightnessY = event.y;
|
||||
|
||||
+10
-1
@@ -1,5 +1,8 @@
|
||||
package com.gtnewhorizons.angelica.mixins.early.shaders;
|
||||
|
||||
import net.coderbot.iris.Iris;
|
||||
import net.coderbot.iris.texture.format.TextureFormatLoader;
|
||||
import net.coderbot.iris.texture.pbr.PBRTextureManager;
|
||||
import net.coderbot.iris.uniforms.CapturedRenderingState;
|
||||
import net.minecraft.client.renderer.texture.TextureManager;
|
||||
import net.minecraft.client.resources.IResourceManager;
|
||||
@@ -9,13 +12,19 @@ import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
/**
|
||||
* Hook into TextureManger to increment the reload count.
|
||||
* Hook into TextureManger to reload the PBR texture format and increment the reload count.
|
||||
*/
|
||||
@Mixin(TextureManager.class)
|
||||
public class MixinTextureManager_ReloadCount {
|
||||
|
||||
@Inject(method = "onResourceManagerReload", at = @At("TAIL"))
|
||||
private void angelica$bumpTextureReloadCount(IResourceManager resourceManager, CallbackInfo ci) {
|
||||
try {
|
||||
TextureFormatLoader.reload(resourceManager);
|
||||
} catch (Exception e) {
|
||||
Iris.logger.error("Failed to reload the shader pipeline for a texture format change", e);
|
||||
}
|
||||
PBRTextureManager.INSTANCE.clear();
|
||||
CapturedRenderingState.INSTANCE.incrementTextureReloadCount();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package com.gtnewhorizons.angelica.rendering;
|
||||
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.vertex.VertexFormatElement;
|
||||
import com.gtnewhorizons.angelica.glsm.ffp.InstancedAttribs;
|
||||
import net.coderbot.iris.gl.shader.ProgramCreator;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/**
|
||||
* Make sure we don't ever have collisions again, that was annoying.
|
||||
*/
|
||||
class VertexAttributeLayoutTest {
|
||||
|
||||
private static final int MAX_VERTEX_ATTRIBS = 16;
|
||||
|
||||
private final Map<Integer, String> claimed = new HashMap<>();
|
||||
|
||||
private void claim(int location, String owner) {
|
||||
assertTrue(location >= 0 && location < MAX_VERTEX_ATTRIBS,
|
||||
owner + " uses location " + location + ", outside 0.." + (MAX_VERTEX_ATTRIBS - 1));
|
||||
final String previous = claimed.put(location, owner);
|
||||
assertNull(previous, "location " + location + " claimed by both " + previous + " and " + owner);
|
||||
}
|
||||
|
||||
@Test
|
||||
void reservedAttributeLocationsDoNotOverlap() {
|
||||
for (VertexFormatElement.Usage usage : VertexFormatElement.Usage.values()) {
|
||||
final int loc = usage.getAttributeLocation();
|
||||
if (loc < 0) continue;
|
||||
claim(loc, "vertex format " + usage.name());
|
||||
}
|
||||
|
||||
claim(InstancedAttribs.LOC_MATRIX_COL0, "InstancedAttribs.LOC_MATRIX_COL0");
|
||||
claim(InstancedAttribs.LOC_MATRIX_COL1, "InstancedAttribs.LOC_MATRIX_COL1");
|
||||
claim(InstancedAttribs.LOC_MATRIX_COL2, "InstancedAttribs.LOC_MATRIX_COL2");
|
||||
claim(InstancedAttribs.LOC_MATRIX_COL3, "InstancedAttribs.LOC_MATRIX_COL3");
|
||||
claim(InstancedAttribs.LOC_COLOR, "InstancedAttribs.LOC_COLOR");
|
||||
claim(InstancedAttribs.LOC_LIGHTMAP, "InstancedAttribs.LOC_LIGHTMAP");
|
||||
|
||||
claim(ProgramCreator.MC_ENTITY, "ProgramCreator.MC_ENTITY");
|
||||
claim(ProgramCreator.MC_MID_TEX_COORD, "ProgramCreator.MC_MID_TEX_COORD");
|
||||
claim(ProgramCreator.AT_TANGENT, "ProgramCreator.AT_TANGENT");
|
||||
claim(ProgramCreator.AT_MIDBLOCK, "ProgramCreator.AT_MIDBLOCK");
|
||||
}
|
||||
|
||||
@Test
|
||||
void instancedMatrixColumnsAreContiguous() {
|
||||
final int[] columns = {
|
||||
InstancedAttribs.LOC_MATRIX_COL0, InstancedAttribs.LOC_MATRIX_COL1,
|
||||
InstancedAttribs.LOC_MATRIX_COL2, InstancedAttribs.LOC_MATRIX_COL3
|
||||
};
|
||||
for (int c = 1; c < columns.length; c++) {
|
||||
assertEquals(columns[0] + c, columns[c],
|
||||
"instance matrix column " + c + " must sit at LOC_MATRIX_COL0 + " + c);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void reportsRemainingFreeLocations() {
|
||||
reservedAttributeLocationsDoNotOverlap();
|
||||
final TreeSet<Integer> free = new TreeSet<>();
|
||||
for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++) {
|
||||
if (!claimed.containsKey(i)) free.add(i);
|
||||
}
|
||||
System.out.println("free vertex attribute locations: " + free);
|
||||
}
|
||||
}
|
||||
+29
-9
@@ -1,5 +1,11 @@
|
||||
package net.coderbot.iris.pipeline.transform;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import java.util.HashMap;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.regex.Matcher;
|
||||
import net.coderbot.iris.gl.shader.ProgramCreator;
|
||||
import com.gtnewhorizons.angelica.glsm.ffp.InstancedAttribs;
|
||||
import com.gtnewhorizons.angelica.glsm.RenderSystem;
|
||||
import com.gtnewhorizons.angelica.glsm.testutil.Reflect;
|
||||
import net.coderbot.iris.gbuffer_overrides.matching.InputAvailability;
|
||||
@@ -93,15 +99,29 @@ class AttributeTransformerInstancedTest {
|
||||
return squash(shader).indexOf(squash(snippet));
|
||||
}
|
||||
|
||||
@Test
|
||||
void generatedInstancedShaderHasNoOverlappingAttributeLocations() {
|
||||
final String v = instancedVertex(VERTEX);
|
||||
final Matcher m = Pattern.compile("layout\\s*\\(\\s*location\\s*=\\s*(\\d+)\\s*\\)\\s*in\\s+\\w+\\s+(\\w+)").matcher(v);
|
||||
final Map<Integer, String> byLocation = new HashMap<>();
|
||||
while (m.find()) {
|
||||
final int loc = Integer.parseInt(m.group(1));
|
||||
final String name = m.group(2);
|
||||
final String previous = byLocation.put(loc, name);
|
||||
assertNull(previous, "location " + loc + " declared twice: " + previous + " and " + name);
|
||||
}
|
||||
assertFalse(byLocation.isEmpty(), "expected the instanced variant to declare attribute locations");
|
||||
}
|
||||
|
||||
@Test
|
||||
void declaresInstanceAttribsAndGlobalMatrices() {
|
||||
final String v = instancedVertex(VERTEX);
|
||||
assertHas(v, "layout(location = 7) in vec4 iris_InstMat0");
|
||||
assertHas(v, "layout(location = 8) in vec4 iris_InstMat1");
|
||||
assertHas(v, "layout(location = 9) in vec4 iris_InstMat2");
|
||||
assertHas(v, "layout(location = 10) in vec4 iris_InstMat3");
|
||||
assertHas(v, "layout(location = 11) in vec4 iris_InstColor");
|
||||
assertHas(v, "layout(location = 12) in vec2 iris_InstLightmap");
|
||||
assertHas(v, "layout(location = " + InstancedAttribs.LOC_MATRIX_COL0 + ") in vec4 iris_InstMat0");
|
||||
assertHas(v, "layout(location = " + InstancedAttribs.LOC_MATRIX_COL1 + ") in vec4 iris_InstMat1");
|
||||
assertHas(v, "layout(location = " + InstancedAttribs.LOC_MATRIX_COL2 + ") in vec4 iris_InstMat2");
|
||||
assertHas(v, "layout(location = " + InstancedAttribs.LOC_MATRIX_COL3 + ") in vec4 iris_InstMat3");
|
||||
assertHas(v, "layout(location = " + InstancedAttribs.LOC_COLOR + ") in vec4 iris_InstColor");
|
||||
assertHas(v, "layout(location = " + InstancedAttribs.LOC_LIGHTMAP + ") in vec2 iris_InstLightmap");
|
||||
assertLacks(v, "uniform mat4 iris_ModelViewMatrix;");
|
||||
assertLacks(v, "uniform mat3 iris_NormalMatrix;");
|
||||
assertHas(v, "mat4 iris_ModelViewMatrix;");
|
||||
@@ -123,12 +143,12 @@ class AttributeTransformerInstancedTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void foldsEntityAndMidTexCoordAttributes() {
|
||||
void foldsEntityAttributeButKeepsMidTexCoord() {
|
||||
final String v = instancedVertex(VERTEX);
|
||||
assertLacks(v, "mc_Entity");
|
||||
assertLacks(v, "mc_midTexCoord");
|
||||
assertHas(v, "vec4(-1.0, -1.0, 0.0, 1.0)");
|
||||
assertHas(v, "vec4(0.5, 0.5, 0.0, 1.0)");
|
||||
assertHas(v, "mc_midTexCoord");
|
||||
assertLacks(v, "vec4(0.5, 0.5, 0.0, 1.0)");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in new issue
Block a user