diff --git a/src/main/java/com/seibel/lod/core/builders/lodBuilding/bufferBuilding/BufferMergeDirectionEnum.java b/src/main/java/com/seibel/lod/core/builders/lodBuilding/bufferBuilding/BufferMergeDirectionEnum.java
new file mode 100644
index 000000000..991987d3f
--- /dev/null
+++ b/src/main/java/com/seibel/lod/core/builders/lodBuilding/bufferBuilding/BufferMergeDirectionEnum.java
@@ -0,0 +1,35 @@
+/*
+ * This file is part of the Distant Horizons mod (formerly the LOD Mod),
+ * licensed under the GNU GPL v3 License.
+ *
+ * Copyright (C) 2020-2022 James Seibel
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package com.seibel.lod.core.builders.lodBuilding.bufferBuilding;
+
+/**
+ * EastWest
+ * NorthSouthOrUpDown
+ *
+ * @author James Seibel
+ * @version 2022-4-9
+ */
+public enum BufferMergeDirectionEnum
+{
+ EastWest,
+
+ /** NorthSouth and UpDown are merged since */
+ NorthSouthOrUpDown
+}
diff --git a/src/main/java/com/seibel/lod/core/builders/lodBuilding/bufferBuilding/BufferQuad.java b/src/main/java/com/seibel/lod/core/builders/lodBuilding/bufferBuilding/BufferQuad.java
new file mode 100644
index 000000000..5b8131c8f
--- /dev/null
+++ b/src/main/java/com/seibel/lod/core/builders/lodBuilding/bufferBuilding/BufferQuad.java
@@ -0,0 +1,278 @@
+/*
+ * This file is part of the Distant Horizons mod (formerly the LOD Mod),
+ * licensed under the GNU GPL v3 License.
+ *
+ * Copyright (C) 2020-2022 James Seibel
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package com.seibel.lod.core.builders.lodBuilding.bufferBuilding;
+
+import com.seibel.lod.core.enums.LodDirection;
+import com.seibel.lod.core.util.ColorUtil;
+
+import static com.seibel.lod.core.render.LodRenderer.EVENT_LOGGER;
+
+/**
+ * Represents a renderable quad.
+ *
+ * @author James Seibel
+ * @author ?
+ * @version 4-9-2022
+ */
+public class BufferQuad
+{
+ final short x;
+ final short y;
+ final short z;
+ short widthEastWest;
+ /** This is both North/South and Up/Down since the merging logic is the same either way */
+ short widthNorthSouthOrUpDown;
+ int color;
+ final byte skyLight;
+ final byte blockLight;
+ final LodDirection direction;
+
+
+ BufferQuad(short x, short y, short z, short widthEastWest, short widthNorthSouthOrUpDown,
+ int color, byte skylight, byte blocklight,
+ LodDirection direction)
+ {
+ if (widthEastWest == 0 || widthNorthSouthOrUpDown == 0)
+ throw new IllegalArgumentException("Size 0 quad!");
+ if (widthEastWest < 0 || widthNorthSouthOrUpDown < 0)
+ throw new IllegalArgumentException("Negative sized quad!");
+
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ this.widthEastWest = widthEastWest;
+ this.widthNorthSouthOrUpDown = widthNorthSouthOrUpDown;
+ this.color = color;
+ this.skyLight = skylight;
+ this.blockLight = blocklight;
+ this.direction = direction;
+ }
+
+
+
+ /** a rough but fast calculation */
+ double calculateDistance(double relativeX, double relativeY, double relativeZ)
+ {
+ return Math.pow(relativeX - x, 2) + Math.pow(relativeY - y, 2) + Math.pow(relativeZ - z, 2);
+ }
+
+
+ /** compares this quad's position to the given quad */
+ public int compare(BufferQuad quad, BufferMergeDirectionEnum compareDirection)
+ {
+ if (direction != quad.direction)
+ throw new IllegalArgumentException("The other quad is not in the same direction: " + quad.direction + " vs " + direction);
+
+ if (compareDirection == BufferMergeDirectionEnum.EastWest)
+ {
+ switch (direction.getAxis())
+ {
+ case X:
+ return threeDimensionalCompare(x, y, z, quad.x, quad.y, quad.z);
+ case Y:
+ return threeDimensionalCompare(y, z, x, quad.y, quad.z, quad.x);
+ case Z:
+ return threeDimensionalCompare(z, y, x, quad.z, quad.y, quad.x);
+
+ default:
+ throw new IllegalArgumentException("Invalid Axis enum: " + direction.getAxis());
+ }
+ }
+ else // if ()
+ {
+ switch (direction.getAxis())
+ {
+ case X:
+ return threeDimensionalCompare(x, z, y, quad.x, quad.z, quad.y);
+ case Y:
+ return threeDimensionalCompare(y, x, z, quad.y, quad.x, quad.z);
+ case Z:
+ return threeDimensionalCompare(z, x, y, quad.z, quad.x, quad.y);
+
+ default:
+ throw new IllegalArgumentException("Invalid Axis enum: " + direction.getAxis());
+ }
+ }
+ }
+ /**
+ * Compares two 3D points A and B.
+ * The X, Y, and Z coordinates can be passed into parameters 0, 1, and 2 in any order
+ * provided they are in the same order for both A and B.
+ * With the 0th parameter being the most significant when comparing.
+ */
+ private static int threeDimensionalCompare(short a0, short a1, short a2, short b0, short b1, short b2)
+ {
+ long a = (long) a0 << 48 | (long) a1 << 32 | (long) a2 << 16;
+ long b = (long) b0 << 48 | (long) b1 << 32 | (long) b2 << 16;
+ return Long.compare(a, b);
+ }
+
+
+ /**
+ * Attempts to merge the given quad into this one.
+ * @returns true if the quads were merged, false otherwise.
+ */
+ public boolean tryMerge(BufferQuad quad, BufferMergeDirectionEnum mergeDirection)
+ {
+ // only merge quads that are in the same direction
+ if (direction != quad.direction)
+ return false;
+
+ // make sure these quads share the same perpendicular axis
+ if ((mergeDirection == BufferMergeDirectionEnum.EastWest && this.y != quad.y) ||
+ (mergeDirection == BufferMergeDirectionEnum.NorthSouthOrUpDown && this.x != quad.x))
+ {
+ return false;
+ }
+
+
+ // get the position of each quad to compare against
+ short thisPerpendicularCompareStartPos; // edge perpendicular to the merge direction
+ short thisParallelCompareStartPos; // edge parallel to the merge direction
+ short otherPerpendicularCompareStartPos;
+ short otherParallelCompareStartPos;
+ switch (this.direction.getAxis())
+ {
+ default: // shouldn't normally happen, just here to make the compiler happy
+ case X:
+ if (mergeDirection == BufferMergeDirectionEnum.EastWest)
+ {
+ thisPerpendicularCompareStartPos = this.z;
+ thisParallelCompareStartPos = this.x;
+
+ otherPerpendicularCompareStartPos = quad.z;
+ otherParallelCompareStartPos = quad.x;
+ }
+ else //if (mergeDirection == MergeDirection.NorthSouthOrUpDown)
+ {
+ thisPerpendicularCompareStartPos = this.y;
+ thisParallelCompareStartPos = this.z;
+
+ otherPerpendicularCompareStartPos = quad.y;
+ otherParallelCompareStartPos = quad.z;
+ }
+ break;
+
+ case Y:
+ if (mergeDirection == BufferMergeDirectionEnum.EastWest)
+ {
+ thisPerpendicularCompareStartPos = this.x;
+ thisParallelCompareStartPos = this.z;
+
+ otherPerpendicularCompareStartPos = quad.x;
+ otherParallelCompareStartPos = quad.z;
+ }
+ else //if (mergeDirection == MergeDirection.NorthSouthOrUpDown)
+ {
+ thisPerpendicularCompareStartPos = this.z;
+ thisParallelCompareStartPos = this.y;
+
+ otherPerpendicularCompareStartPos = quad.z;
+ otherParallelCompareStartPos = quad.y;
+ }
+ break;
+
+ case Z:
+ if (mergeDirection == BufferMergeDirectionEnum.EastWest)
+ {
+ thisPerpendicularCompareStartPos = this.x;
+ thisParallelCompareStartPos = this.z;
+
+ otherPerpendicularCompareStartPos = quad.x;
+ otherParallelCompareStartPos = quad.z;
+ }
+ else //if (mergeDirection == MergeDirection.NorthSouthOrUpDown)
+ {
+ thisPerpendicularCompareStartPos = this.y;
+ thisParallelCompareStartPos = this.z;
+
+ otherPerpendicularCompareStartPos = quad.y;
+ otherParallelCompareStartPos = quad.z;
+ }
+ break;
+ }
+
+ // get the width of this quad in the relevant axis
+ short thisPerpendicularCompareWidth;
+ short thisParallelCompareWidth;
+ short otherParallelCompareWidth;
+ if (mergeDirection == BufferMergeDirectionEnum.EastWest)
+ {
+ thisPerpendicularCompareWidth = this.widthEastWest;
+
+ thisParallelCompareWidth = this.widthNorthSouthOrUpDown;
+ otherParallelCompareWidth = quad.widthNorthSouthOrUpDown;
+ }
+ else
+ {
+ thisPerpendicularCompareWidth = this.widthNorthSouthOrUpDown;
+
+ thisParallelCompareWidth = this.widthEastWest;
+ otherParallelCompareWidth = quad.widthEastWest;
+ }
+
+
+
+ // check if these quads are adjacent
+ if (thisPerpendicularCompareStartPos + thisPerpendicularCompareWidth < otherPerpendicularCompareStartPos ||
+ thisParallelCompareStartPos != otherParallelCompareStartPos)
+ {
+ // these quads aren't adjacent, they can't be merged
+ return false;
+ }
+ else if (thisPerpendicularCompareStartPos + thisPerpendicularCompareWidth > otherPerpendicularCompareStartPos)
+ {
+ // these quads are overlapping, they can't be merged
+ EVENT_LOGGER.warn("Overlapping quads detected!");
+ quad.color = ColorUtil.rgbToInt(255, 0, 0);
+ return false;
+ }
+
+
+ // only merge quads that have the same width edges
+ if (thisParallelCompareWidth != otherParallelCompareWidth)
+ {
+ return false;
+ }
+
+ // do the quads' color, light, etc. match?
+ if (color != quad.color ||
+ skyLight != quad.skyLight ||
+ blockLight != quad.blockLight)
+ {
+ // we can only merge identically colored/lit quads
+ return false;
+ }
+
+ // merge the two quads
+ if (mergeDirection == BufferMergeDirectionEnum.NorthSouthOrUpDown)
+ {
+ widthNorthSouthOrUpDown += quad.widthNorthSouthOrUpDown;
+ }
+ else // if (mergeDirection == MergeDirection.EastWest)
+ {
+ widthEastWest += quad.widthEastWest;
+ }
+
+ // merge successful
+ return true;
+ }
+
+}
diff --git a/src/main/java/com/seibel/lod/core/builders/lodBuilding/bufferBuilding/CubicLodTemplate.java b/src/main/java/com/seibel/lod/core/builders/lodBuilding/bufferBuilding/CubicLodTemplate.java
index 7cc5c8c6e..21e77830c 100644
--- a/src/main/java/com/seibel/lod/core/builders/lodBuilding/bufferBuilding/CubicLodTemplate.java
+++ b/src/main/java/com/seibel/lod/core/builders/lodBuilding/bufferBuilding/CubicLodTemplate.java
@@ -19,19 +19,15 @@
package com.seibel.lod.core.builders.lodBuilding.bufferBuilding;
-import com.seibel.lod.core.api.ApiShared;
import com.seibel.lod.core.enums.rendering.DebugMode;
import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler;
import com.seibel.lod.core.objects.opengl.LodBox;
-import com.seibel.lod.core.objects.opengl.LodQuadBuilder;
import com.seibel.lod.core.util.ColorUtil;
import com.seibel.lod.core.util.DataPointUtil;
import com.seibel.lod.core.util.LevelPosUtil;
import com.seibel.lod.core.util.LodUtil;
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton;
-import java.awt.*;
-
/**
* Builds LODs as rectangular prisms.
* @author James Seibel
diff --git a/src/main/java/com/seibel/lod/core/builders/lodBuilding/bufferBuilding/LodQuadBuilder.java b/src/main/java/com/seibel/lod/core/builders/lodBuilding/bufferBuilding/LodQuadBuilder.java
new file mode 100644
index 000000000..557e55406
--- /dev/null
+++ b/src/main/java/com/seibel/lod/core/builders/lodBuilding/bufferBuilding/LodQuadBuilder.java
@@ -0,0 +1,468 @@
+/*
+ * This file is part of the Distant Horizons mod (formerly the LOD Mod),
+ * licensed under the GNU GPL v3 License.
+ *
+ * Copyright (C) 2020-2022 James Seibel
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package com.seibel.lod.core.builders.lodBuilding.bufferBuilding;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.ListIterator;
+
+import com.seibel.lod.core.builders.lodBuilding.LodBuilder;
+import com.seibel.lod.core.enums.LodDirection;
+import com.seibel.lod.core.enums.LodDirection.Axis;
+import com.seibel.lod.core.enums.config.GpuUploadMethod;
+import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler;
+import com.seibel.lod.core.objects.opengl.LodVertexBuffer;
+import com.seibel.lod.core.util.ColorUtil;
+import com.seibel.lod.core.util.LodUtil;
+import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton;
+
+import static com.seibel.lod.core.render.LodRenderer.EVENT_LOGGER;
+
+/**
+ * Used to create the quads before they are converted to renderable buffers.
+ *
+ * @version 2022-4-9
+ */
+public class LodQuadBuilder
+{
+ static final int MAX_BUFFER_SIZE = (1024 * 1024);
+ static final int QUAD_BYTE_SIZE = (12 * 6);
+ static final int MAX_QUADS_PER_BUFFER = MAX_BUFFER_SIZE / QUAD_BYTE_SIZE;
+
+ static final ILodConfigWrapperSingleton CONFIG = SingletonHandler.get(ILodConfigWrapperSingleton.class);
+
+ public final boolean skipQuadsWithZeroSkylight;
+ public final short skyLightCullingBelow;
+
+ final ArrayList[] quads = (ArrayList[]) new ArrayList[6];
+
+ public static final int[][][] DIRECTION_VERTEX_QUAD = new int[][][]
+ {
+ // X,Z //
+ { // UP
+ { 1, 0 }, // 0
+ { 1, 1 }, // 1
+ { 0, 1 }, // 2
+
+ { 1, 0 }, // 0
+ { 0, 1 }, // 2
+ { 0, 0 }, // 3
+ },
+ { // DOWN
+ { 0, 0 }, // 0
+ { 0, 1 }, // 1
+ { 1, 1 }, // 2
+
+ { 0, 0 }, // 0
+ { 1, 1 }, // 2
+ { 1, 0 }, // 3
+ },
+
+ // X,Y //
+ { // NORTH
+ { 0, 0 }, // 0
+ { 0, 1 }, // 1
+ { 1, 1 }, // 2
+
+ { 0, 0 }, // 0
+ { 1, 1 }, // 2
+ { 1, 0 }, // 3
+ },
+ { // SOUTH
+ { 1, 0 }, // 0
+ { 1, 1 }, // 1
+ { 0, 1 }, // 2
+
+ { 1, 0 }, // 0
+ { 0, 1 }, // 2
+ { 0, 0 }, // 3
+ },
+
+ // Z,Y //
+ { // WEST
+ { 0, 0 }, // 0
+ { 1, 0 }, // 1
+ { 1, 1 }, // 2
+
+ { 0, 0 }, // 0
+ { 1, 1 }, // 2
+ { 0, 1 }, // 3
+ },
+ { // EAST
+ { 0, 1 }, // 0
+ { 1, 1 }, // 1
+ { 1, 0 }, // 2
+
+ { 0, 1 }, // 0
+ { 1, 0 }, // 2
+ { 0, 0 }, // 3
+ },
+ };
+
+
+
+ public LodQuadBuilder(boolean enableSkylightCulling, int skyLightCullingBelow)
+ {
+ for (int i = 0; i < 6; i++)
+ quads[i] = new ArrayList<>();
+
+ this.skipQuadsWithZeroSkylight = enableSkylightCulling;
+ this.skyLightCullingBelow = (short) (skyLightCullingBelow - LodBuilder.MIN_WORLD_HEIGHT);
+ }
+
+
+
+
+ public void addQuadAdj(LodDirection dir, short x, short y, short z,
+ short widthEastWest, short widthNorthSouthOrUpDown,
+ int color, byte skylight, byte blocklight)
+ {
+ if (dir.ordinal() <= LodDirection.DOWN.ordinal())
+ throw new IllegalArgumentException("addQuadAdj() is only for adj direction! Not UP or Down!");
+ if (skipQuadsWithZeroSkylight && skylight == 0 && y < skyLightCullingBelow)
+ return;
+ quads[dir.ordinal()].add(new BufferQuad(x, y, z, widthEastWest, widthNorthSouthOrUpDown, color, skylight, blocklight, dir));
+ }
+
+ // XZ
+ public void addQuadUp(short x, short y, short z, short width, short wz, int color, byte skylight, byte blocklight)
+ {
+ if (skipQuadsWithZeroSkylight && skylight == 0 && y < skyLightCullingBelow)
+ return;
+ quads[LodDirection.UP.ordinal()].add(new BufferQuad(x, y, z, width, wz, color, skylight, blocklight, LodDirection.UP));
+ }
+
+ public void addQuadDown(short x, short y, short z, short width, short wz, int color, byte skylight, byte blocklight)
+ {
+ if (skipQuadsWithZeroSkylight && skylight == 0 && y < skyLightCullingBelow)
+ return;
+ quads[LodDirection.DOWN.ordinal()].add(new BufferQuad(x, y, z, width, wz, color, skylight, blocklight, LodDirection.DOWN));
+ }
+
+ // XY
+ public void addQuadN(short x, short y, short z, short width, short wy, int color, byte skylight, byte blocklight)
+ {
+ if (skipQuadsWithZeroSkylight && skylight == 0 && y < skyLightCullingBelow)
+ return;
+ quads[LodDirection.NORTH.ordinal()].add(new BufferQuad(x, y, z, width, wy, color, skylight, blocklight, LodDirection.NORTH));
+ }
+
+ public void addQuadS(short x, short y, short z, short width, short wy, int color, byte skylight, byte blocklight)
+ {
+ if (skipQuadsWithZeroSkylight && skylight == 0 && y < skyLightCullingBelow)
+ return;
+ quads[LodDirection.SOUTH.ordinal()].add(new BufferQuad(x, y, z, width, wy, color, skylight, blocklight, LodDirection.SOUTH));
+ }
+
+ // ZY
+ public void addQuadW(short x, short y, short z, short width, short wy, int color, byte skylight, byte blocklight)
+ {
+ if (skipQuadsWithZeroSkylight && skylight == 0 && y < skyLightCullingBelow)
+ return;
+ quads[LodDirection.WEST.ordinal()].add(new BufferQuad(x, y, z, width, wy, color, skylight, blocklight, LodDirection.WEST));
+ }
+
+ public void addQuadE(short x, short y, short z, short width, short wy, int color, byte skylight, byte blocklight)
+ {
+ if (skipQuadsWithZeroSkylight && skylight == 0 && y < skyLightCullingBelow)
+ return;
+ quads[LodDirection.EAST.ordinal()].add(new BufferQuad(x, y, z, width, wy, color, skylight, blocklight, LodDirection.EAST));
+ }
+
+
+
+ private static void putVertex(ByteBuffer bb, short x, short y, short z, int color, byte skylight, byte blocklight)
+ {
+ skylight %= 16;
+ blocklight %= 16;
+
+ bb.putShort(x);
+ bb.putShort(y);
+ bb.putShort(z);
+
+ bb.putShort((short) (skylight | (blocklight << 4)));
+ byte r = (byte) ColorUtil.getRed(color);
+ byte g = (byte) ColorUtil.getGreen(color);
+ byte b = (byte) ColorUtil.getBlue(color);
+ byte a = (byte) ColorUtil.getAlpha(color);
+ bb.put(r);
+ bb.put(g);
+ bb.put(b);
+ bb.put(a);
+ }
+
+ private static void putQuad(ByteBuffer bb, BufferQuad quad)
+ {
+ int[][] quadBase = DIRECTION_VERTEX_QUAD[quad.direction.ordinal()];
+ short widthEastWest = quad.widthEastWest;
+ short widthNorthSouth = quad.widthNorthSouthOrUpDown;
+ Axis axis = quad.direction.getAxis();
+ for (int i = 0; i < quadBase.length; i++)
+ {
+ short dx, dy, dz;
+ switch (axis)
+ {
+ case X: // ZY
+ dx = 0;
+ dy = quadBase[i][1] == 1 ? widthNorthSouth : 0;
+ dz = quadBase[i][0] == 1 ? widthEastWest : 0;
+ break;
+ case Y: // XZ
+ dx = quadBase[i][0] == 1 ? widthEastWest : 0;
+ dy = 0;
+ dz = quadBase[i][1] == 1 ? widthNorthSouth : 0;
+ break;
+ case Z: // XY
+ dx = quadBase[i][0] == 1 ? widthEastWest : 0;
+ dy = quadBase[i][1] == 1 ? widthNorthSouth : 0;
+ dz = 0;
+ break;
+ default:
+ throw new IllegalArgumentException("Invalid Axis enum: " + axis);
+ }
+ putVertex(bb, (short) (quad.x + dx), (short) (quad.y + dy), (short) (quad.z + dz), quad.color,
+ quad.skyLight, quad.blockLight);
+ }
+ }
+
+ /** Uses Greedy meshing to merge this builder's Quads. */
+ public void mergeQuads()
+ {
+ long mergeCount = 0;
+ long preQuadsCount = getCurrentQuadsCount();
+ if (preQuadsCount <= 1)
+ return;
+
+ for (int directionIndex = 0; directionIndex < 6; directionIndex++)
+ {
+ mergeCount += mergeQuadsInternal(directionIndex, BufferMergeDirectionEnum.EastWest);
+
+ // only merge after the top has been merged
+ if (directionIndex == 1)
+ {
+ long pass2 = mergeQuadsInternal(directionIndex, BufferMergeDirectionEnum.NorthSouthOrUpDown);
+ mergeCount += pass2;
+ }
+ }
+ long postQuadsCount = getCurrentQuadsCount();
+ //if (mergeCount != 0)
+ EVENT_LOGGER.debug("Merged {}/{}({}) quads", mergeCount, preQuadsCount, mergeCount / (double) preQuadsCount);
+ }
+ /** Merges all of this builder's quads for the given directionIndex (up, down, left, etc.) in the given direction */
+ private long mergeQuadsInternal(int directionIndex, BufferMergeDirectionEnum mergeDirection)
+ {
+ if (quads[directionIndex].size() <= 1)
+ return 0;
+
+ quads[directionIndex].sort( (objOne, objTwo) -> objOne.compare(objTwo, mergeDirection) );
+
+ long mergeCount = 0;
+ ListIterator iter = quads[directionIndex].listIterator();
+ BufferQuad currentQuad = iter.next();
+ while (iter.hasNext())
+ {
+ BufferQuad nextQuad = iter.next();
+
+ if (currentQuad.tryMerge(nextQuad, mergeDirection))
+ {
+ // merge successful, attempt to merge the next quad
+ mergeCount++;
+ iter.set(null);
+ }
+ else
+ {
+ // merge fail, move on to the next quad
+ currentQuad = nextQuad;
+ }
+ }
+ quads[directionIndex].removeIf(o -> o == null);
+ return mergeCount;
+ }
+
+
+
+ public Iterator makeVertexBuffers()
+ {
+ return new Iterator()
+ {
+ final ByteBuffer bb = ByteBuffer.allocateDirect(MAX_QUADS_PER_BUFFER * QUAD_BYTE_SIZE)
+ .order(ByteOrder.nativeOrder());
+ int dir = skipEmpty(0);
+ int quad = 0;
+
+ private int skipEmpty(int d)
+ {
+ while (d < 6 && quads[d].isEmpty())
+ d++;
+ return d;
+ }
+
+ @Override
+ public boolean hasNext()
+ {
+ return dir < 6;
+ }
+
+ @Override
+ public ByteBuffer next()
+ {
+ if (dir >= 6)
+ {
+ return null;
+ }
+ bb.clear();
+ bb.limit(MAX_QUADS_PER_BUFFER * QUAD_BYTE_SIZE);
+ while (bb.hasRemaining() && dir < 6)
+ {
+ writeData();
+ }
+ bb.limit(bb.position());
+ bb.rewind();
+ return bb;
+ }
+
+ private void writeData()
+ {
+ int i = quad;
+ for (; i < quads[dir].size(); i++)
+ {
+ if (!bb.hasRemaining())
+ {
+ break;
+ }
+ putQuad(bb, quads[dir].get(i));
+ }
+
+ if (i >= quads[dir].size())
+ {
+ quad = 0;
+ dir++;
+ dir = skipEmpty(dir);
+ }
+ else
+ {
+ quad = i;
+ }
+ }
+ };
+ }
+
+ public interface BufferFiller
+ {
+ /** If true: more data needs to be filled */
+ boolean fill(LodVertexBuffer vbo);
+ }
+
+ public BufferFiller makeBufferFiller(GpuUploadMethod method)
+ {
+ return new BufferFiller()
+ {
+ int dir = 0;
+ int quad = 0;
+
+ public boolean fill(LodVertexBuffer vbo)
+ {
+ if (dir >= 6)
+ {
+ vbo.vertexCount = 0;
+ return false;
+ }
+
+ int numOfQuads = _countRemainingQuads();
+ if (numOfQuads > MAX_QUADS_PER_BUFFER)
+ numOfQuads = MAX_QUADS_PER_BUFFER;
+ if (numOfQuads == 0)
+ {
+ vbo.vertexCount = 0;
+ return false;
+ }
+ ByteBuffer bb = vbo.mapBuffer(numOfQuads * QUAD_BYTE_SIZE, method, MAX_QUADS_PER_BUFFER * QUAD_BYTE_SIZE);
+ if (bb == null)
+ throw new NullPointerException("mapBuffer returned null");
+ bb.clear();
+ bb.limit(numOfQuads * QUAD_BYTE_SIZE);
+ while (bb.hasRemaining() && dir < 6)
+ {
+ writeData(bb);
+ }
+ bb.rewind();
+ vbo.unmapBuffer(method);
+ vbo.vertexCount = numOfQuads * 6;
+ return dir < 6;
+ }
+
+ private int _countRemainingQuads()
+ {
+ int a = quads[dir].size() - quad;
+ for (int i = dir + 1; i < quads.length; i++)
+ {
+ a += quads[i].size();
+ }
+ return a;
+ }
+
+ private void writeData(ByteBuffer bb)
+ {
+ int startQ = quad;
+
+ int i = startQ;
+ for (i = startQ; i < quads[dir].size(); i++)
+ {
+ if (!bb.hasRemaining())
+ {
+ break;
+ }
+ putQuad(bb, quads[dir].get(i));
+ }
+
+ if (i >= quads[dir].size())
+ {
+ quad = 0;
+ dir++;
+ while (dir < 6 && quads[dir].isEmpty())
+ dir++;
+ }
+ else
+ {
+ quad = i;
+ }
+ }
+ };
+ }
+
+
+
+ public int getCurrentQuadsCount()
+ {
+ int i = 0;
+ for (ArrayList qs : quads)
+ i += qs.size();
+ return i;
+ }
+
+ /** Returns how many Buffers will be needed to render everything in this builder. */
+ public int getCurrentNeededVertexBufferCount()
+ {
+ return LodUtil.ceilDiv(getCurrentQuadsCount(), MAX_QUADS_PER_BUFFER);
+ }
+
+}
diff --git a/src/main/java/com/seibel/lod/core/enums/LodDirection.java b/src/main/java/com/seibel/lod/core/enums/LodDirection.java
index 7e1b4c2b6..8007ddc00 100644
--- a/src/main/java/com/seibel/lod/core/enums/LodDirection.java
+++ b/src/main/java/com/seibel/lod/core/enums/LodDirection.java
@@ -28,11 +28,18 @@ import java.util.stream.Collectors;
import com.seibel.lod.core.objects.math.Vec3i;
/**
- * A (almost) exact copy of Minecraft's
+ * An (almost) exact copy of Minecraft's
* Direction enum.
- *
+ *
+ * Up
+ * Down
+ * North
+ * South
+ * East
+ * West
+ *
* @author James Seibel
- * @version 11-13-2021
+ * @version 2021-11-13
*/
public enum LodDirection
{
diff --git a/src/main/java/com/seibel/lod/core/objects/opengl/LodBox.java b/src/main/java/com/seibel/lod/core/objects/opengl/LodBox.java
index 1cd34b9a2..bdde5c9e3 100644
--- a/src/main/java/com/seibel/lod/core/objects/opengl/LodBox.java
+++ b/src/main/java/com/seibel/lod/core/objects/opengl/LodBox.java
@@ -19,11 +19,11 @@
package com.seibel.lod.core.objects.opengl;
+import com.seibel.lod.core.builders.lodBuilding.bufferBuilding.LodQuadBuilder;
import com.seibel.lod.core.enums.LodDirection;
import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler;
import com.seibel.lod.core.util.ColorUtil;
import com.seibel.lod.core.util.DataPointUtil;
-import com.seibel.lod.core.util.LodUtil;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
public class LodBox
diff --git a/src/main/java/com/seibel/lod/core/objects/opengl/LodQuadBuilder.java b/src/main/java/com/seibel/lod/core/objects/opengl/LodQuadBuilder.java
deleted file mode 100644
index 347e12b8b..000000000
--- a/src/main/java/com/seibel/lod/core/objects/opengl/LodQuadBuilder.java
+++ /dev/null
@@ -1,693 +0,0 @@
-/*
- * This file is part of the Distant Horizons mod (formerly the LOD Mod),
- * licensed under the GNU GPL v3 License.
- *
- * Copyright (C) 2020-2022 James Seibel
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, version 3.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-package com.seibel.lod.core.objects.opengl;
-
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.ListIterator;
-
-import com.seibel.lod.core.builders.lodBuilding.LodBuilder;
-import com.seibel.lod.core.enums.LodDirection;
-import com.seibel.lod.core.enums.LodDirection.Axis;
-import com.seibel.lod.core.enums.config.GpuUploadMethod;
-import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler;
-import com.seibel.lod.core.util.ColorUtil;
-import com.seibel.lod.core.util.LodUtil;
-import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton;
-
-import static com.seibel.lod.core.render.LodRenderer.EVENT_LOGGER;
-
-public class LodQuadBuilder
-{
- static final int MAX_BUFFER_SIZE = (1024 * 1024);
- static final int QUAD_BYTE_SIZE = (12 * 6);
- static final int MAX_QUADS_PER_BUFFER = MAX_BUFFER_SIZE / QUAD_BYTE_SIZE;
- //static final int MAX_MERGED_QUAD_SIZE = 64;
-
- static final ILodConfigWrapperSingleton CONFIG = SingletonHandler.get(ILodConfigWrapperSingleton.class);
-
- public final boolean skipSkylight0Quads;
- public final short skyLightCullingBelow;
-
- static class Quad
- {
- final short x;
- final short y;
- final short z;
- short w0;
- short w1;
- int color;
- final byte skylight;
- final byte blocklight;
- final LodDirection dir;
- double distance = 0d;
-
- Quad(short x, short y, short z, short w0, short w1, int color, byte skylight, byte blocklight,
- LodDirection dir)
- {
- if (w0 == 0 || w1 == 0)
- throw new IllegalArgumentException("Size 0 quad!");
- if (w0 < 0 || w1 < 0)
- throw new IllegalArgumentException("Negative sized quad!");
- this.x = x;
- this.y = y;
- this.z = z;
- this.w0 = w0;
- this.w1 = w1;
- this.color = color;
- this.skylight = skylight;
- this.blocklight = blocklight;
- this.dir = dir;
- }
-
- private static double pow(double d)
- {
- return d * d;
- }
-
- // NOTE: This is only a rough but fast calculation!
- void calculateDistance(double relativeX, double relativeY, double relativeZ)
- {
- distance = pow(relativeX - x) + pow(relativeY - y) + pow(relativeZ - z);
- }
-
- private static int _compondCompare(short a0, short a1, short a2, short b0, short b1, short b2)
- {
- long a = (long) a0 << 48 | (long) a1 << 32 | (long) a2 << 16;
- long b = (long) b0 << 48 | (long) b1 << 32 | (long) b2 << 16;
- return Long.compare(a, b);
- }
-
- public int compareTo1(Quad o)
- {
- if (dir != o.dir)
- throw new IllegalArgumentException("The other quad is not in the same direction: " + o.dir + " vs " + dir);
- switch (dir.getAxis())
- {
- case X:
- return _compondCompare(x, y, z, o.x, o.y, o.z);
- case Y:
- return _compondCompare(y, z, x, o.y, o.z, o.x);
- case Z:
- return _compondCompare(z, y, x, o.z, o.y, o.x);
- default:
- throw new IllegalArgumentException("Invalid Axis enum: " + dir.getAxis());
- }
- }
-
- public int compareTo2(Quad o)
- {
- if (dir != o.dir)
- throw new IllegalArgumentException("The other quad is not in the same direction: " + o.dir + " vs " + dir);
- switch (dir.getAxis())
- {
- case X:
- return _compondCompare(x, z, y, o.x, o.z, o.y);
- case Y:
- return _compondCompare(y, x, z, o.y, o.x, o.z);
- case Z:
- return _compondCompare(z, x, y, o.z, o.x, o.y);
- default:
- throw new IllegalArgumentException("Invalid Axis enum: " + dir.getAxis());
- }
- }
-
- public boolean tryMergeWith1(Quad o)
- {
- if (dir != o.dir)
- return false;
- //if (w0 >= MAX_MERGED_QUAD_SIZE) return false;
- switch (dir.getAxis())
- {
- case X:
- if (x != o.x ||
- y != o.y ||
- z + w0 < o.z)
- return false;
- if (z + w0 > o.z)
- {
- EVENT_LOGGER.warn("Overlapping quads detected!");
- o.color = ColorUtil.rgbToInt(255, 0, 0);
- return false;
- }
- if (w1 != o.w1 ||
- color != o.color ||
- skylight != o.skylight ||
- blocklight != o.blocklight)
- return false;
-
- w0 += o.w0;
- return true;
- case Y:
- if (y != o.y ||
- z != o.z ||
- x + w0 < o.x)
- return false;
- if (x + w0 > o.x)
- {
- EVENT_LOGGER.warn("Overlapping quads detected!");
- o.color = ColorUtil.rgbToInt(255, 0, 0);
- return false;
- }
- if (w1 != o.w1 ||
- color != o.color ||
- skylight != o.skylight ||
- blocklight != o.blocklight)
- return false;
-
- w0 += o.w0;
- return true;
- case Z:
- if (z != o.z ||
- y != o.y ||
- x + w0 < o.x)
- return false;
- if (x + w0 > o.x)
- {
- EVENT_LOGGER.warn("Overlapping quads detected!");
- o.color = ColorUtil.rgbToInt(255, 0, 0);
- return false;
- }
- if (w1 != o.w1 ||
- color != o.color ||
- skylight != o.skylight ||
- blocklight != o.blocklight)
- return false;
-
- w0 += o.w0;
- return true;
- default:
- throw new IllegalArgumentException("Invalid Axis enum: " + dir.getAxis());
- }
- }
-
- public boolean tryMergeWith2(Quad o)
- {
- if (dir != o.dir)
- return false;
- //if (w1 >= MAX_MERGED_QUAD_SIZE) return false;
- switch (dir.getAxis())
- {
- case X:
- if (x != o.x ||
- z != o.z ||
- y + w1 < o.y)
- return false;
- if (y + w1 > o.y)
- {
- EVENT_LOGGER.warn("Overlapping quads detected!");
- o.color = ColorUtil.rgbToInt(255, 0, 0);
- return false;
- }
- if (w0 != o.w0 ||
- color != o.color ||
- skylight != o.skylight ||
- blocklight != o.blocklight)
- return false;
- w1 += o.w1;
- return true;
- case Y:
- if (y != o.y ||
- x != o.x ||
- z + w1 < o.z)
- return false;
- if (z + w1 > o.z)
- {
- EVENT_LOGGER.warn("Overlapping quads detected!");
- o.color = ColorUtil.rgbToInt(255, 0, 0);
- return false;
- }
- if (w0 != o.w0 ||
- color != o.color ||
- skylight != o.skylight ||
- blocklight != o.blocklight)
- return false;
- w1 += o.w1;
- return true;
- case Z:
- if (z != o.z ||
- x != o.x ||
- y + w1 < o.y)
- return false;
- if (y + w1 > o.y)
- {
- EVENT_LOGGER.warn("Overlapping quads detected!");
- o.color = ColorUtil.rgbToInt(255, 0, 0);
- return false;
- }
- if (w0 != o.w0 ||
- color != o.color ||
- skylight != o.skylight ||
- blocklight != o.blocklight)
- return false;
- w1 += o.w1;
- return true;
- default:
- throw new IllegalArgumentException("Invalid Axis enum: " + dir.getAxis());
- }
- }
-
- }
-
- final ArrayList[] quads = (ArrayList[]) new ArrayList[6];
-
- public LodQuadBuilder(int initialSize, boolean enableSkylightCulling, int skyLightCullingBelow)
- {
- for (int i = 0; i < 6; i++)
- quads[i] = new ArrayList();
- this.skipSkylight0Quads = enableSkylightCulling;
- this.skyLightCullingBelow = (short) (skyLightCullingBelow - LodBuilder.MIN_WORLD_HEIGHT);
- }
-
- public void addQuadAdj(LodDirection dir, short x, short y, short z, short w0, short wy, int color, byte skylight,
- byte blocklight)
- {
- if (dir.ordinal() <= LodDirection.DOWN.ordinal())
- throw new IllegalArgumentException("addQuadAdj() is only for adj direction! Not UP or Down!");
- if (skipSkylight0Quads && skylight == 0 && y < skyLightCullingBelow)
- return;
- quads[dir.ordinal()].add(new Quad(x, y, z, w0, wy, color, skylight, blocklight, dir));
- }
-
- // XZ
- public void addQuadUp(short x, short y, short z, short wx, short wz, int color, byte skylight, byte blocklight)
- {
- if (skipSkylight0Quads && skylight == 0 && y < skyLightCullingBelow)
- return;
- quads[LodDirection.UP.ordinal()].add(new Quad(x, y, z, wx, wz, color, skylight, blocklight, LodDirection.UP));
- }
-
- public void addQuadDown(short x, short y, short z, short wx, short wz, int color, byte skylight, byte blocklight)
- {
- if (skipSkylight0Quads && skylight == 0 && y < skyLightCullingBelow)
- return;
- quads[LodDirection.DOWN.ordinal()].add(new Quad(x, y, z, wx, wz, color, skylight, blocklight, LodDirection.DOWN));
- }
-
- // XY
- public void addQuadN(short x, short y, short z, short wx, short wy, int color, byte skylight, byte blocklight)
- {
- if (skipSkylight0Quads && skylight == 0 && y < skyLightCullingBelow)
- return;
- quads[LodDirection.NORTH.ordinal()].add(new Quad(x, y, z, wx, wy, color, skylight, blocklight, LodDirection.NORTH));
- }
-
- public void addQuadS(short x, short y, short z, short wx, short wy, int color, byte skylight, byte blocklight)
- {
- if (skipSkylight0Quads && skylight == 0 && y < skyLightCullingBelow)
- return;
- quads[LodDirection.SOUTH.ordinal()].add(new Quad(x, y, z, wx, wy, color, skylight, blocklight, LodDirection.SOUTH));
- }
-
- // ZY
- public void addQuadW(short x, short y, short z, short wz, short wy, int color, byte skylight, byte blocklight)
- {
- if (skipSkylight0Quads && skylight == 0 && y < skyLightCullingBelow)
- return;
- quads[LodDirection.WEST.ordinal()].add(new Quad(x, y, z, wz, wy, color, skylight, blocklight, LodDirection.WEST));
- }
-
- public void addQuadE(short x, short y, short z, short wz, short wy, int color, byte skylight, byte blocklight)
- {
- if (skipSkylight0Quads && skylight == 0 && y < skyLightCullingBelow)
- return;
- quads[LodDirection.EAST.ordinal()].add(new Quad(x, y, z, wz, wy, color, skylight, blocklight, LodDirection.EAST));
- }
-
- private static void putVertex(ByteBuffer bb, short x, short y, short z, int color, byte skylight, byte blocklight)
- {
- skylight %= 16;
- blocklight %= 16;
-
- bb.putShort(x);
- bb.putShort(y);
- bb.putShort(z);
-
- bb.putShort((short) (skylight | (blocklight << 4)));
- byte r = (byte) ColorUtil.getRed(color);
- byte g = (byte) ColorUtil.getGreen(color);
- byte b = (byte) ColorUtil.getBlue(color);
- byte a = (byte) ColorUtil.getAlpha(color);
- bb.put(r);
- bb.put(g);
- bb.put(b);
- bb.put(a);
- }
-
- private static void putQuad(ByteBuffer bb, Quad quad)
- {
- int[][] quadBase = DIRECTION_VERTEX_QUAD[quad.dir.ordinal()];
- short d0 = quad.w0;
- short d1 = quad.w1;
- Axis axis = quad.dir.getAxis();
- for (int i = 0; i < quadBase.length; i++)
- {
- short dx, dy, dz;
- switch (axis)
- {
- case X: // ZY
- dx = 0;
- dz = quadBase[i][0] == 1 ? d0 : 0;
- dy = quadBase[i][1] == 1 ? d1 : 0;
- break;
- case Y: // XZ
- dy = 0;
- dx = quadBase[i][0] == 1 ? d0 : 0;
- dz = quadBase[i][1] == 1 ? d1 : 0;
- break;
- case Z: // XY
- dz = 0;
- dx = quadBase[i][0] == 1 ? d0 : 0;
- dy = quadBase[i][1] == 1 ? d1 : 0;
- break;
- default:
- throw new IllegalArgumentException("Invalid Axis enum: " + axis);
- }
- putVertex(bb, (short) (quad.x + dx), (short) (quad.y + dy), (short) (quad.z + dz), quad.color,
- quad.skylight, quad.blocklight);
- }
- }
-
- public void sort(double dPlayerPosX, double dPlayerPosY, double dPlayerPosZ)
- {
-
- }
-
- private long mergeQuadsPass1(int dir)
- {
- if (quads[dir].size() <= 1)
- return 0;
- quads[dir].sort(Quad::compareTo1);
- ListIterator iter = quads[dir].listIterator();
- long mergeCount = 0;
- Quad currentQuad = iter.next();
- while (iter.hasNext())
- {
- Quad nextQuad = iter.next();
- if (currentQuad.tryMergeWith1(nextQuad))
- {
- mergeCount++;
- iter.set(null);
- }
- else
- {
- currentQuad = nextQuad;
- }
- }
- quads[dir].removeIf(o -> o == null);
- return mergeCount;
- }
-
- private long mergeQuadsPass2(int dir)
- {
- if (quads[dir].size() <= 1)
- return 0;
- quads[dir].sort(Quad::compareTo2);
- ListIterator iter = quads[dir].listIterator();
- long mergeCount = 0;
- Quad currentQuad = iter.next();
- while (iter.hasNext())
- {
- Quad nextQuad = iter.next();
- if (currentQuad.tryMergeWith2(nextQuad))
- {
- mergeCount++;
- iter.set(null);
- }
- else
- {
- currentQuad = nextQuad;
- }
- }
- quads[dir].removeIf(o -> o == null);
- return mergeCount;
- }
-
-
-
- public void mergeQuads()
- {
- long mergeCount = 0;
- long preQuadsCount = getCurrentQuadsCount();
- if (preQuadsCount <= 1)
- return;
- for (int i = 0; i < 6; i++)
- {
- mergeCount += mergeQuadsPass1(i);
- if (i >= 2)
- {
- continue;
- //long pass2 = mergeQuadsPass2(i);
- //mergeCount += pass2;
- //skipperMerge += pass2;
- }
- else
- {
- long pass2 = mergeQuadsPass2(i);
- mergeCount += pass2;
- }
- }
- long postQuadsCount = getCurrentQuadsCount();
- //if (mergeCount != 0)
- EVENT_LOGGER.debug("Merged {}/{}({}) quads", mergeCount, preQuadsCount, mergeCount / (double) preQuadsCount);
- }
-
- public Iterator makeVertexBuffers()
- {
- return new Iterator()
- {
- final ByteBuffer bb = ByteBuffer.allocateDirect(MAX_QUADS_PER_BUFFER * QUAD_BYTE_SIZE)
- .order(ByteOrder.nativeOrder());
- int dir = skipEmpty(0);
- int quad = 0;
-
- private int skipEmpty(int d)
- {
- while (d < 6 && quads[d].isEmpty())
- d++;
- return d;
- }
-
- @Override
- public boolean hasNext()
- {
- return dir < 6;
- }
-
- @Override
- public ByteBuffer next()
- {
- if (dir >= 6)
- {
- return null;
- }
- bb.clear();
- bb.limit(MAX_QUADS_PER_BUFFER * QUAD_BYTE_SIZE);
- while (bb.hasRemaining() && dir < 6)
- {
- writeData();
- }
- bb.limit(bb.position());
- bb.rewind();
- return bb;
- }
-
- private void writeData()
- {
- int startQ = quad;
-
- int i = startQ;
- for (i = startQ; i < quads[dir].size(); i++)
- {
- if (!bb.hasRemaining())
- {
- break;
- }
- putQuad(bb, quads[dir].get(i));
- }
-
- if (i >= quads[dir].size())
- {
- quad = 0;
- dir++;
- dir = skipEmpty(dir);
- }
- else
- {
- quad = i;
- }
- }
- };
- }
-
- public interface BufferFiller
- {
- boolean fill(LodVertexBuffer vbo); // If true: means more data is needed to be filled
- }
-
- public BufferFiller makeBufferFiller(GpuUploadMethod method)
- {
- return new BufferFiller()
- {
- int dir = 0;
- int quad = 0;
-
- public boolean fill(LodVertexBuffer vbo)
- {
- if (dir >= 6)
- {
- vbo.vertexCount = 0;
- return false;
- }
-
- int numOfQuads = _countRemainingQuads();
- if (numOfQuads > MAX_QUADS_PER_BUFFER)
- numOfQuads = MAX_QUADS_PER_BUFFER;
- if (numOfQuads == 0)
- {
- vbo.vertexCount = 0;
- return false;
- }
- ByteBuffer bb = vbo.mapBuffer(numOfQuads * QUAD_BYTE_SIZE, method, MAX_QUADS_PER_BUFFER * QUAD_BYTE_SIZE);
- if (bb == null)
- throw new NullPointerException("mapBuffer returned null");
- bb.clear();
- bb.limit(numOfQuads * QUAD_BYTE_SIZE);
- while (bb.hasRemaining() && dir < 6)
- {
- writeData(bb);
- }
- bb.rewind();
- vbo.unmapBuffer(method);
- vbo.vertexCount = numOfQuads * 6;
- return dir < 6;
- }
-
- private int _countRemainingQuads()
- {
- int a = quads[dir].size() - quad;
- for (int i = dir + 1; i < quads.length; i++)
- {
- a += quads[i].size();
- }
- return a;
- }
-
- private void writeData(ByteBuffer bb)
- {
- int startQ = quad;
-
- int i = startQ;
- for (i = startQ; i < quads[dir].size(); i++)
- {
- if (!bb.hasRemaining())
- {
- break;
- }
- putQuad(bb, quads[dir].get(i));
- }
-
- if (i >= quads[dir].size())
- {
- quad = 0;
- dir++;
- while (dir < 6 && quads[dir].isEmpty())
- dir++;
- }
- else
- {
- quad = i;
- }
- }
- };
- }
-
- public int getCurrentQuadsCount()
- {
- int i = 0;
- for (ArrayList qs : quads)
- i += qs.size();
- return i;
- }
-
- public int getCurrentNeededVertexBuffers()
- {
- return LodUtil.ceilDiv(getCurrentQuadsCount(), MAX_QUADS_PER_BUFFER);
- }
-
- public static final int[][][] DIRECTION_VERTEX_QUAD = new int[][][] {
- // X,Z
- { // UP
- { 1, 0 }, // 0
- { 1, 1 }, // 1
- { 0, 1 }, // 2
-
- { 1, 0 }, // 0
- { 0, 1 }, // 2
- { 0, 0 }, // 3
- }, { // DOWN
- { 0, 0 }, // 0
- { 0, 1 }, // 1
- { 1, 1 }, // 2
-
- { 0, 0 }, // 0
- { 1, 1 }, // 2
- { 1, 0 }, // 3
- },
- // X,Y
- { // NORTH
- { 0, 0 }, // 0
- { 0, 1 }, // 1
- { 1, 1 }, // 2
-
- { 0, 0 }, // 0
- { 1, 1 }, // 2
- { 1, 0 }, // 3
- }, { // SOUTH
- { 1, 0 }, // 0
- { 1, 1 }, // 1
- { 0, 1 }, // 2
-
- { 1, 0 }, // 0
- { 0, 1 }, // 2
- { 0, 0 }, // 3
- },
- // Z,Y
- { // WEST
- { 0, 0 }, // 0
- { 1, 0 }, // 1
- { 1, 1 }, // 2
-
- { 0, 0 }, // 0
- { 1, 1 }, // 2
- { 0, 1 }, // 3
- }, { // EAST
- { 0, 1 }, // 0
- { 1, 1 }, // 1
- { 1, 0 }, // 2
-
- { 0, 1 }, // 0
- { 1, 0 }, // 2
- { 0, 0 }, // 3
- }, };
-
-}
diff --git a/src/main/java/com/seibel/lod/core/objects/opengl/RenderBuffer.java b/src/main/java/com/seibel/lod/core/objects/opengl/RenderBuffer.java
index 09d89206a..2651879d3 100644
--- a/src/main/java/com/seibel/lod/core/objects/opengl/RenderBuffer.java
+++ b/src/main/java/com/seibel/lod/core/objects/opengl/RenderBuffer.java
@@ -21,6 +21,7 @@ package com.seibel.lod.core.objects.opengl;
import java.util.ConcurrentModificationException;
+import com.seibel.lod.core.builders.lodBuilding.bufferBuilding.LodQuadBuilder;
import com.seibel.lod.core.enums.config.GpuUploadMethod;
import com.seibel.lod.core.render.LodRenderProgram;
import com.seibel.lod.core.util.StatsMap;
diff --git a/src/main/java/com/seibel/lod/core/objects/opengl/RenderRegion.java b/src/main/java/com/seibel/lod/core/objects/opengl/RenderRegion.java
index 6d4b29113..310816b8b 100644
--- a/src/main/java/com/seibel/lod/core/objects/opengl/RenderRegion.java
+++ b/src/main/java/com/seibel/lod/core/objects/opengl/RenderRegion.java
@@ -29,6 +29,7 @@ import java.util.concurrent.atomic.AtomicReference;
import com.seibel.lod.core.api.ClientApi;
import com.seibel.lod.core.builders.lodBuilding.bufferBuilding.CubicLodTemplate;
import com.seibel.lod.core.builders.lodBuilding.LodBuilder;
+import com.seibel.lod.core.builders.lodBuilding.bufferBuilding.LodQuadBuilder;
import com.seibel.lod.core.enums.LodDirection;
import com.seibel.lod.core.enums.config.GpuUploadMethod;
import com.seibel.lod.core.enums.rendering.DebugMode;
@@ -160,7 +161,7 @@ public class RenderRegion implements AutoCloseable
private void recreateBuffer(LodQuadBuilder builder) {
if (renderBufferBack != null) throw new RuntimeException("Assert Error");
- boolean useSimpleBuffer = (builder.getCurrentNeededVertexBuffers() <= 6) || true;
+ boolean useSimpleBuffer = (builder.getCurrentNeededVertexBufferCount() <= 6) || true;
renderBufferBack = useSimpleBuffer ?
new SimpleRenderBuffer()
: null; //new ComplexRenderRegion(regPos);
@@ -192,7 +193,7 @@ public class RenderRegion implements AutoCloseable
int skyLightCullingBelow = CONFIG.client().graphics().advancedGraphics().getCaveCullingHeight();
// FIXME: Clamp also to the max world height.
skyLightCullingBelow = Math.max(skyLightCullingBelow, LodBuilder.MIN_WORLD_HEIGHT);
- LodQuadBuilder builder = new LodQuadBuilder(10, useSkylightCulling, skyLightCullingBelow);
+ LodQuadBuilder builder = new LodQuadBuilder(useSkylightCulling, skyLightCullingBelow);
Runnable buildRun = ()->{
makeLodRenderData(builder, region, adjRegions, playerPosX, playerPosZ);
};
diff --git a/src/main/java/com/seibel/lod/core/objects/opengl/SimpleRenderBuffer.java b/src/main/java/com/seibel/lod/core/objects/opengl/SimpleRenderBuffer.java
index 1f2d2353e..e845b3ac5 100644
--- a/src/main/java/com/seibel/lod/core/objects/opengl/SimpleRenderBuffer.java
+++ b/src/main/java/com/seibel/lod/core/objects/opengl/SimpleRenderBuffer.java
@@ -23,13 +23,14 @@ import java.nio.ByteBuffer;
import java.util.Iterator;
import java.util.concurrent.TimeUnit;
+import com.seibel.lod.core.builders.lodBuilding.bufferBuilding.LodQuadBuilder;
import org.lwjgl.opengl.GL32;
import com.seibel.lod.core.api.ApiShared;
import com.seibel.lod.core.builders.lodBuilding.bufferBuilding.LodBufferBuilderFactory;
import com.seibel.lod.core.enums.config.GpuUploadMethod;
import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler;
-import com.seibel.lod.core.objects.opengl.LodQuadBuilder.BufferFiller;
+import com.seibel.lod.core.builders.lodBuilding.bufferBuilding.LodQuadBuilder.BufferFiller;
import com.seibel.lod.core.render.GLProxy;
import com.seibel.lod.core.render.LodRenderProgram;
import com.seibel.lod.core.util.LodUtil;
@@ -112,7 +113,7 @@ public class SimpleRenderBuffer extends RenderBuffer
}
private void _uploadBuffersDirect(LodQuadBuilder builder, GpuUploadMethod method) {
- resize(builder.getCurrentNeededVertexBuffers());
+ resize(builder.getCurrentNeededVertexBufferCount());
long remainingNS = 0;
long BPerNS = CONFIG.client().advanced().buffers().getGpuUploadPerMegabyteInMilliseconds();
@@ -147,7 +148,7 @@ public class SimpleRenderBuffer extends RenderBuffer
private void _uploadBuffersMapped(LodQuadBuilder builder, GpuUploadMethod method)
{
- resize(builder.getCurrentNeededVertexBuffers());
+ resize(builder.getCurrentNeededVertexBufferCount());
for (int i=0; i