First I think somewhat prob should work renderbuffer impl?
This commit is contained in:
+68
@@ -22,6 +22,8 @@ package com.seibel.lod.core.builders.lodBuilding.bufferBuilding;
|
||||
import com.seibel.lod.core.enums.rendering.DebugMode;
|
||||
import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler;
|
||||
import com.seibel.lod.core.objects.LodDataView;
|
||||
import com.seibel.lod.core.objects.a7.datatype.column.ColumnArrayView;
|
||||
import com.seibel.lod.core.objects.a7.datatype.column.ColumnBox;
|
||||
import com.seibel.lod.core.objects.opengl.LodBox;
|
||||
import com.seibel.lod.core.util.ColorUtil;
|
||||
import com.seibel.lod.core.util.DataPointUtil;
|
||||
@@ -104,4 +106,70 @@ public class CubicLodTemplate
|
||||
fullBright ? 15 : DataPointUtil.getLightBlock(data), // setBlockLights
|
||||
topData, botData, adjData, adjFillBlack); // setAdjData
|
||||
}
|
||||
|
||||
public static void addLodToBuffer(long data, long topData, long botData, ColumnArrayView[][] adjData, byte detailLevel, int offsetPosX, int offsetOosZ, LodQuadBuilder quadBuilder, DebugMode debugging)
|
||||
{
|
||||
short width = (short) (1 << detailLevel);
|
||||
short x = (short) LevelPosUtil.convert(detailLevel, offsetPosX, LodUtil.BLOCK_DETAIL_LEVEL);
|
||||
short y = DataPointUtil.getDepth(data);
|
||||
short z = (short) LevelPosUtil.convert(detailLevel, offsetOosZ, LodUtil.BLOCK_DETAIL_LEVEL);
|
||||
short dy = (short) (DataPointUtil.getHeight(data) - y);
|
||||
if (dy == 0)
|
||||
return;
|
||||
if (dy < 0)
|
||||
{
|
||||
throw new IllegalArgumentException("Negative y size for the data! Data: " + DataPointUtil.toString(data));
|
||||
}
|
||||
|
||||
int color;
|
||||
boolean fullBright = false;
|
||||
switch (debugging) {
|
||||
case OFF:
|
||||
case SHOW_WIREFRAME:
|
||||
{
|
||||
float saturationMultiplier = (float)CONFIG.client().graphics().advancedGraphics().getSaturationMultiplier();
|
||||
float brightnessMultiplier = (float)CONFIG.client().graphics().advancedGraphics().getBrightnessMultiplier();
|
||||
if (saturationMultiplier == 1.0 && brightnessMultiplier == 1.0) {
|
||||
color = DataPointUtil.getColor(data);
|
||||
} else {
|
||||
float[] ahsv = ColorUtil.argbToAhsv(DataPointUtil.getColor(data));
|
||||
color = ColorUtil.ahsvToArgb(ahsv[0], ahsv[1], ahsv[2] * saturationMultiplier, ahsv[3] * brightnessMultiplier);
|
||||
//ApiShared.LOGGER.info("Raw color:[{}], AHSV:{}, Out color:[{}]",
|
||||
// ColorUtil.toString(DataPointUtil.getColor(data)),
|
||||
// ahsv, ColorUtil.toString(color));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SHOW_DETAIL:
|
||||
case SHOW_DETAIL_WIREFRAME:
|
||||
{
|
||||
color = LodUtil.DEBUG_DETAIL_LEVEL_COLORS[detailLevel];
|
||||
fullBright = true;
|
||||
break;
|
||||
}
|
||||
case SHOW_GENMODE:
|
||||
case SHOW_GENMODE_WIREFRAME:
|
||||
{
|
||||
color = LodUtil.DEBUG_DETAIL_LEVEL_COLORS[DataPointUtil.getGenerationMode(data)];
|
||||
fullBright = true;
|
||||
break;
|
||||
}
|
||||
case SHOW_OVERLAPPING_QUADS:
|
||||
case SHOW_OVERLAPPING_QUADS_WIREFRAME:
|
||||
{
|
||||
color = ColorUtil.WHITE;
|
||||
fullBright = true;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown debug mode: " + debugging);
|
||||
}
|
||||
ColumnBox.addBoxQuadsToBuilder(quadBuilder, // buffer
|
||||
width, dy, width, // setWidth
|
||||
x, y, z, // setOffset
|
||||
color, // setColor
|
||||
DataPointUtil.getLightSky(data), // setSkyLights
|
||||
fullBright ? 15 : DataPointUtil.getLightBlock(data), // setBlockLights
|
||||
topData, botData, adjData); // setAdjData
|
||||
}
|
||||
}
|
||||
|
||||
@@ -467,9 +467,9 @@ public abstract class LodQuadTree {
|
||||
if (!section.isLoaded() && !section.isLoading()) {
|
||||
section.load(getRenderDataProvider(), containerType);
|
||||
}
|
||||
if (section.childCount == 4) section.enableRender();
|
||||
if (section.childCount == 4) section.enableRender(this);
|
||||
if (section.childCount == 0) section.disableRender();
|
||||
section.tick();
|
||||
section.tick(this);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -26,10 +26,10 @@ public class LodSection {
|
||||
this.pos = pos;
|
||||
}
|
||||
|
||||
public void enableRender() {
|
||||
public void enableRender(LodQuadTree quadTree) {
|
||||
if (isRenderEnabled) return;
|
||||
if (renderDataSource != null) {
|
||||
renderDataSource.enableRender();
|
||||
renderDataSource.enableRender(quadTree);
|
||||
}
|
||||
isRenderEnabled = true;
|
||||
}
|
||||
@@ -46,12 +46,12 @@ public class LodSection {
|
||||
loadFuture = renderDataProvider.createRenderData(renderDataSourceClass, pos);
|
||||
}
|
||||
|
||||
public void tick() {
|
||||
public void tick(LodQuadTree quadTree) {
|
||||
if (loadFuture != null && loadFuture.isDone()) {
|
||||
renderDataSource = loadFuture.join();
|
||||
loadFuture = null;
|
||||
if (isRenderEnabled) {
|
||||
renderDataSource.enableRender();
|
||||
renderDataSource.enableRender(quadTree);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,309 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
|
||||
* licensed under the GNU LGPL 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 Lesser 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.lod.core.objects.a7.datatype.column;
|
||||
|
||||
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.objects.LodDataView;
|
||||
import com.seibel.lod.core.util.ColorUtil;
|
||||
import com.seibel.lod.core.util.DataPointUtil;
|
||||
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
||||
|
||||
public class ColumnBox
|
||||
{
|
||||
private static final IMinecraftClientWrapper MC = SingletonHandler.get(IMinecraftClientWrapper.class);
|
||||
|
||||
public static void addBoxQuadsToBuilder(LodQuadBuilder builder, short xSize, short ySize, short zSize, short x,
|
||||
short y, short z, int color, byte skyLight, byte blockLight, long topData, long botData, ColumnArrayView[][] adjData)
|
||||
{
|
||||
short maxX = (short) (x + xSize);
|
||||
short maxY = (short) (y + ySize);
|
||||
short maxZ = (short) (z + zSize);
|
||||
byte skyLightTop = skyLight;
|
||||
byte skyLightBot = DataPointUtil.doesItExist(botData) ? DataPointUtil.getLightSky(botData) : 0;
|
||||
|
||||
// Up direction case
|
||||
boolean skipTop = DataPointUtil.doesItExist(topData) && DataPointUtil.getDepth(topData) == maxY;// &&
|
||||
// DataPointUtil.getAlpha(singleAdjDataPoint)
|
||||
// == 255;
|
||||
boolean skipBot = DataPointUtil.doesItExist(botData) && DataPointUtil.getHeight(botData) == y;// &&
|
||||
// DataPointUtil.getAlpha(singleAdjDataPoint)
|
||||
// == 255;
|
||||
|
||||
if (!skipTop)
|
||||
builder.addQuadUp(x, maxY, z, xSize, zSize, ColorUtil.applyShade(color, MC.getShade(LodDirection.UP)), skyLightTop, blockLight);
|
||||
if (!skipBot)
|
||||
builder.addQuadDown(x, y, z, xSize, zSize, ColorUtil.applyShade(color, MC.getShade(LodDirection.DOWN)), skyLightBot, blockLight);
|
||||
|
||||
//If the adj pos is at the same level we cull the faces normally, otherwise we divide the face in two and cull the two part separately
|
||||
|
||||
//NORTH face vertex creation
|
||||
{
|
||||
ColumnArrayView[] adjDataNorth = adjData[LodDirection.NORTH.ordinal() - 2];
|
||||
int adjOverlapNorth = ColorUtil.TRANSPARENT;
|
||||
if (adjDataNorth == null)
|
||||
{
|
||||
builder.addQuadAdj(LodDirection.NORTH, x, y, z, xSize, ySize, color, (byte) 15, blockLight);
|
||||
}
|
||||
else if (adjDataNorth.length == 1)
|
||||
{
|
||||
makeAdjQuads(builder, adjDataNorth[0], LodDirection.NORTH, x, y, z, xSize, ySize,
|
||||
color, adjOverlapNorth, skyLightTop, blockLight);
|
||||
}
|
||||
else
|
||||
{
|
||||
makeAdjQuads(builder, adjDataNorth[0], LodDirection.NORTH, x, y, z, (short) (xSize / 2), ySize,
|
||||
color, adjOverlapNorth, skyLightTop, blockLight);
|
||||
makeAdjQuads(builder, adjDataNorth[1], LodDirection.NORTH, (short) (x + xSize / 2), y, z, (short) (xSize / 2), ySize,
|
||||
color, adjOverlapNorth, skyLightTop, blockLight);
|
||||
}
|
||||
}
|
||||
|
||||
//SOUTH face vertex creation
|
||||
{
|
||||
ColumnArrayView[] adjDataSouth = adjData[LodDirection.SOUTH.ordinal() - 2];
|
||||
int adjOverlapSouth = ColorUtil.TRANSPARENT;
|
||||
if (adjDataSouth == null)
|
||||
{
|
||||
builder.addQuadAdj(LodDirection.SOUTH, x, y, maxZ, xSize, ySize, color, (byte) 15, blockLight);
|
||||
}
|
||||
else if (adjDataSouth.length == 1)
|
||||
{
|
||||
makeAdjQuads(builder, adjDataSouth[0], LodDirection.SOUTH, x, y, maxZ, xSize, ySize,
|
||||
color, adjOverlapSouth, skyLightTop, blockLight);
|
||||
}
|
||||
else
|
||||
{
|
||||
makeAdjQuads(builder, adjDataSouth[0], LodDirection.SOUTH, x, y, maxZ, (short) (xSize / 2), ySize,
|
||||
color, adjOverlapSouth, skyLightTop, blockLight);
|
||||
|
||||
makeAdjQuads(builder, adjDataSouth[1], LodDirection.SOUTH, (short) (x + xSize / 2), y, maxZ, (short) (xSize / 2), ySize,
|
||||
color, adjOverlapSouth, skyLightTop, blockLight);
|
||||
}
|
||||
}
|
||||
|
||||
//WEST face vertex creation
|
||||
{
|
||||
ColumnArrayView[] adjDataWest = adjData[LodDirection.WEST.ordinal() - 2];
|
||||
int adjOverlapWest = ColorUtil.TRANSPARENT;
|
||||
if (adjDataWest == null)
|
||||
{
|
||||
builder.addQuadAdj(LodDirection.WEST, x, y, z, zSize, ySize, color, (byte) 15, blockLight);
|
||||
}
|
||||
else if (adjDataWest.length == 1)
|
||||
{
|
||||
makeAdjQuads(builder, adjDataWest[0], LodDirection.WEST, x, y, z, zSize, ySize,
|
||||
color, adjOverlapWest, skyLightTop, blockLight);
|
||||
}
|
||||
else
|
||||
{
|
||||
makeAdjQuads(builder, adjDataWest[0], LodDirection.WEST, x, y, z, (short) (zSize / 2), ySize,
|
||||
color, adjOverlapWest, skyLightTop, blockLight);
|
||||
makeAdjQuads(builder, adjDataWest[1], LodDirection.WEST, x, y, (short) (z + zSize / 2), (short) (zSize / 2), ySize,
|
||||
color, adjOverlapWest, skyLightTop, blockLight);
|
||||
}
|
||||
}
|
||||
|
||||
//EAST face vertex creation
|
||||
{
|
||||
ColumnArrayView[] adjDataEast = adjData[LodDirection.EAST.ordinal() - 2];
|
||||
int adjOverlapEast = ColorUtil.TRANSPARENT;
|
||||
if (adjData[LodDirection.EAST.ordinal() - 2] == null)
|
||||
{
|
||||
builder.addQuadAdj(LodDirection.EAST, maxX, y, z, zSize, ySize, color, (byte) 15, blockLight);
|
||||
}
|
||||
else if (adjDataEast.length == 1)
|
||||
{
|
||||
makeAdjQuads(builder, adjDataEast[0], LodDirection.EAST, maxX, y, z, zSize, ySize,
|
||||
color, adjOverlapEast, skyLightTop, blockLight);
|
||||
}
|
||||
else
|
||||
{
|
||||
makeAdjQuads(builder, adjDataEast[0], LodDirection.EAST, maxX, y, z, (short) (zSize / 2), ySize,
|
||||
color, adjOverlapEast, skyLightTop, blockLight);
|
||||
makeAdjQuads(builder, adjDataEast[1], LodDirection.EAST, maxX, y, (short) (z + zSize / 2), (short) (zSize / 2), ySize,
|
||||
color, adjOverlapEast, skyLightTop, blockLight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void makeAdjQuads(LodQuadBuilder builder, ColumnArrayView adjData, LodDirection direction, short x, short y,
|
||||
short z, short w0, short wy, int color, int overlapColor, byte upSkyLight, byte blockLight)
|
||||
{
|
||||
color = ColorUtil.applyShade(color, MC.getShade(direction));
|
||||
ColumnArrayView dataPoint = adjData;
|
||||
if (dataPoint == null || DataPointUtil.isVoid(dataPoint.get(0)))
|
||||
{
|
||||
builder.addQuadAdj(direction, x, y, z, w0, wy, color, (byte) 15, blockLight);
|
||||
return;
|
||||
}
|
||||
|
||||
int i;
|
||||
boolean firstFace = true;
|
||||
boolean allAbove = true;
|
||||
short previousDepth = -1;
|
||||
byte nextSkyLight = upSkyLight;
|
||||
|
||||
// TODO transparency ocean floor fix
|
||||
// boolean isOpaque = ((colorMap[0] >> 24) & 0xFF) == 255;
|
||||
for (i = 0; i < dataPoint.size() && DataPointUtil.doesItExist(adjData.get(i))
|
||||
&& !DataPointUtil.isVoid(adjData.get(i)); i++)
|
||||
{
|
||||
long adjPoint = adjData.get(i);
|
||||
|
||||
// TODO transparency ocean floor fix
|
||||
// if (isOpaque && DataPointUtil.getAlpha(singleAdjDataPoint) != 255)
|
||||
// continue;
|
||||
|
||||
short height = DataPointUtil.getHeight(adjPoint);
|
||||
short depth = DataPointUtil.getDepth(adjPoint);
|
||||
|
||||
// If the depth of said block is higher than our max Y, continue
|
||||
// Basically: y < maxY <= _____ height
|
||||
// _______&&: y < maxY <= depth
|
||||
if (y + wy <= depth)
|
||||
continue;
|
||||
// Now: depth < maxY
|
||||
allAbove = false;
|
||||
|
||||
if (height < y)
|
||||
{
|
||||
// Basically: _____ height < y < maxY
|
||||
// _______&&: depth ______ < y < maxY
|
||||
if (firstFace)
|
||||
{
|
||||
builder.addQuadAdj(direction, x, y, z, w0, wy, color, DataPointUtil.getLightSky(adjPoint),
|
||||
blockLight);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Now: depth < height < y < previousDepth < maxY
|
||||
if (previousDepth == -1)
|
||||
throw new RuntimeException("Loop error");
|
||||
builder.addQuadAdj(direction, x, y, z, w0, (short) (previousDepth - y), color,
|
||||
DataPointUtil.getLightSky(adjPoint), blockLight);
|
||||
previousDepth = -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (depth <= y)
|
||||
{ // AND y <= height
|
||||
if (y + wy <= height)
|
||||
{
|
||||
// Basically: ________ y < maxY <= height
|
||||
// _______&&: depth <= y < maxY
|
||||
// The face is inside adj face completely.
|
||||
if (overlapColor != 0)
|
||||
{
|
||||
builder.addQuadAdj(direction, x, y, z, w0, wy, overlapColor, (byte) 15, (byte) 15);
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Otherwise: ________ y <= Height < maxY
|
||||
// _______&&: depth <= y _________ < maxY
|
||||
// the adj data intersects the lower part of the current data
|
||||
if (height > y && overlapColor != 0)
|
||||
{
|
||||
builder.addQuadAdj(direction, x, y, z, w0, (short) (height - y), overlapColor, (byte) 15, (byte) 15);
|
||||
}
|
||||
// if this is the only face, use the maxY and break,
|
||||
// if there was another face we finish the last one and break
|
||||
if (firstFace)
|
||||
{
|
||||
builder.addQuadAdj(direction, x, height, z, w0, (short) (y + wy - height), color,
|
||||
DataPointUtil.getLightSky(adjPoint), blockLight);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Now: depth <= y <= height <= previousDepth < maxY
|
||||
if (previousDepth == -1)
|
||||
throw new RuntimeException("Loop error");
|
||||
if (previousDepth > height)
|
||||
{
|
||||
builder.addQuadAdj(direction, x, height, z, w0, (short) (previousDepth - height), color,
|
||||
DataPointUtil.getLightSky(adjPoint), blockLight);
|
||||
}
|
||||
previousDepth = -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// In here always true: y < depth < maxY
|
||||
// _________________&&: y < _____ (height and maxY)
|
||||
|
||||
if (y + wy <= height)
|
||||
{
|
||||
// Basically: y _______ < maxY <= height
|
||||
// _______&&: y < depth < maxY
|
||||
// the adj data intersects the higher part of the current data
|
||||
if (overlapColor != 0)
|
||||
{
|
||||
builder.addQuadAdj(direction, x, depth, z, w0, (short) (y + wy - depth), overlapColor, (byte) 15, (byte) 15);
|
||||
}
|
||||
// we start the creation of a new face
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise: y < _____ height < maxY
|
||||
// _______&&: y < depth ______ < maxY
|
||||
if (overlapColor != 0)
|
||||
{
|
||||
builder.addQuadAdj(direction, x, depth, z, w0, (short) (height - depth), overlapColor, (byte) 15, (byte) 15);
|
||||
}
|
||||
if (firstFace)
|
||||
{
|
||||
builder.addQuadAdj(direction, x, height, z, w0, (short) (y + wy - height), color,
|
||||
DataPointUtil.getLightSky(adjPoint), blockLight);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Now: y < depth < height <= previousDepth < maxY
|
||||
if (previousDepth == -1)
|
||||
throw new RuntimeException("Loop error");
|
||||
if (previousDepth > height)
|
||||
{
|
||||
builder.addQuadAdj(direction, x, height, z, w0, (short) (previousDepth - height), color,
|
||||
DataPointUtil.getLightSky(adjPoint), blockLight);
|
||||
}
|
||||
previousDepth = -1;
|
||||
}
|
||||
}
|
||||
// set next top as current depth
|
||||
previousDepth = depth;
|
||||
firstFace = false;
|
||||
nextSkyLight = upSkyLight;
|
||||
if (i + 1 < adjData.size() && DataPointUtil.doesItExist(adjData.get(i + 1)))
|
||||
nextSkyLight = DataPointUtil.getLightSky(adjData.get(i + 1));
|
||||
}
|
||||
|
||||
if (allAbove)
|
||||
{
|
||||
builder.addQuadAdj(direction, x, y, z, w0, wy, color, upSkyLight, blockLight);
|
||||
}
|
||||
else if (previousDepth != -1)
|
||||
{
|
||||
// We need to finish the last quad.
|
||||
builder.addQuadAdj(direction, x, y, z, w0, (short) (previousDepth - y), color, nextSkyLight,
|
||||
blockLight);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,15 @@
|
||||
package com.seibel.lod.core.objects.a7.datatype.column;
|
||||
|
||||
import com.seibel.lod.core.enums.LodDirection;
|
||||
import com.seibel.lod.core.objects.LodDataView;
|
||||
import com.seibel.lod.core.objects.a7.DHLevel;
|
||||
import com.seibel.lod.core.objects.a7.LodQuadTree;
|
||||
import com.seibel.lod.core.objects.a7.LodSection;
|
||||
import com.seibel.lod.core.objects.a7.data.DataSourceLoader;
|
||||
import com.seibel.lod.core.objects.a7.pos.DhSectionPos;
|
||||
import com.seibel.lod.core.objects.a7.render.RenderDataSource;
|
||||
import com.seibel.lod.core.objects.opengl.RenderBuffer;
|
||||
import com.seibel.lod.core.objects.a7.render.RenderBuffer;
|
||||
import com.seibel.lod.core.util.LodThreadFactory;
|
||||
import com.seibel.lod.core.util.LodUtil;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
@@ -14,6 +17,9 @@ import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
public class ColumnDatatype implements RenderDataSource, IColumnDatatype {
|
||||
@@ -251,28 +257,57 @@ public class ColumnDatatype implements RenderDataSource, IColumnDatatype {
|
||||
return SECTION_SIZE_OFFSET;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enableRender() {
|
||||
private CompletableFuture<ColumnRenderBuffer> inBuildRenderBuffer = null;
|
||||
|
||||
|
||||
private void tryBuildBuffer(LodQuadTree quadTree) {
|
||||
if (inBuildRenderBuffer == null) {
|
||||
ColumnDatatype[] data = new ColumnDatatype[LodDirection.ADJ_DIRECTIONS.length];
|
||||
for (LodDirection direction : LodDirection.ADJ_DIRECTIONS) {
|
||||
LodSection section = quadTree.getSection(sectionPos.getAdjacent(direction)); //FIXME: Handle traveling through different detail levels
|
||||
if (section.getRenderContainer() != null && section.getRenderContainer() instanceof ColumnRenderBuffer) {
|
||||
data[direction.ordinal()-2] = ((ColumnDatatype) section.getRenderContainer());
|
||||
}
|
||||
}
|
||||
inBuildRenderBuffer = ColumnRenderBuffer.build( this, data);
|
||||
}
|
||||
}
|
||||
private void cancelBuildBuffer() {
|
||||
if (inBuildRenderBuffer != null) {
|
||||
inBuildRenderBuffer.cancel(false);
|
||||
inBuildRenderBuffer = null;
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void enableRender(LodQuadTree quadTree) {
|
||||
tryBuildBuffer(quadTree);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disableRender() {
|
||||
|
||||
cancelBuildBuffer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRenderReady() {
|
||||
return false;
|
||||
return (inBuildRenderBuffer != null && inBuildRenderBuffer.isDone());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
cancelBuildBuffer();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean trySwapRenderBuffer(AtomicReference<RenderBuffer> referenceSlot) {
|
||||
public boolean trySwapRenderBuffer(LodQuadTree quadTree, AtomicReference<RenderBuffer> referenceSlot) {
|
||||
if (inBuildRenderBuffer != null && inBuildRenderBuffer.isDone()) {
|
||||
referenceSlot.set(inBuildRenderBuffer.join());
|
||||
inBuildRenderBuffer = null;
|
||||
return true;
|
||||
} else {
|
||||
tryBuildBuffer(quadTree);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
+331
-1
@@ -1,5 +1,335 @@
|
||||
package com.seibel.lod.core.objects.a7.datatype.column;
|
||||
|
||||
public class ColumnRenderBuffer {
|
||||
import com.seibel.lod.core.Config;
|
||||
import com.seibel.lod.core.api.internal.ClientApi;
|
||||
import com.seibel.lod.core.builders.lodBuilding.LodBuilder;
|
||||
import com.seibel.lod.core.builders.lodBuilding.bufferBuilding.CubicLodTemplate;
|
||||
import com.seibel.lod.core.builders.lodBuilding.bufferBuilding.LodBufferBuilderFactory;
|
||||
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;
|
||||
import com.seibel.lod.core.enums.rendering.GLProxyContext;
|
||||
import com.seibel.lod.core.logging.ConfigBasedLogger;
|
||||
import com.seibel.lod.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.lod.core.objects.a7.render.RenderBuffer;
|
||||
import com.seibel.lod.core.render.GLProxy;
|
||||
import com.seibel.lod.core.render.LodRenderProgram;
|
||||
import com.seibel.lod.core.render.LodRenderer;
|
||||
import com.seibel.lod.core.render.objects.GLVertexBuffer;
|
||||
import com.seibel.lod.core.util.*;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.lwjgl.opengl.GL32;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Iterator;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static com.seibel.lod.core.render.GLProxy.GL_LOGGER;
|
||||
import static com.seibel.lod.core.render.LodRenderer.EVENT_LOGGER;
|
||||
|
||||
|
||||
public class ColumnRenderBuffer extends RenderBuffer {
|
||||
//TODO: Make the pool use configurable number of threads
|
||||
public static final ExecutorService BUFFER_BUILDERS =
|
||||
Executors.newCachedThreadPool(new LodThreadFactory("ColumnBufferBuilders", 5));
|
||||
public static final ExecutorService BUFFER_UPLOADER = LodUtil.makeSingleThreadPool("ColumnBufferUploader");
|
||||
|
||||
public static final ConfigBasedLogger EVENT_LOGGER = new ConfigBasedLogger(LogManager.getLogger(LodRenderer.class),
|
||||
() -> Config.Client.Advanced.Debugging.DebugSwitch.logRendererBufferEvent.get());
|
||||
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;
|
||||
|
||||
public ColumnRenderBuffer() {
|
||||
vbos = new GLVertexBuffer[0];
|
||||
}
|
||||
|
||||
|
||||
private void _uploadBuffersDirect(LodQuadBuilder builder, GpuUploadMethod method) throws InterruptedException {
|
||||
resize(builder.getCurrentNeededVertexBufferCount());
|
||||
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);
|
||||
int size = bb.limit() - bb.position();
|
||||
try {
|
||||
vbo.bind();
|
||||
vbo.uploadBuffer(bb, size/LodUtil.LOD_VERTEX_FORMAT.getByteSize(), method, LodBufferBuilderFactory.FULL_SIZED_BUFFER);
|
||||
} catch (Exception e) {
|
||||
vbos[i-1] = null;
|
||||
vbo.close();
|
||||
LOGGER.error("Failed to upload buffer: ", e);
|
||||
}
|
||||
if (BPerNS<=0) continue;
|
||||
// upload buffers over an extended period of time
|
||||
// to hopefully prevent stuttering.
|
||||
remainingNS += size * BPerNS;
|
||||
if (remainingNS >= TimeUnit.NANOSECONDS.convert(1000 / 60, TimeUnit.MILLISECONDS)) {
|
||||
if (remainingNS > MAX_BUFFER_UPLOAD_TIMEOUT_NANOSECONDS)
|
||||
remainingNS = MAX_BUFFER_UPLOAD_TIMEOUT_NANOSECONDS;
|
||||
Thread.sleep(remainingNS / 1000000, (int) (remainingNS % 1000000));
|
||||
remainingNS = 0;
|
||||
}
|
||||
}
|
||||
if (i < vbos.length) {
|
||||
throw new RuntimeException("Too few vertex buffers!!");
|
||||
}
|
||||
}
|
||||
|
||||
private void _uploadBuffersMapped(LodQuadBuilder builder, GpuUploadMethod method)
|
||||
{
|
||||
resize(builder.getCurrentNeededVertexBufferCount());
|
||||
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++])) {}
|
||||
}
|
||||
|
||||
private GLVertexBuffer getOrMakeVbo(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 boolean uploadBuffer(LodQuadBuilder builder, GpuUploadMethod method) throws InterruptedException {
|
||||
if (method.useEarlyMapping) {
|
||||
_uploadBuffersMapped(builder, method);
|
||||
} else {
|
||||
_uploadBuffersDirect(builder, method);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean render(LodRenderProgram shaderProgram) {
|
||||
boolean hasRendered = false;
|
||||
for (GLVertexBuffer vbo : vbos) {
|
||||
if (vbo == null) continue;
|
||||
if (vbo.getVertexCount() == 0) continue;
|
||||
hasRendered = true;
|
||||
vbo.bind();
|
||||
shaderProgram.bindVertexBuffer(vbo.getId());
|
||||
if (LodRenderer.ENABLE_IBO) {
|
||||
GL32.glDrawElements(GL32.GL_TRIANGLES, (vbo.getVertexCount()/4)*6, ClientApi.renderer.quadIBO.getType(), 0);
|
||||
} else {
|
||||
GL32.glDrawArrays(GL32.GL_TRIANGLES, 0, vbo.getVertexCount());
|
||||
}
|
||||
//LodRenderer.tickLogger.info("Vertex buffer: {}", vbo);
|
||||
}
|
||||
return hasRendered;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debugDumpStats(StatsMap statsMap) {
|
||||
statsMap.incStat("RenderBuffers");
|
||||
statsMap.incStat("SimpleRenderBuffers");
|
||||
for (GLVertexBuffer b : vbos) {
|
||||
if (b == null) continue;
|
||||
statsMap.incStat("VBOs");
|
||||
if (b.getSize() == LodBufferBuilderFactory.FULL_SIZED_BUFFER) {
|
||||
statsMap.incStat("FullsizedVBOs");
|
||||
}
|
||||
if (b.getSize() == 0) GL_LOGGER.warn("VBO with size 0");
|
||||
statsMap.incBytesStat("TotalUsage", b.getSize());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
GLProxy.getInstance().recordOpenGlCall(() -> {
|
||||
for (GLVertexBuffer b : vbos) {
|
||||
if (b == null) continue;
|
||||
b.destroy(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public static CompletableFuture<ColumnRenderBuffer> build(ColumnDatatype data, ColumnDatatype[] adjData) {
|
||||
EVENT_LOGGER.trace("RenderRegion startBuild @ {}", data.sectionPos);
|
||||
return CompletableFuture.supplyAsync(() -> {
|
||||
try {
|
||||
EVENT_LOGGER.trace("RenderRegion start QuadBuild @ {}", data.sectionPos);
|
||||
int skyLightCullingBelow = Config.Client.Graphics.AdvancedGraphics.caveCullingHeight.get();
|
||||
// FIXME: Clamp also to the max world height.
|
||||
skyLightCullingBelow = Math.max(skyLightCullingBelow, LodBuilder.MIN_WORLD_HEIGHT);
|
||||
LodQuadBuilder builder = new LodQuadBuilder(true, skyLightCullingBelow);
|
||||
Runnable buildRun = ()->{
|
||||
makeLodRenderData(builder, data, adjData);
|
||||
};
|
||||
buildRun.run();
|
||||
EVENT_LOGGER.trace("RenderRegion end QuadBuild @ {}", data.sectionPos);
|
||||
return builder;
|
||||
} catch (Throwable e3) {
|
||||
EVENT_LOGGER.error("\"LodNodeBufferBuilder\" was unable to build quads: ", e3);
|
||||
throw e3;
|
||||
}
|
||||
}, BUFFER_BUILDERS)
|
||||
.thenApplyAsync((builder) -> {
|
||||
try {
|
||||
EVENT_LOGGER.trace("RenderRegion start Upload @ {}", data.sectionPos);
|
||||
GLProxy glProxy = GLProxy.getInstance();
|
||||
GpuUploadMethod method = GLProxy.getInstance().getGpuUploadMethod();
|
||||
GLProxyContext oldContext = glProxy.getGlContext();
|
||||
glProxy.setGlContext(GLProxyContext.LOD_BUILDER);
|
||||
ColumnRenderBuffer buffer = new ColumnRenderBuffer();
|
||||
try {
|
||||
buffer.uploadBuffer(builder, method);
|
||||
} finally {
|
||||
glProxy.setGlContext(oldContext); //FIXME: Close buffer on exception?
|
||||
}
|
||||
EVENT_LOGGER.trace("RenderRegion end Upload @ {}", data.sectionPos);
|
||||
return buffer;
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (Throwable e3) {
|
||||
EVENT_LOGGER.error("\"LodNodeBufferBuilder\" was unable to upload buffer: ", e3);
|
||||
throw e3;
|
||||
}
|
||||
}, BUFFER_UPLOADER).handle((v, e) -> {
|
||||
if (e != null) {
|
||||
return null;
|
||||
} else {
|
||||
return v;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static void makeLodRenderData(LodQuadBuilder quadBuilder, ColumnDatatype region, ColumnDatatype[] adjRegions) {
|
||||
|
||||
// Variable initialization
|
||||
DebugMode debugMode = Config.Client.Advanced.Debugging.debugMode.get();
|
||||
|
||||
byte detailLevel = region.getDataDetail();
|
||||
int dataSize = 1 << detailLevel;
|
||||
for (int x = 0; x < dataSize; x++) {
|
||||
for (int z = 0; z < dataSize; z++) {
|
||||
ColumnArrayView posData = region.getVerticalDataView(x, z);
|
||||
if (posData.size() == 0 || !DataPointUtil.doesItExist(posData.get(0))
|
||||
|| DataPointUtil.isVoid(posData.get(0)))
|
||||
continue;
|
||||
|
||||
ColumnArrayView[][] adjData = new ColumnArrayView[4][];
|
||||
// We extract the adj data in the four cardinal direction
|
||||
|
||||
// we first reset the adjShadeDisabled. This is used to disable the shade on the
|
||||
// border when we have transparent block like water or glass
|
||||
// to avoid having a "darker border" underground
|
||||
// Arrays.fill(adjShadeDisabled, false);
|
||||
|
||||
// We check every adj block in each direction
|
||||
|
||||
// If the adj block is rendered in the same region and with same detail
|
||||
// and is positioned in a place that is not going to be rendered by vanilla game
|
||||
// then we can set this position as adj
|
||||
// We avoid cases where the adjPosition is in player chunk while the position is
|
||||
// not
|
||||
// to always have a wall underwater
|
||||
for (LodDirection lodDirection : LodDirection.ADJ_DIRECTIONS) {
|
||||
try {
|
||||
int xAdj = x + lodDirection.getNormal().x;
|
||||
int zAdj = z + lodDirection.getNormal().z;
|
||||
boolean isCrossRegionBoundary = (xAdj < 0 || xAdj >= dataSize) ||
|
||||
(zAdj < 0 || zAdj >= dataSize);
|
||||
ColumnDatatype adjRegion;
|
||||
byte adjDetail;
|
||||
|
||||
//we check if the detail of the adjPos is equal to the correct one (region border fix)
|
||||
//or if the detail is wrong by 1 value (region+circle border fix)
|
||||
if (isCrossRegionBoundary) {
|
||||
//we compute at which detail that position should be rendered
|
||||
adjRegion = adjRegions[lodDirection.ordinal()-2];
|
||||
if(adjRegion == null) continue;
|
||||
adjDetail = adjRegion.getDataDetail();
|
||||
if (adjDetail != detailLevel) {
|
||||
//TODO: Implement this
|
||||
} else {
|
||||
if (xAdj < 0) xAdj += dataSize;
|
||||
if (zAdj < 0) zAdj += dataSize;
|
||||
if (xAdj >= dataSize) xAdj -= dataSize;
|
||||
if (zAdj >= dataSize) zAdj -= dataSize;
|
||||
}
|
||||
} else {
|
||||
adjRegion = region;
|
||||
adjDetail = detailLevel;
|
||||
}
|
||||
|
||||
if (adjDetail < detailLevel-1 || adjDetail > detailLevel+1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (adjDetail == detailLevel || adjDetail > detailLevel) {
|
||||
adjData[lodDirection.ordinal() - 2] = new ColumnArrayView[1];
|
||||
adjData[lodDirection.ordinal() - 2][0] = adjRegion.getVerticalDataView(xAdj, zAdj);
|
||||
} else {
|
||||
adjData[lodDirection.ordinal() - 2] = new ColumnArrayView[2];
|
||||
adjData[lodDirection.ordinal() - 2][0] = adjRegion.getVerticalDataView(xAdj, zAdj);
|
||||
adjData[lodDirection.ordinal() - 2][1] = adjRegion.getVerticalDataView(
|
||||
xAdj + (lodDirection.getAxis()==LodDirection.Axis.X ? 0 : 1),
|
||||
zAdj + (lodDirection.getAxis()==LodDirection.Axis.Z ? 0 : 1));
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
EVENT_LOGGER.warn("Failed to get adj data for [{}:{},{}] at [{}]", detailLevel, x, z, lodDirection);
|
||||
EVENT_LOGGER.warn("Detail exception: ", e);
|
||||
}
|
||||
}
|
||||
|
||||
// We render every vertical lod present in this position
|
||||
// We only stop when we find a block that is void or non-existing block
|
||||
for (int i = 0; i < posData.size(); i++) {
|
||||
long data = posData.get(i);
|
||||
// If the data is not renderable (Void or non-existing) we stop since there is
|
||||
// no data left in this position
|
||||
if (DataPointUtil.isVoid(data) || !DataPointUtil.doesItExist(data))
|
||||
break;
|
||||
|
||||
long adjDataTop = i - 1 >= 0 ? posData.get(i - 1) : DataPointUtil.EMPTY_DATA;
|
||||
long adjDataBot = i + 1 < posData.size() ? posData.get(i + 1) : DataPointUtil.EMPTY_DATA;
|
||||
|
||||
// We send the call to create the vertices
|
||||
CubicLodTemplate.addLodToBuffer(data, adjDataTop, adjDataBot, adjData, detailLevel,
|
||||
x, z, quadBuilder, debugMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
quadBuilder.mergeQuads();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
package com.seibel.lod.core.objects.a7.render;
|
||||
|
||||
import com.seibel.lod.core.objects.a7.LodQuadTree;
|
||||
import com.seibel.lod.core.objects.a7.data.LodDataSource;
|
||||
import com.seibel.lod.core.objects.a7.pos.DhSectionPos;
|
||||
import com.seibel.lod.core.objects.opengl.RenderBuffer;
|
||||
import com.seibel.lod.core.objects.a7.render.RenderBuffer;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
@@ -11,23 +12,34 @@ public class EmptyRenderContainer implements RenderDataSource {
|
||||
|
||||
// NOTE: No register() needed since this should never be loaded from a actual data.
|
||||
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
public void enableRender(LodQuadTree quadTree) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unload() {
|
||||
public void disableRender() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRenderReady() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean trySwapRenderBuffer(AtomicReference<RenderBuffer> referenceSlot) {
|
||||
public byte getDetailOffset() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean trySwapRenderBuffer(LodQuadTree quadTree, AtomicReference<RenderBuffer> referenceSlot) {
|
||||
return false; // no swap
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
|
||||
* licensed under the GNU LGPL 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 Lesser 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.lod.core.objects.a7.render;
|
||||
|
||||
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;
|
||||
|
||||
import java.util.ConcurrentModificationException;
|
||||
|
||||
public abstract class RenderBuffer implements AutoCloseable
|
||||
{
|
||||
// ======================================================================
|
||||
// ====================== Methods for implementations ===================
|
||||
// ======================================================================
|
||||
|
||||
// ========== Called by render thread ==========
|
||||
/* Called on... well... rendering.
|
||||
* Return false if nothing rendered. (Optional) */
|
||||
public abstract boolean render(LodRenderProgram shaderProgram);
|
||||
|
||||
// ========== Called by any thread. (thread safe) ==========
|
||||
|
||||
/* Called by anyone. This method is allowed to throw exceptions, but
|
||||
* are never allowed to modify any values. This should behave the same
|
||||
* to other methods as if the method have never been called.
|
||||
* Note: This method is PURELY for debug or stats logging ONLY! */
|
||||
public abstract void debugDumpStats(StatsMap statsMap);
|
||||
|
||||
// ========= Called only when 1 thread is using it =======
|
||||
/* This method is called when object is no longer in use.
|
||||
* Called either after uploadBuffers() returned false (On buffer Upload
|
||||
* thread), or by others when the object is not being used. (not in build,
|
||||
* upload, or render state). */
|
||||
public abstract void close();
|
||||
|
||||
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import com.seibel.lod.core.objects.Pos2D;
|
||||
import com.seibel.lod.core.objects.a7.LodQuadTree;
|
||||
import com.seibel.lod.core.objects.a7.LodSection;
|
||||
import com.seibel.lod.core.objects.a7.pos.DhSectionPos;
|
||||
import com.seibel.lod.core.objects.opengl.RenderBuffer;
|
||||
import com.seibel.lod.core.objects.a7.render.RenderBuffer;
|
||||
import com.seibel.lod.core.render.LodRenderProgram;
|
||||
import com.seibel.lod.core.util.LodUtil;
|
||||
import com.seibel.lod.core.util.gridList.MovableGridRingList;
|
||||
@@ -57,7 +57,7 @@ public class RenderBufferHandler {
|
||||
}
|
||||
} else {
|
||||
LodUtil.assertTrue(container != null); // section.isLoaded() should have ensured this
|
||||
container.trySwapRenderBuffer(renderBufferSlot);
|
||||
container.trySwapRenderBuffer(target, renderBufferSlot);
|
||||
}
|
||||
|
||||
// Update children's render buffer state
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.seibel.lod.core.objects.a7.render;
|
||||
|
||||
import com.seibel.lod.core.objects.opengl.RenderBuffer;
|
||||
import com.seibel.lod.core.objects.a7.LodQuadTree;
|
||||
import com.seibel.lod.core.objects.a7.render.RenderBuffer;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
@@ -43,7 +44,7 @@ public interface RenderDataSource {
|
||||
// return null;
|
||||
// }
|
||||
|
||||
void enableRender();
|
||||
void enableRender(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)
|
||||
@@ -56,6 +57,6 @@ public interface RenderDataSource {
|
||||
* @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(AtomicReference<RenderBuffer> referenceSlot);
|
||||
boolean trySwapRenderBuffer(LodQuadTree quadTree, AtomicReference<RenderBuffer> referenceSlot);
|
||||
|
||||
}
|
||||
|
||||
@@ -252,18 +252,6 @@ public class RenderRegion implements AutoCloseable
|
||||
});
|
||||
}
|
||||
|
||||
private static final int ADJACENT8[][] = {
|
||||
{-1,-1},
|
||||
{-1, 0},
|
||||
{-1, 1},
|
||||
{ 0,-1},
|
||||
//{ 0, 0},
|
||||
{ 0, 1},
|
||||
{ 1,-1},
|
||||
{ 1, 0},
|
||||
{ 1, 1}
|
||||
};
|
||||
|
||||
private static void makeLodRenderData(LodQuadBuilder quadBuilder, LodRegion region, LodRegion[] adjRegions, int playerX,
|
||||
int playerZ) {
|
||||
byte minDetail = region.getMinDetailLevel();
|
||||
|
||||
Reference in New Issue
Block a user