From d6ba5205adcfb29319bbc9dd03323f9bb804e42d Mon Sep 17 00:00:00 2001 From: tom lee Date: Tue, 22 Feb 2022 23:07:40 +0800 Subject: [PATCH] Too many changes. See details: - Fix new block color with tint system slowdown - Fix leaves block color - Fix rgba not translating to rgb properly - Which changed water color to be darker - Optimized quad merging to be faster - Fix All types of gray color texture issue - Fix Textures that rely on BlockState - Fix All types of tint - (?)Create Model perhaps no longer purple - Fixed LodBufferBuilder always in single thread mode --- .../LodBufferBuilderFactory.java | 6 +- .../core/objects/opengl/LodQuadBuilder.java | 208 ++++++++++++------ .../core/render/objects/VertexAttribute.java | 4 +- .../com/seibel/lod/core/util/ColorUtil.java | 27 ++- .../com/seibel/lod/core/util/LodUtil.java | 7 + .../wrapperInterfaces/block/BlockDetail.java | 2 +- 6 files changed, 173 insertions(+), 81 deletions(-) diff --git a/src/main/java/com/seibel/lod/core/builders/bufferBuilding/LodBufferBuilderFactory.java b/src/main/java/com/seibel/lod/core/builders/bufferBuilding/LodBufferBuilderFactory.java index bd2e7aea0..d9822da91 100644 --- a/src/main/java/com/seibel/lod/core/builders/bufferBuilding/LodBufferBuilderFactory.java +++ b/src/main/java/com/seibel/lod/core/builders/bufferBuilding/LodBufferBuilderFactory.java @@ -298,12 +298,12 @@ public class LodBufferBuilderFactory { LodQuadBuilder quadBuilder = new LodQuadBuilder(6); makeLodRenderData(quadBuilder, lodDim, regionPos, pX, pZ, minDetail); return new ResultPair(quadBuilder, regionPos); - }, bufferUploadThread).whenCompleteAsync((result, e) -> { + }, bufferBuilderThreads).whenCompleteAsync((result, e) -> { if (e != null) return; try { uploadBuffers(result.quadBuilder, result.regionPos); - } catch (Exception e3) { + } catch (Throwable e3) { ApiShared.LOGGER.error("\"LodNodeBufferBuilder\" was unable to upload buffer: ", e3); } }, bufferUploadThread); @@ -320,7 +320,7 @@ public class LodBufferBuilderFactory { CompletableFuture allFutures = CompletableFuture .allOf(futuresBuffer.toArray(new CompletableFuture[futuresBuffer.size()])); try { - allFutures.get(5, TimeUnit.MINUTES); + allFutures.get(1, TimeUnit.MINUTES); } catch (TimeoutException te) { ApiShared.LOGGER.error("LodBufferBuilder timed out: ", te); bufferBuilderThreadFactory.dumpAllThreadStacks(); 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 index 7803ddc11..44660c75e 100644 --- a/src/main/java/com/seibel/lod/core/objects/opengl/LodQuadBuilder.java +++ b/src/main/java/com/seibel/lod/core/objects/opengl/LodQuadBuilder.java @@ -7,11 +7,11 @@ import java.util.Iterator; import java.util.ListIterator; import com.seibel.lod.core.api.ApiShared; -import com.seibel.lod.core.api.ClientApi; 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.util.ColorUtil; +import com.seibel.lod.core.util.LodUtil; public class LodQuadBuilder { static final int MAX_BUFFER_SIZE = (1024 * 1024 * 1); @@ -51,14 +51,14 @@ public class LodQuadBuilder { distance = pow(relativeX-x) + pow(relativeY-y) + pow(relativeZ-z); } - private static int _compondCompare(short a0, short b0, short c0, short a1, short b1, short c1) { - if (a0 != a1) return a0-a1; - if (b0 != b1) return b0-b1; - return c0-c1; + 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) return dir.compareTo(o.dir); + 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); @@ -71,7 +71,7 @@ public class LodQuadBuilder { } } public int compareTo2(Quad o) { - if (dir != o.dir) return dir.compareTo(o.dir); + 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); @@ -221,44 +221,45 @@ public class LodQuadBuilder { } - final ArrayList quads; + final ArrayList[] quads; public LodQuadBuilder(int initialSize) { - quads = new ArrayList(); + quads = new ArrayList[6]; + for (int i=0; i<6; i++) quads[i] = new ArrayList(); } 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!"); - quads.add(new Quad(x, y, z, w0, wy, color, skylight, blocklight, dir)); + 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) { - quads.add(new Quad(x, y, z, wx, wz, color, skylight, blocklight, LodDirection.UP)); + 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) { - quads.add(new Quad(x, y, z, wx, wz, color, skylight, blocklight, LodDirection.DOWN)); + 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) { - quads.add(new Quad(x, y, z, wx, wy, color, skylight, blocklight, LodDirection.NORTH)); + 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) { - quads.add(new Quad(x, y, z, wx, wy, color, skylight, blocklight, LodDirection.SOUTH)); + 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) { - quads.add(new Quad(x, y, z, wz, wy, color, skylight, blocklight, LodDirection.WEST)); + 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) { - quads.add(new Quad(x, y, z, wz, wy, color, skylight, blocklight, LodDirection.EAST)); + 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) { @@ -268,6 +269,7 @@ public class LodQuadBuilder { 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); @@ -308,30 +310,16 @@ public class LodQuadBuilder { putVertex(bb, (short) (quad.x + dx), (short) (quad.y + dy), (short) (quad.z + dz), quad.color, quad.skylight, quad.blocklight); } - - } - - private ByteBuffer writeVertexData(ByteBuffer bb, int quadsStart, int quadsCount) { - if (quadsStart + quadsCount > quads.size()) - quadsCount = quads.size() - quadsStart; - bb.clear(); - bb.limit(quadsCount * QUAD_BYTE_SIZE); - for (Quad quad : quads.subList(quadsStart, quadsStart + quadsCount)) { - putQuad(bb, quad); - } - if (bb.hasRemaining()) - throw new RuntimeException(); - bb.rewind(); - return bb; } public void sort(double dPlayerPosX, double dPlayerPosY, double dPlayerPosZ) { - quads.forEach(p -> p.calculateDistance(dPlayerPosX, dPlayerPosY, dPlayerPosZ)); - quads.sort((a, b) -> Double.compare(a.distance, b.distance)); + } - private long merggeQuadsPass1() { - quads.sort(Quad::compareTo1); - ListIterator iter = quads.listIterator(); + + 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()) { @@ -343,13 +331,14 @@ public class LodQuadBuilder { currentQuad = nextQuad; } } - quads.removeIf(o -> o==null); + quads[dir].removeIf(o -> o==null); return mergeCount; } - - private long merggeQuadsPass2() { - quads.sort(Quad::compareTo2); - ListIterator iter = quads.listIterator(); + + 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()) { @@ -361,42 +350,84 @@ public class LodQuadBuilder { currentQuad = nextQuad; } } - quads.removeIf(o -> o==null); + quads[dir].removeIf(o -> o==null); return mergeCount; } public void mergeQuads() { - if (quads.size()<=1) return; - long mergeCount = 0; - long preQuadsCount = quads.size(); - mergeCount += merggeQuadsPass1(); - mergeCount += merggeQuadsPass2(); - long postQuadsCount = quads.size(); + long preQuadsCount = getCurrentQuadsCount(); + if (preQuadsCount<=1) return; + long skipperMerge = 0; + 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) - //ApiShared.LOGGER.info("Merged {} out of {} quads, to now {} quads.", mergeCount, preQuadsCount, postQuadsCount); + // ApiShared.LOGGER.info("Merged {}/{}({}) quads, skip {}", mergeCount, preQuadsCount, mergeCount/(double)preQuadsCount, skipperMerge); } public Iterator makeVertexBuffers() { - int numOfBuffers = getCurrentNeededVertexBuffers(); return new Iterator() { - int counter = 0; 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 counter < numOfBuffers; + return dir < 6; } @Override public ByteBuffer next() { - if (counter >= numOfBuffers) { + if (dir >= 6) { return null; } - return writeVertexData(bb, MAX_QUADS_PER_BUFFER * counter++, MAX_QUADS_PER_BUFFER); + 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()) { + quad = 0; + dir++; + dir = skipEmpty(dir); + } else { + quad = i; + } } }; } @@ -406,30 +437,71 @@ public class LodQuadBuilder { } public BufferFiller makeBufferFiller(GpuUploadMethod method) { - int numOfBuffers = getCurrentNeededVertexBuffers(); return new BufferFiller() { - int counter = 0; + int dir = 0; + int quad = 0; public boolean fill(LodVertexBuffer vbo) { - if (counter >= numOfBuffers) { + if (dir >= 6) { + vbo.vertexCount = 0; return false; } - int numOfQuads = MAX_QUADS_PER_BUFFER; - if (quads.size()-(counter*MAX_QUADS_PER_BUFFER) < MAX_QUADS_PER_BUFFER) - numOfQuads = quads.size()-(counter*MAX_QUADS_PER_BUFFER); - if (numOfQuads != 0) { - 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"); - writeVertexData(bb, MAX_QUADS_PER_BUFFER * counter++, numOfQuads).rewind(); - vbo.unmapBuffer(method); + + 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 counter < numOfBuffers; + return dir < 6; + } + private int _countRemainingQuads() { + int a = quads[dir].size() - quad; + for (int i=dir+1; 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 quads.size() / MAX_QUADS_PER_BUFFER + 1; + return LodUtil.ceilDiv(getCurrentQuadsCount(), MAX_QUADS_PER_BUFFER); } public static final int[][][] DIRECTION_VERTEX_QUAD = new int[][][] { diff --git a/src/main/java/com/seibel/lod/core/render/objects/VertexAttribute.java b/src/main/java/com/seibel/lod/core/render/objects/VertexAttribute.java index 2f3d0a95f..31d8cdc02 100644 --- a/src/main/java/com/seibel/lod/core/render/objects/VertexAttribute.java +++ b/src/main/java/com/seibel/lod/core/render/objects/VertexAttribute.java @@ -21,6 +21,8 @@ package com.seibel.lod.core.render.objects; import org.lwjgl.opengl.GL32; +import com.seibel.lod.core.util.LodUtil; + public abstract class VertexAttribute { public static final class VertexPointer { @@ -35,7 +37,7 @@ public abstract class VertexAttribute { this.byteSize = byteSize; } private static int _align(int bytes) { - return (-Math.floorDiv(-bytes, 4))*4; + return LodUtil.ceilDiv(bytes, 4)*4; } public static VertexPointer addFloatPointer(boolean normalized) { diff --git a/src/main/java/com/seibel/lod/core/util/ColorUtil.java b/src/main/java/com/seibel/lod/core/util/ColorUtil.java index 92b7f2476..2b8bbd401 100644 --- a/src/main/java/com/seibel/lod/core/util/ColorUtil.java +++ b/src/main/java/com/seibel/lod/core/util/ColorUtil.java @@ -31,6 +31,11 @@ import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftWrapper; */ public class ColorUtil { + //note: Minecraft color format is: 0xAA BB GG RR + //________ DH mod color format is: 0xAA RR GG BB + //OpenGL RGBA format native order: 0xRR GG BB AA + //_ OpenGL RGBA format Java Order: 0xAA BB GG RR + private static final IMinecraftWrapper MC = SingletonHandler.get(IMinecraftWrapper.class); public static int rgbToInt(int red, int green, int blue) @@ -46,7 +51,7 @@ public class ColorUtil /** Returns a value between 0 and 255 */ public static int getAlpha(int color) { - return (color >> 24) & 0xFF; + return (color >>> 24) & 0xFF; } /** Returns a value between 0 and 255 */ @@ -91,7 +96,7 @@ public class ColorUtil int green = ColorUtil.getGreen(lightColor); int blue = ColorUtil.getBlue(lightColor); - return ColorUtil.multiplyRGBcolors(color, ColorUtil.rgbToInt(red, green, blue)); + return ColorUtil.multiplyARGBwithRGB(color, ColorUtil.rgbToInt(red, green, blue)); } /** Edit the given color as an HSV (Hue Saturation Value) color */ @@ -104,18 +109,24 @@ public class ColorUtil LodUtil.clamp(0.0f, hsv[2] * brightnessMultiplier, 1.0f)).getRGB(); } + /** Multiply ARGB with RGB colors */ + public static int multiplyARGBwithRGB(int argb, int rgb) + { + return ((getAlpha(argb) << 24) | ((getRed(argb) * getRed(rgb) / 255) << 16) + | ((getGreen(argb) * getGreen(rgb) / 255) << 8) | (getBlue(argb) * getBlue(rgb) / 255)); + } + /** Multiply 2 RGB colors */ - public static int multiplyRGBcolors(int color1, int color2) + public static int multiplyARGBwithARGB(int color1, int color2) { return ((getAlpha(color1) * getAlpha(color2) / 255) << 24) | ((getRed(color1) * getRed(color2) / 255) << 16) | ((getGreen(color1) * getGreen(color2) / 255) << 8) | (getBlue(color1) * getBlue(color2) / 255); } - - @SuppressWarnings("unused") + public static String toString(int color) { - return Integer.toHexString(getAlpha(color)) + " " + - Integer.toHexString(getRed(color)) + " " + - Integer.toHexString(getGreen(color)) + " " + + return "A:"+Integer.toHexString(getAlpha(color)) + ",R:" + + Integer.toHexString(getRed(color)) + ",G:" + + Integer.toHexString(getGreen(color)) + ",B:" + Integer.toHexString(getBlue(color)); } } diff --git a/src/main/java/com/seibel/lod/core/util/LodUtil.java b/src/main/java/com/seibel/lod/core/util/LodUtil.java index 1f05e4ed5..9630f54f1 100644 --- a/src/main/java/com/seibel/lod/core/util/LodUtil.java +++ b/src/main/java/com/seibel/lod/core/util/LodUtil.java @@ -293,6 +293,13 @@ public class LodUtil { return Math.min(max, Math.max(value, min)); } + + /** + * Like Math.floorDiv, but reverse in that it is a ceilDiv + */ + public static int ceilDiv(int value, int divider) { + return -Math.floorDiv(-value, divider); + } /** * Get a HashSet of all ChunkPos within the normal render distance diff --git a/src/main/java/com/seibel/lod/core/wrapperInterfaces/block/BlockDetail.java b/src/main/java/com/seibel/lod/core/wrapperInterfaces/block/BlockDetail.java index 868a8a771..3ad213e4e 100644 --- a/src/main/java/com/seibel/lod/core/wrapperInterfaces/block/BlockDetail.java +++ b/src/main/java/com/seibel/lod/core/wrapperInterfaces/block/BlockDetail.java @@ -3,7 +3,7 @@ package com.seibel.lod.core.wrapperInterfaces.block; import com.seibel.lod.core.enums.config.BlocksToAvoid; import com.seibel.lod.core.util.ColorUtil; -public class BlockDetail +public final class BlockDetail { public final int color; public final boolean isFullBlock;