diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/generic/GenericObjectRenderer.java b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/generic/GenericObjectRenderer.java index ffedf7b3b..997b070ca 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/generic/GenericObjectRenderer.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/generic/GenericObjectRenderer.java @@ -48,8 +48,6 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.ISodiumAcce import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector; import com.seibel.distanthorizons.coreapi.DependencyInjection.OverrideInjector; import com.seibel.distanthorizons.coreapi.ModInfo; -import org.apache.logging.log4j.LogManager; -import com.seibel.distanthorizons.core.logging.DhLogger; import org.lwjgl.opengl.ARBInstancedArrays; import org.lwjgl.opengl.GL32; import org.lwjgl.opengl.GL33; @@ -476,6 +474,18 @@ public class GenericObjectRenderer implements IDhApiCustomRenderRegister continue; } + // update instanced data if needed + if (useInstancedRendering) + { + boxGroup.tryUpdateInstancedDataAsync(); + + // skip groups that haven't been uploaded yet + if (boxGroup.instancedVbos.state != InstancedVboContainer.EState.RENDER) + { + continue; + } + } + // render // @@ -535,7 +545,6 @@ public class GenericObjectRenderer implements IDhApiCustomRenderRegister // update instance data // profiler.push("vertex setup"); - boxGroup.updateVertexAttributeData(); DhApiRenderableBoxGroupShading shading = boxGroup.shading; if (shading == null) @@ -553,27 +562,27 @@ public class GenericObjectRenderer implements IDhApiCustomRenderRegister // Bind instance data // profiler.popPush("binding"); - GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, boxGroup.instanceColorVbo); + GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, boxGroup.instancedVbos.color); GL32.glEnableVertexAttribArray(1); GL32.glVertexAttribPointer(1, 4, GL32.GL_FLOAT, false, 4 * Float.BYTES, 0); this.vertexAttribDivisor(1, 1); - GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, boxGroup.instanceScaleVbo); + GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, boxGroup.instancedVbos.scale); GL32.glEnableVertexAttribArray(2); this.vertexAttribDivisor(2, 1); GL32.glVertexAttribPointer(2, 3, GL32.GL_FLOAT, false, 3 * Float.BYTES, 0); - GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, boxGroup.instanceChunkPosVbo); + GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, boxGroup.instancedVbos.chunkPos); GL32.glEnableVertexAttribArray(3); this.vertexAttribDivisor(3, 1); GL32.glVertexAttribIPointer(3, 3, GL32.GL_INT, 3 * Integer.BYTES, 0); - GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, boxGroup.instanceSubChunkPosVbo); + GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, boxGroup.instancedVbos.subChunkPos); GL32.glEnableVertexAttribArray(4); this.vertexAttribDivisor(4, 1); GL32.glVertexAttribPointer(4, 3, GL32.GL_FLOAT, false, 3 * Float.BYTES, 0); - GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, boxGroup.instanceMaterialVbo); + GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, boxGroup.instancedVbos.material); GL32.glEnableVertexAttribArray(5); this.vertexAttribDivisor(5, 1); GL32.glVertexAttribIPointer(5, 1, GL32.GL_BYTE, Byte.BYTES, 0); @@ -581,9 +590,9 @@ public class GenericObjectRenderer implements IDhApiCustomRenderRegister // Draw instanced profiler.popPush("render"); - if (boxGroup.uploadedBoxCount > 0) + if (boxGroup.instancedVbos.uploadedBoxCount > 0) { - GL32.glDrawElementsInstanced(GL32.GL_TRIANGLES, BOX_INDICES.length, GL32.GL_UNSIGNED_INT, 0, boxGroup.uploadedBoxCount); + GL32.glDrawElementsInstanced(GL32.GL_TRIANGLES, BOX_INDICES.length, GL32.GL_UNSIGNED_INT, 0, boxGroup.instancedVbos.uploadedBoxCount); } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/generic/InstancedVboContainer.java b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/generic/InstancedVboContainer.java new file mode 100644 index 000000000..744e3d64c --- /dev/null +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/generic/InstancedVboContainer.java @@ -0,0 +1,193 @@ +package com.seibel.distanthorizons.core.render.renderer.generic; + +import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBox; +import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; +import com.seibel.distanthorizons.core.logging.DhLogger; +import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; +import com.seibel.distanthorizons.core.util.LodUtil; +import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftGLWrapper; +import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper; +import org.lwjgl.opengl.GL32; + +import java.awt.*; +import java.util.List; + +/** + * For use by {@link RenderableBoxGroup} + * + * @see RenderableBoxGroup + */ +public class InstancedVboContainer implements AutoCloseable +{ + private static final DhLogger LOGGER = new DhLoggerBuilder().build(); + + private static final IMinecraftGLWrapper GLMC = SingletonInjector.INSTANCE.get(IMinecraftGLWrapper.class); + private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class); + + + + public int chunkPos = 0; + public int subChunkPos = 0; + public int scale = 0; + public int color = 0; + public int material = 0; + + public int[] chunkPosData = new int[0]; + public float[] subChunkPosData = new float[0]; + public float[] scalingData = new float[0]; + public float[] colorData = new float[0]; + public int[] materialData = new int[0]; + + public int uploadedBoxCount = 0; + + public EState state = EState.NEW; + + + + //===========================// + // render building/uploading // + //===========================// + //region + + /** needs to be done on the render thread */ + public void tryRunRenderThreadSetup() + { + if (this.chunkPos == 0) + { + this.chunkPos = GLMC.glGenBuffers(); + this.subChunkPos = GLMC.glGenBuffers(); + this.scale = GLMC.glGenBuffers(); + this.color = GLMC.glGenBuffers(); + this.material = GLMC.glGenBuffers(); + } + } + + public void updateVertexData(List uploadBoxList) + { + int boxCount = uploadBoxList.size(); + + + // recreate the data arrays if their size is different + if (this.uploadedBoxCount != boxCount) + { + this.uploadedBoxCount = boxCount; + + this.chunkPosData = new int[boxCount * 3]; // 3 elements XYZ + this.subChunkPosData = new float[boxCount * 3]; // 3 elements XYZ + this.scalingData = new float[boxCount * 3]; // 3 elements XYZ + + this.colorData = new float[boxCount * 4]; // 4 elements, RGBA + this.materialData = new int[boxCount]; + } + + + // transformation / scaling // + for (int i = 0; i < boxCount; i++) + { + DhApiRenderableBox box = uploadBoxList.get(i); + + int dataIndex = i * 3; + + this.chunkPosData[dataIndex] = LodUtil.getChunkPosFromDouble(box.minPos.x); + this.chunkPosData[dataIndex + 1] = LodUtil.getChunkPosFromDouble(box.minPos.y); + this.chunkPosData[dataIndex + 2] = LodUtil.getChunkPosFromDouble(box.minPos.z); + + this.subChunkPosData[dataIndex] = LodUtil.getSubChunkPosFromDouble(box.minPos.x); + this.subChunkPosData[dataIndex + 1] = LodUtil.getSubChunkPosFromDouble(box.minPos.y); + this.subChunkPosData[dataIndex + 2] = LodUtil.getSubChunkPosFromDouble(box.minPos.z); + + this.scalingData[dataIndex] = (float) (box.maxPos.x - box.minPos.x); + this.scalingData[dataIndex + 1] = (float) (box.maxPos.y - box.minPos.y); + this.scalingData[dataIndex + 2] = (float) (box.maxPos.z - box.minPos.z); + } + + + // colors/materials // + for (int i = 0; i < boxCount; i++) + { + DhApiRenderableBox box = uploadBoxList.get(i); + Color color = box.color; + int colorIndex = i * 4; + this.colorData[colorIndex] = color.getRed() / 255.0f; + this.colorData[colorIndex + 1] = color.getGreen() / 255.0f; + this.colorData[colorIndex + 2] = color.getBlue() / 255.0f; + this.colorData[colorIndex + 3] = color.getAlpha() / 255.0f; + + this.materialData[i] = box.material; + } + + this.state = InstancedVboContainer.EState.READY_TO_UPLOAD; + } + + public void uploadDataToGpu() + { + // Upload transformation matrices + GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, this.chunkPos); + GL32.glBufferData(GL32.GL_ARRAY_BUFFER, this.chunkPosData, GL32.GL_DYNAMIC_DRAW); + GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, this.subChunkPos); + GL32.glBufferData(GL32.GL_ARRAY_BUFFER, this.subChunkPosData, GL32.GL_DYNAMIC_DRAW); + GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, this.scale); + GL32.glBufferData(GL32.GL_ARRAY_BUFFER, this.scalingData, GL32.GL_DYNAMIC_DRAW); + + // Upload colors + GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, this.color); + GL32.glBufferData(GL32.GL_ARRAY_BUFFER, this.colorData, GL32.GL_DYNAMIC_DRAW); + + // Upload materials + GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, this.material); + GL32.glBufferData(GL32.GL_ARRAY_BUFFER, this.materialData, GL32.GL_DYNAMIC_DRAW); + + this.state = EState.RENDER; + } + + //endregion + + + + //================// + // base overrides // + //================// + //region + + @Override + public void close() + { + tryDeleteBuffer(this.chunkPos); + tryDeleteBuffer(this.subChunkPos); + tryDeleteBuffer(this.scale); + tryDeleteBuffer(this.color); + tryDeleteBuffer(this.material); + } + private static void tryDeleteBuffer(int bufferId) + { + // usually unnecessary, but just in case + if (bufferId != 0) + { + GLMC.glDeleteBuffers(bufferId); + } + } + + //endregion + + + + //================// + // helper classes // + //================// + //region + + public enum EState + { + NEW, + UPDATING_DATA, + READY_TO_UPLOAD, + RENDER, + + ERROR, + } + + //endregion + + + +} diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/generic/RenderBoxArrayCache.java b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/generic/RenderBoxArrayCache.java deleted file mode 100644 index 027585c7d..000000000 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/generic/RenderBoxArrayCache.java +++ /dev/null @@ -1,91 +0,0 @@ -package com.seibel.distanthorizons.core.render.renderer.generic; - -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.RemovalNotification; -import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; -import com.seibel.distanthorizons.core.logging.DhLogger; - -import java.util.concurrent.ConcurrentMap; - -/** - * @see RenderableBoxGroup - */ -public class RenderBoxArrayCache -{ - private static final DhLogger LOGGER = new DhLoggerBuilder().build(); - - public static final int ARRAY_LENGTH_WIDTH = 24; - public static final int ARRAY_ID_WIDTH = 8; - - public static final int ARRAY_LENGTH_OFFSET = 0; - public static final int ARRAY_ID_OFFSET = ARRAY_LENGTH_OFFSET + ARRAY_LENGTH_WIDTH; - - public static final int ARRAY_LENGTH_MASK = (int) Math.pow(2, ARRAY_LENGTH_WIDTH) - 1; - public static final int ARRAY_ID_MASK = (int) Math.pow(2, ARRAY_ID_WIDTH) - 1; - - - private static final ConcurrentMap FLOAT_ARRAY_BY_KEY = CacheBuilder.newBuilder() - // This number needs to be high enough so that - // the number of generic object groups won't cause array thrashing. - // For now 512 should be way more than needed, unless - // someone adds a boatload of random generic objects. - .maximumSize(512) - .removalListener((RemovalNotification notification) -> { /* TODO log a warning if arrays start getting removed, that means we may need to re-think how the caching here works */ }) - .build().asMap(); - private static final ConcurrentMap INT_ARRAY_BY_KEY = CacheBuilder.newBuilder() - .maximumSize(512) - .removalListener((RemovalNotification notification) -> {}) - .build().asMap(); - - - - //============// - // get arrays // - //============// - - /** - * The ID parameter is to prevent returning the same array - * multiple times when the same length is requested. - */ - public static float[] getCachedFloatArray(int length, int id) - { - int key = encodeKey(length, id); - return FLOAT_ARRAY_BY_KEY.computeIfAbsent(key, (newKey) -> - { - int newLength = getLengthFromKey(newKey); - return new float[newLength]; - }); - } - public static int[] getCachedIntArray(int length, int id) - { - int key = encodeKey(length, id); - return INT_ARRAY_BY_KEY.computeIfAbsent(key, (newKey) -> - { - int newLength = getLengthFromKey(newKey); - return new int[newLength]; - }); - } - - - - //==============// - // key encoding // - //==============// - - private static int encodeKey(int arrayLength, int id) - { - if (id > Byte.MAX_VALUE) - { - throw new IndexOutOfBoundsException("The array's ID can only be 8 bytes long."); - } - - int data = 0; - data |= (arrayLength & ARRAY_LENGTH_MASK); - data |= (id & ARRAY_ID_MASK) << ARRAY_ID_OFFSET; - return data; - } - - private static int getLengthFromKey(int key) { return (key & ARRAY_LENGTH_MASK); } - private static int getIdFromKey(int key) { return ((key >> ARRAY_ID_OFFSET) & ARRAY_ID_MASK); } - -} diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/generic/RenderableBoxGroup.java b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/generic/RenderableBoxGroup.java index a509d6422..56f7a0d17 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/generic/RenderableBoxGroup.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/generic/RenderableBoxGroup.java @@ -5,28 +5,23 @@ import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhAp import com.seibel.distanthorizons.api.objects.math.DhApiVec3d; import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBox; import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBoxGroupShading; -import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.ColumnRenderBufferBuilder; -import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.LodBufferContainer; -import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.LodQuadBuilder; import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; -import com.seibel.distanthorizons.core.enums.EDhDirection; +import com.seibel.distanthorizons.core.logging.DhLogger; +import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.render.glObject.GLProxy; -import com.seibel.distanthorizons.core.util.ColorUtil; import com.seibel.distanthorizons.core.util.LodUtil; import com.seibel.distanthorizons.core.util.threading.PriorityTaskPicker; import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftGLWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper; -import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper; import org.jetbrains.annotations.Nullable; -import org.lwjgl.opengl.GL32; import java.awt.*; import java.io.Closeable; import java.util.*; import java.util.List; +import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.locks.ReentrantLock; import java.util.function.Consumer; import java.util.function.Predicate; import java.util.function.UnaryOperator; @@ -36,6 +31,8 @@ public class RenderableBoxGroup extends AbstractList implements IDhApiRenderableBoxGroup, Closeable { + private static final DhLogger LOGGER = new DhLoggerBuilder().build(); + private static final IMinecraftGLWrapper GLMC = SingletonInjector.INSTANCE.get(IMinecraftGLWrapper.class); private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class); @@ -70,13 +67,10 @@ public class RenderableBoxGroup public Consumer afterRenderFunc; // instance data - public int instanceColorVbo = 0; - public int instanceMaterialVbo = 0; - public int instanceScaleVbo = 0; - public int instanceChunkPosVbo = 0; - public int instanceSubChunkPosVbo = 0; + public InstancedVboContainer instancedVbos = new InstancedVboContainer(); + /** double buffering for thread safety and to prevent locking the render thread during update */ + private InstancedVboContainer altInstancedVbos = new InstancedVboContainer(); - public int uploadedBoxCount = -1; //=================// @@ -194,24 +188,52 @@ public class RenderableBoxGroup @Override public void triggerBoxChange() { this.vertexDataDirty = true; } - /** Does nothing if the vertex data is already up-to-date */ - public void updateVertexAttributeData() + /** + * Does nothing if the vertex data is already up-to-date + * and is meaningless if using direct rendering. + */ + public void tryUpdateInstancedDataAsync() { + // if the alt container is done, swap it in + if (this.altInstancedVbos.state == InstancedVboContainer.EState.READY_TO_UPLOAD) + { + this.altInstancedVbos.uploadDataToGpu(); + + // swap VBO references for rendering + InstancedVboContainer temp = this.instancedVbos; + this.instancedVbos = this.altInstancedVbos; + this.altInstancedVbos = temp; + + this.vertexDataDirty = false; + + return; + } + + + + // if the vertex data is already up to date, do nothing if (!this.vertexDataDirty) { return; } - this.vertexDataDirty = false; - if (this.instanceChunkPosVbo == 0) + PriorityTaskPicker.Executor executor = ThreadPoolUtil.getRenderLoadingExecutor(); + if (executor == null || executor.isTerminated()) { - this.instanceChunkPosVbo = GLMC.glGenBuffers(); - this.instanceSubChunkPosVbo = GLMC.glGenBuffers(); - this.instanceScaleVbo = GLMC.glGenBuffers(); - this.instanceColorVbo = GLMC.glGenBuffers(); - this.instanceMaterialVbo = GLMC.glGenBuffers(); + return; } + // if the alternate container is already updating, don't double-queue it + if (this.altInstancedVbos.state == InstancedVboContainer.EState.UPDATING_DATA) + { + return; + } + this.altInstancedVbos.state = InstancedVboContainer.EState.UPDATING_DATA; + + + + this.altInstancedVbos.tryRunRenderThreadSetup(); + // copy over the box list so we can upload without concurrent modification issues this.uploadBoxList.clear(); synchronized (this.uploadBoxList) @@ -219,69 +241,26 @@ public class RenderableBoxGroup this.uploadBoxList.addAll(this.boxList); } - - int boxCount = this.uploadBoxList.size(); - this.uploadedBoxCount = boxCount; - - - - // transformation / scaling // - int[] chunkPosData = RenderBoxArrayCache.getCachedIntArray(boxCount * 3, 0); - float[] subChunkPosData = RenderBoxArrayCache.getCachedFloatArray(boxCount * 3, 1); - float[] scalingData = RenderBoxArrayCache.getCachedFloatArray(boxCount * 3, 2); - for (int i = 0; i < boxCount; i++) + try { - DhApiRenderableBox box = this.uploadBoxList.get(i); - - int dataIndex = i * 3; - - chunkPosData[dataIndex] = LodUtil.getChunkPosFromDouble(box.minPos.x); - chunkPosData[dataIndex + 1] = LodUtil.getChunkPosFromDouble(box.minPos.y); - chunkPosData[dataIndex + 2] = LodUtil.getChunkPosFromDouble(box.minPos.z); - - subChunkPosData[dataIndex] = LodUtil.getSubChunkPosFromDouble(box.minPos.x); - subChunkPosData[dataIndex + 1] = LodUtil.getSubChunkPosFromDouble(box.minPos.y); - subChunkPosData[dataIndex + 2] = LodUtil.getSubChunkPosFromDouble(box.minPos.z); - - scalingData[dataIndex] = (float) (box.maxPos.x - box.minPos.x); - scalingData[dataIndex + 1] = (float) (box.maxPos.y - box.minPos.y); - scalingData[dataIndex + 2] = (float) (box.maxPos.z - box.minPos.z); - + executor.runTask(() -> + { + try + { + this.altInstancedVbos.updateVertexData(this.uploadBoxList); + } + catch (Exception e) + { + LOGGER.error("Unexpected error updating instanced VBO data for: ["+this+"], error: ["+e.getMessage()+"].", e); + this.altInstancedVbos.state = InstancedVboContainer.EState.ERROR; + } + }); } - - - // colors/materials // - float[] colorData = RenderBoxArrayCache.getCachedFloatArray(boxCount * 4, 3); - int[] materialData = RenderBoxArrayCache.getCachedIntArray(boxCount, 4); - for (int i = 0; i < boxCount; i++) + catch (RejectedExecutionException ignore) { - DhApiRenderableBox box = this.uploadBoxList.get(i); - Color color = box.color; - int colorIndex = i * 4; - colorData[colorIndex] = color.getRed() / 255.0f; - colorData[colorIndex + 1] = color.getGreen() / 255.0f; - colorData[colorIndex + 2] = color.getBlue() / 255.0f; - colorData[colorIndex + 3] = color.getAlpha() / 255.0f; - - materialData[i] = box.material; + // the executor was shut down, it should be back up shortly and able to accept new jobs + this.altInstancedVbos.state = InstancedVboContainer.EState.NEW; } - - - // Upload transformation matrices - GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, this.instanceChunkPosVbo); - GL32.glBufferData(GL32.GL_ARRAY_BUFFER, chunkPosData, GL32.GL_DYNAMIC_DRAW); - GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, this.instanceSubChunkPosVbo); - GL32.glBufferData(GL32.GL_ARRAY_BUFFER, subChunkPosData, GL32.GL_DYNAMIC_DRAW); - GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, this.instanceScaleVbo); - GL32.glBufferData(GL32.GL_ARRAY_BUFFER, scalingData, GL32.GL_DYNAMIC_DRAW); - - // Upload colors - GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, this.instanceColorVbo); - GL32.glBufferData(GL32.GL_ARRAY_BUFFER, colorData, GL32.GL_DYNAMIC_DRAW); - - // Upload materials - GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, this.instanceMaterialVbo); - GL32.glBufferData(GL32.GL_ARRAY_BUFFER, materialData, GL32.GL_DYNAMIC_DRAW); } //endregion @@ -362,42 +341,15 @@ public class RenderableBoxGroup //region @Override - public String toString() { return "ID:["+this.id+"], pos:["+this.originBlockPos.x+","+this.originBlockPos.y+","+this.originBlockPos.z+"], size:["+this.size()+"], active:["+this.active+"]"; } + public String toString() { return "["+this.resourceLocationNamespace+":"+this.resourceLocationPath+"] ID:["+this.id+"], pos:["+this.originBlockPos.x+","+this.originBlockPos.y+","+this.originBlockPos.z+"], size:["+this.size()+"], active:["+this.active+"]"; } @Override public void close() { GLProxy.queueRunningOnRenderThread(() -> { - if (this.instanceChunkPosVbo != 0) - { - GLMC.glDeleteBuffers(this.instanceChunkPosVbo); - this.instanceChunkPosVbo = 0; - } - - if (this.instanceSubChunkPosVbo != 0) - { - GLMC.glDeleteBuffers(this.instanceSubChunkPosVbo); - this.instanceSubChunkPosVbo = 0; - } - - if (this.instanceScaleVbo != 0) - { - GLMC.glDeleteBuffers(this.instanceScaleVbo); - this.instanceScaleVbo = 0; - } - - if (this.instanceColorVbo != 0) - { - GLMC.glDeleteBuffers(this.instanceColorVbo); - this.instanceColorVbo = 0; - } - - if (this.instanceMaterialVbo != 0) - { - GLMC.glDeleteBuffers(this.instanceMaterialVbo); - this.instanceMaterialVbo = 0; - } + this.instancedVbos.close(); + this.altInstancedVbos.close(); }); }