Clean up transparency and buffer render orders.
This commit is contained in:
@@ -472,7 +472,10 @@ public class Mat4f
|
||||
this.m33,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
public Vec3f asNonNormalizedLookForwardVector() {
|
||||
return new Vec3f(this.m02, this.m12, this.m22);
|
||||
}
|
||||
|
||||
//===============//
|
||||
// Forge methods //
|
||||
|
||||
@@ -17,18 +17,16 @@ public interface LodRenderSource {
|
||||
|
||||
void enableRender(IClientLevel level, LodQuadTree quadTree);
|
||||
void disableRender();
|
||||
boolean isRenderReady();
|
||||
void dispose(); // notify the container that the parent lodSection is now disposed (can be in loaded or unloaded state)
|
||||
|
||||
|
||||
/**
|
||||
* Try and swap in new render buffer for this section. Note that before this call, there should be no other
|
||||
* places storing or referencing the render buffer.
|
||||
* @param referenceSlotsOpaque The opaque slot for swapping in the new buffer.
|
||||
* @param referenceSlotsTransparent The transparent slot for swapping in the new buffer.
|
||||
* @param referenceSlot The slot for swapping in the new buffer.
|
||||
* @return True if the swap was successful. False if swap is not needed or if it is in progress.
|
||||
*/
|
||||
boolean trySwapRenderBuffer(LodQuadTree quadTree, AtomicReference<RenderBuffer> referenceSlotsOpaque, AtomicReference<RenderBuffer> referenceSlotsTransparent);
|
||||
boolean trySwapRenderBuffer(LodQuadTree quadTree, AtomicReference<RenderBuffer> referenceSlot);
|
||||
|
||||
void saveRender(IClientLevel level, RenderMetaFile file, OutputStream dataStream) throws IOException;
|
||||
|
||||
|
||||
@@ -34,15 +34,10 @@ public class PlaceHolderRenderSource implements LodRenderSource {
|
||||
|
||||
@Override
|
||||
public void disableRender() {}
|
||||
|
||||
@Override
|
||||
public boolean isRenderReady() {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public void dispose() {}
|
||||
@Override
|
||||
public boolean trySwapRenderBuffer(LodQuadTree quadTree, AtomicReference<RenderBuffer> referenceSlotsOpaque, AtomicReference<RenderBuffer> referenceSlotsTransparent) {
|
||||
public boolean trySwapRenderBuffer(LodQuadTree quadTree, AtomicReference<RenderBuffer> referenceSlots) {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
|
||||
@@ -265,9 +265,8 @@ public class ColumnRenderSource implements LodRenderSource, IColumnDatatype {
|
||||
return SECTION_SIZE_OFFSET;
|
||||
}
|
||||
|
||||
private CompletableFuture<ColumnRenderBuffer[]> inBuildRenderBuffer = null;
|
||||
private Reference<ColumnRenderBuffer> usedBufferOpaque = new Reference<>();
|
||||
private Reference<ColumnRenderBuffer> usedBufferTransparent = new Reference<>();
|
||||
private CompletableFuture<ColumnRenderBuffer> inBuildRenderBuffer = null;
|
||||
private Reference<ColumnRenderBuffer> usedBuffer = new Reference<>();
|
||||
|
||||
|
||||
private void tryBuildBuffer(IClientLevel level, LodQuadTree quadTree) {
|
||||
@@ -279,7 +278,7 @@ public class ColumnRenderSource implements LodRenderSource, IColumnDatatype {
|
||||
data[direction.ordinal()-2] = ((ColumnRenderSource) section.getRenderSource());
|
||||
}
|
||||
}
|
||||
inBuildRenderBuffer = ColumnRenderBuffer.build(level, usedBufferOpaque, usedBufferTransparent, this, data);
|
||||
inBuildRenderBuffer = ColumnRenderBuffer.build(level, usedBuffer, this, data);
|
||||
}
|
||||
}
|
||||
private void cancelBuildBuffer() {
|
||||
@@ -302,11 +301,6 @@ public class ColumnRenderSource implements LodRenderSource, IColumnDatatype {
|
||||
cancelBuildBuffer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRenderReady() {
|
||||
return inBuildRenderBuffer == null || inBuildRenderBuffer.isDone();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
cancelBuildBuffer();
|
||||
@@ -318,7 +312,7 @@ public class ColumnRenderSource implements LodRenderSource, IColumnDatatype {
|
||||
private static final long SWAP_BUSY_COLLISION_TIMEOUT = /* 1 sec */ 1_000_000_000L;
|
||||
|
||||
@Override
|
||||
public boolean trySwapRenderBuffer(LodQuadTree quadTree, AtomicReference<RenderBuffer> referenceSlotsOpaque, AtomicReference<RenderBuffer> referenceSlotsTransparent) {
|
||||
public boolean trySwapRenderBuffer(LodQuadTree quadTree, AtomicReference<RenderBuffer> referenceSlot) {
|
||||
if (lastNs != -1 && System.nanoTime() - lastNs < SWAP_TIMEOUT) {
|
||||
return false;
|
||||
}
|
||||
@@ -326,29 +320,12 @@ public class ColumnRenderSource implements LodRenderSource, IColumnDatatype {
|
||||
if (inBuildRenderBuffer.isDone()) {
|
||||
lastNs = System.nanoTime();
|
||||
//LOGGER.info("Swapping render buffer for {}", sectionPos);
|
||||
|
||||
RenderBuffer[] newBuffers = inBuildRenderBuffer.join();
|
||||
|
||||
RenderBuffer oldBuffersOpaque = referenceSlotsOpaque.getAndSet(newBuffers[0]);
|
||||
|
||||
ColumnRenderBuffer swapped;
|
||||
|
||||
|
||||
if (oldBuffersOpaque instanceof ColumnRenderBuffer) {
|
||||
swapped = usedBufferOpaque.swap((ColumnRenderBuffer) oldBuffersOpaque);
|
||||
RenderBuffer newBuffer = inBuildRenderBuffer.join();
|
||||
RenderBuffer oldBuffer = referenceSlot.getAndSet(newBuffer);
|
||||
if (oldBuffer instanceof ColumnRenderBuffer) {
|
||||
ColumnRenderBuffer swapped = usedBuffer.swap((ColumnRenderBuffer) oldBuffer);
|
||||
LodUtil.assertTrue(swapped == null);
|
||||
}
|
||||
|
||||
if(LodRenderer.transparencyEnabled) {
|
||||
RenderBuffer oldBuffersTransparent = referenceSlotsTransparent.getAndSet(newBuffers[1]);
|
||||
|
||||
if (LodRenderer.transparencyEnabled) {
|
||||
if (oldBuffersTransparent instanceof ColumnRenderBuffer) {
|
||||
swapped = usedBufferTransparent.swap((ColumnRenderBuffer) oldBuffersTransparent);
|
||||
LodUtil.assertTrue(swapped == null);
|
||||
}
|
||||
}
|
||||
}
|
||||
inBuildRenderBuffer = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
+84
-88
@@ -42,27 +42,25 @@ public class ColumnRenderBuffer extends RenderBuffer {
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger(MethodHandles.lookup().lookupClass().getSimpleName());
|
||||
private static final long MAX_BUFFER_UPLOAD_TIMEOUT_NANOSECONDS = 1_000_000;
|
||||
GLVertexBuffer[] vbos;
|
||||
GLVertexBuffer[] vbosTransparent;
|
||||
public final DhBlockPos pos;
|
||||
|
||||
public ColumnRenderBuffer(DhBlockPos pos) {
|
||||
this.pos = pos;
|
||||
vbos = new GLVertexBuffer[0];
|
||||
vbosTransparent = new GLVertexBuffer[0];
|
||||
}
|
||||
|
||||
|
||||
private void _uploadBuffersDirect(LodQuadBuilder builder, EGpuUploadMethod method) throws InterruptedException {
|
||||
resize(builder.getCurrentNeededVertexBufferCount());
|
||||
private static void _doUploadBuffersDirect(GLVertexBuffer[] vbos, Iterator<ByteBuffer> iter, EGpuUploadMethod method) throws InterruptedException {
|
||||
long remainingNS = 0;
|
||||
long BPerNS = Config.Client.Advanced.Buffers.gpuUploadPerMegabyteInMilliseconds.get();
|
||||
|
||||
int i = 0;
|
||||
Iterator<ByteBuffer> iter = builder.makeVertexBuffers();
|
||||
while (iter.hasNext()) {
|
||||
if (i >= vbos.length) {
|
||||
throw new RuntimeException("Too many vertex buffers!!");
|
||||
}
|
||||
ByteBuffer bb = iter.next();
|
||||
GLVertexBuffer vbo = getOrMakeVbo(i++, method.useBufferStorage);
|
||||
GLVertexBuffer vbo = getOrMake(vbos, i++, method.useBufferStorage);
|
||||
int size = bb.limit() - bb.position();
|
||||
try {
|
||||
vbo.bind();
|
||||
@@ -88,44 +86,59 @@ public class ColumnRenderBuffer extends RenderBuffer {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void _uploadBuffersDirect(LodQuadBuilder builder, EGpuUploadMethod method) throws InterruptedException {
|
||||
vbos = resize(vbos, builder.getCurrentNeededOpaqueVertexBufferCount());
|
||||
_doUploadBuffersDirect(vbos, builder.makeOpaqueVertexBuffers(), method);
|
||||
vbosTransparent = resize(vbosTransparent, builder.getCurrentNeededTransparentVertexBufferCount());
|
||||
_doUploadBuffersDirect(vbosTransparent, builder.makeTransparentVertexBuffers(), method);
|
||||
}
|
||||
|
||||
private void _uploadBuffersMapped(LodQuadBuilder builder, EGpuUploadMethod method)
|
||||
{
|
||||
resize(builder.getCurrentNeededVertexBufferCount());
|
||||
vbos = resize(vbos, builder.getCurrentNeededOpaqueVertexBufferCount());
|
||||
for (int i=0; i<vbos.length; i++) {
|
||||
if (vbos[i]==null) vbos[i] = new GLVertexBuffer(method.useBufferStorage);
|
||||
}
|
||||
LodQuadBuilder.BufferFiller func = builder.makeBufferFiller(method);
|
||||
int i = 0;
|
||||
while (i < vbos.length && func.fill(vbos[i++])) {}
|
||||
LodQuadBuilder.BufferFiller func = builder.makeOpaqueBufferFiller(method);
|
||||
{
|
||||
int i = 0;
|
||||
while (i < vbos.length && func.fill(vbos[i++])) {
|
||||
}
|
||||
}
|
||||
vbosTransparent = resize(vbosTransparent, builder.getCurrentNeededTransparentVertexBufferCount());
|
||||
for (int i=0; i<vbosTransparent.length; i++) {
|
||||
if (vbosTransparent[i]==null) vbosTransparent[i] = new GLVertexBuffer(method.useBufferStorage);
|
||||
}
|
||||
func = builder.makeTransparentBufferFiller(method);
|
||||
{
|
||||
int i = 0;
|
||||
while (i < vbosTransparent.length && func.fill(vbosTransparent[i++])) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private GLVertexBuffer getOrMakeVbo(int iIndex, boolean useBuffStorage) {
|
||||
private static GLVertexBuffer[] resize(GLVertexBuffer[] vbos, int newSize) {
|
||||
if (vbos.length == newSize) return vbos;
|
||||
GLVertexBuffer[] newVbos = new GLVertexBuffer[newSize];
|
||||
System.arraycopy(vbos, 0, newVbos, 0, Math.min(vbos.length, newSize));
|
||||
if (newSize < vbos.length) {
|
||||
for (int i = newSize; i < vbos.length; i++) {
|
||||
if (vbos[i] != null) {
|
||||
vbos[i].close();
|
||||
}
|
||||
}
|
||||
}
|
||||
return newVbos;
|
||||
}
|
||||
|
||||
private static GLVertexBuffer getOrMake(GLVertexBuffer[] vbos, int iIndex, boolean useBuffStorage) {
|
||||
if (vbos[iIndex] == null) {
|
||||
vbos[iIndex] = new GLVertexBuffer(useBuffStorage);
|
||||
}
|
||||
return vbos[iIndex];
|
||||
}
|
||||
|
||||
private void resize(int size) {
|
||||
if (vbos.length != size) {
|
||||
GLVertexBuffer[] newVbos = new GLVertexBuffer[size];
|
||||
if (vbos.length > size) {
|
||||
for (int i=size; i<vbos.length; i++) {
|
||||
if (vbos[i]!=null) vbos[i].close();
|
||||
vbos[i] = null;
|
||||
}
|
||||
}
|
||||
for (int i=0; i<newVbos.length && i<vbos.length; i++) {
|
||||
newVbos[i] = vbos[i];
|
||||
vbos[i] = null;
|
||||
}
|
||||
for (GLVertexBuffer b : vbos) {
|
||||
if (b != null) throw new RuntimeException("LEAKING VBO!");
|
||||
}
|
||||
vbos = newVbos;
|
||||
}
|
||||
}
|
||||
|
||||
public void uploadBuffer(LodQuadBuilder builder, EGpuUploadMethod method) throws InterruptedException {
|
||||
if (method.useEarlyMapping) {
|
||||
_uploadBuffersMapped(builder, method);
|
||||
@@ -135,7 +148,7 @@ public class ColumnRenderBuffer extends RenderBuffer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean render(LodRenderer renderContext) {
|
||||
public boolean renderOpaque(LodRenderer renderContext) {
|
||||
boolean hasRendered = false;
|
||||
renderContext.setupOffset(pos);
|
||||
for (GLVertexBuffer vbo : vbos) {
|
||||
@@ -148,6 +161,20 @@ public class ColumnRenderBuffer extends RenderBuffer {
|
||||
return hasRendered;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean renderTransparent(LodRenderer renderContext) {
|
||||
boolean hasRendered = false;
|
||||
renderContext.setupOffset(pos);
|
||||
for (GLVertexBuffer vbo : vbosTransparent) {
|
||||
if (vbo == null) continue;
|
||||
if (vbo.getVertexCount() == 0) continue;
|
||||
hasRendered = true;
|
||||
renderContext.drawVbo(vbo);
|
||||
//LodRenderer.tickLogger.info("Vertex buffer: {}", vbo);
|
||||
}
|
||||
return hasRendered;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debugDumpStats(StatsMap statsMap) {
|
||||
statsMap.incStat("RenderBuffers");
|
||||
@@ -173,6 +200,10 @@ public class ColumnRenderBuffer extends RenderBuffer {
|
||||
if (b == null) continue;
|
||||
b.destroy(false);
|
||||
}
|
||||
for (GLVertexBuffer b : vbosTransparent) {
|
||||
if (b == null) continue;
|
||||
b.destroy(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -186,32 +217,23 @@ public class ColumnRenderBuffer extends RenderBuffer {
|
||||
return getCurrentJobsCount() > MAX_CONCURRENT_CALL;
|
||||
}
|
||||
|
||||
public static CompletableFuture<ColumnRenderBuffer[]> build(IClientLevel clientLevel, Reference<ColumnRenderBuffer> usedBufferSlotOpaque, Reference<ColumnRenderBuffer> usedBufferSlotTransparent, ColumnRenderSource data, ColumnRenderSource[] adjData) {
|
||||
public static CompletableFuture<ColumnRenderBuffer> build(IClientLevel clientLevel, Reference<ColumnRenderBuffer> usedBufferSlot, ColumnRenderSource data, ColumnRenderSource[] adjData) {
|
||||
if (isBusy()) return null;
|
||||
//LOGGER.info("RenderRegion startBuild @ {}", data.sectionPos);
|
||||
return CompletableFuture.supplyAsync(() -> {
|
||||
try {
|
||||
boolean enableTransparency = Config.Client.Graphics.Quality.transparency.get().tranparencyEnabled;
|
||||
EVENT_LOGGER.trace("RenderRegion start QuadBuild @ {}", data.sectionPos);
|
||||
boolean enableSkyLightCulling = Config.Client.Graphics.AdvancedGraphics.enableCaveCulling.get();
|
||||
int skyLightCullingBelow = Config.Client.Graphics.AdvancedGraphics.caveCullingHeight.get();
|
||||
// FIXME: Clamp also to the max world height.
|
||||
skyLightCullingBelow = Math.max(skyLightCullingBelow, clientLevel.getMinY());
|
||||
LodQuadBuilder builderOpaque = new LodQuadBuilder(enableSkyLightCulling,
|
||||
(short) (skyLightCullingBelow - clientLevel.getMinY()));
|
||||
LodQuadBuilder builder = new LodQuadBuilder(enableSkyLightCulling,
|
||||
(short) (skyLightCullingBelow - clientLevel.getMinY()), enableTransparency);
|
||||
|
||||
LodQuadBuilder builderTransparent = new LodQuadBuilder(enableSkyLightCulling,
|
||||
(short) (skyLightCullingBelow - clientLevel.getMinY()));
|
||||
|
||||
makeLodRenderData(builderOpaque, builderTransparent, data, adjData);
|
||||
if (builderOpaque.getCurrentQuadsCount() > 0) {
|
||||
//LOGGER.info("her");
|
||||
}
|
||||
makeLodRenderData(builder, data, adjData);
|
||||
EVENT_LOGGER.trace("RenderRegion end QuadBuild @ {}", data.sectionPos);
|
||||
LodQuadBuilder[] builders = new LodQuadBuilder[2];
|
||||
builders[0] = builderOpaque;
|
||||
builders[1] = builderTransparent;
|
||||
|
||||
return builders;
|
||||
return builder;
|
||||
} catch (UncheckedInterruptedException e) {
|
||||
throw e;
|
||||
}
|
||||
@@ -220,35 +242,25 @@ public class ColumnRenderBuffer extends RenderBuffer {
|
||||
throw e3;
|
||||
}
|
||||
}, BUFFER_BUILDERS)
|
||||
.thenApplyAsync((builders) -> {
|
||||
.thenApplyAsync((builder) -> {
|
||||
try {
|
||||
EVENT_LOGGER.trace("RenderRegion start Upload @ {}", data.sectionPos);
|
||||
GLProxy glProxy = GLProxy.getInstance();
|
||||
EGpuUploadMethod method = GLProxy.getInstance().getGpuUploadMethod();
|
||||
EGLProxyContext oldContext = glProxy.getGlContext();
|
||||
glProxy.setGlContext(EGLProxyContext.LOD_BUILDER);
|
||||
ColumnRenderBuffer buffersSlotOpaque = usedBufferSlotOpaque.swap(null);
|
||||
ColumnRenderBuffer buffersSlotTransparent = usedBufferSlotTransparent.swap(null);
|
||||
ColumnRenderBuffer buffer = usedBufferSlot.swap(null);
|
||||
|
||||
if (buffersSlotOpaque == null)
|
||||
buffersSlotOpaque = new ColumnRenderBuffer(
|
||||
if (buffer == null)
|
||||
buffer = new ColumnRenderBuffer(
|
||||
new DhBlockPos(data.sectionPos.getCorner().getCorner(), clientLevel.getMinY())
|
||||
);
|
||||
if (buffersSlotTransparent == null)
|
||||
buffersSlotTransparent = new ColumnRenderBuffer(
|
||||
new DhBlockPos(data.sectionPos.getCorner().getCorner(), clientLevel.getMinY())
|
||||
);
|
||||
try {
|
||||
buffersSlotOpaque.uploadBuffer(builders[0], method);
|
||||
buffersSlotTransparent.uploadBuffer(builders[1], method);
|
||||
buffer.uploadBuffer(builder, method);
|
||||
EVENT_LOGGER.trace("RenderRegion end Upload @ {}", data.sectionPos);
|
||||
ColumnRenderBuffer[] buffers = new ColumnRenderBuffer[2];
|
||||
buffers[0] = buffersSlotOpaque;
|
||||
buffers[1] = buffersSlotTransparent;
|
||||
return buffers;
|
||||
return buffer;
|
||||
} catch (Exception e) {
|
||||
buffersSlotOpaque.close();
|
||||
buffersSlotTransparent.close();
|
||||
buffer.close();
|
||||
throw e;
|
||||
} finally {
|
||||
glProxy.setGlContext(oldContext);
|
||||
@@ -262,14 +274,10 @@ public class ColumnRenderBuffer extends RenderBuffer {
|
||||
}, BUFFER_UPLOADER).handle((v, e) -> {
|
||||
//LOGGER.info("RenderRegion endBuild @ {}", data.sectionPos);
|
||||
if (e != null) {
|
||||
ColumnRenderBuffer buffersSlot;
|
||||
if (!usedBufferSlotOpaque.isEmpty()) {
|
||||
buffersSlot = usedBufferSlotOpaque.swap(null);
|
||||
buffersSlot.close();
|
||||
}
|
||||
if (!usedBufferSlotTransparent.isEmpty()) {
|
||||
buffersSlot = usedBufferSlotTransparent.swap(null);
|
||||
buffersSlot.close();
|
||||
ColumnRenderBuffer buffer;
|
||||
if (!usedBufferSlot.isEmpty()) {
|
||||
buffer = usedBufferSlot.swap(null);
|
||||
buffer.close();
|
||||
}
|
||||
return null;
|
||||
} else {
|
||||
@@ -280,7 +288,7 @@ public class ColumnRenderBuffer extends RenderBuffer {
|
||||
|
||||
|
||||
|
||||
private static void makeLodRenderData(LodQuadBuilder quadBuilderOpaque, LodQuadBuilder quadBuilderTransparent, ColumnRenderSource region, ColumnRenderSource[] adjRegions) {
|
||||
private static void makeLodRenderData(LodQuadBuilder quadBuilder, ColumnRenderSource region, ColumnRenderSource[] adjRegions) {
|
||||
|
||||
// Variable initialization
|
||||
EDebugMode debugMode = Config.Client.Advanced.Debugging.debugMode.get();
|
||||
@@ -372,23 +380,11 @@ public class ColumnRenderBuffer extends RenderBuffer {
|
||||
long adjDataTop = i - 1 >= 0 ? posData.get(i - 1) : ColumnFormat.EMPTY_DATA;
|
||||
long adjDataBot = i + 1 < posData.size() ? posData.get(i + 1) : ColumnFormat.EMPTY_DATA;
|
||||
|
||||
|
||||
// We send the call to create the vertices
|
||||
if(ColumnFormat.getAlpha(data) == 255 || !LodRenderer.transparencyEnabled)
|
||||
{
|
||||
CubicLodTemplate.addLodToBuffer(data, adjDataTop, adjDataBot, adjData, detailLevel,
|
||||
x, z, quadBuilderOpaque, debugMode);
|
||||
}
|
||||
else
|
||||
{
|
||||
CubicLodTemplate.addLodToBuffer(data, adjDataTop, adjDataBot, adjData, detailLevel,
|
||||
x, z, quadBuilderTransparent, debugMode);
|
||||
}
|
||||
CubicLodTemplate.addLodToBuffer(data, adjDataTop, adjDataBot, adjData, detailLevel,
|
||||
x, z, quadBuilder, debugMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
quadBuilderOpaque.mergeQuads();
|
||||
if(LodRenderer.transparencyEnabled)
|
||||
quadBuilderTransparent.mergeQuads();
|
||||
quadBuilder.mergeQuads();
|
||||
}
|
||||
}
|
||||
|
||||
+214
-48
@@ -24,6 +24,7 @@ import java.nio.ByteOrder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Objects;
|
||||
|
||||
import com.seibel.lod.core.render.RenderBuffer;
|
||||
import com.seibel.lod.core.enums.ELodDirection;
|
||||
@@ -47,7 +48,11 @@ public class LodQuadBuilder
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||
public final boolean skipQuadsWithZeroSkylight;
|
||||
public final short skyLightCullingBelow;
|
||||
final ArrayList<BufferQuad>[] quads = (ArrayList<BufferQuad>[]) new ArrayList[6];
|
||||
@SuppressWarnings("unchecked")
|
||||
final ArrayList<BufferQuad>[] opaqueQuads = (ArrayList<BufferQuad>[]) new ArrayList[6];
|
||||
@SuppressWarnings("unchecked")
|
||||
final ArrayList<BufferQuad>[] transparentQuads = (ArrayList<BufferQuad>[]) new ArrayList[6];
|
||||
final boolean doTransparency;
|
||||
|
||||
public static final int[][][] DIRECTION_VERTEX_IBO_QUAD = new int[][][]
|
||||
{
|
||||
@@ -100,18 +105,17 @@ public class LodQuadBuilder
|
||||
|
||||
private int premergeCount = 0;
|
||||
|
||||
public LodQuadBuilder(boolean enableSkylightCulling, short skyLightCullingBelow)
|
||||
public LodQuadBuilder(boolean enableSkylightCulling, short skyLightCullingBelow, boolean doTransparency)
|
||||
{
|
||||
for (int i = 0; i < 6; i++)
|
||||
quads[i] = new ArrayList<>();
|
||||
|
||||
this.doTransparency = doTransparency;
|
||||
for (int i = 0; i < 6; i++) {
|
||||
opaqueQuads[i] = new ArrayList<>();
|
||||
if (doTransparency) transparentQuads[i] = new ArrayList<>();
|
||||
}
|
||||
this.skipQuadsWithZeroSkylight = enableSkylightCulling;
|
||||
this.skyLightCullingBelow = skyLightCullingBelow;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public void addQuadAdj(ELodDirection dir, short x, short y, short z,
|
||||
short widthEastWest, short widthNorthSouthOrUpDown,
|
||||
int color, byte skylight, byte blocklight)
|
||||
@@ -121,7 +125,8 @@ public class LodQuadBuilder
|
||||
if (skipQuadsWithZeroSkylight && skylight == 0 && y < skyLightCullingBelow)
|
||||
return;
|
||||
BufferQuad quad = new BufferQuad(x, y, z, widthEastWest, widthNorthSouthOrUpDown, color, skylight, blocklight, dir);
|
||||
ArrayList<BufferQuad> qs = quads[dir.ordinal()];
|
||||
ArrayList<BufferQuad> qs = (doTransparency && ColorUtil.getAlpha(color) < 255)
|
||||
? transparentQuads[dir.ordinal()] : opaqueQuads[dir.ordinal()];
|
||||
if (!qs.isEmpty() &&
|
||||
(qs.get(qs.size()-1).tryMerge(quad, BufferMergeDirectionEnum.EastWest)
|
||||
|| qs.get(qs.size()-1).tryMerge(quad, BufferMergeDirectionEnum.NorthSouthOrUpDown))
|
||||
@@ -138,7 +143,8 @@ public class LodQuadBuilder
|
||||
if (skipQuadsWithZeroSkylight && skylight == 0 && y < skyLightCullingBelow)
|
||||
return;
|
||||
BufferQuad quad = new BufferQuad(x, y, z, width, wz, color, skylight, blocklight, ELodDirection.UP);
|
||||
ArrayList<BufferQuad> qs = quads[ELodDirection.UP.ordinal()];
|
||||
ArrayList<BufferQuad> qs = (doTransparency && ColorUtil.getAlpha(color) < 255)
|
||||
? transparentQuads[ELodDirection.UP.ordinal()] : opaqueQuads[ELodDirection.UP.ordinal()];
|
||||
if (!qs.isEmpty() &&
|
||||
(qs.get(qs.size()-1).tryMerge(quad, BufferMergeDirectionEnum.EastWest)
|
||||
|| qs.get(qs.size()-1).tryMerge(quad, BufferMergeDirectionEnum.NorthSouthOrUpDown))
|
||||
@@ -154,7 +160,8 @@ public class LodQuadBuilder
|
||||
if (skipQuadsWithZeroSkylight && skylight == 0 && y < skyLightCullingBelow)
|
||||
return;
|
||||
BufferQuad quad = new BufferQuad(x, y, z, width, wz, color, skylight, blocklight, ELodDirection.DOWN);
|
||||
ArrayList<BufferQuad> qs = quads[ELodDirection.DOWN.ordinal()];
|
||||
ArrayList<BufferQuad> qs = (doTransparency && ColorUtil.getAlpha(color) < 255)
|
||||
? transparentQuads[ELodDirection.DOWN.ordinal()] : opaqueQuads[ELodDirection.DOWN.ordinal()];
|
||||
if (!qs.isEmpty() &&
|
||||
(qs.get(qs.size()-1).tryMerge(quad, BufferMergeDirectionEnum.EastWest)
|
||||
|| qs.get(qs.size()-1).tryMerge(quad, BufferMergeDirectionEnum.NorthSouthOrUpDown))
|
||||
@@ -249,35 +256,38 @@ public class LodQuadBuilder
|
||||
public void mergeQuads()
|
||||
{
|
||||
long mergeCount = 0;
|
||||
long preQuadsCount = getCurrentQuadsCount();
|
||||
long preQuadsCount = getCurrentOpaqueQuadsCount() + getCurrentTransparentQuadsCount();
|
||||
if (preQuadsCount <= 1)
|
||||
return;
|
||||
|
||||
for (int directionIndex = 0; directionIndex < 6; directionIndex++)
|
||||
{
|
||||
mergeCount += mergeQuadsInternal(directionIndex, BufferMergeDirectionEnum.EastWest);
|
||||
mergeCount += mergeQuadsInternal(opaqueQuads, directionIndex, BufferMergeDirectionEnum.EastWest);
|
||||
if (doTransparency)
|
||||
mergeCount += mergeQuadsInternal(transparentQuads, directionIndex, BufferMergeDirectionEnum.EastWest);
|
||||
// only run the second merge if the face is the top or bottom
|
||||
//if (directionIndex == LodDirection.UP.ordinal() || directionIndex == LodDirection.DOWN.ordinal())
|
||||
//{
|
||||
// long pass2 = mergeQuadsInternal(directionIndex, BufferMergeDirectionEnum.NorthSouthOrUpDown);
|
||||
// mergeCount += pass2;
|
||||
//}
|
||||
if (directionIndex == ELodDirection.UP.ordinal() || directionIndex == ELodDirection.DOWN.ordinal())
|
||||
{
|
||||
mergeCount += mergeQuadsInternal(opaqueQuads, directionIndex, BufferMergeDirectionEnum.NorthSouthOrUpDown);
|
||||
if (doTransparency)
|
||||
mergeCount += mergeQuadsInternal(transparentQuads, directionIndex, BufferMergeDirectionEnum.NorthSouthOrUpDown);
|
||||
}
|
||||
}
|
||||
long postQuadsCount = getCurrentQuadsCount();
|
||||
long postQuadsCount = getCurrentOpaqueQuadsCount() + getCurrentTransparentQuadsCount();
|
||||
//if (mergeCount != 0)
|
||||
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)
|
||||
private static long mergeQuadsInternal(ArrayList<BufferQuad>[] list, int directionIndex, BufferMergeDirectionEnum mergeDirection)
|
||||
{
|
||||
if (quads[directionIndex].size() <= 1)
|
||||
if (list[directionIndex].size() <= 1)
|
||||
return 0;
|
||||
|
||||
quads[directionIndex].sort( (objOne, objTwo) -> objOne.compare(objTwo, mergeDirection) );
|
||||
|
||||
list[directionIndex].sort( (objOne, objTwo) -> objOne.compare(objTwo, mergeDirection) );
|
||||
|
||||
long mergeCount = 0;
|
||||
ListIterator<BufferQuad> iter = quads[directionIndex].listIterator();
|
||||
ListIterator<BufferQuad> iter = list[directionIndex].listIterator();
|
||||
BufferQuad currentQuad = iter.next();
|
||||
while (iter.hasNext())
|
||||
{
|
||||
@@ -295,13 +305,13 @@ public class LodQuadBuilder
|
||||
currentQuad = nextQuad;
|
||||
}
|
||||
}
|
||||
quads[directionIndex].removeIf(o -> o == null);
|
||||
list[directionIndex].removeIf(Objects::isNull);
|
||||
return mergeCount;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public Iterator<ByteBuffer> makeVertexBuffers()
|
||||
public Iterator<ByteBuffer> makeOpaqueVertexBuffers()
|
||||
{
|
||||
return new Iterator<ByteBuffer>()
|
||||
{
|
||||
@@ -312,7 +322,7 @@ public class LodQuadBuilder
|
||||
|
||||
private int skipEmpty(int d)
|
||||
{
|
||||
while (d < 6 && quads[d].isEmpty())
|
||||
while (d < 6 && opaqueQuads[d].isEmpty())
|
||||
d++;
|
||||
return d;
|
||||
}
|
||||
@@ -344,16 +354,82 @@ public class LodQuadBuilder
|
||||
private void writeData()
|
||||
{
|
||||
int i = quad;
|
||||
for (; i < quads[dir].size(); i++)
|
||||
for (; i < opaqueQuads[dir].size(); i++)
|
||||
{
|
||||
if (!bb.hasRemaining())
|
||||
{
|
||||
break;
|
||||
}
|
||||
putQuad(bb, quads[dir].get(i));
|
||||
putQuad(bb, opaqueQuads[dir].get(i));
|
||||
}
|
||||
|
||||
if (i >= quads[dir].size())
|
||||
if (i >= opaqueQuads[dir].size())
|
||||
{
|
||||
quad = 0;
|
||||
dir++;
|
||||
dir = skipEmpty(dir);
|
||||
}
|
||||
else
|
||||
{
|
||||
quad = i;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public Iterator<ByteBuffer> makeTransparentVertexBuffers()
|
||||
{
|
||||
return new Iterator<ByteBuffer>()
|
||||
{
|
||||
final ByteBuffer bb = ByteBuffer.allocateDirect(RenderBuffer.FULL_SIZED_BUFFER)
|
||||
.order(ByteOrder.nativeOrder());
|
||||
int dir = skipEmpty(0);
|
||||
int quad = 0;
|
||||
|
||||
private int skipEmpty(int d)
|
||||
{
|
||||
while (d < 6 && transparentQuads[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(RenderBuffer.FULL_SIZED_BUFFER);
|
||||
while (bb.hasRemaining() && dir < 6)
|
||||
{
|
||||
writeData();
|
||||
}
|
||||
bb.limit(bb.position());
|
||||
bb.rewind();
|
||||
return bb;
|
||||
}
|
||||
|
||||
private void writeData()
|
||||
{
|
||||
int i = quad;
|
||||
for (; i < transparentQuads[dir].size(); i++)
|
||||
{
|
||||
if (!bb.hasRemaining())
|
||||
{
|
||||
break;
|
||||
}
|
||||
putQuad(bb, transparentQuads[dir].get(i));
|
||||
}
|
||||
|
||||
if (i >= transparentQuads[dir].size())
|
||||
{
|
||||
quad = 0;
|
||||
dir++;
|
||||
@@ -366,14 +442,13 @@ public class LodQuadBuilder
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public interface BufferFiller
|
||||
{
|
||||
/** If true: more data needs to be filled */
|
||||
boolean fill(GLVertexBuffer vbo);
|
||||
}
|
||||
|
||||
public BufferFiller makeBufferFiller(EGpuUploadMethod method)
|
||||
public BufferFiller makeOpaqueBufferFiller(EGpuUploadMethod method)
|
||||
{
|
||||
return new BufferFiller()
|
||||
{
|
||||
@@ -414,10 +489,10 @@ public class LodQuadBuilder
|
||||
|
||||
private int _countRemainingQuads()
|
||||
{
|
||||
int a = quads[dir].size() - quad;
|
||||
for (int i = dir + 1; i < quads.length; i++)
|
||||
int a = opaqueQuads[dir].size() - quad;
|
||||
for (int i = dir + 1; i < opaqueQuads.length; i++)
|
||||
{
|
||||
a += quads[i].size();
|
||||
a += opaqueQuads[i].size();
|
||||
}
|
||||
return a;
|
||||
}
|
||||
@@ -427,20 +502,20 @@ public class LodQuadBuilder
|
||||
int startQ = quad;
|
||||
|
||||
int i = startQ;
|
||||
for (i = startQ; i < quads[dir].size(); i++)
|
||||
for (i = startQ; i < opaqueQuads[dir].size(); i++)
|
||||
{
|
||||
if (!bb.hasRemaining())
|
||||
{
|
||||
break;
|
||||
}
|
||||
putQuad(bb, quads[dir].get(i));
|
||||
putQuad(bb, opaqueQuads[dir].get(i));
|
||||
}
|
||||
|
||||
if (i >= quads[dir].size())
|
||||
if (i >= opaqueQuads[dir].size())
|
||||
{
|
||||
quad = 0;
|
||||
dir++;
|
||||
while (dir < 6 && quads[dir].isEmpty())
|
||||
while (dir < 6 && opaqueQuads[dir].isEmpty())
|
||||
dir++;
|
||||
}
|
||||
else
|
||||
@@ -450,21 +525,112 @@ public class LodQuadBuilder
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
public int getCurrentQuadsCount()
|
||||
|
||||
public BufferFiller makeTransparentBufferFiller(EGpuUploadMethod method)
|
||||
{
|
||||
return new BufferFiller()
|
||||
{
|
||||
int dir = 0;
|
||||
int quad = 0;
|
||||
|
||||
public boolean fill(GLVertexBuffer vbo)
|
||||
{
|
||||
if (dir >= 6)
|
||||
{
|
||||
vbo.setVertexCount(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
int numOfQuads = _countRemainingQuads();
|
||||
if (numOfQuads > RenderBuffer.MAX_QUADS_PER_BUFFER)
|
||||
numOfQuads = RenderBuffer.MAX_QUADS_PER_BUFFER;
|
||||
if (numOfQuads == 0)
|
||||
{
|
||||
vbo.setVertexCount(0);
|
||||
return false;
|
||||
}
|
||||
ByteBuffer bb = vbo.mapBuffer(numOfQuads * RenderBuffer.QUADS_BYTE_SIZE, method,
|
||||
RenderBuffer.FULL_SIZED_BUFFER);
|
||||
if (bb == null)
|
||||
throw new NullPointerException("mapBuffer returned null");
|
||||
bb.clear();
|
||||
bb.limit(numOfQuads * RenderBuffer.QUADS_BYTE_SIZE);
|
||||
while (bb.hasRemaining() && dir < 6)
|
||||
{
|
||||
writeData(bb);
|
||||
}
|
||||
bb.rewind();
|
||||
vbo.unmapBuffer();
|
||||
vbo.setVertexCount(numOfQuads*4);
|
||||
return dir < 6;
|
||||
}
|
||||
|
||||
private int _countRemainingQuads()
|
||||
{
|
||||
int a = transparentQuads[dir].size() - quad;
|
||||
for (int i = dir + 1; i < transparentQuads.length; i++)
|
||||
{
|
||||
a += transparentQuads[i].size();
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
private void writeData(ByteBuffer bb)
|
||||
{
|
||||
int startQ = quad;
|
||||
|
||||
int i = startQ;
|
||||
for (i = startQ; i < transparentQuads[dir].size(); i++)
|
||||
{
|
||||
if (!bb.hasRemaining())
|
||||
{
|
||||
break;
|
||||
}
|
||||
putQuad(bb, transparentQuads[dir].get(i));
|
||||
}
|
||||
|
||||
if (i >= transparentQuads[dir].size())
|
||||
{
|
||||
quad = 0;
|
||||
dir++;
|
||||
while (dir < 6 && transparentQuads[dir].isEmpty())
|
||||
dir++;
|
||||
}
|
||||
else
|
||||
{
|
||||
quad = i;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
public int getCurrentOpaqueQuadsCount()
|
||||
{
|
||||
int i = 0;
|
||||
for (ArrayList<BufferQuad> qs : quads)
|
||||
for (ArrayList<BufferQuad> qs : opaqueQuads)
|
||||
i += qs.size();
|
||||
return i;
|
||||
}
|
||||
public int getCurrentTransparentQuadsCount()
|
||||
{
|
||||
if (!doTransparency) return 0;
|
||||
int i = 0;
|
||||
for (ArrayList<BufferQuad> qs : transparentQuads)
|
||||
i += qs.size();
|
||||
return i;
|
||||
}
|
||||
|
||||
/** Returns how many Buffers will be needed to render everything in this builder. */
|
||||
public int getCurrentNeededVertexBufferCount()
|
||||
/** Returns how many Buffers will be needed to render opaque quads in this builder. */
|
||||
public int getCurrentNeededOpaqueVertexBufferCount()
|
||||
{
|
||||
return MathUtil.ceilDiv(getCurrentQuadsCount(), RenderBuffer.MAX_QUADS_PER_BUFFER);
|
||||
return MathUtil.ceilDiv(getCurrentOpaqueQuadsCount(), RenderBuffer.MAX_QUADS_PER_BUFFER);
|
||||
}
|
||||
/** Returns how many Buffers will be needed to render transparent quads in this builder. */
|
||||
public int getCurrentNeededTransparentVertexBufferCount()
|
||||
{
|
||||
if (!doTransparency) return 0;
|
||||
return MathUtil.ceilDiv(getCurrentTransparentQuadsCount(), RenderBuffer.MAX_QUADS_PER_BUFFER);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import java.io.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
// WARNING: This is not THREAD-SAFE!
|
||||
public class IdBiomeBlockStateMap {
|
||||
@@ -47,7 +48,7 @@ public class IdBiomeBlockStateMap {
|
||||
|
||||
|
||||
final ArrayList<Entry> entries = new ArrayList<>();
|
||||
final HashMap<Entry, Integer> idMap = new HashMap<>();
|
||||
final ConcurrentHashMap<Entry, Integer> idMap = new ConcurrentHashMap<>(); // FIXME: Improve performance
|
||||
|
||||
public Entry get(int id) {
|
||||
return entries.get(id);
|
||||
|
||||
@@ -46,9 +46,6 @@ public class BatchGenerator implements IChunkGenerator
|
||||
public ILevel targetLodLevel;
|
||||
public static final int generationGroupSize = 4;
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger(MethodHandles.lookup().lookupClass().getSimpleName());
|
||||
|
||||
// private int estimatedSampleNeeded = 128;
|
||||
// private int estimatedPointsToQueue = 1;
|
||||
|
||||
public BatchGenerator(ILevel targetLodLevel) {
|
||||
this.targetLodLevel = targetLodLevel;
|
||||
@@ -56,198 +53,6 @@ public class BatchGenerator implements IChunkGenerator
|
||||
LOGGER.info("Batch Chunk Generator initialized");
|
||||
}
|
||||
|
||||
// @SuppressWarnings("unused")
|
||||
// public void queueGenerationRequests() {
|
||||
// EDistanceGenerationMode mode = Config.Client.WorldGenerator.distanceGenerationMode.get();
|
||||
// int newThreadCount = Config.Client.Advanced.Threading.numberOfWorldGenerationThreads.get()<1 ? 1 : (int) Math.ceil(Config.Client.Advanced.Threading.numberOfWorldGenerationThreads.get());
|
||||
// if (newThreadCount != previousThreadCount) {
|
||||
// generationGroup.resizeThreadPool(newThreadCount);
|
||||
// previousThreadCount = newThreadCount;
|
||||
// }
|
||||
// if (estimatedPointsToQueue < newThreadCount)
|
||||
// estimatedPointsToQueue = newThreadCount;
|
||||
//
|
||||
// EGenerationPriority priority = Config.Client.WorldGenerator.generationPriority.get();
|
||||
// if (priority == EGenerationPriority.AUTO)
|
||||
// priority = MC.hasSinglePlayerServer() ? EGenerationPriority.FAR_FIRST : EGenerationPriority.NEAR_FIRST;
|
||||
//
|
||||
// generationGroup.updateAllFutures();
|
||||
// if (!MC.hasSinglePlayerServer())
|
||||
// return;
|
||||
// if (!LodUtil.checkRamUsage(0.1, 64)) return;
|
||||
//
|
||||
// int eventsCount = generationGroup.getEventCount();
|
||||
// // If we still all jobs running, return.
|
||||
// if (eventsCount >= estimatedPointsToQueue) {
|
||||
// estimatedPointsToQueue--;
|
||||
// if (estimatedPointsToQueue < newThreadCount)
|
||||
// estimatedPointsToQueue = newThreadCount;
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// final int targetToGenerate = estimatedPointsToQueue - eventsCount;
|
||||
// int toGenerate = targetToGenerate;
|
||||
// int positionGoneThough = 0;
|
||||
//
|
||||
// // round the player's block position down to the nearest chunk BlockPos
|
||||
// int playerPosX = MC.getPlayerBlockPos().getX();
|
||||
// int playerPosZ = MC.getPlayerBlockPos().getZ();
|
||||
// double runTimeRatio = Config.Client.Advanced.Threading.numberOfWorldGenerationThreads.get()>1 ? 1.0 : Config.Client.Advanced.Threading.numberOfWorldGenerationThreads.get();
|
||||
//
|
||||
// //FIXME
|
||||
// PosToGenerateContainer posToGenerate = null;//lodDim.getPosToGenerate(estimatedSampleNeeded, playerPosX, playerPosZ,
|
||||
// //priority, mode);
|
||||
//
|
||||
// if (eventsCount == 0 && posToGenerate.getNumberOfPos() >= estimatedSampleNeeded) {
|
||||
// estimatedPointsToQueue++;
|
||||
// if (estimatedPointsToQueue > newThreadCount * 10)
|
||||
// estimatedPointsToQueue = newThreadCount * 10;
|
||||
// }
|
||||
//
|
||||
// // ApiShared.LOGGER.info("PosToGenerate: {}", posToGenerate);
|
||||
//
|
||||
// // Find the max number of iterations we need to go though.
|
||||
// // We are checking one FarPos, and one NearPos per iterations.
|
||||
// // This ensures we aren't just always picking one or the other.
|
||||
// Steps targetStep;
|
||||
// switch (mode) {
|
||||
// case NONE:
|
||||
// targetStep = Steps.Empty; // NOTE: Only load in existing chunks. No new chunk generation
|
||||
// break;
|
||||
// case BIOME_ONLY:
|
||||
// targetStep = Steps.Biomes; // NOTE: No block. Require fake height in LodBuilder
|
||||
// break;
|
||||
// case BIOME_ONLY_SIMULATE_HEIGHT:
|
||||
// targetStep = Steps.Noise; // NOTE: Stone only. Require fake surface
|
||||
// break;
|
||||
// case SURFACE:
|
||||
// targetStep = Steps.Surface; // Carvers or Surface???
|
||||
// break;
|
||||
// case FEATURES:
|
||||
// case FULL:
|
||||
// targetStep = Steps.Features;
|
||||
// break;
|
||||
// default:
|
||||
// assert false;
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// if (ENABLE_GENERATOR_STATS_LOGGING)
|
||||
// LOGGER.info("WorldGen. Near:" + posToGenerate.getNumberOfNearPos() + " Far:"
|
||||
// + posToGenerate.getNumberOfFarPos());
|
||||
// if (priority == EGenerationPriority.FAR_FIRST || priority == EGenerationPriority.BALANCED) {
|
||||
//
|
||||
// int nearCount = posToGenerate.getNumberOfNearPos();
|
||||
// int farCount = posToGenerate.getNumberOfFarPos();
|
||||
// if (ENABLE_GENERATOR_STATS_LOGGING)
|
||||
// LOGGER.info("WorldGen. Near:" + nearCount + " Far:" + farCount);
|
||||
// int maxIteration = Math.max(nearCount, farCount);
|
||||
// for (int i = 0; i < maxIteration; i++) {
|
||||
//
|
||||
// // We have farPos to go though
|
||||
// if (i < farCount && posToGenerate.getNthDetail(i, false) != 0) {
|
||||
// positionGoneThough++;
|
||||
// byte detailLevel = (byte) (posToGenerate.getNthDetail(i, false) - 1);
|
||||
// int chunkX = LevelPosUtil.getChunkPos(detailLevel, posToGenerate.getNthPosX(i, false));
|
||||
// int chunkZ = LevelPosUtil.getChunkPos(detailLevel, posToGenerate.getNthPosZ(i, false));
|
||||
// int genSize = detailLevel > LodUtil.CHUNK_DETAIL_LEVEL ? 0 : generationGroupSize;
|
||||
// if (generationGroup.tryAddPoint(chunkX, chunkZ, genSize, targetStep, false, runTimeRatio)) {
|
||||
// toGenerate--;
|
||||
// }
|
||||
// }
|
||||
// if (toGenerate <= 0)
|
||||
// break;
|
||||
//
|
||||
// // We have nearPos to go though
|
||||
// if (i < nearCount && posToGenerate.getNthDetail(i, true) != 0) {
|
||||
// positionGoneThough++;
|
||||
// byte detailLevel = (byte) (posToGenerate.getNthDetail(i, true) - 1);
|
||||
// int chunkX = LevelPosUtil.getChunkPos(detailLevel, posToGenerate.getNthPosX(i, true));
|
||||
// int chunkZ = LevelPosUtil.getChunkPos(detailLevel, posToGenerate.getNthPosZ(i, true));
|
||||
// int genSize = detailLevel > LodUtil.CHUNK_DETAIL_LEVEL ? 0 : generationGroupSize;
|
||||
// if (generationGroup.tryAddPoint(chunkX, chunkZ, genSize, targetStep, true, runTimeRatio)) {
|
||||
// toGenerate--;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if (toGenerate <= 0)
|
||||
// break;
|
||||
// }
|
||||
// } else {
|
||||
// int nearCount = posToGenerate.getNumberOfNearPos();
|
||||
// for (int i = 0; i < nearCount; i++) {
|
||||
//
|
||||
// // We have nearPos to go though
|
||||
// if (posToGenerate.getNthDetail(i, true) != 0) {
|
||||
// positionGoneThough++;
|
||||
// byte detailLevel = (byte) (posToGenerate.getNthDetail(i, true) - 1);
|
||||
// int chunkX = LevelPosUtil.getChunkPos(detailLevel, posToGenerate.getNthPosX(i, true));
|
||||
// int chunkZ = LevelPosUtil.getChunkPos(detailLevel, posToGenerate.getNthPosZ(i, true));
|
||||
// int genSize = detailLevel > LodUtil.CHUNK_DETAIL_LEVEL ? 0 : generationGroupSize;
|
||||
// if (generationGroup.tryAddPoint(chunkX, chunkZ, genSize, targetStep, true, runTimeRatio)) {
|
||||
// toGenerate--;
|
||||
// }
|
||||
// if (toGenerate <= 0)
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// // Only do far gen if toGenerate is non 0 and that we have requested all samples
|
||||
// // we can get.
|
||||
// if (toGenerate > 0 && estimatedSampleNeeded > posToGenerate.getNumberOfPos()) {
|
||||
// int farCount = posToGenerate.getNumberOfFarPos();
|
||||
// for (int i = 0; i < farCount; i++) {
|
||||
// // We have farPos to go though
|
||||
// if (posToGenerate.getNthDetail(i, false) != 0) {
|
||||
// positionGoneThough++;
|
||||
// byte detailLevel = (byte) (posToGenerate.getNthDetail(i, false) - 1);
|
||||
// int chunkX = LevelPosUtil.getChunkPos(detailLevel, posToGenerate.getNthPosX(i, false));
|
||||
// int chunkZ = LevelPosUtil.getChunkPos(detailLevel, posToGenerate.getNthPosZ(i, false));
|
||||
// int genSize = detailLevel > LodUtil.CHUNK_DETAIL_LEVEL ? 0 : generationGroupSize;
|
||||
// if (generationGroup.tryAddPoint(chunkX, chunkZ, genSize, targetStep, false, runTimeRatio)) {
|
||||
// toGenerate--;
|
||||
// }
|
||||
// }
|
||||
// if (toGenerate <= 0)
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if (targetToGenerate != toGenerate && ENABLE_GENERATOR_STATS_LOGGING) {
|
||||
// if (toGenerate <= 0) {
|
||||
// LOGGER.info(
|
||||
// "WorldGenerator: Sampled " + posToGenerate.getNumberOfPos() + " out of " + estimatedSampleNeeded
|
||||
// + " points, started all targeted " + targetToGenerate + " generations.");
|
||||
// } else {
|
||||
// LOGGER.info("WorldGenerator: Sampled " + posToGenerate.getNumberOfPos() + " out of "
|
||||
// + estimatedSampleNeeded + " points, started " + (targetToGenerate - toGenerate)
|
||||
// + " out of targeted " + targetToGenerate + " generations.");
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if (toGenerate > 0 && estimatedSampleNeeded <= posToGenerate.getNumberOfPos()) {
|
||||
// // We failed to generate enough points from the samples.
|
||||
// // Let's increase the estimatedSampleNeeded.
|
||||
// estimatedSampleNeeded *= 1.3;
|
||||
// // Ensure wee don't go to basically infinity
|
||||
// if (estimatedSampleNeeded > 32768)
|
||||
// estimatedSampleNeeded = 32768;
|
||||
// if (ENABLE_GENERATOR_STATS_LOGGING)
|
||||
// LOGGER.info("WorldGenerator: Increasing estimatedSampleNeeded to " + estimatedSampleNeeded);
|
||||
//
|
||||
// } else if (toGenerate <= 0 && positionGoneThough * 1.5 < posToGenerate.getNumberOfPos()) {
|
||||
// // We haven't gone through half of them, and it's already enough.
|
||||
// // Let's shrink the estimatedSampleNeeded.
|
||||
// estimatedSampleNeeded /= 1.2;
|
||||
// // Ensure we don't go near zero.
|
||||
// if (estimatedSampleNeeded < 4)
|
||||
// estimatedSampleNeeded = 4;
|
||||
// if (ENABLE_GENERATOR_STATS_LOGGING)
|
||||
// LOGGER.info("WorldGenerator: Decreasing estimatedSampleNeeded to " + estimatedSampleNeeded);
|
||||
// }
|
||||
//
|
||||
// }
|
||||
|
||||
public void stop(boolean blocking) {
|
||||
LOGGER.info("1.18 Experimental Chunk Generator shutting down...");
|
||||
generationGroup.stop(blocking);
|
||||
|
||||
@@ -82,7 +82,7 @@ public class LodRenderSection {
|
||||
}
|
||||
|
||||
public boolean canRender() {
|
||||
return isLoaded() && isRenderEnabled && lodRenderSource != null && lodRenderSource.isRenderReady();
|
||||
return isLoaded() && isRenderEnabled && lodRenderSource != null;
|
||||
}
|
||||
|
||||
public boolean isLoaded() {
|
||||
|
||||
@@ -32,7 +32,8 @@ public abstract class RenderBuffer implements AutoCloseable
|
||||
// ========== Called by render thread ==========
|
||||
/* Called on... well... rendering.
|
||||
* Return false if nothing rendered. (Optional) */
|
||||
public abstract boolean render(LodRenderer renderContext);
|
||||
public abstract boolean renderOpaque(LodRenderer renderContext);
|
||||
public abstract boolean renderTransparent(LodRenderer renderContext);
|
||||
|
||||
// ========== Called by any thread. (thread safe) ==========
|
||||
|
||||
@@ -57,5 +58,4 @@ public abstract class RenderBuffer implements AutoCloseable
|
||||
public static final int FULL_SIZED_BUFFER = MAX_QUADS_PER_BUFFER * QUADS_BYTE_SIZE;
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,63 +1,128 @@
|
||||
package com.seibel.lod.core.render;
|
||||
|
||||
import com.seibel.lod.core.datatype.LodRenderSource;
|
||||
import com.seibel.lod.core.enums.ELodDirection;
|
||||
import com.seibel.lod.core.pos.Pos2D;
|
||||
import com.seibel.lod.core.pos.DhSectionPos;
|
||||
import com.seibel.lod.core.render.renderer.LodRenderer;
|
||||
import com.seibel.lod.core.util.LodUtil;
|
||||
import com.seibel.lod.core.util.gridList.MovableGridRingList;
|
||||
import com.seibel.lod.core.util.math.Mat4f;
|
||||
import com.seibel.lod.core.util.math.Vec3f;
|
||||
import com.seibel.lod.core.util.objects.SortedArraySet;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
import java.util.Vector;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
public class RenderBufferHandler {
|
||||
public final LodQuadTree target;
|
||||
private final MovableGridRingList<RenderBufferNode> renderBufferNodes;
|
||||
|
||||
private static class LoadedRenderBuffer {
|
||||
public final RenderBuffer buffer;
|
||||
public final DhSectionPos pos;
|
||||
LoadedRenderBuffer(RenderBuffer buffer, DhSectionPos pos) {
|
||||
this.buffer = buffer;
|
||||
this.pos = pos;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Make sorting go into the update loop instead of the render loop as it doesn't need to be done every frame
|
||||
private SortedArraySet<LoadedRenderBuffer> loadedNearToFarBuffers = null;
|
||||
|
||||
// The followiing buildRenderList sorting method is based on the following reddit post:
|
||||
// https://www.reddit.com/r/VoxelGameDev/comments/a0l8zc/correct_depthordering_for_translucent_discrete/
|
||||
public void buildRenderList(Vec3f lookForwardVector) {
|
||||
ELodDirection[] axisDirections = new ELodDirection[3];
|
||||
// Do the axis that are longest first (i.e. the largest absolute value of the lookForwardVector)
|
||||
// , with the sign being the opposite of the respective lookForwardVector component's sign
|
||||
float absX = Math.abs(lookForwardVector.x);
|
||||
float absY = Math.abs(lookForwardVector.y);
|
||||
float absZ = Math.abs(lookForwardVector.z);
|
||||
ELodDirection xDir = lookForwardVector.x < 0 ? ELodDirection.EAST : ELodDirection.WEST;
|
||||
ELodDirection yDir = lookForwardVector.y < 0 ? ELodDirection.UP : ELodDirection.DOWN;
|
||||
ELodDirection zDir = lookForwardVector.z < 0 ? ELodDirection.SOUTH : ELodDirection.NORTH;
|
||||
if (absX >= absY && absX >= absZ) {
|
||||
axisDirections[0] = xDir;
|
||||
if (absY >= absZ) {
|
||||
axisDirections[1] = yDir;
|
||||
axisDirections[2] = zDir;
|
||||
} else {
|
||||
axisDirections[1] = zDir;
|
||||
axisDirections[2] = yDir;
|
||||
}
|
||||
} else if (absY >= absX && absY >= absZ) {
|
||||
axisDirections[0] = yDir;
|
||||
if (absX >= absZ) {
|
||||
axisDirections[1] = xDir;
|
||||
axisDirections[2] = zDir;
|
||||
} else {
|
||||
axisDirections[1] = zDir;
|
||||
axisDirections[2] = xDir;
|
||||
}
|
||||
} else {
|
||||
axisDirections[0] = zDir;
|
||||
if (absX >= absY) {
|
||||
axisDirections[1] = xDir;
|
||||
axisDirections[2] = yDir;
|
||||
} else {
|
||||
axisDirections[1] = yDir;
|
||||
axisDirections[2] = xDir;
|
||||
}
|
||||
}
|
||||
|
||||
// Now that we have the axis directions, we can sort the render list
|
||||
Comparator<LoadedRenderBuffer> sortFarToNear = (a, b) -> {
|
||||
Pos2D aPos = a.pos.getCenter().getCenter().toPos2D();
|
||||
Pos2D bPos = b.pos.getCenter().getCenter().toPos2D();
|
||||
for (ELodDirection axisDirection : axisDirections) {
|
||||
if (axisDirection.getAxis().isVertical()) continue; // We works on the horizontal plane only for section sorting
|
||||
int abDiff;
|
||||
if (axisDirection.getAxis().equals(ELodDirection.Axis.X)) {
|
||||
abDiff = aPos.x - bPos.x;
|
||||
} else {
|
||||
abDiff = aPos.y - bPos.y;
|
||||
}
|
||||
if (abDiff == 0) continue;
|
||||
if (axisDirection.getAxisDirection().equals(ELodDirection.AxisDirection.NEGATIVE)) {
|
||||
abDiff = -abDiff; // Reverse the sign
|
||||
}
|
||||
return abDiff;
|
||||
}
|
||||
return a.pos.sectionDetail - b.pos.sectionDetail; // If all else fails, sort by detail
|
||||
};
|
||||
Comparator<LoadedRenderBuffer> sortNearToFar = (a, b) -> -sortFarToNear.compare(a, b);
|
||||
// Build the sorted list
|
||||
loadedNearToFarBuffers = new SortedArraySet<>(sortNearToFar);
|
||||
// Add all the loaded buffers to the sorted list
|
||||
renderBufferNodes.forEach((r) -> {if (r!=null) r.collect(loadedNearToFarBuffers);});
|
||||
}
|
||||
|
||||
|
||||
class RenderBufferNode implements AutoCloseable {
|
||||
public final DhSectionPos pos;
|
||||
public volatile RenderBufferNode[] children = null;
|
||||
|
||||
//FIXME: The multiple Atomics will cause race conditions between them!
|
||||
public final AtomicReference<RenderBuffer> renderBufferSlotOpaque = new AtomicReference<>();
|
||||
public final AtomicReference<RenderBuffer> renderBufferSlotTransparent = new AtomicReference<>();
|
||||
public final AtomicReference<RenderBuffer> renderBufferSlot = new AtomicReference<>();
|
||||
|
||||
public RenderBufferNode(DhSectionPos pos) {
|
||||
this.pos = pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* This will render all opaque lods
|
||||
* @param renderContext
|
||||
*/
|
||||
public void renderOpaque(LodRenderer renderContext) {
|
||||
public void collect(SortedArraySet<LoadedRenderBuffer> sortedSet) {
|
||||
RenderBuffer buff;
|
||||
|
||||
buff = renderBufferSlotOpaque.get();
|
||||
buff = renderBufferSlot.get();
|
||||
if (buff != null) {
|
||||
buff.render(renderContext);
|
||||
sortedSet.add(new LoadedRenderBuffer(buff, pos));
|
||||
} else {
|
||||
RenderBufferNode[] childs = children;
|
||||
if (childs != null) {
|
||||
for (RenderBufferNode child : childs) {
|
||||
child.renderOpaque(renderContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This will render all transparent lods
|
||||
* @param renderContext
|
||||
*/
|
||||
public void renderTransparent(LodRenderer renderContext) {
|
||||
RenderBuffer buff;
|
||||
buff = renderBufferSlotTransparent.get();
|
||||
if (buff != null) {
|
||||
buff.render(renderContext);
|
||||
} else {
|
||||
RenderBufferNode[] childs = children;
|
||||
if (childs != null) {
|
||||
for (RenderBufferNode child : childs) {
|
||||
child.renderTransparent(renderContext);
|
||||
child.collect(sortedSet);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -77,17 +142,13 @@ public class RenderBufferHandler {
|
||||
boolean shouldRender = section.canRender();
|
||||
if (!shouldRender) {
|
||||
//TODO: Does this really need to force the old buffer to not be rendered?
|
||||
RenderBuffer buff = renderBufferSlotOpaque.getAndSet(null);
|
||||
if (buff != null) {
|
||||
buff.close();
|
||||
}
|
||||
buff = renderBufferSlotTransparent.getAndSet(null);
|
||||
RenderBuffer buff = renderBufferSlot.getAndSet(null);
|
||||
if (buff != null) {
|
||||
buff.close();
|
||||
}
|
||||
} else {
|
||||
LodUtil.assertTrue(container != null); // section.isLoaded() should have ensured this
|
||||
container.trySwapRenderBuffer(target, renderBufferSlotOpaque, renderBufferSlotTransparent);
|
||||
container.trySwapRenderBuffer(target, renderBufferSlot);
|
||||
}
|
||||
|
||||
// Update children's render buffer state
|
||||
@@ -109,7 +170,7 @@ public class RenderBufferHandler {
|
||||
} else {
|
||||
if (children != null) {
|
||||
//FIXME: Concurrency issue here: If render thread is concurrently using the child's buffer,
|
||||
// and this thread got priority to close the buffer, it causes a bug wher the render thread
|
||||
// and this thread got priority to close the buffer, it causes a bug where the render thread
|
||||
// will be using a closed buffer!!!!
|
||||
RenderBufferNode[] childs = children;
|
||||
children = null;
|
||||
@@ -128,11 +189,7 @@ public class RenderBufferHandler {
|
||||
}
|
||||
}
|
||||
RenderBuffer buff;
|
||||
buff = renderBufferSlotOpaque.getAndSet(null);
|
||||
if (buff != null) {
|
||||
buff.close();
|
||||
}
|
||||
buff = renderBufferSlotTransparent.getAndSet(null);
|
||||
buff = renderBufferSlot.getAndSet(null);
|
||||
if (buff != null) {
|
||||
buff.close();
|
||||
}
|
||||
@@ -146,14 +203,19 @@ public class RenderBufferHandler {
|
||||
renderBufferNodes = new MovableGridRingList<>(referenceList.getHalfSize(), center);
|
||||
}
|
||||
|
||||
public void render(LodRenderer renderContext) {
|
||||
//TODO: This might get locked by update() causing move() call. Is there a way to avoid this?
|
||||
// Maybe dupe the base list and use atomic swap on render? Or is this not worth it?
|
||||
//TODO: This might get locked by update() causing move() call. Is there a way to avoid this?
|
||||
// Maybe dupe the base list and use atomic swap on render? Or is this not worth it?
|
||||
public void prepare(LodRenderer renderContext) {
|
||||
buildRenderList(renderContext.getLookVector());
|
||||
}
|
||||
|
||||
public void renderOpaque(LodRenderer renderContext) {
|
||||
//TODO: Directional culling
|
||||
//TODO: Ordered by distance
|
||||
renderBufferNodes.forEachOrdered(n -> n.renderOpaque(renderContext));
|
||||
loadedNearToFarBuffers.forEach(b -> b.buffer.renderOpaque(renderContext));
|
||||
}
|
||||
public void renderTransparent(LodRenderer renderContext) {
|
||||
if(LodRenderer.transparencyEnabled)
|
||||
renderBufferNodes.forEachOrdered(n -> n.renderTransparent(renderContext));
|
||||
loadedNearToFarBuffers.forEach(b -> b.buffer.renderTransparent(renderContext));
|
||||
}
|
||||
|
||||
public void update() {
|
||||
@@ -186,31 +248,6 @@ public class RenderBufferHandler {
|
||||
// Update node
|
||||
node.update();
|
||||
});
|
||||
|
||||
|
||||
/**TODO improve the ordering*/
|
||||
/* DHBlockPos playerPos = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class).getPlayerBlockPos();
|
||||
int x = playerPos.x;
|
||||
int z = playerPos.z;
|
||||
Comparator<RenderBufferNode> byDistance = new Comparator<RenderBufferNode>() {
|
||||
@Override
|
||||
public int compare(RenderBufferNode o1, RenderBufferNode o2) {
|
||||
if ((o1 == null) && (o2 == null)) {
|
||||
return 0;
|
||||
} else if (o1 == null) {
|
||||
return 1;
|
||||
} else if (o2 == null) {
|
||||
return -1;
|
||||
}
|
||||
int x1 = o1.pos.sectionX;
|
||||
int z1 = o1.pos.sectionZ;
|
||||
int x2 = o2.pos.sectionX;
|
||||
int z2 = o2.pos.sectionZ;
|
||||
|
||||
return Integer.compare((x1 - x) ^ 2 + (z1 - z) ^ 2, (x2 - x) ^ 2 + (z2 - z) ^ 2);
|
||||
}
|
||||
};
|
||||
renderBufferNodes.sort(byDistance);*/
|
||||
}
|
||||
|
||||
public void close() {
|
||||
|
||||
@@ -36,6 +36,7 @@ public class GLState {
|
||||
public int blendSrc;
|
||||
public int blendDst;
|
||||
public boolean depth;
|
||||
public boolean depthWrite;
|
||||
public int depthFunc;
|
||||
public boolean stencil;
|
||||
public int stencilFunc;
|
||||
@@ -61,6 +62,7 @@ public class GLState {
|
||||
blendSrc = GL32.glGetInteger(GL32.GL_BLEND_SRC);
|
||||
blendDst = GL32.glGetInteger(GL32.GL_BLEND_DST);
|
||||
depth = GL32.glIsEnabled(GL32.GL_DEPTH_TEST);
|
||||
depthWrite = GL32.glGetInteger(GL32.GL_DEPTH_WRITEMASK) == GL32.GL_TRUE;
|
||||
depthFunc = GL32.glGetInteger(GL32.GL_DEPTH_FUNC);
|
||||
stencil = GL32.glIsEnabled(GL32.GL_STENCIL_TEST);
|
||||
stencilFunc = GL32.glGetInteger(GL32.GL_STENCIL_FUNC);
|
||||
@@ -100,7 +102,9 @@ public class GLState {
|
||||
GL32.glBindVertexArray(vao);
|
||||
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, vbo);
|
||||
GL32.glBindBuffer(GL32.GL_ELEMENT_ARRAY_BUFFER, ebo);
|
||||
GL32.glUseProgram(prog);
|
||||
|
||||
GL32.glDepthMask(depthWrite);
|
||||
GL32.glBlendFunc(blendSrc, blendDst);
|
||||
if (depth) {
|
||||
GL32.glEnable(GL32.GL_DEPTH_TEST);
|
||||
@@ -115,7 +119,6 @@ public class GLState {
|
||||
}
|
||||
GL32.glStencilFunc(stencilFunc, stencilRef, stencilMask);
|
||||
GL32.glViewport(view[0], view[1], view[2], view[3]);
|
||||
GL32.glUseProgram(prog);
|
||||
if (cull) {
|
||||
GL32.glEnable(GL32.GL_CULL_FACE);
|
||||
} else {
|
||||
|
||||
@@ -85,6 +85,10 @@ public class LodRenderer
|
||||
GL32.glDrawElements(GL32.GL_TRIANGLES, (vbo.getVertexCount()/4)*6,
|
||||
quadIBO.getType(), 0);
|
||||
}
|
||||
public Vec3f getLookVector() {
|
||||
return MC_RENDER.getLookAtVector();
|
||||
}
|
||||
|
||||
|
||||
public static class LagSpikeCatcher {
|
||||
long timer = System.nanoTime();
|
||||
@@ -130,7 +134,6 @@ public class LodRenderer
|
||||
EVENT_LOGGER.error("drawLODs() called after close()!");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// get MC's shader program
|
||||
// Save all MC render state
|
||||
@@ -179,13 +182,9 @@ public class LodRenderer
|
||||
|
||||
transparencyEnabled = Config.Client.Graphics.Quality.transparency.get().tranparencyEnabled;
|
||||
fakeOceanFloor = Config.Client.Graphics.Quality.transparency.get().fakeTransparencyEnabled;
|
||||
if(transparencyEnabled) {
|
||||
GL32.glBlendFunc(GL32.GL_SRC_ALPHA, GL32.GL_ONE_MINUS_SRC_ALPHA);
|
||||
GL32.glEnable(GL32.GL_BLEND);
|
||||
}else{
|
||||
GL32.glDisable(GL32.GL_BLEND);
|
||||
}
|
||||
|
||||
GL32.glDisable(GL32.GL_BLEND); // We render opaque first, then transparent
|
||||
GL32.glDepthMask(true);
|
||||
GL32.glClear(GL32.GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
/*---------Bind required objects--------*/
|
||||
@@ -223,6 +222,8 @@ public class LodRenderer
|
||||
//GL32.glEnable( GL32.GL_POLYGON_OFFSET_FILL );
|
||||
//GL32.glPolygonOffset( 1f, 1f );
|
||||
|
||||
bufferHandler.prepare(this);
|
||||
|
||||
//===========//
|
||||
// rendering //
|
||||
//===========//
|
||||
@@ -233,11 +234,20 @@ public class LodRenderer
|
||||
Vec3d cameraPos = MC_RENDER.getCameraExactPosition();
|
||||
DhBlockPos cameraBlockPos = MC_RENDER.getCameraBlockPosition();
|
||||
Vec3f cameraDir = MC_RENDER.getLookAtVector();
|
||||
int drawCount = 0;
|
||||
|
||||
//TODO: Directional culling
|
||||
bufferHandler.render(this);
|
||||
bufferHandler.renderOpaque(this);
|
||||
|
||||
//======================//
|
||||
// render transparency //
|
||||
//======================//
|
||||
if (LodRenderer.transparencyEnabled) {
|
||||
GL32.glEnable(GL32.GL_BLEND);
|
||||
GL32.glBlendFunc(GL32.GL_SRC_ALPHA, GL32.GL_ONE_MINUS_SRC_ALPHA);
|
||||
GL32.glDepthMask(false); // This so that even on incorrect sorting of transparent blocks, it still mostly looks correct
|
||||
bufferHandler.renderTransparent(this);
|
||||
GL32.glDepthMask(true); // Apparently the depth mask state is stored in the FBO, so glState fails to restore it...
|
||||
}
|
||||
//if (drawCall==0)
|
||||
// tickLogger.info("DrawCall Count: {}", drawCount);
|
||||
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
package com.seibel.lod.core.util.objects;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class SortedArraySet<E> implements SortedSet<E> {
|
||||
private final ArrayList<E> list;
|
||||
private final Comparator<? super E> comparator;
|
||||
|
||||
public SortedArraySet() {
|
||||
list = new ArrayList<>();
|
||||
comparator = null;
|
||||
}
|
||||
|
||||
public SortedArraySet(Comparator<? super E> comparator) {
|
||||
list = new ArrayList<>();
|
||||
this.comparator = comparator;
|
||||
}
|
||||
|
||||
public SortedArraySet(Collection<? extends E> collection) {
|
||||
list = new ArrayList<>(collection);
|
||||
comparator = null;
|
||||
list.sort(null);
|
||||
}
|
||||
|
||||
public SortedArraySet(Collection<? extends E> collection, Comparator<? super E> comparator) {
|
||||
list = new ArrayList<>(collection);
|
||||
this.comparator = comparator;
|
||||
list.sort(comparator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Comparator<? super E> comparator() {
|
||||
return comparator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public E first() {
|
||||
return list.get(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public E last() {
|
||||
return list.get(list.size() - 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return list.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return list.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
return list.contains(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<E> iterator() {
|
||||
return list.iterator();
|
||||
}
|
||||
|
||||
public ListIterator<E> listIterator() {
|
||||
return list.listIterator();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Object[] toArray() {
|
||||
return list.toArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T[] toArray(T[] a) {
|
||||
return list.toArray(a);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(E e) {
|
||||
int index = Collections.binarySearch(list, e, comparator);
|
||||
if (index < 0) {
|
||||
index = ~index;
|
||||
}
|
||||
list.add(index, e);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object o) {
|
||||
return list.remove(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAll(Collection<?> c) {
|
||||
return list.containsAll(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(Collection<? extends E> c) {
|
||||
boolean changed = false;
|
||||
for (E e : c) {
|
||||
changed |= add(e);
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retainAll(Collection<?> c) {
|
||||
return list.retainAll(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAll(Collection<?> c) {
|
||||
return list.removeAll(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
list.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SortedArraySet{" +
|
||||
"list=" + list +
|
||||
", comparator=" + comparator +
|
||||
'}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortedSet<E> subSet(E fromElement, E toElement) {
|
||||
int fromIndex = Collections.binarySearch(list, fromElement, comparator);
|
||||
if (fromIndex < 0) fromIndex = ~fromIndex;
|
||||
int toIndex = Collections.binarySearch(list, toElement, comparator);
|
||||
if (toIndex < 0) toIndex = ~toIndex;
|
||||
return new SortedArraySet<>(list.subList(fromIndex, toIndex), comparator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortedSet<E> headSet(E toElement) {
|
||||
int toIndex = Collections.binarySearch(list, toElement, comparator);
|
||||
if (toIndex < 0) toIndex = ~toIndex;
|
||||
return new SortedArraySet<>(list.subList(0, toIndex), comparator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortedSet<E> tailSet(E fromElement) {
|
||||
int fromIndex = Collections.binarySearch(list, fromElement, comparator);
|
||||
if (fromIndex < 0) fromIndex = ~fromIndex;
|
||||
return new SortedArraySet<>(list.subList(fromIndex, list.size()), comparator);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user