diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/Contraption.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/Contraption.java index 3e363d2d3..e783d6436 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/Contraption.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/Contraption.java @@ -712,16 +712,15 @@ public abstract class Contraption { } ListNBT superglueNBT = new ListNBT(); - for (Pair glueEntry : superglue) { - CompoundNBT c = new CompoundNBT(); - c.put("Pos", NBTUtil.writeBlockPos(glueEntry.getKey())); - c.putByte("Direction", (byte) glueEntry.getValue() - .getIndex()); - superglueNBT.add(c); - } - ListNBT storageNBT = new ListNBT(); if (!spawnPacket) { + for (Pair glueEntry : superglue) { + CompoundNBT c = new CompoundNBT(); + c.put("Pos", NBTUtil.writeBlockPos(glueEntry.getKey())); + c.putByte("Direction", (byte) glueEntry.getValue().getIndex()); + superglueNBT.add(c); + } + for (BlockPos pos : storage.keySet()) { CompoundNBT c = new CompoundNBT(); MountedStorage mountedStorage = storage.get(pos); diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/Backend.java b/src/main/java/com/simibubi/create/foundation/render/backend/Backend.java index 6a416b187..858d54572 100644 --- a/src/main/java/com/simibubi/create/foundation/render/backend/Backend.java +++ b/src/main/java/com/simibubi/create/foundation/render/backend/Backend.java @@ -11,6 +11,7 @@ import java.util.Map; import java.util.function.Consumer; import java.util.function.Predicate; +import com.simibubi.create.foundation.render.backend.gl.versioned.GlFunctions; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.lwjgl.opengl.GL; @@ -44,16 +45,12 @@ public class Backend { private static boolean enabled; public static GLCapabilities capabilities; - private static MapBuffer mapBuffer; + public static GlFunctions functions; public Backend() { throw new IllegalStateException(); } - public static void mapBuffer(int target, int offset, int length, Consumer upload) { - mapBuffer.mapBuffer(target, offset, length, upload); - } - /** * Register a shader program. TODO: replace with forge registry? */ @@ -71,47 +68,21 @@ public class Backend { return (P) programs.get(spec); } - /** - * Get the most compatible version of a specific OpenGL feature by iterating over enum constants in order. - * - * @param clazz The class of the versioning enum. - * @param The type of the versioning enum. - * @return The first defined enum variant to return true. - */ - public static & GlVersioned> V getLatest(Class clazz) { - return getLatest(clazz, capabilities); - } - - /** - * Get the most compatible version of a specific OpenGL feature by iterating over enum constants in order. - * - * @param clazz The class of the versioning enum. - * @param caps The current system's supported features. - * @param The type of the versioning enum. - * @return The first defined enum variant to return true. - */ - public static & GlVersioned> V getLatest(Class clazz, GLCapabilities caps) { - V[] constants = clazz.getEnumConstants(); - V last = constants[constants.length - 1]; - if (!last.supported(caps)) { - throw new IllegalStateException(""); - } - - return Arrays.stream(constants).filter(it -> it.supported(caps)).findFirst().orElse(last); + public static boolean available() { + return canUseVBOs(); } public static boolean canUseInstancing() { - return enabled && gl33(); + return enabled && + functions.vertexArrayObjectsSupported() && + functions.drawInstancedSupported() && + functions.instancedArraysSupported(); } public static boolean canUseVBOs() { return enabled && gl20(); } - public static boolean available() { - return enabled && gl20(); - } - public static boolean gl33() { return capabilities.OpenGL33; } @@ -136,7 +107,7 @@ public class Backend { private static void onResourceManagerReload(IResourceManager manager, Predicate predicate) { if (predicate.test(VanillaResourceType.SHADERS)) { capabilities = GL.createCapabilities(); - mapBuffer = getLatest(MapBuffer.class); + functions = new GlFunctions(capabilities); OptifineHandler.refresh(); refresh(); diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/GlBuffer.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/GlBuffer.java index 42a72736b..8420dab87 100644 --- a/src/main/java/com/simibubi/create/foundation/render/backend/gl/GlBuffer.java +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/GlBuffer.java @@ -3,9 +3,9 @@ package com.simibubi.create.foundation.render.backend.gl; import java.nio.ByteBuffer; import java.util.function.Consumer; -import org.lwjgl.opengl.GL20; - import com.simibubi.create.foundation.render.backend.Backend; +import com.simibubi.create.foundation.render.backend.gl.versioned.GlFunctions; +import org.lwjgl.opengl.GL20; public class GlBuffer extends GlObject { @@ -35,11 +35,11 @@ public class GlBuffer extends GlObject { } public void map(int length, Consumer upload) { - Backend.mapBuffer(bufferType, 0, length, upload); + Backend.functions.mapBuffer(bufferType, 0, length, upload); } public void map(int offset, int length, Consumer upload) { - Backend.mapBuffer(bufferType, offset, length, upload); + Backend.functions.mapBuffer(bufferType, offset, length, upload); } protected void deleteInternal(int handle) { diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/GlVertexArray.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/GlVertexArray.java index 33ff7461b..cf6229f6e 100644 --- a/src/main/java/com/simibubi/create/foundation/render/backend/gl/GlVertexArray.java +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/GlVertexArray.java @@ -2,19 +2,20 @@ package com.simibubi.create.foundation.render.backend.gl; import java.util.function.Consumer; +import com.simibubi.create.foundation.render.backend.Backend; import org.lwjgl.opengl.GL30; public class GlVertexArray extends GlObject { public GlVertexArray() { - setHandle(GL30.glGenVertexArrays()); + setHandle(Backend.functions.genVertexArrays()); } public void bind() { - GL30.glBindVertexArray(handle()); + Backend.functions.bindVertexArray(handle()); } public void unbind() { - GL30.glBindVertexArray(0); + Backend.functions.bindVertexArray(0); } public void with(Consumer action) { @@ -24,6 +25,6 @@ public class GlVertexArray extends GlObject { } protected void deleteInternal(int handle) { - GL30.glDeleteVertexArrays(handle); + Backend.functions.deleteVertexArrays(handle); } } diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/versioned/DrawInstanced.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/versioned/DrawInstanced.java new file mode 100644 index 000000000..4c206581d --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/versioned/DrawInstanced.java @@ -0,0 +1,54 @@ +package com.simibubi.create.foundation.render.backend.gl.versioned; + +import org.lwjgl.opengl.*; + +public enum DrawInstanced implements GlVersioned { + GL31_DRAW_INSTANCED { + @Override + public boolean supported(GLCapabilities caps) { + return caps.OpenGL31; + } + + @Override + public void drawArraysInstanced(int mode, int first, int count, int primcount) { + GL31.glDrawArraysInstanced(mode, first, count, primcount); + } + }, + ARB_DRAW_INSTANCED { + @Override + public boolean supported(GLCapabilities caps) { + return caps.GL_ARB_draw_instanced; + } + + @Override + public void drawArraysInstanced(int mode, int first, int count, int primcount) { + ARBDrawInstanced.glDrawArraysInstancedARB(mode, first, count, primcount); + } + }, + EXT_DRAW_INSTANCED { + @Override + public boolean supported(GLCapabilities caps) { + return caps.GL_EXT_draw_instanced; + } + + @Override + public void drawArraysInstanced(int mode, int first, int count, int primcount) { + EXTDrawInstanced.glDrawArraysInstancedEXT(mode, first, count, primcount); + } + }, + UNSUPPORTED { + @Override + public boolean supported(GLCapabilities caps) { + return true; + } + + @Override + public void drawArraysInstanced(int mode, int first, int count, int primcount) { + throw new UnsupportedOperationException(); + } + } + + ; + + public abstract void drawArraysInstanced(int mode, int first, int count, int primcount); +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/versioned/GlFunctions.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/versioned/GlFunctions.java new file mode 100644 index 000000000..1345661fc --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/versioned/GlFunctions.java @@ -0,0 +1,85 @@ +package com.simibubi.create.foundation.render.backend.gl.versioned; + +import org.lwjgl.opengl.GLCapabilities; + +import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.function.Consumer; + +/** + * An instance of this class stores information + * about what OpenGL features are available. + * + * Each field stores an enum variant that provides access to the + * most appropriate version of a feature for the current system. + */ +public class GlFunctions { + public final MapBuffer mapBuffer; + + public final VertexArrayObject vertexArrayObject; + public final InstancedArrays instancedArrays; + public final DrawInstanced drawInstanced; + + public GlFunctions(GLCapabilities caps) { + mapBuffer = getLatest(MapBuffer.class, caps); + + vertexArrayObject = getLatest(VertexArrayObject.class, caps); + instancedArrays = getLatest(InstancedArrays.class, caps); + drawInstanced = getLatest(DrawInstanced.class, caps); + } + + public void mapBuffer(int target, int offset, int length, Consumer upload) { + mapBuffer.mapBuffer(target, offset, length, upload); + } + + public void vertexAttribDivisor(int index, int divisor) { + instancedArrays.vertexAttribDivisor(index, divisor); + } + + public void drawArraysInstanced(int mode, int first, int count, int primcount) { + drawInstanced.drawArraysInstanced(mode, first, count, primcount); + } + + public int genVertexArrays() { + return vertexArrayObject.genVertexArrays(); + } + + public void deleteVertexArrays(int array) { + vertexArrayObject.deleteVertexArrays(array); + } + + public void bindVertexArray(int array) { + vertexArrayObject.bindVertexArray(array); + } + + public boolean vertexArrayObjectsSupported() { + return vertexArrayObject != VertexArrayObject.UNSUPPORTED; + } + + public boolean instancedArraysSupported() { + return instancedArrays != InstancedArrays.UNSUPPORTED; + } + + public boolean drawInstancedSupported() { + return drawInstanced != DrawInstanced.UNSUPPORTED; + } + + /** + * Get the most compatible version of a specific OpenGL feature by iterating over enum constants in order. + * + * @param clazz The class of the versioning enum. + * @param caps The current system's supported features. + * @param The type of the versioning enum. + * @return The first defined enum variant to return true. + */ + public static & GlVersioned> V getLatest(Class clazz, GLCapabilities caps) { + V[] constants = clazz.getEnumConstants(); + V last = constants[constants.length - 1]; + if (!last.supported(caps)) { + throw new IllegalStateException(""); + } + + return Arrays.stream(constants).filter(it -> it.supported(caps)).findFirst().get(); + } +} + diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/versioned/GlVersioned.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/versioned/GlVersioned.java index 53d929ea0..6f456c802 100644 --- a/src/main/java/com/simibubi/create/foundation/render/backend/gl/versioned/GlVersioned.java +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/versioned/GlVersioned.java @@ -2,7 +2,15 @@ package com.simibubi.create.foundation.render.backend.gl.versioned; import org.lwjgl.opengl.GLCapabilities; - +/** + * This interface should be implemented by enums such that the + * last defined variant always returns true. + */ public interface GlVersioned { + /** + * Queries whether this variant is supported by the current system. + * @param caps The {@link GLCapabilities} reported by the current system. + * @return true if this variant is supported, or if this is the last defined variant. + */ boolean supported(GLCapabilities caps); } diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/versioned/InstancedArrays.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/versioned/InstancedArrays.java new file mode 100644 index 000000000..1c000a37d --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/versioned/InstancedArrays.java @@ -0,0 +1,43 @@ +package com.simibubi.create.foundation.render.backend.gl.versioned; + +import org.lwjgl.opengl.*; + +public enum InstancedArrays implements GlVersioned { + GL33_INSTANCED_ARRAYS { + @Override + public boolean supported(GLCapabilities caps) { + return caps.OpenGL33; + } + + @Override + public void vertexAttribDivisor(int index, int divisor) { + GL33.glVertexAttribDivisor(index, divisor); + } + }, + ARB_INSTANCED_ARRAYS { + @Override + public boolean supported(GLCapabilities caps) { + return caps.GL_ARB_instanced_arrays; + } + + @Override + public void vertexAttribDivisor(int index, int divisor) { + ARBInstancedArrays.glVertexAttribDivisorARB(index, divisor); + } + }, + UNSUPPORTED { + @Override + public boolean supported(GLCapabilities caps) { + return true; + } + + @Override + public void vertexAttribDivisor(int index, int divisor) { + throw new UnsupportedOperationException(); + } + } + + ; + + public abstract void vertexAttribDivisor(int index, int divisor); +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/versioned/VertexArrayObject.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/versioned/VertexArrayObject.java new file mode 100644 index 000000000..58b9f0fc8 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/versioned/VertexArrayObject.java @@ -0,0 +1,77 @@ +package com.simibubi.create.foundation.render.backend.gl.versioned; + +import org.lwjgl.opengl.*; + +public enum VertexArrayObject implements GlVersioned { + GL30_VAO { + @Override + public boolean supported(GLCapabilities caps) { + return caps.OpenGL30; + } + + @Override + public int genVertexArrays() { + return GL30.glGenVertexArrays(); + } + + @Override + public void bindVertexArray(int array) { + GL30.glBindVertexArray(array); + } + + @Override + public void deleteVertexArrays(int array) { + GL30.glDeleteVertexArrays(array); + } + }, + ARB_VAO { + @Override + public boolean supported(GLCapabilities caps) { + return caps.GL_ARB_vertex_array_object; + } + + @Override + public int genVertexArrays() { + return ARBVertexArrayObject.glGenVertexArrays(); + } + + @Override + public void bindVertexArray(int array) { + ARBVertexArrayObject.glBindVertexArray(array); + } + + @Override + public void deleteVertexArrays(int array) { + ARBVertexArrayObject.glDeleteVertexArrays(array); + } + }, + UNSUPPORTED { + @Override + public boolean supported(GLCapabilities caps) { + return true; + } + + @Override + public int genVertexArrays() { + throw new UnsupportedOperationException(); + } + + @Override + public void bindVertexArray(int array) { + throw new UnsupportedOperationException(); + } + + @Override + public void deleteVertexArrays(int array) { + throw new UnsupportedOperationException(); + } + } + + ; + + public abstract int genVertexArrays(); + + public abstract void bindVertexArray(int array); + + public abstract void deleteVertexArrays(int array); +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/instancing/InstancedModel.java b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/InstancedModel.java index b18cffcc4..3b092c919 100644 --- a/src/main/java/com/simibubi/create/foundation/render/backend/instancing/InstancedModel.java +++ b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/InstancedModel.java @@ -5,11 +5,10 @@ import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.function.Consumer; +import com.simibubi.create.foundation.render.backend.Backend; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL15; import org.lwjgl.opengl.GL20; -import org.lwjgl.opengl.GL31; -import org.lwjgl.opengl.GL33; import com.simibubi.create.foundation.render.RenderMath; import com.simibubi.create.foundation.render.backend.BufferedModel; @@ -116,7 +115,7 @@ public abstract class InstancedModel extends BufferedMod protected void doRender() { vao.with(vao -> { renderSetup(); - GL31.glDrawArraysInstanced(GL11.GL_QUADS, 0, vertexCount, glInstanceCount); + Backend.functions.drawArraysInstanced(GL11.GL_QUADS, 0, vertexCount, glInstanceCount); }); } @@ -163,7 +162,7 @@ public abstract class InstancedModel extends BufferedMod instanceFormat.vertexAttribPointers(staticAttributes); for (int i = 0; i < instanceFormat.getShaderAttributeCount(); i++) { - GL33.glVertexAttribDivisor(i + staticAttributes, 1); + Backend.functions.vertexAttribDivisor(i + staticAttributes, 1); } });